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)
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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);
+ }
+}
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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
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];
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;
};
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;
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 */
/* 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]];
}
* ----------------------------------------------
*/
-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];
#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;
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[])
{
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");
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) {
/* 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];
}
/* 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];
/* 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:
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! */
/* 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++;
}
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 */
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
}
#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)
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);
}
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 */