put snr_curve.sh system back in from codec2-dev, curves for datac14

dr-datac14
drowe67 2024-03-30 08:08:09 +10:30 committed by David Rowe
parent 3b9037c9c7
commit 23a7d60bf8
7 changed files with 611 additions and 2 deletions

View File

@ -30,7 +30,7 @@ Feature Requests can be submitted via GitHub Issues.
Before writing any code or submitting a PR - **please discuss** the PR with developers by raising a GitHub Issue. We have many years of experience and a carefully considered plan for Codec 2 development, and can guide you on work that will most benefit this project. Before writing any code or submitting a PR - **please discuss** the PR with developers by raising a GitHub Issue. We have many years of experience and a carefully considered plan for Codec 2 development, and can guide you on work that will most benefit this project.
Some key guidelines about the code in the `codec2` repo: Some key guidelines about the code in the `codec2` repo:
1. Code that is required to build libcodec2, or to test libcodec2 goes in codec2. 1. Only code that is required to build, test, or document libcodec2 goes in codec2.
2. Experimental work, code used for algorithm development, should probably go into some other repo. 2. Experimental work, code used for algorithm development, should probably go into some other repo.
3. Only widely used “production” code goes in codec2. If it has an user base of < 2 (e.g. personal projects, early R&D) - it should probably be application code or a fork. 3. Only widely used “production” code goes in codec2. If it has an user base of < 2 (e.g. personal projects, early R&D) - it should probably be application code or a fork.

View File

@ -146,6 +146,7 @@ These modes use an OFDM modem with powerful LDPC codes and are designed for send
| DATAC3 | 500 | 321 | 126 | (2048,1024) | 3.19 | 74/100 at 0dB | Forward link data (low SNR) | | DATAC3 | 500 | 321 | 126 | (2048,1024) | 3.19 | 74/100 at 0dB | Forward link data (low SNR) |
| DATAC4 | 250 | 87 | 56 | (1472,448) | 5.17 | 90/100 at -4dB | Forward link data (low SNR) | | DATAC4 | 250 | 87 | 56 | (1472,448) | 5.17 | 90/100 at -4dB | Forward link data (low SNR) |
| DATAC13 | 200 | 64 | 14 | (384,128) | 2.0 | 90/100 at -4dB | Reverse link ACK packets (low SNR) | | DATAC13 | 200 | 64 | 14 | (384,128) | 2.0 | 90/100 at -4dB | Reverse link ACK packets (low SNR) |
| DATAC14 | 250 | 58 | 3 | (112,56) | 0.69 | 90/100 at -4dB | Reverse link ACK packets (low SNR) |
Notes: Notes:
1. 16 bits (2 bytes) per frame are reserved for a 16 bit CRC, e.g. for `datac3` we have 128 byte frames, and 128-2=126 bytes/frame of payload data. 1. 16 bits (2 bytes) per frame are reserved for a 16 bit CRC, e.g. for `datac3` we have 128 byte frames, and 128-2=126 bytes/frame of payload data.

View File

