From: drowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63> Date: Mon, 16 Apr 2018 21:57:54 +0000 (+0000) Subject: C interleaver sync working, trying new C state macine to preventfalse syncs when... X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=03e4c1fa0d9cc7d67f572b7c678481a9af87f379;p=freetel-svn-tracking.git 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 --- 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 <assert.h> +#include <stdio.h> #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<Nbits; i++) { - j = b*i % Nbits; + j = (b*i) % Nbits; interleaved_frame[j] = frame[i]; } } +void gp_deinterleave_comp(COMP frame[], COMP interleaved_frame[], int Nbits) { + int b = choose_interleaver_b(Nbits); + int i,j; + for (i=0; i<Nbits; i++) { + j = (b*i) % Nbits; + frame[i] = interleaved_frame[j]; + } +} + void gp_interleave_float(float interleaved_frame[], float frame[], int Nbits) { int b = choose_interleaver_b(Nbits); int i,j; for (i=0; i<Nbits; i++) { - j = b*i % Nbits; + j = (b*i) % Nbits; interleaved_frame[j] = frame[i]; } } +void gp_deinterleave_float(float frame[], float interleaved_frame[], int Nbits) { + int b = choose_interleaver_b(Nbits); + int i,j; + + for (i=0; i<Nbits; i++) { + j = (b*i) % Nbits; + frame[i] = interleaved_frame[j]; + } +} + diff --git a/codec2-dev/src/gp_interleaver.h b/codec2-dev/src/gp_interleaver.h index fd8a602b..b95820ad 100644 --- a/codec2-dev/src/gp_interleaver.h +++ b/codec2-dev/src/gp_interleaver.h @@ -34,6 +34,8 @@ #include "comp.h" void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits); +void gp_deinterleave_comp(COMP frame[], COMP interleaved_frame[], int Nbits); void gp_interleave_float(float frame[], float interleaved_frame[], int Nbits); +void gp_deinterleave_float(float interleaved_frame[], float frame[], int Nbits); #endif diff --git a/codec2-dev/src/horus_demod.c b/codec2-dev/src/horus_demod.c index 9d50fd39..cf95d3be 100644 --- a/codec2-dev/src/horus_demod.c +++ b/codec2-dev/src/horus_demod.c @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) { fprintf(stderr,"\n"); fprintf(stderr,"InputModemRawFile 48 kHz 16 bit shorts real modem signal from radio\n"); fprintf(stderr," -m RTTY|binary\n"); - fprintf(stderr,"--mode=RTTY|binary[r] RTTY or binary Horus protcols\n"); + fprintf(stderr,"--mode=RTTY|binary RTTY or binary Horus protcols\n"); fprintf(stderr," -t[r] --stats=[r] Print out modem statistics to stderr in JSON.\n"); fprintf(stderr," r, if provided, sets the number of modem frames\n" " between statistic printouts\n"); diff --git a/codec2-dev/src/mpdecode_core.c b/codec2-dev/src/mpdecode_core.c index 5cda6795..62172e05 100644 --- a/codec2-dev/src/mpdecode_core.c +++ b/codec2-dev/src/mpdecode_core.c @@ -12,6 +12,19 @@ #include <stdio.h> #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; i<nsyms*QPSK_BITS_PER_SYMBOL; i++) { + llr[i] = -bit_likelihood[i]; + } +} diff --git a/codec2-dev/src/mpdecode_core.h b/codec2-dev/src/mpdecode_core.h index 6fd202db..50517a40 100644 --- a/codec2-dev/src/mpdecode_core.h +++ b/codec2-dev/src/mpdecode_core.h @@ -35,6 +35,7 @@ void sd_to_llr(double llr[], double sd[], int n); void Demod2D(double symbol_likelihood[], COMP r[], COMP S_matrix[], float EsNo, float fading[], int number_symbols); void Somap(double bit_likelihood[], double symbol_likelihood[], int number_symbols); +int symbols_to_llrs(double llr[], COMP rx_qpsk_symbols[], float rx_amps[], float EsNo, int nsyms); struct v_node { int degree; diff --git a/codec2-dev/src/ofdm.c b/codec2-dev/src/ofdm.c index baf18430..a66351a1 100644 --- a/codec2-dev/src/ofdm.c +++ b/codec2-dev/src/ofdm.c @@ -52,7 +52,7 @@ static void dft(struct OFDM *, complex float *, complex float *); static void idft(struct OFDM *, complex float *, complex float *); static complex float vector_sum(complex float *, int); static complex float qpsk_mod(int *); -static void qpsk_demod(complex float, int *); +void qpsk_demod(complex float, int *); static void ofdm_txframe(struct OFDM *, complex float [OFDM_SAMPLESPERFRAME], complex float *); static int coarse_sync(struct OFDM *, complex float *, int, float *foff_est); @@ -92,7 +92,7 @@ static complex float qpsk_mod(int *bits) { /* Gray coded QPSK demodulation function */ -static void qpsk_demod(complex float symbol, int *bits) { +void qpsk_demod(complex float symbol, int *bits) { complex float rotate = symbol * cexpf(I * (M_PI / 4.0f)); bits[0] = crealf(rotate) < 0.0f; bits[1] = cimagf(rotate) < 0.0f; @@ -392,6 +392,10 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { ofdm->sync_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; i<OFDM_NUWBITS; i++) { ofdm->uw_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; i<n; i++) { + acc.real += round(v[i].real); + acc.imag += round(v[i].imag); + //fprintf(stderr, "%d %10f %10f %10f %10f\n", i, round(v[i].real), round(v[i].imag), acc.real, acc.imag); + } + return acc; +} + +void printf_n(COMP v[], int n) { + int i; + for(i=0; i<n; i++) { + fprintf(stderr, "%d %10f %10f\n", i, round(v[i].real), round(v[i].imag)); + } +} + int main(int argc, char *argv[]) { FILE *fin, *fout, *foct; @@ -77,9 +102,9 @@ int main(int argc, char *argv[]) float foff_hz_log[NFRAMES]; int timing_est_log[NFRAMES]; - int i, j, f, oct, logframes, arg, llr_en; + int i, j, f, oct, logframes, arg, llr_en, interleave_frames; int Nerrs, Terrs, Tbits, Terrs2, Tbits2, testframes, frame_count; - int ldpc_en, Nerrs_coded, Tbits_coded, Terrs_coded; + int ldpc_en, Nerrs_coded, Tbits_coded, Terrs_coded, Nerrs_raw; struct LDPC ldpc; ldpc.max_iter = HRA_112_112_MAX_ITER; @@ -151,6 +176,15 @@ int main(int argc, char *argv[]) llr_en = 1; } + interleave_frames = 1; + if ((arg = opt_exists(argv, argc, "--interleave"))) { + interleave_frames = atoi(argv[arg+1]); + fprintf(stderr, "interleave_frames: %d\n", interleave_frames); + /* we can't de-interleave without LDPC for sync, so switch that on */ + ldpc_en = 1; + llr_en = 1; + } + ofdm = ofdm_create(OFDM_CONFIG_700D); assert(ofdm != NULL); @@ -172,6 +206,11 @@ int main(int argc, char *argv[]) float EsNo = 10; fprintf(stderr,"Warning EsNo: %f hard coded\n", EsNo); + COMP codeword_symbols[interleave_frames*CODED_SYMSPERFRAME]; + float codeword_amps[interleave_frames*CODED_SYMSPERFRAME]; + COMP codeword_symbols_de[interleave_frames*CODED_SYMSPERFRAME]; + float codeword_amps_de[interleave_frames*CODED_SYMSPERFRAME]; + nin_frame = ofdm_get_nin(ofdm); while(fread(rx_scaled, sizeof(short), nin_frame, fin) == nin_frame) { @@ -190,61 +229,115 @@ int main(int argc, char *argv[]) ofdm_demod(ofdm, rx_bits, rxbuf_in); if (llr_en) { - double symbol_likelihood[ (CODED_BITSPERFRAME/OFDM_BPS) * (1<<OFDM_BPS) ]; - double bit_likelihood[CODED_BITSPERFRAME]; - double llr[CODED_BITSPERFRAME]; - - /* first few symbols are used for UW and txt bits, find start of (224,112) LDPC codeword */ + + /* first few symbols are used for UW and txt bits, find start of (224,112) LDPC codeword + and extract QPSK symbols and amplitude estimates */ assert((OFDM_NUWBITS+OFDM_NTXTBITS+CODED_BITSPERFRAME) == OFDM_BITSPERFRAME); - COMP ldpc_codeword_symbols[CODED_BITSPERFRAME/OFDM_BPS]; - for(i=0, j=(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i<(CODED_BITSPERFRAME/OFDM_BPS); i++,j++) { - ldpc_codeword_symbols[i].real = crealf(ofdm->rx_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; i<CODED_BITSPERFRAME; i++) { - llr[i] = -bit_likelihood[i]; - } + /* shift interleaved symbol buffers to make room for new symbols */ - char out_char[CODED_BITSPERFRAME]; + for(i=0, j=CODED_SYMSPERFRAME; j<interleave_frames*CODED_SYMSPERFRAME; i++,j++) { + codeword_symbols[i] = codeword_symbols[j]; + codeword_amps[i] = codeword_amps[j]; + } + + /* newest symbols at end of buffer (uses final i from last loop), note we + change COMP formats from what modem uses internally */ - for(i=0; i<CODED_BITSPERFRAME; i++) { - llr[i] = -bit_likelihood[i]; + for(i=(interleave_frames-1)*CODED_SYMSPERFRAME,j=(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i<interleave_frames*CODED_SYMSPERFRAME; i++,j++) { + codeword_symbols[i].real = crealf(ofdm->rx_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; i<DATA_BITSPERFRAME; i++) { - if (payload_data_bits[i] != out_char[i]) { - Nerrs_coded++; - } + char next_sync_state_interleaver[OFDM_STATE_STR]; + strcpy(next_sync_state_interleaver, ofdm->sync_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; j<interleave_frames; j++) { + for(i=0; i<CODED_SYMSPERFRAME; i++) { + complex float s = codeword_symbols_de[j*CODED_SYMSPERFRAME+i].real + I*codeword_symbols_de[j*CODED_SYMSPERFRAME+i].imag; + qpsk_demod(s, &rx_bits_raw[OFDM_BPS*i]); + } + Nerrs = 0; + for(i=0; i<CODED_BITSPERFRAME; i++) { + //fprintf(stderr, "%d %d %d\n", i, test_bits_ofdm[i], rx_bits_raw[i]); + if (test_bits_ofdm[i] != rx_bits_raw[i]) { + Nerrs++; + } + } + Nerrs_raw += Nerrs; + } + Terrs += Nerrs_raw; + Tbits += Nbitsperframe; + } + + for (j=0; j<interleave_frames; j++) { + symbols_to_llrs(llr, &codeword_symbols_de[j*CODED_SYMSPERFRAME], + &codeword_amps_de[j*CODED_SYMSPERFRAME], + EsNo, CODED_SYMSPERFRAME); + iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount); + + if (testframes) { + Nerrs_coded = 0; + for(i=0; i<DATA_BITSPERFRAME; i++) { + if (payload_data_bits[i] != out_char[i]) { + Nerrs_coded++; + } + } + Terrs_coded += Nerrs_coded; + Tbits_coded += DATA_BITSPERFRAME; + } + fwrite(out_char, sizeof(char), CODED_BITSPERFRAME, fout); + } + } /* if interleaver synced ..... */ + } else { - /* external LDPC decoder, so output LLRs */ - fwrite(llr, sizeof(double), CODED_BITSPERFRAME, fout); + /* lpdc_en == 0, external LDPC decoder, so output LLRs */ + symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, CODED_SYMSPERFRAME); + fwrite(llr, sizeof(double), CODED_BITSPERFRAME, fout); } - } else { /* simple hard decision output for uncoded testing, all bits in frame dumped inlcuding UW and txt */ for(i=0; i<Nbitsperframe; i++) { @@ -259,9 +352,9 @@ int main(int argc, char *argv[]) rx_uw[i] = rx_bits[i]; } - /* optional error counting in testframe mode */ + /* optional error counting on uncoded data in non-LDPC testframe mode */ - if (testframes) { + if (testframes && (ldpc_en == 0)) { Nerrs = 0; for(i=0; i<Nbitsperframe; i++) { if (test_bits_ofdm[i] != rx_bits[i]) { @@ -286,15 +379,14 @@ int main(int argc, char *argv[]) /* act on any events returned by state machine */ if (ofdm->sync_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[]={