add_executable(ofdm_mod ofdm_mod.c)
target_link_libraries(ofdm_mod ${CMAKE_REQUIRED_LIBRARIES} codec2)
-add_executable(ofdm_demod ofdm_demod.c octave.c mpdecode_core.c)
+add_executable(ofdm_demod ofdm_demod.c octave.c mpdecode_core.c gp_interleaver.c)
target_link_libraries(ofdm_demod ${CMAKE_REQUIRED_LIBRARIES} codec2)
add_executable(fmfsk_mod fmfsk_mod.c)
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: gp_interleaver.c
+ AUTHOR......: David Rowe
+ DATE CREATED: April 2018
+
+ Golden Prime Interleaver. My interprestation of "On the Analysis and
+ Design of Good Algebraic Interleavers", Xie et al,eq (5).
+
+ See also octvae/gp_interleaver.m
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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 "gp_interleaver.h"
+
+/*
+ Choose b for Golden Prime Interleaver. b is chosen to be the
+ closest integer, which is relatively prime to N, to the Golden
+ section of N.
+
+ Implemented with a LUT in C for convenience, Octave version
+ has a more complete implementation.
+*/
+
+int b_table[] = {
+ 112,71,
+ 224,139,
+ 448,277,
+ 672,419,
+ 896,557,
+ 1120,701,
+ 1344,839,
+ 1568,971,
+ 1792,1109,
+ 2016,1249,
+ 2240,1399,
+ 2464,1523,
+ 2688,1663,
+ 2912,1801,
+ 3136,1949,
+ 3360,2081,
+ 3584,2213
+};
+
+int choose_interleaver_b(int Nbits)
+{
+ int i;
+
+ for(i=0; i<sizeof(b_table)/(2*sizeof(int)); i+=2) {
+ if (b_table[i] == Nbits) {
+ return b_table[i+1];
+ }
+ }
+
+ /* if we get it means a Nbits we dont have in our table so choke */
+
+ assert(0);
+}
+
+
+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;
+ interleaved_frame[j] = frame[i];
+ }
+}
+
+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;
+ interleaved_frame[j] = frame[i];
+ }
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: gp_interleaver.h
+ AUTHOR......: David Rowe
+ DATE CREATED: April 2018
+
+ Golden Prime Interleaver. My interprestation of "On the Analysis and
+ Design of Good Algebraic Interleavers", Xie et al,eq (5).
+
+ See also octvae/gp_interleaver.m
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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 __GP_INTERLEAVER__
+#define __GP_INTERLEAVER__
+
+#include "comp.h"
+
+void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits);
+void gp_interleave_float(float frame[], float interleaved_frame[], int Nbits);
+
+#endif
fprintf(stderr, " InOneSymbolPerDouble Input file of double LLRs, use - for the \n"); \r
fprintf(stderr, " file names to use stdin/stdout\n");\r
fprintf(stderr, " --code Use LDPC code CodeName\n");\r
+ fprintf(stderr, " --listcodes List available LDPC codes\n");\r
fprintf(stderr, " --sd Treat input file samples as Soft Decision\n");\r
fprintf(stderr, " demod outputs rather than LLRs\n");\r
fprintf(stderr, " --half Load framesize/2 input samples for each decode\n");\r
input_double[i] = 0.0;\r
}\r
}\r
+ fprintf(stderr, "CodeLength: %d offset: %d\n", CodeLength, offset);\r
\r
while(fread(&input_double[offset], sizeof(double), nread, fin) == nread) {\r
if (sdinput) {\r
\r
// Output data bits if decoder converged, or was\r
// within 10% of all parity checks converging (10% est\r
- // BER). usefule for real world operation as it can\r
+ // BER). useful for real world operation as it can\r
// resync and won't send crappy packets to the decoder\r
\r
float ber_est = (float)(ldpc.NumberParityBits - parityCheckCount)/ldpc.NumberParityBits;\r
break;\r
}\r
state = next_state;\r
- //fprintf(stderr, "state: %d iter: %d\n", state, iter);\r
+ fprintf(stderr, "state: %d iter: %d\n", state, iter);\r
}\r
\r
for(i=0; i<offset; i++) {\r
return 0;
}
-void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]) {
- unsigned int p, i, tmp, par, prev=0;
- int ind;
- double *H_rows = ldpc->H_rows;
-
- for (p=0; p<ldpc->NumberParityBits; p++) {
- par = 0;
-
- for (i=0; i<ldpc->max_row_weight; i++) {
- ind = (int)H_rows[p + i*ldpc->NumberParityBits];
- par = par + ibits[ind-1];
- }
-
- tmp = par + prev;
-
- tmp &= 1; // only retain the lsb
- prev = tmp;
- pbits[p] = tmp;
- }
-}
-
int main(int argc, char *argv[])
{
unsigned char ibits[NUMBERROWSHCOLS];
int extract_output(char out_char[], int DecodedBits[], int ParityCheckCount[],
int max_iter, int CodeLength, int NumberParityBits);
+void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]) {
+ unsigned int p, i, tmp, par, prev=0;
+ int ind;
+ double *H_rows = ldpc->H_rows;
+
+ for (p=0; p<ldpc->NumberParityBits; p++) {
+ par = 0;
+
+ for (i=0; i<ldpc->max_row_weight; i++) {
+ ind = (int)H_rows[p + i*ldpc->NumberParityBits];
+ par = par + ibits[ind-1];
+ }
+
+ tmp = par + prev;
+
+ tmp &= 1; // only retain the lsb
+ prev = tmp;
+ pbits[p] = tmp;
+ }
+}
+
/* Phi function */
static float phi0(
float x )
double *H_cols;
};
+void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]);
+
int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[], int *parityCheckCount);
void sd_to_llr(double llr[], double sd[], int n);
\*---------------------------------------------------------------------------*/
/*
- Copyright (C) 2015 David Rowe
+ Copyright (C) 2018 David Rowe
All rights reserved.
#include "octave.h"
#include "test_bits_ofdm.h"
#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 */
+#include "HRA_112_112.h" /* generated by ldpc_fsk_lib.m:ldpc_decode() */
+#define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */
+
int opt_exists(char *argv[], int argc, char opt[]) {
int i;
for (i=0; i<argc; i++) {
int i, j, f, oct, logframes, arg, llr_en;
int Nerrs, Terrs, Tbits, Terrs2, Tbits2, testframes, frame_count;
+ 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;
+
if (argc < 3) {
fprintf(stderr, "\n");
- printf("usage: %s InputModemRawFile OutputFile [-o OctaveLogFile] [--sd] [-v VerboseLevel]\n", argv[0]);
+ 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, " -t Receive test frames and count errors\n");
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 */
assert((OFDM_NUWBITS+OFDM_NTXTBITS+CODED_BITSPERFRAME) == OFDM_BITSPERFRAME);
- COMP ldpc_codeword_symbols[(CODED_BITSPERFRAME/OFDM_BPS)];
+ 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);
- Demod2D(symbol_likelihood, ldpc_codeword_symbols, S_matrix, EsNo, ldpc_codeword_symbol_amps, CODED_BITSPERFRAME/OFDM_BPS);
+ 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];
+ }
+
+ int iter;
+ char out_char[CODED_BITSPERFRAME];
+ int parityCheckCount;
+
+
+ fprintf(stderr, "\n");
+ for(i=0; i<CODED_BITSPERFRAME; i++) {
+ llr[i] = -bit_likelihood[i];
+ if (i <5) {
+ fprintf(stderr, "%d symb: %f %f a: %f llr %f\n", i,
+ ldpc_codeword_symbols[i].real, ldpc_codeword_symbols[i].imag,
+ ldpc_codeword_symbol_amps[i], llr[i]);
+ }
+ }
+
+ fprintf(stderr, "\n");
+
+ iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
- fwrite(bit_likelihood, sizeof(double), CODED_BITSPERFRAME, fout);
+ fprintf(stderr, "iter: %d parityCheckCount: %d\n", iter, parityCheckCount);
+ /*
+ for(i=0; i<CODED_BITSPERFRAME; i++) {
+ fprintf(stderr, "%d ", out_char[i]);
+ }
+ */
+
+ fwrite(llr, sizeof(double), CODED_BITSPERFRAME, fout);
} else {
/* simple hard decision output for uncoded testing, all bits in frame dumped inlcuding UW and txt */