@ -0,0 +1,267 @@
% snr_curves_plot.m
%
% Companion script for unittest/raw_data_curves
1;
function state_vec = set_graphics_state_print()
textfontsize = get(0,"defaulttextfontsize");
linewidth = get(0,"defaultlinelinewidth");
markersize = get(0, "defaultlinemarkersize");
set(0, "defaulttextfontsize", 16);
set(0, "defaultaxesfontsize", 16);
set(0, "defaultlinelinewidth", 1);
state_vec = [textfontsize linewidth markersize];
endfunction
function set_graphics_state_screen(state_vec)
textfontsize = state_vec(1);
linewidth = state_vec(2);
markersize = state_vec(3);
set(0, "defaulttextfontsize", textfontsize);
set(0, "defaultaxesfontsize", textfontsize);
set(0, "defaultlinelinewidth", linewidth);
set(0, "defaultlinemarkersize", markersize);
endfunction
function [snr_ch per] = snr_scatter(source, mode, channel, colour)
suffix = sprintf("_%s_%s_%s",source, mode, channel);
snr = load(sprintf("snr%s.txt",suffix));
offset = load(sprintf("offset%s.txt",suffix));
snr -= offset;
snr_x = []; snrest_y = [];
for i=1:length(snr)
fn = sprintf('snrest%s_%d.txt',suffix,i);
if exist(fn,'file') == 2
snrest=load(fn);
if i == length(snr)
plot(snr(i)*ones(1,length(snrest)), snrest, sprintf('%s;%s %s;',colour,source,mode));
else
plot(snr(i)*ones(1,length(snrest)), snrest, sprintf('%s',colour));
end
snr_x = [snr_x snr(i)]; snrest_y = [snrest_y mean(snrest)];
end
end
plot(snr_x, snrest_y, sprintf('%s', colour));
endfunction
function [snr_ch per] = per_snr(mode, colour)
snrch = load(sprintf("snrch_%s.txt",mode));
snroffset = load(sprintf("snroffset_%s.txt",mode));
snrch -= snroffset;
per = load(sprintf("per_%s.txt",mode));
plot(snrch, per, sprintf('%so-;%s;', colour, mode));
endfunction
function snrest_snr_screen(source, channel)
clf; hold on;
snr_scatter(source, 'datac0', channel,'b+-')
snr_scatter(source, 'datac1', channel,'g+-')
snr_scatter(source, 'datac3', channel,'r+-')
snr_scatter(source, 'datac4', channel,'c+-')
snr_scatter(source, 'datac13', channel,'m+-')
xlabel('SNR (dB)'); ylabel('SNRest (dB)'); grid('minor');
axis([-12 12 -12 12]);
a = axis;
plot([a(1) a(2)],[a(1) a(2)],'bk-');
hold off; grid;
if strcmp(source,'ctx')
title(sprintf('SNR estimate versus SNR (%s) (no compression)', channel));
else
title(sprintf('SNR estimate versus SNR (%s) (with compression)', channel));
end
legend('location','northwest');
endfunction
function snrest_snr_print(source, channel)
state_vec = set_graphics_state_print();
snrest_snr_screen(source, channel);
print(sprintf("snrest_snr_%s.png", source), "-dpng", "-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
function ber_per_v_snr(source, mode, channel, colour)
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
snr = load(sprintf("snr%s",suffix));
offset = load(sprintf("offset%s",suffix));
snr -= offset;
ber = load(sprintf("ber%s",suffix)) + 1E-6;
per = load(sprintf("per%s",suffix)) + 1E-6;
semilogy(snr, ber, sprintf('%s;%s %s ber;', colour, source, mode));
semilogy(snr, per, sprintf('%s;%s %s per;', colour, source, mode),'linewidth',3,'markersize',10);
endfunction
function per_v_snr(source, mode, channel, colour)
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
snr = load(sprintf("snr%s",suffix));
offset = load(sprintf("offset%s",suffix));
snr -= offset;
per = load(sprintf("per%s",suffix)) + 1E-6;
if strcmp(channel,"awgn")
semilogy(snr, per, sprintf('%s;%s %s;', colour, mode, channel));
else
semilogy(snr, per, sprintf('%s;%s %s;', colour, mode, channel),'linewidth',3,'markersize',10);
end
endfunction
function thruput_v_snr(source, mode, channel, colour)
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
snr = load(sprintf("snr%s",suffix));
offset = load(sprintf("offset%s",suffix));
snr -= offset;
per = load(sprintf("per%s",suffix)) + 1E-6;
if strcmp(mode,"datac0") Rb=291; end;
if strcmp(mode,"datac1") Rb=980; end;
if strcmp(mode,"datac3") Rb=321; end;
if strcmp(mode,"datac4") Rb=87; end;
if strcmp(mode,"datac13") Rb=65; end;
if strcmp(mode,"datac14") Rb=58; end;
if strcmp(channel,"awgn")
plot(snr, Rb*(1-per), sprintf('%s;%s %s;', colour, mode, channel));
else
plot(snr, Rb*(1-per), sprintf('%s;%s %s;', colour, mode, channel),'linewidth',3,'markersize',10);
end
endfunction
function octave_ch_noise_screen(channel)
clf; hold on;
ber_per_v_snr('oct','datac0',channel,'bo-')
ber_per_v_snr('ch' ,'datac0',channel,'bx-')
ber_per_v_snr('oct','datac1',channel,'go-')
ber_per_v_snr('ch' ,'datac1',channel,'gx-')
ber_per_v_snr('oct','datac3',channel,'ro-')
ber_per_v_snr('ch' ,'datac3',channel,'rx-')
xlabel('SNR (dB)'); grid;
hold off;
if strcmp(channel,"awgn")
axis([-6 8 1E-3 1]);
else
axis([-2 12 1E-3 1]);
end
title(sprintf('Comparsion of Measuring SNR from Octave and ch tool (%s)', channel));
endfunction
function octave_ch_noise_print(channel)
state_vec = set_graphics_state_print();
octave_ch_noise_screen(channel);
print(sprintf("octave_ch_noise_%s.png", channel), "-dpng","-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
function octave_c_tx_screen(channel)
clf; hold on;
ber_per_v_snr('oct','datac0',channel,'bo-')
ber_per_v_snr('ctx','datac0',channel,'bx-')
ber_per_v_snr('oct','datac1',channel,'go-')
ber_per_v_snr('ctx','datac1',channel,'gx-')
ber_per_v_snr('oct','datac3',channel,'ro-')
ber_per_v_snr('ctx','datac3',channel,'rx-')
xlabel('SNR (dB)'); grid;
hold off;
if strcmp(channel,"awgn")
axis([-6 8 1E-3 1]);
else
axis([-2 12 1E-3 1]);
end
title(sprintf('Comparsion of Octave Tx and C Tx (no compression) (%s)', channel));
endfunction
function octave_c_tx_print(channel)
state_vec = set_graphics_state_print();
octave_c_tx_screen(channel);
print(sprintf("octave_c_tx_%s.png", channel), "-dpng","-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
function octave_c_tx_comp_screen(channel)
clf; hold on;
ber_per_v_snr('oct','datac0',channel,'bo-')
ber_per_v_snr('ctxc','datac0',channel,'bx-')
ber_per_v_snr('oct','datac1',channel,'go-')
ber_per_v_snr('ctxc','datac1',channel,'gx-')
ber_per_v_snr('oct','datac3',channel,'ro-')
ber_per_v_snr('ctxc','datac3',channel,'rx-')
xlabel('SNR (dB)'); grid;
hold off;
if strcmp(channel,"awgn")
axis([-6 8 1E-3 1]);
else
axis([-2 12 1E-3 1]);
end
title(sprintf('Comparsion of Octave Tx and C Tx (with compression) (%s)', channel));
endfunction
function octave_c_tx_comp_print(channel)
state_vec = set_graphics_state_print();
octave_c_tx_comp_screen(channel);
print(sprintf("octave_c_tx_comp_%s.png", channel), "-dpng","-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
% composite AWGN and MPP for compressed
function c_tx_comp_screen
clf; hold on;
per_v_snr('ctxc','datac0','awgn','bo-')
per_v_snr('ctxc','datac1','awgn','go-')
per_v_snr('ctxc','datac3','awgn','ro-')
per_v_snr('ctxc','datac4','awgn','co-')
per_v_snr('ctxc','datac13','awgn','mo-')
per_v_snr('ctxc','datac14','awgn','ko-')
per_v_snr('ctxc','datac0','mpp','bx-')
per_v_snr('ctxc','datac1','mpp','gx-')
per_v_snr('ctxc','datac3','mpp','rx-')
per_v_snr('ctxc','datac4','mpp','cx-')
per_v_snr('ctxc','datac13','mpp','mx-')
per_v_snr('ctxc','datac14','mpp','kx-')
xlabel('SNR (dB)'); ylabel('PER'); grid;
hold off;
axis([-10 14 1E-3 1]);
title('PER of C Raw Data Modes (with compression)');
endfunction
function c_tx_comp_print;
state_vec = set_graphics_state_print();
c_tx_comp_screen;
print("c_tx_comp.png", "-dpng","-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
function c_tx_comp_thruput_screen
clf; hold on;
thruput_v_snr('ctxc','datac0','awgn','bo-')
thruput_v_snr('ctxc','datac1','awgn','go-')
thruput_v_snr('ctxc','datac3','awgn','ro-')
thruput_v_snr('ctxc','datac4','awgn','co-')
thruput_v_snr('ctxc','datac13','awgn','mo-')
thruput_v_snr('ctxc','datac14','awgn','ko-')
thruput_v_snr('ctxc','datac0','mpp','bx-')
thruput_v_snr('ctxc','datac1','mpp','gx-')
thruput_v_snr('ctxc','datac3','mpp','rx-')
thruput_v_snr('ctxc','datac4','mpp','cx-')
thruput_v_snr('ctxc','datac13','mpp','mx-')
thruput_v_snr('ctxc','datac14','mpp','kx-')
xlabel('SNR (dB)'); ylabel('bits/s'); grid;
hold off;
axis([-10 10 0 1000]);
title(' Throughput for C Tx (with compression)');
legend('location','west');
endfunction
function c_tx_comp_thruput_print;
state_vec = set_graphics_state_print;
c_tx_comp_thruput_screen;
print("c_tx_comp_thruput.png", "-dpng","-S1000,800");
set_graphics_state_screen(state_vec);
endfunction
#{
figure(1); octave_ch_noise_screen;
figure(2); octave_c_tx_screen;
figure(3); octave_c_tx_comp_screen
figure(4); snrest_snr_screen;
figure(5); octave_ch_noise_print;
figure(6); octave_c_tx_print;
figure(7); octave_c_tx_comp_print;
figure(8); snrest_snr_print;
#}

View File

@ -256,7 +256,7 @@ int main(int argc, char *argv[]) {
stderr, stderr,
"\nAdjust path --fading_dir or use GNU Octave to generate:\n\n"); "\nAdjust path --fading_dir or use GNU Octave to generate:\n\n");
gen_fading_file: gen_fading_file:
fprintf(stderr, "$ octave --no-gui\n"); fprintf(stderr, "$ octave-cli\n");
fprintf(stderr, "octave:24> pkg load signal\n"); fprintf(stderr, "octave:24> pkg load signal\n");
fprintf(stderr, "octave:24> time_secs=60\n"); fprintf(stderr, "octave:24> time_secs=60\n");
fprintf(stderr, fprintf(stderr,

View File

@ -51,6 +51,7 @@ if [ "$1" == "LPCNet" ]; then
data_test "datac3" data_test "datac3"
data_test "datac4" data_test "datac4"
data_test "datac13" data_test "datac13"
data_test "datac14"
fi fi
exit 0 exit 0

View File

@ -0,0 +1,149 @@
# Makefile
# Dec 2022
#
# Automates PER/BER curve generation for raw data mode:
#
# 1. Compare "ch" noise injection/SNR measurement against reference Octave Tx
# 2. Compare C Tx against Octave Tx (with and without compression)
# 3. Plot curves for SNR estimated from C Rx against actual SNR
# 4. Plot AWGN/PER C Tx curves for end user documentation
#
# usage:
#
# 1. Create 20 minutes of MPP fading samples:
# $ cd codec2/octave/
# $ octave-cli
# octave:24> pkg load signal
# octave:24> time_secs=60*20
# octave:26> ch_fading("~/codec2/build_linux/unittest/fast_fading_samples.float", 8000, 1.0, 8000*time_secs)
#
# 2. Run scripts:
#
# $ make
SHELL := /bin/bash
CODEC2 := $(HOME)/codec2
all: test \
octave_ch_noise_awgn.png octave_c_tx_awgn.png octave_c_tx_comp_awgn.png \
octave_ch_noise_mpp.png octave_c_tx_mpp.png octave_c_tx_comp_mpp.png \
snrest_snr_ctx.png snrest_snr_ctxc.png \
c_tx_comp.png c_tx_comp_thruput.png
clean:
rm -f *.txt *.png *.raw
# run this first, traps common CML setup error
test:
source snr_curves.sh; test_ldpc
# subset of files generated, but enough to set up Makefile dependencies
snr_oct = snr_oct_datac0_awgn.txt snr_oct_datac1_awgn.txt snr_oct_datac3_awgn.txt
snr_ch = snr_ch_datac0_awgn.txt snr_ch_datac1_awgn.txt snr_ch_datac3_awgn.txt
snr_ctx = snr_ctx_datac0_awgn.txt snr_ctx_datac1_awgn.txt snr_ctx_datac3_awgn.txt
snr_ctxc = snr_ctxc_datac0_awgn.txt snr_ctxc_datac3_awgn.txt
snr_oct_mpp = snr_oct_datac0_mpp.txt snr_oct_datac1_mpp.txt snr_oct_datac3_mpp.txt
snr_ch_mpp = snr_ch_datac0_mpp.txt snr_ch_datac1_mpp.txt snr_ch_datac3_mpp.txt
snr_ctx_mpp = snr_ctx_datac0_mpp.txt snr_ctx_datac1_mpp.txt snr_ctx_datac3_mpp.txt
snr_ctxc_mpp = snr_ctxc_datac0_mpp.txt snr_ctxc_datac3_mpp.txt
$(snr_oct):
source snr_curves.sh; generate_octave_tx_data datac0 awgn
source snr_curves.sh; generate_octave_tx_data datac1 awgn
source snr_curves.sh; generate_octave_tx_data datac3 awgn
$(snr_oct_mpp):
source snr_curves.sh; generate_octave_tx_data datac0 mpp
source snr_curves.sh; generate_octave_tx_data datac1 mpp
source snr_curves.sh; generate_octave_tx_data datac3 mpp
$(snr_ch):
source snr_curves.sh; generate_ch_data datac0 awgn
source snr_curves.sh; generate_ch_data datac1 awgn
source snr_curves.sh; generate_ch_data datac3 awgn
$(snr_ch_mpp):
source snr_curves.sh; generate_ch_data datac0 mpp
source snr_curves.sh; generate_ch_data datac1 mpp
source snr_curves.sh; generate_ch_data datac3 mpp
# C without compression
$(snr_ctx):
source snr_curves.sh; generate_snrest_v_snr_data datac0 awgn
source snr_curves.sh; generate_snrest_v_snr_data datac1 awgn
source snr_curves.sh; generate_snrest_v_snr_data datac3 awgn
source snr_curves.sh; generate_snrest_v_snr_data datac4 awgn
source snr_curves.sh; generate_snrest_v_snr_data datac13 awgn
source snr_curves.sh; generate_snrest_v_snr_data datac14 awgn
$(snr_ctx_mpp):
source snr_curves.sh; generate_snrest_v_snr_data datac0 mpp
source snr_curves.sh; generate_snrest_v_snr_data datac1 mpp
source snr_curves.sh; generate_snrest_v_snr_data datac3 mpp
source snr_curves.sh; generate_snrest_v_snr_data datac4 mpp
source snr_curves.sh; generate_snrest_v_snr_data datac13 mpp
source snr_curves.sh; generate_snrest_v_snr_data datac14 mpp
# C with compression
$(snr_ctxc):
source snr_curves.sh; generate_snrest_v_snr_data datac0 awgn 1
source snr_curves.sh; generate_snrest_v_snr_data datac1 awgn 1
source snr_curves.sh; generate_snrest_v_snr_data datac3 awgn 1
source snr_curves.sh; generate_snrest_v_snr_data datac4 awgn 1
source snr_curves.sh; generate_snrest_v_snr_data datac13 awgn 1
source snr_curves.sh; generate_snrest_v_snr_data datac14 awgn 1
$(snr_ctxc_mpp):
source snr_curves.sh; generate_snrest_v_snr_data datac0 mpp 1
source snr_curves.sh; generate_snrest_v_snr_data datac1 mpp 1
source snr_curves.sh; generate_snrest_v_snr_data datac3 mpp 1
source snr_curves.sh; generate_snrest_v_snr_data datac4 mpp 1
source snr_curves.sh; generate_snrest_v_snr_data datac13 mpp 1
source snr_curves.sh; generate_snrest_v_snr_data datac14 mpp 1
# Octave and C curves should be on top of each other, indicating Octave
# and ch noise injection/SNR measurement are equivalent
octave_ch_noise_awgn.png: $(snr_oct) $(snr_ch)
echo "snr_curves_plot; octave_ch_noise_print('awgn'); quit" | \
octave-cli -p $(CODEC2)/octave
octave_ch_noise_mpp.png: $(snr_oct_mpp) $(snr_ch_mpp)
echo "snr_curves_plot; octave_ch_noise_print('mpp'); quit" | \
octave-cli -p $(CODEC2)/octave
# Octave Tx and C Tx curves should be on top of each other
octave_c_tx_awgn.png: $(snr_oct) $(snr_ctx)
echo "snr_curves_plot; octave_c_tx_print('awgn'); quit" | \
octave-cli -p $(CODEC2)/octave
octave_c_tx_mpp.png: $(snr_oct_mpp) $(snr_ctx_mpp)
echo "snr_curves_plot; octave_c_tx_print('mpp'); quit" | \
octave-cli -p $(CODEC2)/octave
# Octave Tx and C Tx (compressed) curves should be close, but C may be 1dB
# poorer
octave_c_tx_comp_awgn.png: $(snr_oc) $(snr_ctxc)
echo "snr_curves_plot; octave_c_tx_comp_print('awgn'); quit" | \
octave-cli -p $(CODEC2)/octave
octave_c_tx_comp_mpp.png: $(snr_oct_mpp) $(snr_ctxc_mpp)
echo "snr_curves_plot; octave_c_tx_comp_print('mpp'); quit" | \
octave-cli -p $(CODEC2)/octave
# combined AWGN and MPP from C Tx (compressed) - what end users would run
c_tx_comp.png: $(snr_ctxc) $(snr_ctxc_mpp)
echo "snr_curves_plot; c_tx_comp_print; quit" | \
octave-cli -p $(CODEC2)/octave
# Curves of SNR estimates from C Rx compared to actual SNR, useful for "gear shifting"
snrest_snr_ctx.png: $(snr_ctx)
echo "snr_curves_plot; snrest_snr_print('ctx', 'awgn'); quit" | \
octave-cli -p $(CODEC2)/octave
snrest_snr_ctxc.png: $(snr_ctxc)
echo "snr_curves_plot; snrest_snr_print('ctxc', 'awgn'); quit" | \
octave-cli -p $(CODEC2)/octave
# Throughput of payload data in bits/s of modes against SNR
c_tx_comp_thruput.png: $(snr_ctxc) $(snr_ctxc_mpp)
echo "snr_curves_plot; c_tx_comp_thruput_print; quit" | \
octave-cli -p $(CODEC2)/octave

View File

@ -0,0 +1,191 @@
# snr_curves.sh
#
# Library of bash functions to generate data for SNR curves.
#
# testing a function example:
# $ bash -c "source ./snr_curves.sh; generate_octave_tx_data datac0 awgn"
set -x
PATH=${PATH}:${HOME}/codec2/build_linux/src
CODEC2=${HOME}/codec2
FADING_DIR=${CODEC2}/build_linux/unittest
snr_list='-5 -4 -3 -2 0 1 2 4'
No_list='-13 -14 -15 -16 -18 -20 -22 -24 -26'
Nbursts_awgn=20
Nbursts_mpp=100
# Octave Tx injects noise and is source of truth for SNR, measure BER/PER v SNR
function generate_octave_tx_data {
mode=$1
channel=$2
Nbursts=$Nbursts_awgn
snr_nudge=0
if [ "$channel" == "mpp" ]; then
Nbursts=$Nbursts_mpp
snr_nudge=4
fi
rx_log=$(mktemp)
i=1
rm -f snr_oct_${mode}_${channel}*.txt
rm -f ber_oct_${mode}_${channel}*.txt
rm -f per_oct_${mode}_${channel}*.txt
for snr in $snr_list
do
snr_adj=$((${snr}+${snr_nudge}))
echo "warning ('off', 'Octave:data-file-in-path');
ofdm_ldpc_tx('test_${mode}.raw','${mode}',1,${snr_adj},'${channel}','bursts',${Nbursts},'crc');
quit" | DISPLAY="" octave-cli -p ${CODEC2}/octave
freedv_data_raw_rx --testframes $mode test_${mode}.raw /dev/null 2>${rx_log} -v
BERmeas=$(cat ${rx_log} | grep 'BER......:' | cut -d' ' -f2)
PERmeas=$(cat ${rx_log} | grep 'Coded FER' | cut -d' ' -f3)
echo ${snr_adj} >> snr_oct_${mode}_${channel}.txt
echo ${BERmeas} >> ber_oct_${mode}_${channel}.txt
echo ${PERmeas} >> per_oct_${mode}_${channel}.txt
i=$((i+1))
done
echo 0 > offset_oct_${mode}_${channel}.txt
}
# ch injects noise and is source of truth for SNR, measure BER/PER v SNR
# Octave Tx
function generate_ch_data {
mode=$1
channel=$2
ch_multipath=''
Nbursts=$Nbursts_awgn
snr_nudge=0
if [ "$channel" == "mpp" ]; then
ch_multipath='--mpp'
Nbursts=$Nbursts_mpp
snr_nudge=4
fi
octave_log=$(mktemp)
ch_log=$(mktemp)
rx_log=$(mktemp)
i=1
rm -f snr_ch_${mode}_${channel}*.txt
rm -f ber_ch_${mode}_${channel}*.txt
rm -f per_ch_${mode}_${channel}*.txt
for No in $No_list
do
No_adj=$((${No}-${snr_nudge}))
echo "warning ('off', 'Octave:data-file-in-path');
ofdm_ldpc_tx('test_${mode}.raw','${mode}',1,100,'awgn','bursts',${Nbursts},'crc');
quit" | DISPLAY="" octave-cli -p ${CODEC2}/octave 1>${octave_log}
SNRoffset=$(cat ${octave_log} | grep 'Burst offset:' | cut -d' ' -f5)
ch test_${mode}.raw - --No $No_adj ${ch_multipath} --fading_dir ${FADING_DIR} 2>>${ch_log} | \
freedv_data_raw_rx --testframes $mode - /dev/null -v 2>${rx_log}
BERmeas=$(cat ${rx_log} | grep 'BER......:' | cut -d' ' -f2)
PERmeas=$(cat ${rx_log} | grep 'Coded FER' | cut -d' ' -f3)
echo ${BERmeas} >> ber_ch_${mode}_${channel}.txt
echo ${PERmeas} >> per_ch_${mode}_${channel}.txt
i=$((i+1))
# trap not enough fading file samples (with mpp)
grep "Fading file finished" ${ch_log}
if [ $? -eq 0 ]; then
cat ${ch_log}
exit 1
fi
done
echo ${SNRoffset} > offset_ch_${mode}_${channel}.txt
SNRch=$(cat ${ch_log} | grep SNR3k | tr -s ' ' | cut -d' ' -f3)
echo ${SNRch} > snr_ch_${mode}_${channel}.txt
}
# ch injects noise and is source of truth for SNR, measure BER/PER v SNR and
# SNR estimates v SNR from rx, C Tx
function generate_snrest_v_snr_data {
mode=$1
channel=$2
snr_nudge=0
aNo_list=$No_list
# nudge SNR test range to get meaningful results for these tests
if [ "$mode" == "datac1" ]; then
snr_nudge=4
fi
if [[ "$mode" == "datac4" || "$mode" == "datac13" || "$mode" == "datac14" ]]; then
snr_nudge=-6
fi
ch_multipath=''
Nbursts=$Nbursts_awgn
if [ "$channel" == "mpp" ]; then
ch_multipath='--mpp'
Nbursts=$Nbursts_mpp
snr_nudge=$((${snr_nudge}+4))
fi
clip=0
id='ctx'
if [ "$#" -eq 3 ]; then
clip=$3
id='ctxc'
snr_nudge=$((${snr_nudge}-4))
fi
tx_log=$(mktemp)
ch_log=$(mktemp)
rx_log=$(mktemp)
i=1
rm -f snrest_${id}_${mode}_${channel}*.txt
rm -f ber_${id}_${mode}_${channel}*.txt
rm -f per_${id}_${mode}_${channel}*.txt
for No in $aNo_list
do
No_adj=$((${No}-${snr_nudge}))
freedv_data_raw_tx --clip ${clip} --delay 1000 --txbpf ${clip} --bursts $Nbursts --testframes $Nbursts $mode /dev/zero - 2>${tx_log} | \
ch - - --No $No_adj ${ch_multipath} --fading_dir ${FADING_DIR} 2>>${ch_log} | \
freedv_data_raw_rx --testframes $mode - /dev/null 2>${rx_log} -v
SNRoffset=$(cat ${tx_log} | grep "mark:space" | tr -s ' ' | cut -d' ' -f 5)
SNRest=$(cat ${rx_log} | grep '\-BS\-' | tr -s ' ' | cut -d' ' -f17)
if [ ! -z "$SNRest" ]; then
echo ${SNRest} > snrest_${id}_${mode}_${channel}_${i}.txt
fi
BERmeas=$(cat ${rx_log} | grep 'BER......:' | cut -d' ' -f2)
PERmeas=$(cat ${rx_log} | grep 'Coded FER' | cut -d' ' -f3)
echo ${BERmeas} >> ber_${id}_${mode}_${channel}.txt
echo ${PERmeas} >> per_${id}_${mode}_${channel}.txt
i=$((i+1))
done
echo ${SNRoffset} > offset_${id}_${mode}_${channel}.txt
# trap not enough fading file samples (with mpp)
grep "Fading file finished" ${ch_log}
if [ $? -eq 0 ]; then
cat ${ch_log}
exit 1
fi
SNRch=$(cat ${ch_log} | grep SNR3k | tr -s ' ' | cut -d' ' -f3)
echo ${SNRch} > snr_${id}_${mode}_${channel}.txt
}
# Sanity check to make sure Octave/CML is set up OK
function test_ldpc {
echo "ldpcut; quit" | DISPLAY="" octave-cli -p ${CODEC2}/octave
if [ "$?" -ne 0 ]; then
echo "basic octave test failed, you may need to"
echo "(a) run ctests to create build_xxx/cml"
echo "(b) set up ~/.octaverc as per octave/ldpc.m"
exit 1
else
echo "OK"
fi
}