refactoring of ldpc/interleaver code, added test mode, iterleaving, and ldpc to ofdm_...
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 18 Apr 2018 23:42:22 +0000 (23:42 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 18 Apr 2018 23:42:22 +0000 (23:42 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3501 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/CMakeLists.txt
codec2-dev/src/interldpc.c [new file with mode: 0644]
codec2-dev/src/interldpc.h [new file with mode: 0644]
codec2-dev/src/mpdecode_core.c
codec2-dev/src/mpdecode_core.h
codec2-dev/src/ofdm.c
codec2-dev/src/ofdm_demod.c
codec2-dev/src/ofdm_internal.h
codec2-dev/src/ofdm_mod.c

index bd3dcd931c6c2fbb95183d52b2a305597901e283..18ce356a18847ff667bebafddc4579722d25026b 100644 (file)
@@ -337,10 +337,10 @@ target_link_libraries(ofdm_get_test_bits ${CMAKE_REQUIRED_LIBRARIES} codec2)
 add_executable(ofdm_put_test_bits ofdm_put_test_bits.c)
 target_link_libraries(ofdm_put_test_bits ${CMAKE_REQUIRED_LIBRARIES} codec2)
 
-add_executable(ofdm_mod ofdm_mod.c)
+add_executable(ofdm_mod ofdm_mod.c interldpc.c mpdecode_core.c gp_interleaver.c)
 target_link_libraries(ofdm_mod ${CMAKE_REQUIRED_LIBRARIES} codec2)
 
-add_executable(ofdm_demod ofdm_demod.c octave.c mpdecode_core.c gp_interleaver.c)
+add_executable(ofdm_demod ofdm_demod.c octave.c mpdecode_core.c gp_interleaver.c interldpc.c)
 target_link_libraries(ofdm_demod ${CMAKE_REQUIRED_LIBRARIES} codec2)
 
 add_executable(fmfsk_mod fmfsk_mod.c)
diff --git a/codec2-dev/src/interldpc.c b/codec2-dev/src/interldpc.c
new file mode 100644 (file)
index 0000000..9d4b2ec
--- /dev/null
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: interldpc.c
+  AUTHOR......: David Rowe
+  DATE CREATED: April 2018
+
+  Helper functions for interleaved LDPC modems.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "interldpc.h"
+#include "codec2_ofdm.h"
+#include "ofdm_internal.h"
+#include "mpdecode_core.h"
+#include "gp_interleaver.h"
+#include "HRA_112_112.h"
+
+/* 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));
+    }
+}
+
+void set_up_hra_112_112(struct LDPC *ldpc) {
+    ldpc->max_iter = HRA_112_112_MAX_ITER;
+    ldpc->dec_type = 0;
+    ldpc->q_scale_factor = 1;
+    ldpc->r_scale_factor = 1;
+    ldpc->CodeLength = HRA_112_112_CODELENGTH;
+    ldpc->NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
+    ldpc->NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
+    ldpc->max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
+    ldpc->max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
+    ldpc->H_rows = HRA_112_112_H_rows;
+    ldpc->H_cols = HRA_112_112_H_cols;
+
+    /* provided for convenience and to match Octave vaiable names */
+    
+    ldpc->data_bits_per_frame = HRA_112_112_CODELENGTH - HRA_112_112_NUMBERPARITYBITS;
+    ldpc->coded_bits_per_frame = HRA_112_112_CODELENGTH;
+    ldpc->coded_syms_per_frame = ldpc->coded_bits_per_frame/OFDM_BPS;
+}
+
+void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]) {
+    unsigned char pbits[ldpc->coded_bits_per_frame];
+    int           i,j;
+    
+    encode(ldpc, tx_bits_char, pbits);
+    for(i=0; i<ldpc->data_bits_per_frame; i++) {
+        codeword[i] = tx_bits_char[i];
+    }
+    for(j=0; i<ldpc->coded_bits_per_frame; i++,j++) {
+        codeword[i] = pbits[i];
+    }
+}
+
+void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n) {
+    int s,i;
+    int dibit[2];
+    complex float qpsk_symb;
+    
+    for(s=0,i=0; i<n; s += 2,i++) {
+        dibit[0] = codeword[s+1] & 0x1;
+        dibit[1] = codeword[s] & 0x1;
+        qpsk_symb = qpsk_mod(dibit);
+        tx_symbols[i].real = crealf(qpsk_symb);
+        tx_symbols[i].imag = cimagf(qpsk_symb);
+    }    
+}
diff --git a/codec2-dev/src/interldpc.h b/codec2-dev/src/interldpc.h
new file mode 100644 (file)
index 0000000..b14a3bc
--- /dev/null
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: interldpc.h
+  AUTHOR......: David Rowe
+  DATE CREATED: April 2018
+
+  Helper functions for interleaved LDPC modems.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __INTERLDPC__
+#define __INTERLDPC__
+
+#include "comp.h"
+#include "mpdecode_core.h"
+
+/* CRC type function, used to compare QPSK vectors when debugging */
+
+COMP test_acc(COMP v[], int n);
+void printf_n(COMP v[], int n);
+void set_up_hra_112_112(struct LDPC *ldpc);
+void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]);
+void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n);
+
+#endif
index 62172e0502fa996c3e81c37df1903eb6290c549f..8b425a3dc98da16a546aa89e5bb6dcf50e5cbecb 100644 (file)
@@ -871,7 +871,7 @@ 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) {
+void 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];
index 50517a4085bfdf9122c37649e74cc51a72d0a548..e0ba45a74a5a73ec6373ba77e6a63c32b9016185 100644 (file)
@@ -23,6 +23,9 @@ struct LDPC {
     int NumberRowsHcols;
     int max_row_weight;
     int max_col_weight;
+    int data_bits_per_frame;
+    int coded_bits_per_frame;
+    int coded_syms_per_frame;
     double *H_rows;
     double *H_cols;
 };
