aboutsummaryrefslogtreecommitdiff
path: root/src/ofdm_demod.c
diff options
context:
space:
mode:
authorAuthor Name <[email protected]>2023-07-07 12:20:59 +0930
committerDavid Rowe <[email protected]>2023-07-07 12:29:06 +0930
commitac7c48b4dee99d4c772f133d70d8d1b38262fcd2 (patch)
treea2d0ace57a9c0e2e5b611c4987f6fed1b38b81e7 /src/ofdm_demod.c
shallow zip-file copy from codec2 e9d726bf20
Diffstat (limited to 'src/ofdm_demod.c')
-rw-r--r--src/ofdm_demod.c692
1 files changed, 692 insertions, 0 deletions
diff --git a/src/ofdm_demod.c b/src/ofdm_demod.c
new file mode 100644
index 0000000..babe91e
--- /dev/null
+++ b/src/ofdm_demod.c
@@ -0,0 +1,692 @@
+/*---------------------------------------------------------------------------*\
+
+ FILE........: ofdm_demod.c
+ AUTHOR......: David Rowe
+ DATE CREATED: Mar 2018
+
+ Demodulates an input file of raw file (8kHz, 16 bit shorts) OFDM modem
+ samples. Runs in uncoded or LDPC coded modes.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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.1, 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/>.
+ */
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#include "optparse.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+
+#include "codec2_ofdm.h"
+#include "ofdm_internal.h"
+#include "octave.h"
+#include "mpdecode_core.h"
+#include "ldpc_codes.h"
+#include "gp_interleaver.h"
+#include "interldpc.h"
+
+#define IS_DIR_SEPARATOR(c) ((c) == '/')
+
+#define NFRAMES 100 /* just log the first 100 frames */
+#define NDISCARD 20 /* BER2 measure discards first 20 frames */
+#define FS 8000.0f
+
+static const char *progname;
+
+static const char *statemode[] = {
+ "search",
+ "trial",
+ "synced"
+};
+
+void opt_help() {
+ fprintf(stderr, "\nusage: %s [options]\n\n", progname);
+ fprintf(stderr, " Default output file format is one byte per bit hard decision\n\n");
+ fprintf(stderr, " --in filename Name of InputModemRawFile\n");
+ fprintf(stderr, " --out filename Name of OutputOneCharPerBitFile\n");
+ fprintf(stderr, " --log filename Octave log file for testing\n");
+ fprintf(stderr, " --mode modeName Predefined mode e.g. 700D|2020|datac1 etc\n");
+ fprintf(stderr, " --nc [17..62] Number of Carriers (17 default, 62 max)\n");
+ fprintf(stderr, " --np Number of packets\n");
+ fprintf(stderr, " --ns Nframes One pilot every ns symbols (8 default)\n");
+ fprintf(stderr, " --tcp Nsecs Cyclic Prefix Duration (.002 default)\n");
+ fprintf(stderr, " --ts Nsecs Symbol Duration (.018 default)\n");
+ fprintf(stderr, " --bandwidth [0|1] Select phase est bw mode AUTO low or high (0) or LOCKED high (1) (default 0)\n");
+ fprintf(stderr, " Must also specify --ldpc option\n");
+ fprintf(stderr, " --tx_freq freq Set modulation TX centre Frequency (1500.0 default)\n");
+ fprintf(stderr, " --rx_freq freq Set modulation RX centre Frequency (1500.0 default)\n");
+ fprintf(stderr, " --verbose [1|2|3] Verbose output level to stderr (default off)\n");
+ fprintf(stderr, " --testframes Receive test frames and count errors\n");
+ fprintf(stderr, " --ldpc Run LDPC decoder\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " --start_secs secs Number of seconds delay before we start to demod\n");
+ fprintf(stderr, " --len_secs secs Number of seconds to run demod\n");
+ fprintf(stderr, " --skip_secs timeSecs At timeSecs introduce a large timing error by skipping half a frame of samples\n");
+ fprintf(stderr, " --packetsperburst p use burst mode; number of packets we expect per burst\n");
+ fprintf(stderr, "\n");
+
+ exit(-1);
+}
+
+int main(int argc, char *argv[]) {
+ int i, j, opt, val;
+
+ char *pn = argv[0] + strlen(argv[0]);
+
+ while (pn != argv[0] && !IS_DIR_SEPARATOR(pn[-1]))
+ --pn;
+
+ progname = pn;
+
+ /* Turn off stream buffering */
+
+ setvbuf(stdin, NULL, _IONBF, BUFSIZ);
+ setvbuf(stdout, NULL, _IONBF, BUFSIZ);
+
+ FILE *fin = stdin;
+ FILE *fout = stdout;
+ FILE *foct = NULL;
+
+ char *fin_name = NULL;
+ char *fout_name = NULL;
+ char *log_name = NULL;
+
+ int logframes = NFRAMES;
+ int verbose = 0;
+ int phase_est_bandwidth_mode = AUTO_PHASE_EST;
+ int ldpc_en = 0;
+ int Ndatabitsperpacket = 0;
+ int packetsperburst = 0;
+
+ bool testframes = false;
+ bool input_specified = false;
+ bool output_specified = false;
+ bool log_specified = false;
+ bool log_active = false;
+
+ float time_to_sync = -1;
+ float start_secs = 0.0;
+ float len_secs = 0.0;
+ float skip_secs = 0.0;
+
+ /* set up the default modem config */
+ struct OFDM_CONFIG *ofdm_config = (struct OFDM_CONFIG *) calloc(1, sizeof (struct OFDM_CONFIG));
+ assert(ofdm_config != NULL);
+ char mode[32] = "700D";
+ ofdm_init_mode(mode, ofdm_config);
+
+ struct optparse options;
+ struct optparse_long longopts[] = {
+ {"in", 'a', OPTPARSE_REQUIRED},
+ {"out", 'b', OPTPARSE_REQUIRED},
+ {"log", 'c', OPTPARSE_REQUIRED},
+ {"testframes", 'd', OPTPARSE_NONE},
+ {"bandwidth", 'o', OPTPARSE_REQUIRED},
+ {"tx_freq", 'f', OPTPARSE_REQUIRED},
+ {"rx_freq", 'g', OPTPARSE_REQUIRED},
+ {"verbose", 'v', OPTPARSE_REQUIRED},
+ {"ldpc", 'i', OPTPARSE_NONE},
+ {"nc", 'j', OPTPARSE_REQUIRED},
+ {"tcp", 'k', OPTPARSE_REQUIRED},
+ {"ts", 'l', OPTPARSE_REQUIRED},
+ {"ns", 'm', OPTPARSE_REQUIRED},
+ {"np", 'n', OPTPARSE_REQUIRED},
+ {"start_secs", 'x', OPTPARSE_REQUIRED},
+ {"len_secs", 'y', OPTPARSE_REQUIRED},
+ {"skip_secs", 'z', OPTPARSE_REQUIRED},
+ {"mode", 'r', OPTPARSE_REQUIRED},
+ {"packetsperburst", 'e', OPTPARSE_REQUIRED},
+ {0, 0, 0}
+ };
+
+ optparse_init(&options, argv);
+
+ while ((opt = optparse_long(&options, longopts, NULL)) != -1) {
+ switch (opt) {
+ case '?':
+ opt_help();
+ case 'a':
+ fin_name = options.optarg;
+ input_specified = true;
+ break;
+ case 'b':
+ fout_name = options.optarg;
+ output_specified = true;
+ break;
+ case 'c':
+ log_name = options.optarg;
+ log_specified = true;
+ log_active = true;
+ break;
+ case 'd':
+ testframes = true;
+ break;
+ case 'e':
+ packetsperburst = atoi(options.optarg);
+ fprintf(stderr, "burst data mode!\n");
+ break;
+ case 'i':
+ ldpc_en = 1;
+ break;
+ case 'f':
+ ofdm_config->tx_centre = atof(options.optarg);
+ break;
+ case 'g':
+ ofdm_config->rx_centre = atof(options.optarg);
+ break;
+ case 'j':
+ val = atoi(options.optarg);
+
+ if (val > 62 || val < 17) {
+ opt_help();
+ } else {
+ ofdm_config->nc = val;
+ }
+ break;
+ case 'k':
+ ofdm_config->tcp = atof(options.optarg);
+ break;
+ case 'l':
+ ofdm_config->ts = atof(options.optarg);
+ ofdm_config->rs = 1.0f/ofdm_config->ts;
+ break;
+ case 'm':
+ ofdm_config->ns = atoi(options.optarg);
+ break;
+ case 'n':
+ ofdm_config->np = atoi(options.optarg);
+ break;
+ case 'o':
+ phase_est_bandwidth_mode = atoi(options.optarg);
+ break;
+ case 'r':
+ strcpy(mode, options.optarg);
+ ofdm_init_mode(mode, ofdm_config);
+ break;
+ case 'v':
+ verbose = atoi(options.optarg);
+ if (verbose < 0 || verbose > 3)
+ verbose = 0;
+ break;
+ case 'x':
+ start_secs = atoi(options.optarg);
+ break;
+ case 'y':
+ len_secs = atoi(options.optarg);
+ break;
+ case 'z':
+ skip_secs = atoi(options.optarg);
+ break;
+
+ }
+ }
+
+ /* Print remaining arguments to give user a hint */
+ char *arg;
+
+ while ((arg = optparse_arg(&options)))
+ fprintf(stderr, "%s\n", arg);
+
+ if (input_specified == true) {
+ if ((fin = fopen(fin_name, "rb")) == NULL) {
+ fprintf(stderr, "Error opening input modem sample file: %s\n", fin_name);
+ exit(-1);
+ }
+ }
+
+ if (output_specified == true) {
+ if ((fout = fopen(fout_name, "wb")) == NULL) {
+ fprintf(stderr, "Error opening output file: %s\n", fout_name);
+ exit(-1);
+ }
+ }
+
+ if (log_specified == true) {
+ if ((foct = fopen(log_name, "wt")) == NULL) {
+ fprintf(stderr, "Error opening Octave output file: %s\n", log_name);
+ exit(-1);
+ }
+ }
+
+ /* Create OFDM modem ----------------------------------------------------*/
+
+ struct OFDM *ofdm = ofdm_create(ofdm_config);
+ assert(ofdm != NULL);
+ free(ofdm_config);
+
+ ofdm_set_phase_est_bandwidth_mode(ofdm, phase_est_bandwidth_mode);
+ // default to one packet per burst for burst mode
+ if (packetsperburst) {
+ ofdm_set_packets_per_burst(ofdm, packetsperburst);
+ }
+
+ /* Get a copy of the actual modem config (ofdm_create() fills in more parameters) */
+ ofdm_config = ofdm_get_config_param(ofdm);
+
+ int ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm);
+ int ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps);
+ int ofdm_nuwbits = ofdm_config->nuwbits;
+ int ofdm_ntxtbits = ofdm_config->txtbits;
+
+ float phase_est_pilot_log[ofdm_rowsperframe * NFRAMES][ofdm_config->nc];
+ COMP rx_np_log[ofdm_rowsperframe * ofdm_config->nc * NFRAMES];
+ float rx_amp_log[ofdm_rowsperframe * ofdm_config->nc * NFRAMES];
+ float foff_hz_log[NFRAMES];
+ int timing_est_log[NFRAMES];
+
+ /* zero out the log arrays in case we don't run for NFRAMES and fill them with data */
+
+ for (i = 0; i < (ofdm_rowsperframe * NFRAMES); i++) {
+ for (j = 0; j < ofdm_config->nc; j++) {
+ phase_est_pilot_log[i][j] = 0.0f;
+ }
+ }
+
+ for (i = 0; i < (ofdm_rowsperframe * ofdm_config->nc * NFRAMES); i++) {
+ rx_np_log[i].real = 0.0f;
+ rx_np_log[i].imag = 0.0f;
+ rx_amp_log[i] = 0.0f;
+ }
+
+ for (i = 0; i < NFRAMES; i++) {
+ foff_hz_log[i] = 0.0f;
+ timing_est_log[i] = 0.0f;
+ }
+
+ /* some useful constants */
+
+ int Nbitsperframe = ofdm_bitsperframe;
+ int Nbitsperpacket = ofdm_get_bits_per_packet(ofdm);
+ int Nsymsperframe = Nbitsperframe / ofdm_config->bps;
+ int Nsymsperpacket = Nbitsperpacket / ofdm_config->bps;
+ int Nmaxsamperframe = ofdm_get_max_samples_per_frame(ofdm);
+ int Npayloadbitsperframe = ofdm_bitsperframe;
+ int Npayloadbitsperpacket = Nbitsperpacket - ofdm_nuwbits - ofdm_ntxtbits;
+ int Npayloadsymsperframe = Npayloadbitsperframe/ofdm_config->bps;
+ int Npayloadsymsperpacket = Npayloadbitsperpacket/ofdm_config->bps;
+
+ /* Set up LPDC codes */
+
+ struct LDPC ldpc;
+ COMP payload_syms[Npayloadsymsperpacket];
+ float payload_amps[Npayloadsymsperpacket];
+
+ if (ldpc_en) {
+ ldpc_codes_setup(&ldpc, ofdm->codename);
+ ldpc_mode_specific_setup(ofdm, &ldpc);
+ Ndatabitsperpacket = ldpc.data_bits_per_frame;
+
+ if (verbose > 1) {
+ fprintf(stderr, "using: %s\n", ofdm->codename);
+ fprintf(stderr, "LDPC codeword data bits = %d\n", ldpc.ldpc_data_bits_per_frame);
+ fprintf(stderr, "LDPC codeword total bits = %d\n", ldpc.ldpc_coded_bits_per_frame);
+ fprintf(stderr, "LDPC codeword data bits used = %d\n", Ndatabitsperpacket);
+ fprintf(stderr, "LDPC codeword total length in modem packet = %d\n", Npayloadbitsperpacket);
+ }
+ }
+
+ if (verbose != 0) {
+ ofdm_set_verbose(ofdm, verbose);
+ }
+
+ complex float rx_syms[Nsymsperpacket]; float rx_amps[Nsymsperpacket];
+ for(int i=0; i<Nsymsperpacket; i++) {
+ rx_syms[i] = 0.0;
+ rx_amps[i]= 0.0;
+ }
+
+ short rx_scaled[Nmaxsamperframe];
+ int rx_bits[Nbitsperframe];
+ uint8_t rx_bits_char[Nbitsperframe];
+ uint8_t rx_uw[ofdm_nuwbits];
+ short txt_bits[ofdm_ntxtbits];
+
+ /* error counting */
+ int Terrs, Tbits, Terrs2, Tbits2, Terrs_coded, Tbits_coded, frame_count, packet_count, Ndiscard;
+ Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = packet_count = 0;
+ int Nerrs_raw = 0;
+ int Nerrs_coded = 0;
+ int Ncoded;
+ int Tper = 0;
+ int iter = 0;
+ int parityCheckCount = 0;
+ float SNR3kdB = 0.0;
+ float sum_SNR3kdB = 0.0;
+
+ if (strlen(ofdm->data_mode) == 0)
+ Ndiscard = NDISCARD; /* backwards compatibility with 700D/2020 */
+ else
+ Ndiscard = 1; /* much longer packets, so discard thresh smaller */
+
+ float EsNo = 3.0f;
+
+ if (verbose == 2)
+ fprintf(stderr, "Warning EsNo: %f hard coded\n", EsNo);
+
+ /* More logging */
+ COMP payload_syms_log[NFRAMES][Npayloadsymsperpacket];
+ float payload_amps_log[NFRAMES][Npayloadsymsperpacket];
+
+ for (i = 0; i < NFRAMES; i++) {
+ for (j = 0; j < Npayloadsymsperframe; j++) {
+ payload_syms_log[i][j].real = 0.0f;
+ payload_syms_log[i][j].imag = 0.0f;
+ payload_amps_log[i][j] = 0.0f;
+ }
+ }
+
+ int nin_frame = ofdm_get_nin(ofdm);
+
+ int f = 0;
+ int finish = 0;
+
+ if (start_secs != 0.0) {
+ int offset = start_secs*FS*sizeof(short);
+ fseek(fin, offset, SEEK_SET);
+ }
+
+ while ((fread(rx_scaled, sizeof (short), nin_frame, fin) == nin_frame) && !finish) {
+
+ if (verbose >= 2)
+ fprintf(stderr, "%3d nin: %4d st: %-6s ", f, nin_frame,statemode[ofdm->sync_state]);
+ bool log_payload_syms = false;
+ Nerrs_raw = Nerrs_coded = 0;
+
+ /* demod */
+
+ if (ofdm->sync_state == search) {
+ ofdm_sync_search_shorts(ofdm, rx_scaled, (ofdm->amp_scale / 2.0f));
+ }
+
+ if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)) {
+ log_payload_syms = true;
+
+ /* demod the latest modem frame */
+ ofdm_demod_shorts(ofdm, rx_bits, rx_scaled, (ofdm->amp_scale / 2.0f));
+
+ /* accumulate a buffer of data symbols for this packet */
+ for(i=0; i<Nsymsperpacket-Nsymsperframe; i++) {
+ rx_syms[i] = rx_syms[i+Nsymsperframe];
+ rx_amps[i] = rx_amps[i+Nsymsperframe];
+ }
+ memcpy(&rx_syms[Nsymsperpacket-Nsymsperframe], ofdm->rx_np, sizeof(complex float)*Nsymsperframe);
+ memcpy(&rx_amps[Nsymsperpacket-Nsymsperframe], ofdm->rx_amp, sizeof(float)*Nsymsperframe);
+
+ /* look for UW as frames enter packet buffer, note UW may span several modem frames */
+ int st_uw = Nsymsperpacket - ofdm->nuwframes*Nsymsperframe;
+ ofdm_extract_uw(ofdm, &rx_syms[st_uw], &rx_amps[st_uw], rx_uw);
+
+ if (ofdm->modem_frame == (ofdm->np-1)) {
+
+ /* we have received enough frames to make a complete packet .... */
+
+ /* extract payload symbols from packet */
+ ofdm_disassemble_qpsk_modem_packet(ofdm, rx_syms, rx_amps, payload_syms, payload_amps, txt_bits);
+
+ if (ldpc_en) {
+ assert((ofdm_nuwbits + ofdm_ntxtbits + Npayloadbitsperpacket) <= Nbitsperpacket);
+
+ /* run de-interleaver */
+ COMP payload_syms_de[Npayloadsymsperpacket];
+ float payload_amps_de[Npayloadsymsperpacket];
+ gp_deinterleave_comp(payload_syms_de, payload_syms, Npayloadsymsperpacket);
+ gp_deinterleave_float(payload_amps_de, payload_amps, Npayloadsymsperpacket);
+
+ float llr[Npayloadbitsperpacket];
+ uint8_t out_char[Npayloadbitsperpacket];
+
+ if (testframes == true) {
+ Nerrs_raw = count_uncoded_errors(&ldpc, ofdm_config, payload_syms_de,0); Terrs += Nerrs_raw;
+ Tbits += Npayloadbitsperpacket; /* not counting errors in txt bits */
+ }
+
+ symbols_to_llrs(llr, payload_syms_de, payload_amps_de,
+ EsNo, ofdm->mean_amp, Npayloadsymsperpacket);
+
+ assert(Ndatabitsperpacket == ldpc.data_bits_per_frame);
+ ldpc_decode_frame(&ldpc, &parityCheckCount, &iter, out_char, llr);
+
+ if (testframes == true) {
+ /* construct payload data bits */
+ uint8_t payload_data_bits[Ndatabitsperpacket];
+ ofdm_generate_payload_data_bits(payload_data_bits, Ndatabitsperpacket);
+ count_errors_protection_mode(ldpc.protection_mode, &Nerrs_coded, &Ncoded,
+ payload_data_bits, out_char, Ndatabitsperpacket);
+ Terrs_coded += Nerrs_coded;
+ Tbits_coded += Ncoded;
+ if (Nerrs_coded) Tper++;
+ }
+
+ fwrite(out_char, sizeof (char), Ndatabitsperpacket, fout);
+ } else {
+ /* simple hard decision output of payload data bits */
+ assert(Npayloadsymsperpacket*ofdm_config->bps == Npayloadbitsperpacket);
+ for (i = 0; i < Npayloadsymsperpacket; i++) {
+ int bits[2];
+ complex float s = payload_syms[i].real + I * payload_syms[i].imag;
+ qpsk_demod(s, bits);
+ rx_bits_char[ofdm_config->bps * i] = bits[1];
+ rx_bits_char[ofdm_config->bps * i + 1] = bits[0];
+ }
+
+ fwrite(rx_bits_char, sizeof (uint8_t), Npayloadbitsperpacket, fout);
+ }
+
+ /* optional error counting on uncoded data in non-LDPC testframe mode */
+
+ if ((testframes == true) && (ldpc_en == 0)) {
+ /* build up a test frame consisting of unique word, txt bits, and psuedo-random
+ uncoded payload bits. The psuedo-random generator is the same as Octave so
+ it can interoperate with ofdm_tx.m/ofdm_rx.m */
+
+ uint8_t payload_bits[Npayloadbitsperpacket];
+ uint8_t txt_bits[ofdm_ntxtbits]; memset(txt_bits, 0, ofdm_ntxtbits);
+ uint8_t tx_bits[Nbitsperpacket];
+ ofdm_generate_payload_data_bits(payload_bits, Npayloadbitsperpacket);
+ ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits);
+
+ /* count errors across UW, payload, txt bits */
+ int rx_bits[Nbitsperpacket];
+ int dibit[2];
+ assert(ofdm->bps == 2); /* this only works for QPSK at this stage */
+ for(int s=0; s<Nsymsperpacket; s++) {
+ qpsk_demod(rx_syms[s], dibit);
+ rx_bits[2*s ] = dibit[1];
+ rx_bits[2*s+1] = dibit[0];
+ }
+ for (Nerrs_raw=0, i = 0; i < Nbitsperpacket; i++) if (tx_bits[i] != rx_bits[i]) Nerrs_raw++;
+ Terrs += Nerrs_raw;
+ Tbits += Nbitsperpacket;
+
+ if (packet_count >= Ndiscard) {
+ Terrs2 += Nerrs_raw;
+ Tbits2 += Nbitsperpacket;
+ }
+ }
+ packet_count++;
+
+ float EsNodB = ofdm_esno_est_calc(rx_syms, Npayloadsymsperpacket);
+ SNR3kdB = ofdm_snr_from_esno(ofdm, EsNodB); sum_SNR3kdB += SNR3kdB;
+ } /* complete packet */
+
+ frame_count++;
+ }
+
+ /* per-frame modem processing */
+
+ nin_frame = ofdm_get_nin(ofdm);
+ ofdm_sync_state_machine(ofdm, rx_uw);
+
+ /* act on any events returned by state machine */
+
+ if (!strcmp(ofdm->data_mode, "streaming") && ofdm->sync_start ) {
+ Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = packet_count = 0;
+ Nerrs_raw = 0;
+ Nerrs_coded = 0;
+ }
+
+ if (verbose >= 2) {
+ if (ofdm->last_sync_state != search) {
+ if ((ofdm->modem_frame == 0) && (ofdm->last_sync_state != trial)) {
+ /* weve just received a complete packet, so print all stats */
+ fprintf(stderr, "euw: %2d %1d mf: %2d f: %5.1f pbw: %d eraw: %3d ecdd: %3d iter: %3d pcc: %3d snr: %5.2f\n",
+ ofdm->uw_errors,
+ ofdm->sync_counter,
+ ofdm->modem_frame,
+ ofdm->foff_est_hz,
+ ofdm->phase_est_bandwidth,
+ Nerrs_raw, Nerrs_coded, iter, parityCheckCount, SNR3kdB);
+ } else {
+ /* weve just received a modem frame, abbreviated stats */
+ fprintf(stderr, "euw: %2d %1d mf: %2d f: %5.1f pbw: %d\n",
+ ofdm->uw_errors,
+ ofdm->sync_counter,
+ ofdm->modem_frame,
+ ofdm->foff_est_hz,
+ ofdm->phase_est_bandwidth);
+ }
+ }
+
+ /* detect a successful sync for time to sync tests */
+ if ((time_to_sync < 0) && ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)))
+ if ((parityCheckCount > 80) && (iter != 100))
+ time_to_sync = (float)(f+1)*ofdm_get_samples_per_frame(ofdm)/FS;
+
+ }
+
+ /* optional logging of states */
+
+ if (log_active == true) {
+ /* note corrected phase (rx no phase) is one big linear array for frame */
+
+ for (i = 0; i < ofdm_rowsperframe * ofdm_config->nc; i++) {
+ rx_np_log[ofdm_rowsperframe * ofdm_config->nc * f + i].real = crealf(ofdm->rx_np[i]);
+ rx_np_log[ofdm_rowsperframe * ofdm_config->nc * f + i].imag = cimagf(ofdm->rx_np[i]);
+ }
+
+ /* note phase/amp ests the same for each col, but check them all anyway */
+
+ for (i = 0; i < ofdm_rowsperframe; i++) {
+ for (j = 0; j < ofdm_config->nc; j++) {
+ phase_est_pilot_log[ofdm_rowsperframe * f + i][j] = ofdm->aphase_est_pilot_log[ofdm_config->nc * i + j];
+ rx_amp_log[ofdm_rowsperframe * ofdm_config->nc * f + ofdm_config->nc * i + j] = ofdm->rx_amp[ofdm_config->nc * i + j];
+ }
+ }
+
+ foff_hz_log[f] = ofdm->foff_est_hz;
+ timing_est_log[f] = ofdm->timing_est + 1; /* offset by 1 to match Octave */
+ if (log_payload_syms == true) {
+ for (i = 0; i < Npayloadsymsperpacket; i++) {
+ payload_syms_log[f][i].real = payload_syms[i].real;
+ payload_syms_log[f][i].imag = payload_syms[i].imag;
+ payload_amps_log[f][i] = payload_amps[i];
+ }
+ }
+
+ if (f == (logframes - 1))
+ log_active = false;
+ }
+
+ if (len_secs != 0.0) {
+ float secs = (float)f*ofdm_get_samples_per_frame(ofdm)/FS;
+ if (secs >= len_secs) finish = 1;
+ }
+
+ if (skip_secs != 0.0) {
+ /* big nasty timing error */
+ float secs = (float)f*ofdm_get_samples_per_frame(ofdm)/FS;
+ if (secs >= skip_secs) {
+ assert(fread(rx_scaled, sizeof (short), nin_frame/2, fin) == nin_frame/2);
+ fprintf(stderr," Skip! Just introduced a nasty big timing slip\n");
+ skip_secs = 0.0; /* make sure we just introduce one error */
+ }
+ }
+
+ f++;
+ }
+
+ if (input_specified == true)
+ fclose(fin);
+
+ if (output_specified == true)
+ fclose(fout);
+
+ /* optionally dump Octave files */
+
+ if (log_specified == true) {
+ octave_save_float(foct, "phase_est_pilot_log_c", (float*) phase_est_pilot_log, ofdm_rowsperframe*NFRAMES, ofdm_config->nc, ofdm_config->nc);
+ octave_save_complex(foct, "rx_np_log_c", (COMP*) rx_np_log, 1, ofdm_rowsperframe * ofdm_config->nc*NFRAMES, ofdm_rowsperframe * ofdm_config->nc * NFRAMES);
+ octave_save_float(foct, "rx_amp_log_c", (float*) rx_amp_log, 1, ofdm_rowsperframe * ofdm_config->nc*NFRAMES, ofdm_rowsperframe * ofdm_config->nc * NFRAMES);
+ octave_save_float(foct, "foff_hz_log_c", foff_hz_log, NFRAMES, 1, 1);
+ octave_save_int(foct, "timing_est_log_c", timing_est_log, NFRAMES, 1);
+ octave_save_complex(foct, "payload_syms_log_c", (COMP*) payload_syms_log, NFRAMES, Npayloadsymsperpacket, Npayloadsymsperpacket);
+ octave_save_float(foct, "payload_amps_log_c", (float*) payload_amps_log, NFRAMES, Npayloadsymsperpacket, Npayloadsymsperpacket);
+
+ fclose(foct);
+ }
+
+ if ((strlen(ofdm->data_mode) == 0) && (verbose == 2))
+ fprintf(stderr, "time_to_sync: %f\n", time_to_sync);
+
+ int ret = 0;
+ if (testframes == true) {
+ float uncoded_ber = (float) Terrs / Tbits;
+ float coded_ber = 0.0;
+
+ if (verbose != 0) {
+ fprintf(stderr, "BER......: %5.4f Tbits: %5d Terrs: %5d Tpackets: %5d SNR3kdB: %5.2f\n",
+ uncoded_ber, Tbits, Terrs, packet_count, sum_SNR3kdB/packet_count);
+
+ if ((ldpc_en == 0) && (packet_count > Ndiscard)) {
+ fprintf(stderr, "BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (float) Terrs2 / Tbits2, Tbits2, Terrs2);
+ }
+ }
+
+ /* set return code for Ctest, 1 for fail */
+
+ if (ldpc_en) {
+ coded_ber = (float) Terrs_coded / Tbits_coded;
+
+ if (verbose != 0) {
+ fprintf(stderr, "Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", coded_ber, Tbits_coded, Terrs_coded);
+ fprintf(stderr, "Coded PER: %5.4f Tpkts: %5d Tpers: %5d Thruput: %5d\n",
+ (float)Tper/packet_count, packet_count, Tper, packet_count - Tper);
+ }
+ if ((Tbits_coded == 0) || (coded_ber >= 0.01f))
+ ret = 1;
+ }
+
+ if ((Tbits == 0) || (uncoded_ber >= 0.1f))
+ ret = 1;
+ }
+
+ if (strlen(ofdm->data_mode)) {
+ fprintf(stderr, "Npre.....: %6d Npost: %5d uw_fails: %2d\n", ofdm->pre, ofdm->post, ofdm->uw_fails);
+ }
+
+ ofdm_destroy(ofdm);
+
+ return ret;
+}