aboutsummaryrefslogtreecommitdiff
path: root/unittest
diff options
context:
space:
mode:
authordrowe67 <[email protected]>2024-05-06 06:19:24 +0930
committerDavid Rowe <[email protected]>2024-05-06 06:19:24 +0930
commite9f64066a5fb8079cc8d217a4c494930ffda2bf4 (patch)
treeec4171cd3f2b16179545e96b00186cff48c772f7 /unittest
parentaebdd11464a6632c9722cf2db2a4494437404674 (diff)
parentd21ff74c5f830a275d291a00043b2526a1bf9e62 (diff)
merge with main and fix conflict (I hope)dr-codec2-doc
Diffstat (limited to 'unittest')
-rwxr-xr-xunittest/check_peak.sh1
-rw-r--r--unittest/raw_data_curves/Makefile149
-rwxr-xr-xunittest/raw_data_curves/snr_curves.sh191
3 files changed, 341 insertions, 0 deletions
diff --git a/unittest/check_peak.sh b/unittest/check_peak.sh
index 8f41c2a..b357534 100755
--- a/unittest/check_peak.sh
+++ b/unittest/check_peak.sh
@@ -51,6 +51,7 @@ if [ "$1" == "LPCNet" ]; then
data_test "datac3"
data_test "datac4"
data_test "datac13"
+ data_test "datac14"
fi
exit 0
diff --git a/unittest/raw_data_curves/Makefile b/unittest/raw_data_curves/Makefile
new file mode 100644
index 0000000..09aa7ca
--- /dev/null
+++ b/unittest/raw_data_curves/Makefile
@@ -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
diff --git a/unittest/raw_data_curves/snr_curves.sh b/unittest/raw_data_curves/snr_curves.sh
new file mode 100755
index 0000000..62f0a52
--- /dev/null
+++ b/unittest/raw_data_curves/snr_curves.sh
@@ -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
+}