From 03e4c1fa0d9cc7d67f572b7c678481a9af87f379 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 16 Apr 2018 21:57:54 +0000 Subject: [PATCH] C interleaver sync working, trying new C state macine to preventfalse syncs when freq offset est makes mistakes git-svn-id: https://svn.code.sf.net/p/freetel/code@3492 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/ofdm_ldpc_rx.m | 34 ++--- codec2-dev/octave/ofdm_lib.m | 22 +++- codec2-dev/src/gp_interleaver.c | 29 ++++- codec2-dev/src/gp_interleaver.h | 2 + codec2-dev/src/horus_demod.c | 2 +- codec2-dev/src/mpdecode_core.c | 29 ++++- codec2-dev/src/mpdecode_core.h | 1 + codec2-dev/src/ofdm.c | 71 +++++++---- codec2-dev/src/ofdm_demod.c | 212 ++++++++++++++++++++++--------- codec2-dev/src/ofdm_internal.h | 17 +-- codec2-dev/src/test_bits_ofdm.h | 2 +- 11 files changed, 300 insertions(+), 121 deletions(-) diff --git a/codec2-dev/octave/ofdm_ldpc_rx.m b/codec2-dev/octave/ofdm_ldpc_rx.m index bbe04efe..3c5fa44b 100644 --- a/codec2-dev/octave/ofdm_ldpc_rx.m +++ b/codec2-dev/octave/ofdm_ldpc_rx.m @@ -39,8 +39,8 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) % load real samples from file - Ascale= 2E5*1.1491; - frx=fopen(filename,"rb"); rx = 2*fread(frx, Inf, "short")/4E5; fclose(frx); + Ascale= 2E5*1.1491/2.0; + frx=fopen(filename,"rb"); rx = fread(frx, Inf, "short")/Ascale; fclose(frx); Nsam = length(rx); Nframes = floor(Nsam/Nsamperframe); prx = 1; @@ -144,6 +144,11 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np(Nuwtxtsymbolsperframe+1:end); rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp(Nuwtxtsymbolsperframe+1:end); + + % de-interleave QPSK symbols and symbol amplitudes + + rx_np_de = gp_deinterleave(rx_np); + rx_amp_de = gp_deinterleave(rx_amp); % Interleaver Sync: % Needs to work on any data @@ -151,14 +156,15 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) % Attempt a decode on every frame, when it converges we have sync next_sync_state_interleaver = states.sync_state_interleaver; + Nerrs_raw = Nerrs_coded = 0; - if strcmp(states.sync_state_interleaver,'searching') - arx_np = gp_deinterleave(rx_np); - arx_amp = gp_deinterleave(rx_amp); + if strcmp(states.sync_state_interleaver,'searching') st = 1; en = Ncodedbitsperframe/bps; - [rx_codeword parity_checks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_np(st:en), min(EsNo,30), arx_amp(st:en)); - if find(parity_checks == code_param.data_bits_per_frame) - % sucessful decode! + [rx_codeword parity_checks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_np_de(st:en), min(EsNo,30), rx_amp_de(st:en)); + Nerrs = code_param.data_bits_per_frame - max(parity_checks); + %printf("Nerrs: %d\n", Nerrs); + if Nerrs < 10 + % sucessful(ish) decode! next_sync_state_interleaver = 'synced'; states.frame_count_interleaver = interleave_frames; end @@ -166,21 +172,15 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) states.sync_state_interleaver = next_sync_state_interleaver; - Nerrs_raw = Nerrs_coded = 0; if strcmp(states.sync_state_interleaver,'synced') && (states.frame_count_interleaver == interleave_frames) states.frame_count_interleaver = 0; - printf("decode!\n"); + %printf("decode!\n"); - % de-interleave QPSK symbols and symbol amplitudes - - arx_np = gp_deinterleave(rx_np); - arx_amp = gp_deinterleave(rx_amp); - % measure uncoded bit errors over interleaver frame rx_bits_raw = []; for s=1:Nsymbolsperinterleavedframe - rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np(s))]; + rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np_de(s))]; end for ff=1:interleave_frames st = (ff-1)*Ncodedbitsperframe+1; en = st+Ncodedbitsperframe-1; @@ -199,7 +199,7 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) rx_bits = []; for ff=1:interleave_frames st = (ff-1)*Ncodedbitsperframe/bps+1; en = st + Ncodedbitsperframe/bps - 1; - [rx_codeword ldpc_errors] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_np(st:en), min(EsNo,30), arx_amp(st:en)); + [rx_codeword ldpc_errors] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_np_de(st:en), min(EsNo,30), rx_amp_de(st:en)); rx_bits = [rx_bits rx_codeword(1:code_param.data_bits_per_frame)]; end diff --git a/codec2-dev/octave/ofdm_lib.m b/codec2-dev/octave/ofdm_lib.m index 63ab4b6d..4a7699d6 100644 --- a/codec2-dev/octave/ofdm_lib.m +++ b/codec2-dev/octave/ofdm_lib.m @@ -519,7 +519,9 @@ function [tx_bits payload_data_bits] = create_ldpc_test_frame Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 17; Ns = 8; states = ofdm_init(bps, Rs, Tcp, Ns, Nc); ofdm_load_const; - + ldpc; + gp_interleaver; + % Set up LDPC code mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray'; @@ -574,13 +576,13 @@ function test_bits_ofdm_file for m=1:length(test_bits_ofdm)-1 fprintf(f," %d,\n",test_bits_ofdm(m)); endfor - fprintf(f," %d\n};\n",test_bits_ofdm(length(payload_data_bits))); + fprintf(f," %d\n};\n",test_bits_ofdm(end)); fprintf(f,"\nconst int payload_data_bits[]={\n"); for m=1:length(payload_data_bits)-1 fprintf(f," %d,\n",payload_data_bits(m)); endfor - fprintf(f," %d\n};\n",payload_data_bits(length(payload_data_bits))); + fprintf(f," %d\n};\n",payload_data_bits(end)); fclose(f); endfunction @@ -651,3 +653,17 @@ function states = sync_state_machine(states, rx_uw) states.last_sync_state_interleaver = states.sync_state_interleaver; states.sync_state = next_state; endfunction + + +% test function, kind of like a CRC for QPSK symbols, to compare two vectors + +function acc = test_acc(v) + sre = 0; sim = 0; + for i=1:length(v) + x = v(i); + re = round(real(x)); im = round(imag(x)); + sre += re; sim += im; + %printf("%d %10f %10f %10f %10f\n", i, re, im, sre, sim); + end + acc = sre + j*sim; +end diff --git a/codec2-dev/src/gp_interleaver.c b/codec2-dev/src/gp_interleaver.c index c138e167..1b92cb18 100644 --- a/codec2-dev/src/gp_interleaver.c +++ b/codec2-dev/src/gp_interleaver.c @@ -4,7 +4,7 @@ AUTHOR......: David Rowe DATE CREATED: April 2018 - Golden Prime Interleaver. My interprestation of "On the Analysis and + Golden Prime Interleaver. My interpretation of "On the Analysis and Design of Good Algebraic Interleavers", Xie et al,eq (5). See also octvae/gp_interleaver.m @@ -29,6 +29,7 @@ */ #include +#include #include "gp_interleaver.h" /* @@ -41,7 +42,7 @@ */ int b_table[] = { - 112,71, + 112,71, 224,139, 448,277, 672,419, @@ -79,20 +80,38 @@ int choose_interleaver_b(int Nbits) void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits) { int b = choose_interleaver_b(Nbits); int i,j; - for (i=0; i #include "mpdecode_core.h" +#define QPSK_CONSTELLATION_SIZE 4 +#define QPSK_BITS_PER_SYMBOL 2 + +/* QPSK constellation for symbol likelihood calculations */ + +static COMP S_matrix[] = { + { 1.0f, 0.0f}, + { 0.0f, 1.0f}, + { 0.0f, -1.0f}, + {-1.0f, 0.0f} +}; + + int extract_output(char out_char[], int DecodedBits[], int ParityCheckCount[], int max_iter, int CodeLength, int NumberParityBits); @@ -767,7 +780,7 @@ void Demod2D(double symbol_likelihood[], /* output, M*number_symbols float fading[], /* real fading values, number_symbols */ int number_symbols) { - int M=4; + int M=QPSK_CONSTELLATION_SIZE; int i,j; double tempsr, tempsi, Er, Ei; @@ -792,7 +805,7 @@ void Somap(double bit_likelihood[], /* number_bits, bps*number_symbols */ double symbol_likelihood[], /* M*number_symbols */ int number_symbols) { - int M=4, bps = 2; + int M=QPSK_CONSTELLATION_SIZE, bps = QPSK_BITS_PER_SYMBOL; int n,i,j,k,mask; double num[bps], den[bps]; double metric; @@ -858,3 +871,15 @@ int extract_output(char out_char[], int DecodedBits[], int ParityCheckCount[], i return iter; } +int symbols_to_llrs(double llr[], COMP rx_qpsk_symbols[], float rx_amps[], float EsNo, int nsyms) { + int i; + + double symbol_likelihood[nsyms*QPSK_CONSTELLATION_SIZE]; + double bit_likelihood[nsyms*QPSK_BITS_PER_SYMBOL]; + + Demod2D(symbol_likelihood, rx_qpsk_symbols, S_matrix, EsNo, rx_amps, nsyms); + Somap(bit_likelihood, symbol_likelihood, nsyms); + for(i=0; isync_start = 0; ofdm->sync_end = 0; + strcpy(ofdm->sync_state_interleaver,"searching"); + strcpy(ofdm->last_sync_state_interleaver,"searching"); + ofdm->frame_count_interleaver = 0; + /* create the OFDM waveform */ complex float temp[OFDM_M]; @@ -954,7 +958,7 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { char next_state[OFDM_STATE_STR]; - int i, j, sync_counter_thresh; + int i, j, sync_counter_thresh, uw_thresh; strcpy(next_state, ofdm->sync_state); ofdm->sync_start = ofdm->sync_end = 0; @@ -988,23 +992,11 @@ void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { } } - if ((strcmp(ofdm->sync_state,"synced") == 0) || (strcmp(ofdm->sync_state, "trial_sync") == 0)) { + if (!strcmp(ofdm->sync_state,"synced") || !strcmp(ofdm->sync_state, "trial_sync")) { ofdm->frame_count++; - - /* during trial sync we don't tolerate errors so much, once we have synced up - we are willing to wait out a fade */ - - if (ofdm->frame_count == 3) { - strcpy(next_state, "synced"); - } - - if (strcmp(ofdm->sync_state, "synced") == 0) { - sync_counter_thresh = 6; - } else { - sync_counter_thresh = 3; - } - + ofdm->frame_count_interleaver++; + /* freq offset est may be too far out, and has aliases every 1/Ts, so we use a Unique Word to get a really solid indication of sync. */ @@ -1012,17 +1004,50 @@ void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { for (i=0; iuw_errors += rx_uw[i]; } - if (ofdm->uw_errors > 2) { - ofdm->sync_counter++; - if (ofdm->sync_counter == sync_counter_thresh) { + + /* during trial sync we don't tolerate errors so much, we look + for 3 consecutive frames with low error rate to confirm + sync */ + + if (!strcmp(ofdm->sync_state, "trial_sync")) { + if (ofdm->uw_errors > 1) { + /* if we exceed thresh stay in trial sync */ + ofdm->sync_counter++; + ofdm->frame_count = 0; + } + if (ofdm->sync_counter == 2) { + /* if we get two bad frames drop sync and start again */ strcpy(next_state, "searching"); + strcpy(ofdm->sync_state_interleaver, "searching"); } - } else { - ofdm->sync_counter = 0; + + if (ofdm->frame_count == 3) { + /* three good frames, sync is OK! */ + strcpy(next_state, "synced"); + } + } + + /* once we have synced up we tolerate a higher error rate to wait out fades */ + + if (!strcmp(ofdm->sync_state, "synced")) { + if (ofdm->uw_errors > 2) { + ofdm->sync_counter++; + } else { + if (ofdm->sync_counter) { + ofdm->sync_counter--; + } + } + + if (ofdm->sync_counter == 6) { + /* run of consective bad frames ... drop sync */ + strcpy(next_state, "searching"); + strcpy(ofdm->sync_state_interleaver, "searching"); + } } } strcpy(ofdm->last_sync_state, ofdm->sync_state); + strcpy(ofdm->last_sync_state_interleaver, ofdm->sync_state_interleaver); strcpy(ofdm->sync_state, next_state); } diff --git a/codec2-dev/src/ofdm_demod.c b/codec2-dev/src/ofdm_demod.c index 37b8b4aa..2afda390 100644 --- a/codec2-dev/src/ofdm_demod.c +++ b/codec2-dev/src/ofdm_demod.c @@ -46,14 +46,19 @@ #include "mpdecode_core.h" #include "gp_interleaver.h" -#define ASCALE (2E5*1.1491/2.0) /* scale from shorts back to floats */ -#define NFRAMES 100 /* just log the first 100 frames */ -#define NDISCARD 20 /* BER2measure disctrds first 20 frames */ -#define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */ -#define DATA_BITSPERFRAME 112 /* number of LDPC payload data bits/frame */ +#define ASCALE (2E5*1.1491/2.0) /* scale from shorts back to floats */ +#define NFRAMES 100 /* just log the first 100 frames */ +#define NDISCARD 20 /* BER2measure disctrds first 20 frames */ +#define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */ +#define DATA_BITSPERFRAME 112 /* number of LDPC payload data bits/frame */ -#include "HRA_112_112.h" /* generated by ldpc_fsk_lib.m:ldpc_decode() */ -#define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */ +/* number of LDPC codeword QPSK symbols/frame */ + +#define CODED_SYMSPERFRAME (CODED_BITSPERFRAME/OFDM_BPS) + +#include "HRA_112_112.h" /* generated by ldpc_fsk_lib.m:ldpc_decode() */ + +void qpsk_demod(complex float symbol, int *bits); int opt_exists(char *argv[], int argc, char opt[]) { int i; @@ -65,6 +70,26 @@ int opt_exists(char *argv[], int argc, char opt[]) { return 0; } +/* CRC type function, used to compare QPSK vectors when debugging */ + +COMP test_acc(COMP v[], int n) { + COMP acc = {0.0,0.0}; + int i; + for(i=0; irx_np[j]); - ldpc_codeword_symbols[i].imag = cimagf(ofdm->rx_np[j]); - } - float *ldpc_codeword_symbol_amps = &ofdm->rx_amp[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS]; - - COMP codeword_symbols_de[CODED_BITSPERFRAME/OFDM_BPS]; - float codeword_amps_de[CODED_BITSPERFRAME/OFDM_BPS]; - - gp_interleave_comp(codeword_symbols_de, ldpc_codeword_symbols, CODED_BITSPERFRAME/OFDM_BPS); - gp_interleave_float(codeword_amps_de, ldpc_codeword_symbol_amps, CODED_BITSPERFRAME/OFDM_BPS); + /* now we need to buffer for de-interleaving -------------------------------------*/ - Demod2D(symbol_likelihood, codeword_symbols_de, S_matrix, EsNo, codeword_amps_de, CODED_BITSPERFRAME/OFDM_BPS); - Somap(bit_likelihood, symbol_likelihood, CODED_BITSPERFRAME/OFDM_BPS); - for(i=0; irx_np[j]); + codeword_symbols[i].imag = cimagf(ofdm->rx_np[j]); + codeword_amps[i] = ofdm->rx_amp[j]; } + + /* run de-interleaver */ + gp_deinterleave_comp (codeword_symbols_de, codeword_symbols, interleave_frames*CODED_SYMSPERFRAME); + gp_deinterleave_float(codeword_amps_de , codeword_amps , interleave_frames*CODED_SYMSPERFRAME); + + double llr[CODED_BITSPERFRAME]; + if (ldpc_en) { + char out_char[CODED_BITSPERFRAME]; + + /* + Interleaver Sync: + Needs to work on any data + Use indication of LDPC convergence, may need to patch CML code for that + Attempt a decode on every frame, when it converges we have sync + */ - /* run LDPC decoder and output decoded bits */ - - iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount); - - if (testframes) { - Nerrs_coded = 0; - for(i=0; isync_state_interleaver); + if (strcmp(ofdm->sync_state_interleaver,"searching") == 0) { + symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, CODED_SYMSPERFRAME); + iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount); + Nerrs = DATA_BITSPERFRAME - parityCheckCount; + fprintf(stderr, "iter: %d pcc: %d Nerrs: %d\n", iter, parityCheckCount, Nerrs); + if (Nerrs < 10) { + /* sucessful decode! */ + strcpy(next_sync_state_interleaver, "synced"); + ofdm->frame_count_interleaver = interleave_frames; } - Terrs_coded += Nerrs_coded; - Tbits_coded += DATA_BITSPERFRAME; } - fwrite(out_char, sizeof(char), CODED_BITSPERFRAME, fout); + strcpy(ofdm->sync_state_interleaver, next_sync_state_interleaver); + + Nerrs_raw = Nerrs_coded = 0; + if (!strcmp(ofdm->sync_state_interleaver,"synced") && (ofdm->frame_count_interleaver == interleave_frames)) { + ofdm->frame_count_interleaver = 0; + // printf("decode!\n"); + + if (testframes) { + + /* measure uncoded (raw) bit errors over interleaver frame */ + + int rx_bits_raw[CODED_BITSPERFRAME]; + for (j=0; jsync_start) { - Terrs = Tbits = Terrs2 = Tbits2 = frame_count = 0; + Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = 0; } if (ofdm->verbose) { - fprintf(stderr, "f: %2d state: %-10s uw_errors: %2d %1d Nerrs: %3d foff: %3.1f", - f, ofdm->last_sync_state, ofdm->uw_errors, ofdm->sync_counter, Nerrs, ofdm->foff_est_hz); - if (ldpc_en) { - fprintf(stderr, " Nerrs_coded: %3d iter: %3d pCC: %3d", Nerrs_coded, iter, parityCheckCount); - } + fprintf(stderr, "f: %2d st: %-10s uw_errs: %2d %1d inter_st: %-10s inter_fr: %d Nerrs_raw: %3d Nerrs_coded: %3d foff: %4.1f", + f, ofdm->last_sync_state, ofdm->uw_errors, ofdm->sync_counter, + ofdm->last_sync_state_interleaver, ofdm->frame_count_interleaver, + Nerrs_raw, Nerrs_coded, ofdm->foff_est_hz); fprintf(stderr, "\n"); } @@ -337,7 +429,9 @@ int main(int argc, char *argv[]) if (testframes) { fprintf(stderr, "BER......: %5.4f Tbits: %5d Terrs: %5d\n", (float)Terrs/Tbits, Tbits, Terrs); - fprintf(stderr, "BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (float)Terrs2/Tbits2, Tbits2, Terrs2); + if (!ldpc_en) { + fprintf(stderr, "BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (float)Terrs2/Tbits2, Tbits2, Terrs2); + } if (ldpc_en) { fprintf(stderr, "Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", (float)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded); diff --git a/codec2-dev/src/ofdm_internal.h b/codec2-dev/src/ofdm_internal.h index aeda3175..043d6d11 100644 --- a/codec2-dev/src/ofdm_internal.h +++ b/codec2-dev/src/ofdm_internal.h @@ -124,7 +124,7 @@ struct OFDM { float rx_amp[OFDM_ROWSPERFRAME * OFDM_NC]; float aphase_est_pilot_log[OFDM_ROWSPERFRAME * OFDM_NC]; - /* sync state machine */ + /* modem sync state machine */ char sync_state[OFDM_STATE_STR]; char last_sync_state[OFDM_STATE_STR]; @@ -133,17 +133,14 @@ struct OFDM { int frame_count; int sync_start; int sync_end; -}; - -/* QPSK constellation for symbol likelihood calculations */ -static COMP S_matrix[] = { - { 1.0f, 0.0f}, - { 0.0f, 1.0f}, - { 0.0f, -1.0f}, - {-1.0f, 0.0f} + /* interleaver sync state machine */ + + char sync_state_interleaver[OFDM_STATE_STR]; + char last_sync_state_interleaver[OFDM_STATE_STR]; + int frame_count_interleaver; }; - + #ifdef __cplusplus } #endif diff --git a/codec2-dev/src/test_bits_ofdm.h b/codec2-dev/src/test_bits_ofdm.h index 02120097..32dda835 100644 --- a/codec2-dev/src/test_bits_ofdm.h +++ b/codec2-dev/src/test_bits_ofdm.h @@ -238,7 +238,7 @@ const int test_bits_ofdm[]={ 0, 0, 0, - 0 + 1 }; const int payload_data_bits[]={ -- 2.25.1