endfunction
+% generate a test frame of ldpc encoded bits, used for raw and
+% coded BER testing. Includes UW and txt files
+
+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;
+
+ % Set up LDPC code
+
+ mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray';
+
+ init_cml('/home/david/Desktop/cml/'); % TODO: make this path sensible and portable
+ load HRA_112_112.txt
+ [code_param framesize rate] = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping);
+ assert(Nbitsperframe == (code_param.code_bits_per_frame + Nuwbits + Ntxtbits));
+
+ rand('seed',1);
+ payload_data_bits = round(rand(1,code_param.data_bits_per_frame));
+ codeword = LdpcEncode(payload_data_bits, code_param.H_rows, code_param.P_matrix);
+ Nsymbolsperframe = length(codeword)/bps;
+
+ % need all these steps to get actual raw codeword bits at demod
+ % note this will only work for single interleaver frame case,
+ % but that's enough for initial quick tests
+
+ tx_symbols = [];
+ for s=1:Nsymbolsperframe
+ tx_symbols = [tx_symbols qpsk_mod( codeword(2*(s-1)+1:2*s) )];
+ end
+
+ tx_symbols = gp_interleave(tx_symbols);
+
+ codeword_raw = [];
+ for s=1:Nsymbolsperframe
+ codeword_raw = [codeword_raw qpsk_demod(tx_symbols(s))];
+ end
+
+ % insert UW and txt bits
+
+ tx_bits = [zeros(1,Nuwbits) zeros(1,Ntxtbits) codeword_raw];
+ assert(Nbitsperframe == length(tx_bits));
+
+endfunction
+
+
% Save test bits frame to a text file in the form of a C array
%
% usage:
%
function test_bits_ofdm_file
-
- 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;
-
- rand('seed',1);
- test_bits_ofdm = round(rand(1,Nbitsperframe));
- test_bits_ofdm(1:states.Ntxtbits) = 0; % insert Unique Word
- printf("%d test bits\n", Nbitsperframe);
+ [test_bits_ofdm payload_data_bits] = create_ldpc_test_frame;
+ printf("%d test bits\n", length(test_bits_ofdm));
f=fopen("../src/test_bits_ofdm.h","wt");
fprintf(f,"/* Generated by test_bits_ofdm_file() Octave function */\n\n");
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(test_bits_ofdm)));
+ fprintf(f," %d\n};\n",test_bits_ofdm(length(payload_data_bits)));
+
+ 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)));
fclose(f);
endfunction
DATE CREATED: Mar 2018
Given an input file of raw file (8kHz, 16 bit shorts) of OFDM modem
- samples. Optionally outputs one char per bit (hard decision), or
- soft decision rx_np and rx_amp QPSK symbols information for LDPC decoder.
+ samples. Optionally:
+
+ 1/ outputs one char per bit (hard decision)
+ 2/ bit LLRS, one double per bir, for external LDPC decoder like ldpc_dec
+ 3/ LDPC decoded bits, one char per bit
+
+ Also has test frame modes for uncoded and coded operation.
\*---------------------------------------------------------------------------*/
#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 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 */
int i, j, f, oct, logframes, arg, llr_en;
int Nerrs, Terrs, Tbits, Terrs2, Tbits2, testframes, frame_count;
+ int ldpc_en, Nerrs_coded, Tbits_coded, Terrs_coded;
struct LDPC ldpc;
ldpc.max_iter = HRA_112_112_MAX_ITER;
printf("usage: %s InputModemRawFile OutputFile [-o OctaveLogFile] [--llr] [-v VerboseLevel]\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, " -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, " -v Verbose info the stderr\n");
fprintf(stderr, " -o Octave log file for testing\n");
- fprintf(stderr, " --llr LLR output, one double per bit, %d doubles/frame\n", CODED_BITSPERFRAME);
fprintf(stderr, "\n");
exit(1);
}
testframes = 1;
}
+ ldpc_en = 0;
+ if (opt_exists(argv, argc, "--ldpc")) {
+ ldpc_en = 1;
+ llr_en = 1;
+ }
+
ofdm = ofdm_create(OFDM_CONFIG_700D);
assert(ofdm != NULL);
if ((arg = opt_exists(argv, argc, "-v")) != 0) {
- ofdm_set_verbose(ofdm, atoi(argv[arg+1]));
+ ofdm_set_verbose(ofdm, 1);
}
int Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
int rx_bits[Nbitsperframe];
char rx_bits_char[Nbitsperframe];
int rx_uw[OFDM_NUWBITS];
- f = 0; Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = frame_count = 0;
+ f = 0; Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = 0;
+ int parityCheckCount, iter;
float EsNo = 10;
- fprintf(stderr,"Warning EsNo: %f hard coded", EsNo);
+ fprintf(stderr,"Warning EsNo: %f hard coded\n", EsNo);
nin_frame = ofdm_get_nin(ofdm);
while(fread(rx_scaled, sizeof(short), nin_frame, fin) == nin_frame) {
llr[i] = -bit_likelihood[i];
}
- int iter;
char out_char[CODED_BITSPERFRAME];
- int parityCheckCount;
for(i=0; i<CODED_BITSPERFRAME; i++) {
llr[i] = -bit_likelihood[i];
}
-
- int ldpc_en = 1;
+
if (ldpc_en) {
+
/* run LDPC decoder and output decoded bits */
- /* TODO
- [ ] how to test uncoded modem, maybe use LDPC encoded frame?
- [ ] log unsucessfully decoded frames, outout them anyway?
- */
iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
- #ifdef TODO
- if (testframes) {
- /* measure raw and coded BER */
- Terrs += Nerrs;
- Tbits += Nbitsperframe;
- }
- if (frame_count >= NDISCARD) {
- Terrs2 += Nerrs;
- Tbits2 += Nbitsperframe;
+ 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;
}
- #endif
+ fwrite(out_char, sizeof(char), CODED_BITSPERFRAME, fout);
+ } else {
+ /* external LDPC decoder, so output LLRs */
+ fwrite(llr, sizeof(double), CODED_BITSPERFRAME, fout);
}
-
- fprintf(stderr, "iter: %d parityCheckCount: %d\n", iter, parityCheckCount);
-
- fwrite(llr, sizeof(double), CODED_BITSPERFRAME, fout);
} else {
/* simple hard decision output for uncoded testing, all bits in frame dumped inlcuding UW and txt */
}
if (ofdm->verbose) {
- fprintf(stderr, "f: %2d state: %-10s uw_errors: %2d %1d Nerrs: %3d foff: %3.1f\n",
+ 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, "\n");
}
/* optional logging of states */
fclose(fout);
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);
+ 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, "Coded BER: %5.4f Tbits: %5d Terrs: %5d\n",
+ (float)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded);
+ }
}
/* optionally dump Octave files */