From a28317a0170fdf5a7778ba565b46caa26e752645 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Wed, 11 Mar 2015 06:46:22 +0000 Subject: [PATCH] starting coherent PSK C port and test framework, compiles OK but not tested git-svn-id: https://svn.code.sf.net/p/freetel/code@2065 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/fsk.m | 13 +-- codec2-dev/octave/test_ldpc.m | 157 +++++++++++++++++++-------- codec2-dev/src/codec2_cohpsk.h | 38 +++++++ codec2-dev/src/cohpsk.c | 121 +++++++++++++++++++++ codec2-dev/src/cohpsk_defs.h | 9 ++ codec2-dev/src/fdmdv.c | 2 +- codec2-dev/src/fdmdv_internal.h | 2 +- codec2-dev/src/pilots_coh.h | 9 ++ codec2-dev/src/test_bits_coh.h | 164 +++++++++++++++++++++++++++++ codec2-dev/unittest/CMakeLists.txt | 3 + codec2-dev/unittest/tcohpsk.c | 95 +++++++++++++++++ 11 files changed, 562 insertions(+), 51 deletions(-) create mode 100644 codec2-dev/src/codec2_cohpsk.h create mode 100644 codec2-dev/src/cohpsk.c create mode 100644 codec2-dev/src/cohpsk_defs.h create mode 100644 codec2-dev/src/pilots_coh.h create mode 100644 codec2-dev/src/test_bits_coh.h create mode 100644 codec2-dev/unittest/tcohpsk.c diff --git a/codec2-dev/octave/fsk.m b/codec2-dev/octave/fsk.m index 74fee23f..d91ba303 100644 --- a/codec2-dev/octave/fsk.m +++ b/codec2-dev/octave/fsk.m @@ -110,6 +110,7 @@ function sim_out = fsk_ber_test(sim_in) printf("EbNo: %f Eb: %f var No: %f EbNo (meas): %f\n", EbNo, var(tx)*Ts/Fs, var(noise)/Fs, (var(tx)*Ts/Fs)/(var(noise)/Fs)); end + save fsk tx_bits rx % Optional AFSK over FM demodulator @@ -233,12 +234,12 @@ function run_fsk_curves end function run_fsk_single - sim_in.fmark = 1200; - sim_in.fspace = 2200; - sim_in.Rs = 1200; - sim_in.nsym = 1200; - sim_in.EbNodB = 16; - sim_in.fm = 1; + sim_in.fmark = 1000; + sim_in.fspace = 2000; + sim_in.Rs = 1000; + sim_in.nsym = 2000; + sim_in.EbNodB = 7; + sim_in.fm = 0; sim_in.verbose = 1; fsk_sim = fsk_ber_test(sim_in); diff --git a/codec2-dev/octave/test_ldpc.m b/codec2-dev/octave/test_ldpc.m index f6472749..603c0096 100644 --- a/codec2-dev/octave/test_ldpc.m +++ b/codec2-dev/octave/test_ldpc.m @@ -22,6 +22,7 @@ rand('state',1); randn('state',1); +graphics_toolkit ("gnuplot"); 1; @@ -50,7 +51,7 @@ function [tx_symb tx_bits prev_sym_tx] = symbol_rate_tx(sim_in, tx_bits, code_pa % data and parity bits are on separate carriers tx_symb = zeros(Nsymbrow,Nc); - + for c=1:Nc for r=1:Nsymbrow i = (c-1)*Nsymbrow + r; @@ -59,7 +60,7 @@ function [tx_symb tx_bits prev_sym_tx] = symbol_rate_tx(sim_in, tx_bits, code_pa end %tx_symb = zeros(Nsymbrow,Nc); - % Optionally insert pilots, one every Ns data symbols + % insert pilots, one every Ns data symbols tx_symb_pilot = zeros(Nsymbrowpilot, Nc); @@ -171,6 +172,53 @@ function [spread spread_2ms hf_gain] = init_hf_model(Fs, Rs, nsam) endfunction +function write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymrow, Npilotsframe, Nc); + + filename = sprintf("../src/cohpsk_defs.h", Npilotsframe, Nc); + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n"); + fprintf(f,"#define NSYMROW %d /* number of data symbols for each row (i.e. each carrier) */\n", Nsymrow); + fprintf(f,"#define NS %d /* number of data symbols between pilots */\n", Ns); + fprintf(f,"#define NPILOTSFRAME %d /* number of pilot symbols of each row */\n", Npilotsframe); + fprintf(f,"#define PILOTS_NC %d /* number of carriers in coh modem */\n\n", Nc); + fprintf(f,"#define NSYMROWPILOT %d /* length of row after pilots inserted */\n\n", Nsymbrowpilot); + fclose(f); + + filename = sprintf("../src/pilots_coh.h", Npilotsframe, Nc); + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n"); + fprintf(f,"float pilots_coh[][PILOTS_NC]={\n"); + for r=1:Npilotsframe + fprintf(f, " {"); + for c=1:Nc-1 + fprintf(f, " %f,", pilot(r, c)); + end + if r < Npilotsframe + fprintf(f, " %f},\n", pilot(r, Nc)); + else + fprintf(f, " %f}\n};", pilot(r, Nc)); + end + end + fclose(f); +endfunction + + +% Save test bits frame to a text file in the form of a C array + +function test_bits_coh_file(test_bits_coh) + + f=fopen("test_bits_coh.h","wt"); + fprintf(f,"/* Generated by test_bits_coh_file() Octave function */\n\n"); + fprintf(f,"const int test_bits_coh[]={\n"); + for m=1:length(test_bits_coh)-1 + fprintf(f," %d,\n",test_bits_coh(m)); + endfor + fprintf(f," %d\n};\n",test_bits_coh(length(test_bits_coh))); + fclose(f); + +endfunction + + % init function for symbol rate processing function sim_in = symbol_rate_init(sim_in) @@ -223,10 +271,13 @@ function sim_in = symbol_rate_init(sim_in) % pilot sequence is used for phase and amplitude estimation, and frame sync - pilot = 1 - 2*(rand(Npilotsframe,Nc) > 0.5); + pilot = 1 - 2*(rand(Npilotsframe,Nc) > 0.5) sim_in.pilot = pilot; sim_in.tx_pilot_buf = [pilot; pilot; pilot]; - + if sim_in.do_write_pilot_file + write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymbrow, Npilotsframe, Nc); + end + % Init LDPC -------------------------------------------------------------------- if ldpc_code @@ -256,6 +307,7 @@ function sim_in = symbol_rate_init(sim_in) sim_in.code_param = code_param; else sim_in.rate = 1; + sim_in.code_param = []; end endfunction @@ -334,7 +386,7 @@ function [rx_symb rx_bits rx_symb_linear amp_linear amp_ phi_ EsNo_ prev_sym_rx if verbose > 2 printf("% 4.3f ", phi_(r,c)) end - rx_symb(r,c) *= exp(-j*phi_(r,c)); + % rx_symb(r,c) *= exp(-j*phi_(r,c)); end if verbose > 2 @@ -810,21 +862,25 @@ function test_single sim_in.verbose = 1; sim_in.plot_scatter = 1; - sim_in.framesize = 576; - sim_in.Nc = 9; + sim_in.framesize = 160; + sim_in.Nc = 4; sim_in.Rs = 50; sim_in.Ns = 4; sim_in.Np = 2; sim_in.Nchip = 1; - sim_in.ldpc_code_rate = 0.5; - sim_in.ldpc_code = 1; +% sim_in.ldpc_code_rate = 0.5; +% sim_in.ldpc_code = 1; + sim_in.ldpc_code_rate = 1; + sim_in.ldpc_code = 0; sim_in.Ntrials = 20; - sim_in.Esvec = 10; - sim_in.hf_sim = 1; + sim_in.Esvec = 100; + sim_in.hf_sim = 0; sim_in.hf_mag_only = 0; sim_in.modulation = 'qpsk'; + sim_in.do_write_pilot_file = 1; + sim_qpsk_hf = ber_test(sim_in); fep=fopen("errors_450.bin","wb"); fwrite(fep, sim_qpsk_hf.ldpc_errors_log, "short"); fclose(fep); @@ -838,14 +894,14 @@ function rate_Fs_tx(tx_filename) sim_in.verbose = 1; sim_in.plot_scatter = 1; - sim_in.framesize = 576; - sim_in.Nc = 9; + sim_in.framesize = 160; + sim_in.Nc = 4; sim_in.Rs = 50; sim_in.Ns = 4; sim_in.Np = 2; sim_in.Nchip = 1; - sim_in.ldpc_code_rate = 0.5; - sim_in.ldpc_code = 1; + sim_in.ldpc_code_rate = 1; + sim_in.ldpc_code = 0; sim_in.Ntrials = 20; sim_in.Esvec = 7; @@ -930,7 +986,7 @@ function rate_Fs_tx(tx_filename) Ascale = 2000; figure(1); clf; - plot(Ascale*tx_fdm(1:800)) + plot(Ascale*tx_fdm(1:8000)) ftx=fopen(tx_filename,"wb"); fwrite(ftx, Ascale*real(tx_fdm), "short"); fclose(ftx); @@ -943,14 +999,14 @@ function rate_Fs_rx(rx_filename) sim_in.verbose = 1; sim_in.plot_scatter = 1; - sim_in.framesize = 576; - sim_in.Nc = 9; + sim_in.framesize = 160; + sim_in.Nc = 4; sim_in.Rs = 50; sim_in.Ns = 4; sim_in.Np = 4; sim_in.Nchip = 1; - sim_in.ldpc_code_rate = 0.5; - sim_in.ldpc_code = 1; + sim_in.ldpc_code_rate = 1; + sim_in.ldpc_code = 0; sim_in.Ntrials = 10; sim_in.Esvec = 40; @@ -1015,7 +1071,7 @@ function rate_Fs_rx(rx_filename) printf("Freq offset and coarse timing est...\n"); [f_max max_s_Fs] = test_freq_off_est(rx_filename, 1,5*6400); - %f_max = 0; max_s_Fs = 4; + f_max = 0; max_s_Fs = 4; max_s = floor(max_s_Fs/M + 6); printf("Downconverting...\n"); @@ -1114,19 +1170,21 @@ function rate_Fs_rx(rx_filename) errors_log = [errors_log error_positions]; Nerrs_log = [Nerrs_log Nerrs]; - % LDPC decode + if sim_in.ldpc_code + % LDPC decode - detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ... - rx_symb_linear, min(100,EsNo_), amp_linear); - error_positions = xor(detected_data(1:framesize*rate), tx_bits(1:framesize*rate) ); - Nerrs = sum(error_positions); - ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs]; - ldpc_errors_log = [ldpc_errors_log error_positions]; - if Nerrs - Ferrsldpc++; + detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ... + rx_symb_linear, min(100,EsNo_), amp_linear); + error_positions = xor(detected_data(1:framesize*rate), tx_bits(1:framesize*rate) ); + Nerrs = sum(error_positions); + ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs]; + ldpc_errors_log = [ldpc_errors_log error_positions]; + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; end - Terrsldpc += Nerrs; - Tbitsldpc += framesize*rate; end end @@ -1135,9 +1193,11 @@ function rate_Fs_rx(rx_filename) EsNo_av, mean(EsNo_to_SNR(10*log10(EsNo__log))), Terrs, Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); - printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f\n", - Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials); - + if sim_in.ldpc_code + printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f\n", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials); + end + figure(3); clf; scat = rx_symb_log .* exp(j*pi/4); @@ -1151,10 +1211,12 @@ function rate_Fs_rx(rx_filename) stem(Nerrs_log) axis([0 Ntrials+1 0 max(Nerrs_log)+1]) title('Uncoded Errors/Frame'); - subplot(212) - stem(ldpc_Nerrs_log) - axis([0 Ntrials+1 0 max(ldpc_Nerrs_log)+1]) - title('Coded Errors/Frame'); + if sim_in.ldpc_code + subplot(212) + stem(ldpc_Nerrs_log) + axis([0 Ntrials+1 0 max(ldpc_Nerrs_log)+1]) + title('Coded Errors/Frame'); + end figure(5) clf @@ -1262,13 +1324,22 @@ function snr = EsNo_to_SNR(EsNo) snr = interp1([20 11.8 9.0 6.7 4.9 3.3 -10], [ 3 3 0 -3 -6 -9 -9], EsNo); endfunction +function gen_test_bits() + sim_in = standard_init(); + framesize = 160; + tx_bits = round(rand(1,framesize)); + test_bits_coh_file(tx_bits); +endfunction + % Start simulations --------------------------------------- more off; %test_curves(); -%test_single(); +test_single(); %rate_Fs_tx("tx_zero.raw"); -%rate_Fs_tx("tx_950.raw"); -rate_Fs_rx("tx_-4dB.wav") -%rate_Fs_rx("mel010.wav") +%rate_Fs_tx("tx.raw"); +%rate_Fs_rx("tx_-4dB.wav") +%rate_Fs_rx("tx.raw") %test_freq_off_est("tx.raw",40,6400) +%gen_test_bits(); + diff --git a/codec2-dev/src/codec2_cohpsk.h b/codec2-dev/src/codec2_cohpsk.h new file mode 100644 index 00000000..1ee3a280 --- /dev/null +++ b/codec2-dev/src/codec2_cohpsk.h @@ -0,0 +1,38 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: cohpsk.h + AUTHOR......: David Rowe + DATE CREATED: March 2015 + + Functions that implement a coherent PSK FDM modem. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#ifndef __CODEC2_COHPSK__ +#define __CODEC2_COHPSK__ + +#define COHPSK_BITS_PER_FRAME 160 /* hard coded for now */ +#define COHPSK_NC 4 /* hard coded for now */ + +#include "comp.h" + +void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC], int tx_bits[], int framesize); + +#endif diff --git a/codec2-dev/src/cohpsk.c b/codec2-dev/src/cohpsk.c new file mode 100644 index 00000000..46530955 --- /dev/null +++ b/codec2-dev/src/cohpsk.c @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: cohpsk.c + AUTHOR......: David Rowe + DATE CREATED: March 2015 + + Functions that implement a coherent PSK FDM modem. + + TODO: + [ ] matching octave function bits_to_dqpsk_symbols() + [ ] framework for test program and octave UT + [ ] testframe used by both Octave and C + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +/*---------------------------------------------------------------------------*\ + + INCLUDES + +\*---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include "codec2_cohpsk.h" +#include "test_bits.h" +#include "cohpsk_defs.h" +#include "pilots_coh.h" + +static COMP qpsk_mod[] = { + { 1.0, 0.0}, + { 0.0, 1.0}, + { 0.0,-1.0}, + {-1.0, 0.0} +}; + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: bits_to_qpsk_symbols() + AUTHOR......: David Rowe + DATE CREATED: March 2015 + + Maps bits to parallel DQPSK symbols and inserts pilot symbols. + +\*---------------------------------------------------------------------------*/ + +void bits_to_qpsk_symbols(COMP tx_symb[][PILOTS_NC], int tx_bits[], int framesize) +{ + COMP tx_symb_data[NSYMROW][PILOTS_NC]; + int i, r, c, p_r, data_r; + short bits; + + assert(COHPSK_NC == PILOTS_NC); + assert((NSYMROW*PILOTS_NC)/2 == framesize); + + /* + Organise QPSK symbols into a NSYMBROWS rows by PILOTS_NC cols matrix, + each column is a carrier, time flows down the rows...... + + Note: the "& 0x1" prevents and non binary tx_bits[] screwing up + our lives. Call me defensive. + */ + + for(c=0; ccurrent_test_bit > (f->ntest_bits-1)) f->current_test_bit = 0; } - } +} float fdmdv_get_fsep(struct FDMDV *f) { diff --git a/codec2-dev/src/fdmdv_internal.h b/codec2-dev/src/fdmdv_internal.h index 97011e8d..4476aea0 100644 --- a/codec2-dev/src/fdmdv_internal.h +++ b/codec2-dev/src/fdmdv_internal.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------------------------*\ FILE........: fdmdv_internal.h - AUTHOR......: David Rowe + AUTHOR......: David Rowe DATE CREATED: April 16 2012 Header file for FDMDV internal functions, exposed via this header diff --git a/codec2-dev/src/pilots_coh.h b/codec2-dev/src/pilots_coh.h new file mode 100644 index 00000000..e5e1debc --- /dev/null +++ b/codec2-dev/src/pilots_coh.h @@ -0,0 +1,9 @@ +/* Generated by write_pilot_file() Octave function */ + +float pilots_coh[][PILOTS_NC]={ + { 1.000000, 1.000000, -1.000000, -1.000000}, + { -1.000000, -1.000000, 1.000000, 1.000000}, + { -1.000000, -1.000000, -1.000000, -1.000000}, + { 1.000000, 1.000000, 1.000000, -1.000000}, + { 1.000000, 1.000000, 1.000000, 1.000000} +}; \ No newline at end of file diff --git a/codec2-dev/src/test_bits_coh.h b/codec2-dev/src/test_bits_coh.h new file mode 100644 index 00000000..2420ea8f --- /dev/null +++ b/codec2-dev/src/test_bits_coh.h @@ -0,0 +1,164 @@ +/* Generated by test_bits_coh_file() Octave function */ + +const int test_bits_coh[]={ + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1 +}; diff --git a/codec2-dev/unittest/CMakeLists.txt b/codec2-dev/unittest/CMakeLists.txt index 31910c2c..1743a80b 100644 --- a/codec2-dev/unittest/CMakeLists.txt +++ b/codec2-dev/unittest/CMakeLists.txt @@ -51,6 +51,9 @@ target_link_libraries(scalarlsptest codec2) add_executable(tfdmdv tfdmdv.c ../src/fdmdv.c ../src/kiss_fft.c ../src/octave.c) target_link_libraries(tfdmdv codec2) +add_executable(tcohpsk tcohpsk.c ../src/cohpsk.c ../src/octave.c) +target_link_libraries(tcohpsk) + add_executable(t16_8 t16_8.c ../src/fdmdv.c ../src/kiss_fft.c) target_link_libraries(t16_8 codec2) diff --git a/codec2-dev/unittest/tcohpsk.c b/codec2-dev/unittest/tcohpsk.c new file mode 100644 index 00000000..96e4ac38 --- /dev/null +++ b/codec2-dev/unittest/tcohpsk.c @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tcopskv.c + AUTHOR......: David Rowe + DATE CREATED: March 2015 + + Tests for the C version of the cohernet PSK FDM modem. This program + outputs a file of Octave vectors that are loaded and automatically + tested against the Octave version of the modem by the Octave script + tcohpsk.m + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include + +#include "fdmdv_internal.h" +#include "codec2_fdmdv.h" +#include "codec2_cohpsk.h" +#include "cohpsk_defs.h" +#include "test_bits_coh.h" +#include "octave.h" + +#define FRAMES 35 +#define CHANNEL_BUF_SIZE (10*M) + +int main(int argc, char *argv[]) +{ + int tx_bits[COHPSK_BITS_PER_FRAME]; + COMP tx_symbols[NSYMROWPILOT][PILOTS_NC]; + + int tx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES]; + COMP tx_symbols_log[NSYMROWPILOT*FRAMES][PILOTS_NC]; + + FILE *fout; + int f, r,c,rx_sym_log_r; + + rx_sym_log_r=0; + + for(f=0; f