From: drowe67 Date: Sat, 14 Mar 2015 06:40:03 +0000 (+0000) Subject: coh psk demod phase correction starting to do something sensible, still to complete... X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=c7f343b365561638974945a0b1c8ac3d1e216324;p=freetel-svn-tracking.git coh psk demod phase correction starting to do something sensible, still to complete testing git-svn-id: https://svn.code.sf.net/p/freetel/code@2073 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/octave/cohpsk.m b/codec2-dev/octave/cohpsk.m index 20f4a5d7..ac5b0f7a 100644 --- a/codec2-dev/octave/cohpsk.m +++ b/codec2-dev/octave/cohpsk.m @@ -88,7 +88,7 @@ function sim_in = symbol_rate_init(sim_in) 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); + write_pilot_file(pilot, Nsymbrowpilot, Ns, Np, Nsymbrow, Npilotsframe, Nc); end % Init LDPC -------------------------------------------------------------------- @@ -127,7 +127,7 @@ endfunction % Symbol rate processing for tx side (modulator) ------------------------------------------------------- -function [tx_symb tx_bits prev_sym_tx] = symbol_rate_tx(sim_in, tx_bits, code_param, prev_sym_tx) +function [tx_symb tx_bits prev_sym_tx] = bits_to_qpsk_symbols(sim_in, tx_bits, code_param, prev_sym_tx) ldpc_code = sim_in.ldpc_code; rate = sim_in.ldpc_code_rate; framesize = sim_in.framesize; @@ -436,16 +436,17 @@ function [spread spread_2ms hf_gain] = init_hf_model(Fs, Rs, nsam) endfunction -function write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymrow, Npilotsframe, Nc); +function write_pilot_file(pilot, Nsymbrowpilot, Ns, Np, 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); + fprintf(f,"#define NS %d /* number of data symbols between pilots */\n", Ns); + fprintf(f,"#define NP %d /* number of pilots to use for channel est */\n", Np); + 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); @@ -566,7 +567,7 @@ function sim_out = ber_test(sim_in) tx_bits = round(rand(1,framesize)); end - [s_ch tx_bits prev_sym_tx] = symbol_rate_tx(sim_in, tx_bits, code_param, prev_sym_tx); + [s_ch tx_bits prev_sym_tx] = bits_to_qpsk_symbols(sim_in, tx_bits, code_param, prev_sym_tx); tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize); tx_bits_buf(framesize+1:2*framesize) = tx_bits; diff --git a/codec2-dev/octave/tcohpsk.m b/codec2-dev/octave/tcohpsk.m index 2c6e9527..89ebaba7 100644 --- a/codec2-dev/octave/tcohpsk.m +++ b/codec2-dev/octave/tcohpsk.m @@ -20,11 +20,30 @@ framesize = 160; load ../build_linux/unittest/tcohpsk_out.txt sim_in = standard_init(); +sim_in.framesize = 160; +sim_in.ldpc_code = 0; +sim_in.ldpc_code_rate = 1; +sim_in.Nc = 4; +sim_in.Rs = 50; +sim_in.Ns = 4; +sim_in.Np = 2; +sim_in.Nchip = 1; +sim_in.modulation = 'qpsk'; +sim_in.do_write_pilot_file = 0; +sim_in = symbol_rate_init(sim_in); + +rand('state',1); tx_bits = round(rand(1,framesize)); tx_bits_log = []; +tx_symb_log = []; for i=1:frames tx_bits_log = [tx_bits_log tx_bits]; + [tx_symb tx_bits prev_tx_sym] = bits_to_qpsk_symbols(sim_in, tx_bits, [], []); + tx_symb_log = [tx_symb_log; tx_symb]; end -stem_sig_and_error(1, 211, tx_bits_log_c(1:n), tx_bits_log(1:n) - tx_bits_log_c(1:n), 'tx bits', [1 n -1.5 1.5]) +stem_sig_and_error(1, 111, tx_bits_log_c(1:n), tx_bits_log(1:n) - tx_bits_log_c(1:n), 'tx bits', [1 n -1.5 1.5]) +stem_sig_and_error(2, 211, real(tx_symb_log_c(1:n)), real(tx_symb_log(1:n) - tx_symb_log_c(1:n)), 'tx symb re', [1 n -1.5 1.5]) +stem_sig_and_error(2, 212, imag(tx_symb_log_c(1:n)), imag(tx_symb_log(1:n) - tx_symb_log_c(1:n)), 'tx symb im', [1 n -1.5 1.5]) check(tx_bits_log, tx_bits_log_c, 'tx_bits'); +check(tx_symb_log, tx_symb_log_c, 'tx_symb'); diff --git a/codec2-dev/src/codec2_cohpsk.h b/codec2-dev/src/codec2_cohpsk.h index 1ee3a280..cef44627 100644 --- a/codec2-dev/src/codec2_cohpsk.h +++ b/codec2-dev/src/codec2_cohpsk.h @@ -33,6 +33,11 @@ #include "comp.h" -void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC], int tx_bits[], int framesize); +struct COHPSK; + +struct COHPSK *cohpsk_create(void); +void cohpsk_destroy(struct COHPSK *coh); +void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC], int tx_bits[], int nbits); +void qpsk_symbols_to_bits(struct COHPSK *coh, int rx_bits[], COMP rx_symb[][COHPSK_NC]); #endif diff --git a/codec2-dev/src/cohpsk.c b/codec2-dev/src/cohpsk.c index 81e8e9e2..32dc29b9 100644 --- a/codec2-dev/src/cohpsk.c +++ b/codec2-dev/src/cohpsk.c @@ -45,7 +45,9 @@ #include "codec2_cohpsk.h" #include "test_bits.h" #include "cohpsk_defs.h" +#include "cohpsk_internal.h" #include "pilots_coh.h" +#include "comp_prim.h" static COMP qpsk_mod[] = { { 1.0, 0.0}, @@ -60,24 +62,71 @@ static COMP qpsk_mod[] = { \*---------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------* \ + + FUNCTION....: cohpsk_create + AUTHOR......: David Rowe + DATE CREATED: Marcg 2015 + + Create and initialise an instance of the modem. Returns a pointer + to the modem states or NULL on failure. One set of states is + sufficient for a full duplex modem. + +\*---------------------------------------------------------------------------*/ + +struct COHPSK *cohpsk_create(void) +{ + struct COHPSK *coh; + + coh = (struct COHPSK*)malloc(sizeof(struct COHPSK)); + if (coh == NULL) + return NULL; + + /* set up buffer of 3 frames of tx pilot symbols */ + + memcpy(&coh->tx_pilot_buf[0][0], pilots_coh, sizeof(pilots_coh)); + memcpy(&coh->tx_pilot_buf[NPILOTSFRAME][0], pilots_coh, sizeof(pilots_coh)); + memcpy(&coh->tx_pilot_buf[2*NPILOTSFRAME][0], pilots_coh, sizeof(pilots_coh)); + + return coh; +} + + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cohpsk_destroy + AUTHOR......: David Rowe + DATE CREATED: March 2015 + + Destroy an instance of the modem. + +\*---------------------------------------------------------------------------*/ + +void cohpsk_destroy(struct COHPSK *coh) +{ + assert(coh != NULL); + free(coh); +} + + /*---------------------------------------------------------------------------*\ FUNCTION....: bits_to_qpsk_symbols() AUTHOR......: David Rowe DATE CREATED: March 2015 - Maps bits to parallel DQPSK symbols and inserts pilot symbols. + Rate Rs modulator. 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) +void bits_to_qpsk_symbols(COMP tx_symb[][PILOTS_NC], int tx_bits[], int nbits) { 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); + assert((NSYMROW*PILOTS_NC)*2 == nbits); /* Organise QPSK symbols into a NSYMBROWS rows by PILOTS_NC cols matrix, @@ -112,7 +161,6 @@ void bits_to_qpsk_symbols(COMP tx_symb[][PILOTS_NC], int tx_bits[], int framesiz for(i=0; irx_pilot_buf[p_r][c] = rx_symb[r][c]; + //printf(" %d %d %f %f", p_r, c, coh->rx_pilot_buf[p_r][c].real, coh->rx_pilot_buf[p_r][c].imag); + } + //printf("\n"); + r++; + + //printf("r: %d data_r: %d\n", r, data_r); + /* copy NS rows of data symbols onto end of data symbol buffer */ + + for(i=0; irx_symb_buf[data_r][c] = rx_symb[r][c]; + } + } + + /* estimate channel amplitude and phase and correct data symbols in middle of buffer */ + + for (r=0, data_r=NSYMROW; r= 0); + assert(en < 3*NPILOTSFRAME); + + printf("r: %d data_r: %d st: %d en: %d\n", r, data_r, st, en); + + /* iterate over all of the carriers */ + + for (c=0; ctx_pilot_buf[i][c], coh->rx_pilot_buf[i][c])); + ch_est = fcmult(1.0/NP, ch_est); + coh->phi_[r][c] = atan2(ch_est.imag,ch_est.real); + coh->amp_[r][c] = cabsolute(ch_est); + + /* correct phase */ + + rot.real = cosf(coh->phi_[r][c]); rot.imag = -sinf(coh->phi_[r][c]); + coh->rx_symb_buf[data_r][c] = cmult(coh->rx_symb_buf[data_r][c], rot); + + /* demodulate */ + + i = c*NSYMROW + r; + rot = cmult(rx_symb[data_r][c], pi_on_4); + rx_bits[2*i] = rot.real < 0; + rx_bits[2*i+1] = rot.imag < 0; + + printf(" c: %d ch_est: %f %f phi_: %f amp_: %f\n",c, ch_est.real, ch_est.imag, coh->phi_[r][c], coh->amp_[r][c]); + } + //exit(0); + } + + /* shift buffers */ + + memcpy(&coh->rx_pilot_buf[0][0], &coh->rx_pilot_buf[NPILOTSFRAME][0], sizeof(COMP)*2*NPILOTSFRAME*PILOTS_NC); + memcpy(&coh->rx_symb_buf[0][0], &coh->rx_symb_buf[NSYMROW][0], sizeof(COMP)*2*NSYMROW*PILOTS_NC); + +} diff --git a/codec2-dev/src/cohpsk_defs.h b/codec2-dev/src/cohpsk_defs.h index 69ab1662..ff00b331 100644 --- a/codec2-dev/src/cohpsk_defs.h +++ b/codec2-dev/src/cohpsk_defs.h @@ -1,9 +1,10 @@ /* Generated by write_pilot_file() Octave function */ #define NSYMROW 20 /* number of data symbols for each row (i.e. each carrier) */ -#define NS 4 /* number of data symbols between pilots */ -#define NPILOTSFRAME 5 /* number of pilot symbols of each row */ -#define PILOTS_NC 4 /* number of carriers in coh modem */ +#define NS 4 /* number of data symbols between pilots */ +#define NP 2 /* number of pilots to use for channel est */ +#define NPILOTSFRAME 5 /* number of pilot symbols of each row */ +#define PILOTS_NC 4 /* number of carriers in coh modem */ -#define NSYMROWPILOT 25 /* length of row after pilots inserted */ +#define NSYMROWPILOT 25 /* length of row after pilots inserted */ diff --git a/codec2-dev/src/cohpsk_internal.h b/codec2-dev/src/cohpsk_internal.h new file mode 100644 index 00000000..354e7e4e --- /dev/null +++ b/codec2-dev/src/cohpsk_internal.h @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: cohpsk_internal.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 __COHPSK_INTERNAL__ +#define __COHPSK_INTERNAL__ + +struct COHPSK { + float tx_pilot_buf[3*NPILOTSFRAME][PILOTS_NC]; /* 3 frames of tx pilot symbols */ + COMP rx_pilot_buf[3*NPILOTSFRAME][PILOTS_NC]; /* 3 frames of rx piloy symbols */ + COMP rx_symb_buf[3*NSYMROW][PILOTS_NC]; /* 3 frames of rx data symbols */ + float phi_[NSYMROW][PILOTS_NC]; /* phase estimates for this frame of rx data symbols */ + float amp_[NSYMROW][PILOTS_NC]; /* amplitude estimates for this frame of rx data symbols */ +}; + +#endif diff --git a/codec2-dev/src/comp_prim.h b/codec2-dev/src/comp_prim.h new file mode 100644 index 00000000..8d86ac7e --- /dev/null +++ b/codec2-dev/src/comp_prim.h @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: comp_prim.h + AUTHOR......: David Rowe + DATE CREATED: Marh 2015 + + Complex number maths primitives. + +\*---------------------------------------------------------------------------*/ + +/* + 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 __COMP_PRIM__ +#define __COMP_PRIM__ + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +static COMP cneg(COMP a) +{ + COMP res; + + res.real = -a.real; + res.imag = -a.imag; + + return res; +} + +static COMP cconj(COMP a) +{ + COMP res; + + res.real = a.real; + res.imag = -a.imag; + + return res; +} + +static COMP cmult(COMP a, COMP b) +{ + COMP res; + + res.real = a.real*b.real - a.imag*b.imag; + res.imag = a.real*b.imag + a.imag*b.real; + + return res; +} + +static COMP fcmult(float a, COMP b) +{ + COMP res; + + res.real = a*b.real; + res.imag = a*b.imag; + + return res; +} + +static COMP cadd(COMP a, COMP b) +{ + COMP res; + + res.real = a.real + b.real; + res.imag = a.imag + b.imag; + + return res; +} + +static float cabsolute(COMP a) +{ + return sqrtf(powf(a.real, 2.0) + powf(a.imag, 2.0)); +} + +#endif diff --git a/codec2-dev/src/fdmdv.c b/codec2-dev/src/fdmdv.c index e96a1cbc..931adabe 100644 --- a/codec2-dev/src/fdmdv.c +++ b/codec2-dev/src/fdmdv.c @@ -39,6 +39,7 @@ #include "fdmdv_internal.h" #include "codec2_fdmdv.h" +#include "comp_prim.h" #include "rn.h" #include "rxdec_coeff.h" #include "test_bits.h" @@ -54,68 +55,7 @@ static int sync_uw[] = {1,-1,1,-1,1,-1}; #define printf gdb_stdio_printf #endif -/*---------------------------------------------------------------------------*\ - - FUNCTIONS - -\*---------------------------------------------------------------------------*/ - -static COMP cneg(COMP a) -{ - COMP res; - - res.real = -a.real; - res.imag = -a.imag; - - return res; -} - -static COMP cconj(COMP a) -{ - COMP res; - - res.real = a.real; - res.imag = -a.imag; - - return res; -} - -static COMP cmult(COMP a, COMP b) -{ - COMP res; - - res.real = a.real*b.real - a.imag*b.imag; - res.imag = a.real*b.imag + a.imag*b.real; - - return res; -} - -static COMP fcmult(float a, COMP b) -{ - COMP res; - - res.real = a*b.real; - res.imag = a*b.imag; - - return res; -} - -static COMP cadd(COMP a, COMP b) -{ - COMP res; - - res.real = a.real + b.real; - res.imag = a.imag + b.imag; - - return res; -} - -static float cabsolute(COMP a) -{ - return sqrtf(powf(a.real, 2.0) + powf(a.imag, 2.0)); -} - -/*---------------------------------------------------------------------------*\ +/*--------------------------------------------------------------------------* \ FUNCTION....: fdmdv_create AUTHOR......: David Rowe diff --git a/codec2-dev/src/fm.c b/codec2-dev/src/fm.c index 8d5e5be0..18f0a532 100644 --- a/codec2-dev/src/fm.c +++ b/codec2-dev/src/fm.c @@ -48,6 +48,7 @@ #include "codec2_fm.h" #include "fm_fir_coeff.h" +#include "comp_prim.h" /*---------------------------------------------------------------------------*\ @@ -55,41 +56,6 @@ \*---------------------------------------------------------------------------*/ -static COMP cconj(COMP a) -{ - COMP res; - - res.real = a.real; - res.imag = -a.imag; - - return res; -} - -static COMP cmult(COMP a, COMP b) -{ - COMP res; - - res.real = a.real*b.real - a.imag*b.imag; - res.imag = a.real*b.imag + a.imag*b.real; - - return res; -} - -static COMP fcmult(float a, COMP b) -{ - COMP res; - - res.real = a*b.real; - res.imag = a*b.imag; - - return res; -} - -static float cabsolute(COMP a) -{ - return sqrtf(powf(a.real, 2.0) + powf(a.imag, 2.0)); -} - /*---------------------------------------------------------------------------*\ FUNCTION....: fm_create diff --git a/codec2-dev/unittest/CMakeLists.txt b/codec2-dev/unittest/CMakeLists.txt index 1743a80b..7d1e98cb 100644 --- a/codec2-dev/unittest/CMakeLists.txt +++ b/codec2-dev/unittest/CMakeLists.txt @@ -52,7 +52,7 @@ 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) +target_link_libraries(tcohpsk codec2) 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 index 5550a207..08c295cb 100644 --- a/codec2-dev/unittest/tcohpsk.c +++ b/codec2-dev/unittest/tcohpsk.c @@ -38,6 +38,7 @@ #include "codec2_fdmdv.h" #include "codec2_cohpsk.h" #include "cohpsk_defs.h" +#include "cohpsk_internal.h" #include "test_bits_coh.h" #include "octave.h" @@ -46,39 +47,58 @@ int main(int argc, char *argv[]) { - int tx_bits[COHPSK_BITS_PER_FRAME]; - COMP tx_symbols[NSYMROWPILOT][PILOTS_NC]; + struct COHPSK *coh; + int tx_bits[COHPSK_BITS_PER_FRAME]; + COMP tx_symb[NSYMROWPILOT][PILOTS_NC]; + int rx_bits[COHPSK_BITS_PER_FRAME]; - int tx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES]; - COMP tx_symbols_log[NSYMROWPILOT*FRAMES][PILOTS_NC]; + int tx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES]; + COMP tx_symb_log[NSYMROWPILOT*FRAMES][PILOTS_NC]; + + float rx_amp_log[NSYMROW*FRAMES][PILOTS_NC]; + float rx_phi_log[NSYMROW*FRAMES][PILOTS_NC]; + int rx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES]; - FILE *fout; - int f, r,c,rx_sym_log_r; + FILE *fout; + int f, r, c, log_r, log_data_r; + + coh = cohpsk_create(); + assert(coh != NULL); - rx_sym_log_r=0; + log_r = log_data_r= 0; memcpy(tx_bits, test_bits_coh, sizeof(int)*COHPSK_BITS_PER_FRAME); for(f=0; famp_[r][c]; + rx_phi_log[log_data_r][c] = coh->phi_[r][c]; + } + } + memcpy(&rx_bits_log[COHPSK_BITS_PER_FRAME*f], rx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME); + + assert(log_r <= NSYMROWPILOT*FRAMES); + assert(log_data_r <= NSYMROW*FRAMES); + } /*---------------------------------------------------------*\ Dump logs to Octave file for evaluation @@ -89,9 +109,13 @@ int main(int argc, char *argv[]) assert(fout != NULL); fprintf(fout, "# Created by tcohpsk.c\n"); octave_save_int(fout, "tx_bits_log_c", tx_bits_log, 1, COHPSK_BITS_PER_FRAME*FRAMES); - octave_save_complex(fout, "tx_symbols_log_c", (COMP*)tx_symbols_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC); + octave_save_complex(fout, "tx_symb_log_c", (COMP*)tx_symb_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC); + octave_save_complex(fout, "rx_amp_log_c", (COMP*)rx_amp_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC); + octave_save_complex(fout, "rx_phi_log_c", (COMP*)rx_phi_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC); fclose(fout); + cohpsk_destroy(coh); + return 0; }