@@ -35,7 +38,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);
+void symbols_to_llrs(double llr[], COMP rx_qpsk_symbols[], float rx_amps[], float EsNo, int nsyms);
 
 struct v_node {
   int degree;
index 6ee6037a2ff03bae5da70e3e63fc84152f4ca28d..d3352c34c6ea4fe24ff23aa53d90576ec7dfb784 100644 (file)
@@ -51,9 +51,6 @@ const struct OFDM_CONFIG  * OFDM_CONFIG_700D = &OFDM_CONFIG_700D_C;
 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 *);
-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);
 
 /* Defines */
@@ -88,7 +85,7 @@ static const int tx_uw[] = {1,0,0,1,0,1,0,0,1,0};
 
 /* Gray coded QPSK modulation function */
 
-static complex float qpsk_mod(int *bits) {
+complex float qpsk_mod(int *bits) {
     return constellation[(bits[1] << 1) | bits[0]];
 }
 
@@ -245,8 +242,11 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float *
  * ----------------------------------------------
  */
 
-static void ofdm_txframe(struct OFDM *ofdm, complex float tx[OFDM_SAMPLESPERFRAME],
-    complex float *tx_sym_lin) {
+void ofdm_txframe(
+    struct OFDM *ofdm,
+    complex float tx[OFDM_SAMPLESPERFRAME],
+    complex float *tx_sym_lin)
+{
     complex float aframe[OFDM_NS][OFDM_NC + 2];
     complex float asymbol[OFDM_M];
     complex float asymbol_cp[OFDM_M + OFDM_NCP];
index 66aac11abfc21ecccaf981bfdc316210e3f61f22..c1219be124f05112d4fd3135cb1b83646ede1168 100644 (file)
 #include "test_bits_ofdm.h"
 #include "mpdecode_core.h"
 #include "gp_interleaver.h"
+#include "interldpc.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 */
-
-/* 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;
@@ -70,25 +61,6 @@ 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[])
 {
@@ -106,28 +78,24 @@ int main(int argc, char *argv[])
     int            Nerrs, Terrs, Tbits, Terrs2, Tbits2, testframes, frame_count;
     int            ldpc_en, Tbits_coded, Terrs_coded;
     
-    struct LDPC   ldpc;
-    ldpc.max_iter = HRA_112_112_MAX_ITER;
-    ldpc.dec_type = 0;
-    ldpc.q_scale_factor = 1;
-    ldpc.r_scale_factor = 1;
-    ldpc.CodeLength = HRA_112_112_CODELENGTH;
-    ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
-    ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
-    ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
-    ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
-    ldpc.H_rows = HRA_112_112_H_rows;
-    ldpc.H_cols = HRA_112_112_H_cols;
+    /* Set up default LPDC code.  We could add other codes here if we like */
+    
+    struct LDPC ldpc;
+    set_up_hra_112_112(&ldpc);
+    int data_bits_per_frame = ldpc.data_bits_per_frame;
+    int coded_bits_per_frame = ldpc.coded_bits_per_frame;
+    int coded_syms_per_frame = ldpc.coded_syms_per_frame;
 
     if (argc < 3) {
         fprintf(stderr, "\n");
        printf("usage: %s InputModemRawFile OutputFile [-o OctaveLogFile] [--llr] [--ldpc] [--interleave depth] [-v]\n", argv[0]);
         fprintf(stderr, "\n");
         fprintf(stderr, "                Default output file format is one byte per bit hard decision\n");
-        fprintf(stderr, "  --llr         LLR output, one double per bit, %d doubles/frame\n", CODED_BITSPERFRAME);
+        fprintf(stderr, "  --llr         LLR output, one double per bit, %d doubles/frame\n", coded_bits_per_frame);
         fprintf(stderr, "  -t            Receive test frames and count errors\n");
-        fprintf(stderr, "  --ldpc        Run (224,112) LDPC decoder.  This forces 112, one char/bit output values\n"
-                        "                per frame.  In testframe mode (-t) raw and coded errors will be counted\n");
+        fprintf(stderr, "  --ldpc        Run (%d,%d) LDPC decoder.  This forces 112, one char/bit output values\n"
+                        "                per frame.  In testframe mode (-t) raw and coded errors will be counted\n",
+                                         coded_bits_per_frame, data_bits_per_frame);
         fprintf(stderr, "  --interleave  Interleaver for LDPC frames, e.g. 1,2,4,8,16, default is 1\n");
         fprintf(stderr, "  -v            Verbose info the stderr\n");
         fprintf(stderr, "  -o            Octave log file for testing\n");
@@ -212,10 +180,10 @@ 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];
+    COMP  codeword_symbols[interleave_frames*coded_syms_per_frame];
+    float codeword_amps[interleave_frames*coded_syms_per_frame];
+    COMP  codeword_symbols_de[interleave_frames*coded_syms_per_frame];
+    float codeword_amps_de[interleave_frames*coded_syms_per_frame];
 
     nin_frame = ofdm_get_nin(ofdm);
     while(fread(rx_scaled, sizeof(short), nin_frame, fin) == nin_frame) {
@@ -239,13 +207,13 @@ int main(int argc, char *argv[])
                 /* 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);
+                assert((OFDM_NUWBITS+OFDM_NTXTBITS+coded_bits_per_frame) == OFDM_BITSPERFRAME);
 
                 /* now we need to buffer for de-interleaving -------------------------------------*/
                 
                 /* shift interleaved symbol buffers to make room for new symbols */
                 
-                for(i=0, j=CODED_SYMSPERFRAME; j<interleave_frames*CODED_SYMSPERFRAME; i++,j++) {
+                for(i=0, j=coded_syms_per_frame; j<interleave_frames*coded_syms_per_frame; i++,j++) {
                     codeword_symbols[i] = codeword_symbols[j];
                     codeword_amps[i] = codeword_amps[j];
                 }
@@ -253,7 +221,7 @@ int main(int argc, char *argv[])
                 /* newest symbols at end of buffer (uses final i from last loop), note we 
                    change COMP formats from what modem uses internally */
                 
-                for(i=(interleave_frames-1)*CODED_SYMSPERFRAME,j=(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i<interleave_frames*CODED_SYMSPERFRAME; i++,j++) {
+                for(i=(interleave_frames-1)*coded_syms_per_frame,j=(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i<interleave_frames*coded_syms_per_frame; 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];
@@ -261,13 +229,13 @@ int main(int argc, char *argv[])
                
                 /* 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);
+                gp_deinterleave_comp (codeword_symbols_de, codeword_symbols, interleave_frames*coded_syms_per_frame);
+                gp_deinterleave_float(codeword_amps_de   , codeword_amps   , interleave_frames*coded_syms_per_frame);
 
-                double llr[CODED_BITSPERFRAME];
+                double llr[coded_bits_per_frame];
 
                 if (ldpc_en) {
-                    char out_char[CODED_BITSPERFRAME];
+                    char out_char[coded_bits_per_frame];
 
                     /* 
                        Interleaver Sync:
@@ -279,9 +247,9 @@ int main(int argc, char *argv[])
                     char next_sync_state_interleaver[OFDM_STATE_STR];
                     strcpy(next_sync_state_interleaver, ofdm->sync_state_interleaver);
                     if (strcmp(ofdm->sync_state_interleaver,"search") == 0) {
-                        symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, CODED_SYMSPERFRAME);               
+                        symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, coded_syms_per_frame);               
                         iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
-                        Nerrs = DATA_BITSPERFRAME - parityCheckCount;
+                        Nerrs = data_bits_per_frame - parityCheckCount;
                         //fprintf(stderr, "iter: %d pcc: %d Nerrs: %d\n", iter, parityCheckCount, Nerrs);
                         if (Nerrs < 10) {
                             /* sucessful decode! */
@@ -299,18 +267,18 @@ int main(int argc, char *argv[])
                             
                             /* measure uncoded (raw) bit errors over interleaver frame */
 
-                            int rx_bits_raw[CODED_BITSPERFRAME];
+                            int rx_bits_raw[coded_bits_per_frame];
                             for (j=0; j<interleave_frames; j++) {
-                                for(i=0; i<CODED_SYMSPERFRAME; i++) {
+                                for(i=0; i<coded_syms_per_frame; i++) {
                                     int bits[2];
-                                    complex float s = codeword_symbols_de[j*CODED_SYMSPERFRAME+i].real + I*codeword_symbols_de[j*CODED_SYMSPERFRAME+i].imag;
+                                    complex float s = codeword_symbols_de[j*coded_syms_per_frame+i].real + I*codeword_symbols_de[j*coded_syms_per_frame+i].imag;
                                     qpsk_demod(s, bits);
                                     rx_bits_raw[OFDM_BPS*i]   = bits[1];
                                     rx_bits_raw[OFDM_BPS*i+1] = bits[0];
                                 }
                                 Nerrs = 0;
-                                assert(sizeof(test_codeword)/sizeof(int) == CODED_BITSPERFRAME);
-                                for(i=0; i<CODED_BITSPERFRAME; i++) {
+                                assert(sizeof(test_codeword)/sizeof(int) == coded_bits_per_frame);
+                                for(i=0; i<coded_bits_per_frame; i++) {
                                     //fprintf(stderr, "%d %d %d\n", i, test_codeword[i], rx_bits_raw[i]);
                                     if (test_codeword[i] != rx_bits_raw[i]) {
                                         Nerrs++;
@@ -324,30 +292,30 @@ int main(int argc, char *argv[])
                         }
 
                         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);               
+                            symbols_to_llrs(llr, &codeword_symbols_de[j*coded_syms_per_frame],
+                                                 &codeword_amps_de[j*coded_syms_per_frame],
+                                                 EsNo, coded_syms_per_frame);               
                             iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
 
                             if (testframes) {
                                 Nerrs = 0;
-                                for(i=0; i<DATA_BITSPERFRAME; i++) {
+                                for(i=0; i<data_bits_per_frame; i++) {
                                     if (payload_data_bits[i] != out_char[i]) {
                                         Nerrs++;
                                     }
                                 }
                                 Nerrs_coded[j] = Nerrs;
                                 Terrs_coded += Nerrs;
-                                Tbits_coded += DATA_BITSPERFRAME;
+                                Tbits_coded += data_bits_per_frame;
                             }
-                            fwrite(out_char, sizeof(char), CODED_BITSPERFRAME, fout);
+                            fwrite(out_char, sizeof(char), coded_bits_per_frame, fout);
                         }
                     } /* if interleaver synced ..... */
                          
                 } else {
                     /* 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);
+                    symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, coded_syms_per_frame);
+                        fwrite(llr, sizeof(double), coded_bits_per_frame, fout);
                 }
             } else {
                 /* simple hard decision output for uncoded testing, all bits in frame dumped inlcuding UW and txt */
index 1586e63f4695973c351231402c1c8c6826e5b7fe..c4b30d5e6e4d8ae5eab1c12d833ef41d7a124899 100644 (file)
@@ -135,13 +135,20 @@ struct OFDM {
     int frame_count;
     int sync_start;
     int sync_end;
-
+    
     /* interleaver sync state machine */
     
     char sync_state_interleaver[OFDM_STATE_STR];
     char last_sync_state_interleaver[OFDM_STATE_STR];
     int  frame_count_interleaver;
 };
+    
+    
+/* function headers exposed for LDPC work */
+    
+complex float qpsk_mod(int *);
+void qpsk_demod(complex float, int *);
+void ofdm_txframe(struct OFDM *, complex float tx_samples[OFDM_SAMPLESPERFRAME], complex float tx_symbols_lin[]);
 
 #ifdef __cplusplus
 }
index 626d0ac8dfc731c3eaf8684825d0fbf9d6104bae..86972ec096b55f8ef173e8b952fd223f74f5bc4e 100644 (file)
 #include <errno.h>
 
 #include "codec2_ofdm.h"
+#include "ofdm_internal.h"
+#include "interldpc.h"
+#include "gp_interleaver.h"
+#include "test_bits_ofdm.h"
 
 #define ASCALE (2E5*1.1491)
 
@@ -53,11 +57,25 @@ int main(int argc, char *argv[])
     FILE          *fin, *fout;
     struct OFDM   *ofdm;
     int           frames;
-    int           i;
-
+    int           i, j, arg;
+    int           testframes, ldpc_en, interleaver_frames;
+   
+    /* Set up default LPDC code.  We could add other codes here if we like */
+    
+    struct LDPC   ldpc;
+    set_up_hra_112_112(&ldpc);
+    int data_bits_per_frame = ldpc.data_bits_per_frame;
+    int coded_bits_per_frame = ldpc.coded_bits_per_frame;
+    int coded_syms_per_frame = ldpc.coded_syms_per_frame;
+    
     if (argc < 3) {
         fprintf(stderr, "\n");
-       fprintf(stderr, "usage: %s InputOneCharPerBitFile OutputModemRawFile\n", argv[0]);
+       fprintf(stderr, "usage: %s InputOneCharPerBitFile OutputModemRawFile [--lpdc] [--interleaver depth]\n\n", argv[0]);
+        fprintf(stderr, "  -t            Transmit test frames (adjusts test frames for raw and LDPC modes)\n");
+        fprintf(stderr, "  --ldpc        Run (%d,%d) LDPC decoder.  This forces 112, one char/bit output values\n"
+                        "                per frame.  In testframe mode (-t) raw and coded errors will be counted\n",
+                                         coded_bits_per_frame, data_bits_per_frame);
+        fprintf(stderr, "  --interleave  Interleaver for LDPC frames, e.g. 1,2,4,8,16, default is 1\n");
         fprintf(stderr, "\n");
        exit(1);
     }
@@ -78,30 +96,114 @@ int main(int argc, char *argv[])
     
     ofdm = ofdm_create(OFDM_CONFIG_700D);
     assert(ofdm != NULL);
-    int Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
-    int Nsamperframe = ofdm_get_samples_per_frame();
 
-    char  tx_bits_char[Nbitsperframe];
-    int   tx_bits[Nbitsperframe];
-    COMP  tx_sams[Nsamperframe];
-    short tx_scaled[Nsamperframe];
+    testframes = 0;
+    if (opt_exists(argv, argc, "-t")) {
+        testframes = 1;
+    }
+
+    /* set for LDPC coded or uncoded frames */
     
-    frames = 0;
+    ldpc_en = 0; interleaver_frames = 1;
+    int Nbitsperframe;
+    if (opt_exists(argv, argc, "--ldpc")) {
 
-    while(fread(tx_bits_char, sizeof(char), Nbitsperframe, fin) == Nbitsperframe) {
-       frames++;
+        assert((OFDM_NUWBITS+OFDM_NTXTBITS+coded_bits_per_frame) == OFDM_BITSPERFRAME); /* sanity check */
+
+        ldpc_en = 1;
+        if ((arg = opt_exists(argv, argc, "--interleaver"))) {
+            interleaver_frames = atoi(argv[arg]);
+        }
+        Nbitsperframe = interleaver_frames*data_bits_per_frame;
         
-        for(i=0; i<Nbitsperframe; i++)
-            tx_bits[i] = tx_bits_char[i];
-       ofdm_mod(ofdm, tx_sams, tx_bits);
+    } else {
+        /* vanilla uncoded input bits mode */
+        Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
+    }
+    
+    int Nsamperframe = ofdm_get_samples_per_frame();
 
-       /* scale and save to disk as shorts */
+    unsigned char tx_bits_char[Nbitsperframe];
+    int           tx_bits[Nbitsperframe];
+    short         tx_scaled[Nsamperframe];
+    
+    /* build modulated UW and txt bits */
 
-       for(i=0; i<Nsamperframe; i++)
-           tx_scaled[i] = ASCALE * tx_sams[i].real;
+    int  uw_txt_bits[OFDM_NUWBITS+OFDM_NTXTBITS];
+    COMP uw_txt_syms[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS];
+    complex float tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS + coded_syms_per_frame];
+    for(i=0; i<OFDM_NUWBITS; i++) {
+        uw_txt_bits[i] = ofdm->tx_uw[i];
+    }
+    for(j=0; j<OFDM_NTXTBITS; j++,i++) {
+        uw_txt_bits[i] = 0;
+    }    
+    qpsk_modulate_frame(uw_txt_syms, uw_txt_bits, (OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS);
+    for(i=0; i<(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i++) {
+        tx_symbols[i] = uw_txt_syms[i].real + I * uw_txt_syms[i].imag;
+    }
+    
+    /* main loop ----------------------------------------------------------------*/
+    
+    frames = 0;
 
-       fwrite(tx_scaled, sizeof(short), Nsamperframe, fout);
+    while(fread(tx_bits_char, sizeof(char), Nbitsperframe, fin) == Nbitsperframe) {
+       frames++;
 
+        if (ldpc_en) {
+            /* fancy interleaved LDPC encoded frames ----------------------------------------*/
+            
+            /* optionally overwrite input data with test frame nown to demodulator */
+            
+            if (testframes) {
+                for (j=0; j<interleaver_frames; j++) {
+                    for(i=0; i<data_bits_per_frame; i++) {
+                        tx_bits_char[j*data_bits_per_frame + i] = payload_data_bits[i];
+                    }
+                }
+            }
+            
+            int codeword[coded_bits_per_frame];
+            COMP coded_symbols[interleaver_frames*coded_syms_per_frame];
+            COMP coded_symbols_inter[interleaver_frames*coded_syms_per_frame];
+            complex float tx_sams[Nsamperframe];
+
+            for (j=0; j<interleaver_frames; j++) {
+                ldpc_encode_frame(&ldpc, codeword, &tx_bits_char[j*data_bits_per_frame]);
+                qpsk_modulate_frame(&coded_symbols[j*coded_syms_per_frame], codeword, coded_syms_per_frame);
+                gp_interleave_comp(coded_symbols_inter, coded_symbols, interleaver_frames*coded_syms_per_frame);
+                for(i=0; i<coded_syms_per_frame; i++) {
+                    tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS+i] = coded_symbols_inter[j*coded_syms_per_frame+i].real
+                                                                        + I * coded_symbols_inter[j*coded_syms_per_frame+i].imag;
+                }
+                ofdm_txframe(ofdm, tx_sams, tx_symbols);
+                for(i=0; i<Nsamperframe; i++) {
+                    tx_scaled[i] = ASCALE * crealf(tx_sams[i]);
+                }
+                fwrite(tx_scaled, sizeof(short), Nsamperframe, fout);
+            }
+        
+        } else {
+            /* just modulate uncoded raw bits ----------------------------------------------*/
+            
+            if (testframes) {
+                for(i=0; i<Nbitsperframe; i++) {
+                    tx_bits_char[i] = test_bits_ofdm[i];
+                }
+            }
+            for(i=0; i<Nbitsperframe; i++)
+                tx_bits[i] = tx_bits_char[i];
+            COMP tx_sams[Nsamperframe];
+            ofdm_mod(ofdm, tx_sams, tx_bits);
+
+            /* scale and save to disk as shorts */
+
+            for(i=0; i<Nsamperframe; i++)
+                tx_scaled[i] = ASCALE * tx_sams[i].real;
+
+            fwrite(tx_scaled, sizeof(short), Nsamperframe, fout);
+        }
+        
        /* if this is in a pipeline, we probably don't want the usual
           buffering to occur */