mirror of https://github.com/drowe67/codec2.git
Merge pull request #44 from drowe67/dr-datac14
datac14 - FreeDATA Feature Request 002 for a < 1s, 5 byte signalling modedr-freedata-001^2
commit
d21ff74c5f
|
@ -662,6 +662,13 @@ endif()
|
|||
cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
cat test.raw | ./ofdm_demod --mode datac13 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
|
||||
|
||||
# DATAC14 Octave Tx, C Rx, burst mode
|
||||
add_test(NAME test_OFDM_modem_datac14_octave
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/octave;
|
||||
DISPLAY=\"\" octave-cli -qf --eval 'ofdm_ldpc_tx(\"${CMAKE_CURRENT_BINARY_DIR}/src/test.raw\",\"datac14\",1,3,\"awgn\",\"bursts\",5)';
|
||||
cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
cat test.raw | ./ofdm_demod --mode datac14 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
|
||||
|
||||
# DATAC4 C Tx, C Rx, burst mode
|
||||
add_test(NAME test_OFDM_modem_datac4_ldpc_burst
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
|
@ -676,7 +683,14 @@ endif()
|
|||
./ch - - --No -17 |
|
||||
./ofdm_demod --mode datac13 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# DATAC14 C Tx, C Rx, burst mode
|
||||
add_test(NAME test_OFDM_modem_datac14_ldpc_burst
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
./ofdm_mod --mode datac14 --in /dev/zero --testframes 1 --verbose 1 --ldpc --bursts 10 |
|
||||
./ch - - --No -17 |
|
||||
./ofdm_demod --mode datac14 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# LDPC
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
@ -1064,6 +1078,12 @@ if (NOT APPLE)
|
|||
./freedv_data_raw_tx --testframes 10 DATAC13 /dev/zero /dev/null")
|
||||
set_tests_properties(test_memory_leak_FreeDV_DATAC13_tx PROPERTIES PASS_REGULAR_EXPRESSION "ERROR SUMMARY: 0 errors")
|
||||
|
||||
add_test(NAME test_memory_leak_FreeDV_DATAC14_tx
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
./freedv_data_raw_tx --testframes 10 DATAC14 /dev/zero /dev/null")
|
||||
set_tests_properties(test_memory_leak_FreeDV_DATAC14_tx PROPERTIES PASS_REGULAR_EXPRESSION "ERROR SUMMARY: 0 errors")
|
||||
|
||||
add_test(NAME test_memory_leak_FreeDV_700E_tx
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
|
@ -1307,6 +1327,13 @@ endif(NOT APPLE)
|
|||
./freedv_data_raw_rx DATAC13 - binaryOut.bin -v;
|
||||
diff binaryIn.bin binaryOut.bin")
|
||||
|
||||
add_test(NAME test_freedv_data_raw_ofdm_datac14_burst_file
|
||||
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
|
||||
head -c $((3*10)) </dev/urandom > binaryIn.bin;
|
||||
./freedv_data_raw_tx DATAC14 binaryIn.bin - --bursts 10 |
|
||||
./freedv_data_raw_rx DATAC14 - binaryOut.bin -v;
|
||||
diff binaryIn.bin binaryOut.bin")
|
||||
|
||||
# FSK LDPC default 100 bit/s 2FSK, enough noise for several % raw BER to give
|
||||
# FEC/acquisition a work out, bursts of 1 frame as that stresses acquisition
|
||||
add_test(NAME test_freedv_data_raw_fsk_ldpc_100
|
||||
|
@ -1392,6 +1419,7 @@ endif(NOT APPLE)
|
|||
test_OFDM_modem_datac3_octave
|
||||
test_OFDM_modem_datac4_octave
|
||||
test_OFDM_modem_datac13_octave
|
||||
test_OFDM_modem_datac14_octave
|
||||
test_fsk_lib_4fsk_ldpc
|
||||
test_OFDM_modem_datac0_compression
|
||||
PROPERTIES
|
||||
|
|
|
@ -30,7 +30,7 @@ If you have a Feature Request, please answer the questions in the [Feature Reque
|
|||
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:
|
||||
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.
|
||||
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.
|
||||
|
||||
|
|
|
@ -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) |
|
||||
| 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) |
|
||||
| DATAC14 | 250 | 58 | 3 | (112,56) | 0.69 | 90/100 at -2dB | Reverse link ACK packets (low SNR) |
|
||||
|
||||
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.
|
||||
|
@ -245,7 +246,7 @@ This command line demonstrates the effect:
|
|||
```
|
||||
Try adjusting `--clip` and `No` argument of `ch` (noise level) for different modes. Note the SNR estimates returned from `freedv_data_raw_rx` compared to the SNR from the channel simulator `ch`. You will notice clipping also increases the RMS power and reduces the PER for a given channel noise power. CPAPR will also reduce with clipping enabled.
|
||||
|
||||
The following plots illustrate the SNR estimates versus actual channel SNR with and without compression (clipping). Not that even with the uncompressed waveform there is a small offset of around 1dB, possibly due to modem implementation loss or noise in the frequency, phase, or timing estimators.
|
||||
The following plots illustrate the SNR estimates versus actual channel SNR with and without compression (clipping). Note that even with the uncompressed waveform there is a small offset of around 1dB, possibly due to modem implementation loss or noise in the frequency, phase, or timing estimators.
|
||||
|
||||

|
||||

|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 39 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
@ -44,7 +44,8 @@ function print_config(states)
|
|||
printf("Nc=%d Ts=%4.3f Tcp=%4.3f Ns: %d Np: %d\n", Nc, 1/Rs, Tcp, Ns, Np);
|
||||
printf("Nsymperframe: %d Nbitsperpacket: %d Nsamperframe: %d Ntxtbits: %d Nuwbits: %d Nuwframes: %d\n",
|
||||
Ns*Nc, Nbitsperpacket, Nsamperframe, Ntxtbits, Nuwbits, Nuwframes);
|
||||
printf("uncoded bits/s: %4.1f\n", Nbitsperpacket*Fs/(Np*Nsamperframe));
|
||||
printf("uncoded bits/s: %4.1f Duration (incl post/preamble): %4.2f s\n",
|
||||
Nbitsperpacket*Fs/(Np*Nsamperframe), (Np+2)*Ns*(Tcp+1/Rs));
|
||||
end
|
||||
|
||||
%-----------------------------------------------------------------------
|
||||
|
|
|
@ -1254,7 +1254,7 @@ endfunction
|
|||
% with acquisition
|
||||
function [rx delay_samples] = ofdm_rx_filter(states, mode, rx)
|
||||
delay_samples = 0;
|
||||
if strcmp(mode,"datac4") || strcmp(mode,"datac13")
|
||||
if strcmp(mode,"datac4") || strcmp(mode,"datac13") || strcmp(mode,"datac14")
|
||||
w_centre = mean(states.w); centre_norm = w_centre/(2*pi);
|
||||
n_coeffs = 100;
|
||||
cutoff_Hz = 400; cutoff_norm = cutoff_Hz/states.Fs;
|
||||
|
|
|
@ -134,6 +134,18 @@ function config = ofdm_init_mode(mode="700D")
|
|||
config.state_machine = "data";
|
||||
config.amp_scale = 2.5*300E3; config.clip_gain1 = 1.2; config.clip_gain2 = 1.0;
|
||||
config.txbpf_width_Hz = 400;
|
||||
elseif strcmp(mode,"datac14")
|
||||
Ns=5; config.Np=4; Tcp = 0.005; Ts = 0.018; Nc = 4; config.data_mode = "streaming";
|
||||
config.edge_pilots = 0;
|
||||
config.Ntxtbits = 0; config.Nuwbits = 32; config.bad_uw_errors = 12;
|
||||
config.ftwindow_width = 80; config.timing_mx_thresh = 0.45;
|
||||
config.tx_uw = zeros(1,config.Nuwbits);
|
||||
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
||||
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
||||
config.amp_est_mode = 1; config.EsNodB = 3;
|
||||
config.state_machine = "data";
|
||||
config.amp_scale = 2*300E3; config.clip_gain1 = 2; config.clip_gain2 = 1;
|
||||
config.txbpf_width_Hz = 400;
|
||||
elseif strcmp(mode,"1")
|
||||
Ns=5; config.Np=10; Tcp=0; Tframe = 0.1; Ts = Tframe/Ns; Nc = 1;
|
||||
else
|
||||
|
@ -231,9 +243,17 @@ function [code_param Nbitspercodecframe Ncodecframespermodemframe] = codec_to_fr
|
|||
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
||||
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
||||
end
|
||||
if strcmp(mode, "datac14")
|
||||
load HRA_56_56.txt
|
||||
code_param = ldpc_init_user(HRA_56_56, modulation, mod_order, mapping);
|
||||
code_param.data_bits_per_frame = 40;
|
||||
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
||||
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
||||
end
|
||||
if strcmp(mode, "datac0") || strcmp(mode, "datac1") || strcmp(mode, "datac3") ...
|
||||
|| strcmp(mode, "datac4") || strcmp(mode, "qam16c1") ...
|
||||
|| strcmp(mode, "qam16c2") || strcmp(mode, "datac5") || strcmp(mode, "datac13")
|
||||
|| strcmp(mode, "qam16c2") || strcmp(mode, "datac5") || strcmp(mode, "datac13") ...
|
||||
|| strcmp(mode, "datac14")
|
||||
printf("ldpc_data_bits_per_frame = %d\n", code_param.ldpc_data_bits_per_frame);
|
||||
printf("ldpc_coded_bits_per_frame = %d\n", code_param.ldpc_coded_bits_per_frame);
|
||||
printf("ldpc_parity_bits_per_frame = %d\n", code_param.ldpc_parity_bits_per_frame);
|
||||
|
|
|
@ -83,7 +83,9 @@ function ofdm_rx(filename, mode="700D", varargin)
|
|||
Nerrs = 0; rx_uw = zeros(1,states.Nuwbits);
|
||||
|
||||
% main loop ----------------------------------------------------------------
|
||||
|
||||
|
||||
rx = ofdm_rx_filter(states, mode, rx);
|
||||
|
||||
f = 1;
|
||||
while(prx < Nsam)
|
||||
|
||||
|
|
|
@ -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;
|
||||
#}
|
2
src/ch.c
2
src/ch.c
|
@ -256,7 +256,7 @@ int main(int argc, char *argv[]) {
|
|||
stderr,
|
||||
"\nAdjust path --fading_dir or use GNU Octave to generate:\n\n");
|
||||
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> time_secs=60\n");
|
||||
fprintf(stderr,
|
||||
|
|
|
@ -197,6 +197,7 @@ void freedv_ofdm_data_open(struct freedv *f) {
|
|||
if (f->mode == FREEDV_MODE_DATAC3) strcpy(mode, "datac3");
|
||||
if (f->mode == FREEDV_MODE_DATAC4) strcpy(mode, "datac4");
|
||||
if (f->mode == FREEDV_MODE_DATAC13) strcpy(mode, "datac13");
|
||||
if (f->mode == FREEDV_MODE_DATAC14) strcpy(mode, "datac14");
|
||||
|
||||
ofdm_init_mode(mode, &ofdm_config);
|
||||
f->ofdm = ofdm_create(&ofdm_config);
|
||||
|
|
|
@ -125,7 +125,8 @@ struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) {
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode)) == false)
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode)) == false)
|
||||
return NULL;
|
||||
|
||||
/* set everything to zero just in case */
|
||||
|
@ -154,6 +155,7 @@ struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) {
|
|||
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, mode)) freedv_ofdm_data_open(f);
|
||||
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, mode)) freedv_ofdm_data_open(f);
|
||||
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode)) freedv_ofdm_data_open(f);
|
||||
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode)) freedv_ofdm_data_open(f);
|
||||
|
||||
varicode_decode_init(&f->varicode_dec_states, 1);
|
||||
|
||||
|
@ -235,7 +237,8 @@ void freedv_close(struct freedv *freedv) {
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, freedv->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, freedv->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, freedv->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, freedv->mode)) {
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, freedv->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, freedv->mode)) {
|
||||
FREE(freedv->rx_syms);
|
||||
FREE(freedv->rx_amps);
|
||||
FREE(freedv->ldpc);
|
||||
|
@ -266,7 +269,8 @@ static int is_ofdm_mode(struct freedv *f) {
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode);
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode);
|
||||
}
|
||||
|
||||
static int is_ofdm_data_mode(struct freedv *f) {
|
||||
|
@ -274,7 +278,8 @@ static int is_ofdm_data_mode(struct freedv *f) {
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode);
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
@ -464,7 +469,8 @@ void freedv_rawdatacomptx(struct freedv *f, COMP mod_out[],
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode))
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode))
|
||||
freedv_comptx_ofdm(f, mod_out);
|
||||
|
||||
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, f->mode)) {
|
||||
|
@ -1063,7 +1069,8 @@ int freedv_rawdatacomprx(struct freedv *f, unsigned char *packed_payload_bits,
|
|||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode))
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
|
||||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode))
|
||||
rx_status = freedv_comp_short_rx_ofdm(f, (void *)demod_in, 0, 1.0f);
|
||||
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, f->mode)) {
|
||||
rx_status = freedv_rx_fsk_ldpc_data(f, demod_in);
|
||||
|
|
|
@ -61,6 +61,7 @@ extern "C" {
|
|||
#define FREEDV_MODE_DATAC0 14
|
||||
#define FREEDV_MODE_DATAC4 18
|
||||
#define FREEDV_MODE_DATAC13 19
|
||||
#define FREEDV_MODE_DATAC14 20
|
||||
|
||||
// Sample rates used
|
||||
#define FREEDV_FS_8000 8000
|
||||
|
@ -140,6 +141,9 @@ extern "C" {
|
|||
#if !defined(FREEDV_MODE_DATAC13_EN)
|
||||
#define FREEDV_MODE_DATAC13_EN FREEDV_MODE_EN_DEFAULT
|
||||
#endif
|
||||
#if !defined(FREEDV_MODE_DATAC14_EN)
|
||||
#define FREEDV_MODE_DATAC14_EN FREEDV_MODE_EN_DEFAULT
|
||||
#endif
|
||||
|
||||
#define FDV_MODE_ACTIVE(mode_name, var) \
|
||||
((mode_name##_EN) == 0 ? 0 : (var) == mode_name)
|
||||
|
|
|
@ -214,6 +214,8 @@ int main(int argc, char *argv[]) {
|
|||
mode = FREEDV_MODE_DATAC4;
|
||||
if (!strcmp(argv[dx], "DATAC13") || !strcmp(argv[dx], "datac13"))
|
||||
mode = FREEDV_MODE_DATAC13;
|
||||
if (!strcmp(argv[dx], "DATAC14") || !strcmp(argv[dx], "datac14"))
|
||||
mode = FREEDV_MODE_DATAC14;
|
||||
if (mode == -1) {
|
||||
fprintf(stderr, "Error in mode: %s\n", argv[dx]);
|
||||
exit(1);
|
||||
|
|
|
@ -236,6 +236,8 @@ int main(int argc, char *argv[]) {
|
|||
mode = FREEDV_MODE_DATAC4;
|
||||
if (!strcmp(argv[dx], "DATAC13") || !strcmp(argv[dx], "datac13"))
|
||||
mode = FREEDV_MODE_DATAC13;
|
||||
if (!strcmp(argv[dx], "DATAC14") || !strcmp(argv[dx], "datac14"))
|
||||
mode = FREEDV_MODE_DATAC14;
|
||||
if (mode == -1) {
|
||||
fprintf(stderr, "Error: in mode: %s", argv[dx]);
|
||||
exit(1);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
*/
|
||||
|
||||
static const int b_table[] = {
|
||||
48, 31, /* datac14: HRA_56_56, 40 data bits used */
|
||||
56, 37, /* 700E: HRA_56_56 */
|
||||
106, 67, /* 2020B: (112,56) partial protection */
|
||||
112, 71, /* 700D: HRA_112_112 */
|
||||
|
|
|
@ -78,6 +78,7 @@ void ldpc_mode_specific_setup(struct OFDM *ofdm, struct LDPC *ldpc) {
|
|||
}
|
||||
if (!strcmp(ofdm->mode, "datac4")) set_data_bits_per_frame(ldpc, 448);
|
||||
if (!strcmp(ofdm->mode, "datac13")) set_data_bits_per_frame(ldpc, 128);
|
||||
if (!strcmp(ofdm->mode, "datac14")) set_data_bits_per_frame(ldpc, 40);
|
||||
}
|
||||
|
||||
/* LDPC encode frame - generate parity bits and a codeword, applying the
|
||||
|
|
|
@ -559,7 +559,8 @@ static void allocate_tx_bpf(struct OFDM *ofdm) {
|
|||
quisk_filt_cfInit(ofdm->tx_bpf, filtP400S600,
|
||||
sizeof(filtP400S600) / sizeof(float));
|
||||
quisk_cfTune(ofdm->tx_bpf, ofdm->tx_centre / ofdm->fs);
|
||||
} else if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13")) {
|
||||
} else if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13") ||
|
||||
!strcmp(ofdm->mode, "datac14")) {
|
||||
quisk_filt_cfInit(ofdm->tx_bpf, filtP200S400,
|
||||
sizeof(filtP200S400) / sizeof(float));
|
||||
// centre the filter on the mean carrier freq, allows a narrower filter to
|
||||
|
@ -590,7 +591,8 @@ static void allocate_rx_bpf(struct OFDM *ofdm) {
|
|||
|
||||
/* Receive bandpass filter; complex coefficients, center frequency */
|
||||
|
||||
if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13")) {
|
||||
if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13") ||
|
||||
!strcmp(ofdm->mode, "datac14")) {
|
||||
quisk_filt_cfInit(ofdm->rx_bpf, filtP200S400,
|
||||
sizeof(filtP200S400) / sizeof(float));
|
||||
// centre the filter on the mean carrier freq, allows a narrower filter to
|
||||
|
|
|
@ -226,6 +226,31 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
|
|||
config->clip_gain1 = 1.2;
|
||||
config->clip_gain2 = 1.0;
|
||||
config->rx_bpf_en = true;
|
||||
} else if (strcmp(mode, "datac14") == 0) {
|
||||
config->ns = 5;
|
||||
config->np = 4;
|
||||
config->tcp = 0.005;
|
||||
config->ts = 0.018;
|
||||
config->nc = 4;
|
||||
config->edge_pilots = 0;
|
||||
config->txtbits = 0;
|
||||
config->state_machine = "data";
|
||||
config->ftwindowwidth = 80;
|
||||
config->timing_mx_thresh = 0.45;
|
||||
config->codename = "HRA_56_56";
|
||||
config->amp_est_mode = 1;
|
||||
config->nuwbits = 32;
|
||||
config->bad_uw_errors = 12;
|
||||
uint8_t uw[] = {1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
|
||||
assert(sizeof(uw) <= MAX_UW_BITS);
|
||||
memcpy(config->tx_uw, uw, sizeof(uw));
|
||||
memcpy(&config->tx_uw[config->nuwbits - sizeof(uw)], uw, sizeof(uw));
|
||||
config->data_mode = "streaming";
|
||||
config->amp_scale = 2.0 * 300E3;
|
||||
config->clip_gain1 = 2.0;
|
||||
config->clip_gain2 = 1.0;
|
||||
config->rx_bpf_en = true;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ if [ "$1" == "LPCNet" ]; then
|
|||
data_test "datac3"
|
||||
data_test "datac4"
|
||||
data_test "datac13"
|
||||
data_test "datac14"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue