diff options
| author | Marin Ivanov <[email protected]> | 2025-07-25 10:17:14 +0300 |
|---|---|---|
| committer | Marin Ivanov <[email protected]> | 2026-01-18 20:09:26 +0200 |
| commit | 0168586485e6310c598713c911b1dec5618d61a1 (patch) | |
| tree | 6aabc2a12ef8fef70683f5389bea00f948015f77 /unittest/tofdm.c | |
* codec2 cut-down version 1.2.0
* Remove codebook and generation of sources
* remove c2dec c2enc binaries
* prepare for emscripten
Diffstat (limited to 'unittest/tofdm.c')
| -rw-r--r-- | unittest/tofdm.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/unittest/tofdm.c b/unittest/tofdm.c new file mode 100644 index 0000000..b4d60b7 --- /dev/null +++ b/unittest/tofdm.c @@ -0,0 +1,626 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tofdm.c + AUTHORS.....: David Rowe & Steve Sampson + DATE CREATED: June 2017 + + Tests for the C version of the OFDM modem. This program outputs a + file of Octave vectors that are loaded and automatically tested + against the Octave version of the modem by the Octave script tofdm.m + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2017 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 <complex.h> +#include <getopt.h> +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "HRA_112_112.h" /* generated by ldpc_fsk_lib.m:ldpc_decode() */ +#include "codec2_ofdm.h" +#include "comp_prim.h" +#include "mpdecode_core.h" +#include "octave.h" +#include "ofdm_internal.h" +#include "test_bits_ofdm.h" + +#define NFRAMES 10 +#define SAMPLE_CLOCK_OFFSET_PPM 100 +#define FOFF_HZ 0.5f + +#define ASCALE (2E5f * 1.1491f / 2.0f) /* scale from shorts back to floats */ + +#define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */ + +/* QPSK constellation for symbol likelihood calculations */ + +static COMP S_matrix[] = { + {1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}}; + +/* constants we use a lot and don't want to have to deference all the time */ + +static float ofdm_tx_centre; /* TX Center frequency */ +static float ofdm_rx_centre; /* RX Center frequency */ +static float ofdm_fs; /* Sample rate */ +static float ofdm_ts; /* Symbol cycle time */ +static float ofdm_rs; /* Symbol rate */ +static float ofdm_tcp; /* Cyclic prefix duration */ +static float + ofdm_timing_mx_thresh; /* See 700D Part 4 Acquisition blog post and + ofdm_dev.m routines for how this was set */ + +static int ofdm_nc; /* NS-1 data symbols between pilots */ +static int ofdm_ns; +static int ofdm_bps; /* Bits per symbol */ +static int ofdm_m; /* duration of each symbol in samples */ +static int ofdm_ncp; /* duration of CP in samples */ + +static int ofdm_ftwindowwidth; +static int ofdm_bitsperframe; +static int ofdm_rowsperframe; +static int ofdm_samplesperframe; +static int ofdm_samplespersymbol; +static int ofdm_max_samplesperframe; +static int ofdm_nrxbuf; +static int + ofdm_ntxtbits; /* reserve bits/frame for auxiliary text information */ +static int ofdm_nuwbits; /* Unique word, used for positive indication of lock */ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: fs_offset() + AUTHOR......: David Rowe + DATE CREATED: May 2015 + + Simulates small Fs offset between mod and demod. + (Note: Won't work with float, works OK with double) + +\*---------------------------------------------------------------------------*/ + +static int fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm) { + double f; + double tin = 0.0; + double step = 1.0 + sample_rate_ppm / 1E6; + int t1, t2; + int tout = 0; + + while (tin < (double)(n - 1)) { + t1 = (int)floor(tin); + t2 = (int)ceil(tin); + assert(t2 < n); + f = tin - (double)t1; + + out[tout].real = + ((double)1.0 - f) * (double)in[t1].real + f * (double)in[t2].real; + out[tout].imag = + ((double)1.0 - f) * (double)in[t1].imag + f * (double)in[t2].imag; + + tin += step; + tout++; + // printf("tin: %f tout: %d f: %f\n", tin, tout, f); + } + + return tout; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freq_shift() + AUTHOR......: David Rowe + DATE CREATED: 26/4/2012 + + Frequency shift modem signal. The use of complex input and output allows + single sided frequency shifting (no images). + +\*---------------------------------------------------------------------------*/ + +static void freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, + COMP *foff_phase_rect, int nin) { + float temp = (TAU * foff / ofdm_fs); + COMP foff_rect = {cosf(temp), sinf(temp)}; + int i; + + for (i = 0; i < nin; i++) { + *foff_phase_rect = cmult(*foff_phase_rect, foff_rect); + rx_fdm_fcorr[i] = cmult(rx_fdm[i], *foff_phase_rect); + } + + /* normalise digital oscillator as the magnitude can drift over time */ + + float mag = cabsolute(*foff_phase_rect); + foff_phase_rect->real /= mag; + foff_phase_rect->imag /= mag; +} + +int main(int argc, char *argv[]) { + int opt_Nc = 0; + int ldpc_enable = 1; + struct OFDM *ofdm; + struct OFDM_CONFIG *ofdm_config; + + static struct option long_options[] = {{"nc", required_argument, 0, 'n'}, + {"noldpc", no_argument, 0, 'l'}, + {0, 0, 0, 0}}; + + int opt_index = 0; + char c; + + while ((c = getopt_long(argc, argv, "n:l", long_options, &opt_index)) != -1) { + switch (c) { + case 'n': + opt_Nc = atoi(optarg); + fprintf(stderr, "Nc = %d\n", opt_Nc); + break; + case 'l': + ldpc_enable = 0; + fprintf(stderr, "LDPC disabled\n"); + break; + default: + fprintf(stderr, + "usage: %s [Options]:\n [-l --noldpc]\n [-n --nc " + "NumberoFCarriers]\n", + argv[0]); + exit(1); + } + } + + // init once to get a copy of default config params + + ofdm = ofdm_create(NULL); + assert(ofdm != NULL); + struct OFDM_CONFIG ofdm_config_default; + memcpy(&ofdm_config_default, ofdm_get_config_param(ofdm), + sizeof(struct OFDM_CONFIG)); + ofdm_destroy(ofdm); + + // now do a little customisation on default config, and re-create modem + // instance + + if (opt_Nc) ofdm_config_default.nc = opt_Nc; + // printf("ofdm_create() 2\n"); + ofdm = ofdm_create(&ofdm_config_default); + assert(ofdm != NULL); + ofdm_config = ofdm_get_config_param(ofdm); + ofdm_set_tx_bpf(ofdm, false); + + // same levels as Octave sim + ofdm->amp_scale = 1.0; + + // make local copies for convenience + ofdm_tx_centre = ofdm_config->tx_centre; + ofdm_rx_centre = ofdm_config->rx_centre; + ofdm_fs = ofdm_config->fs; + ofdm_ts = ofdm_config->ts; + ofdm_rs = ofdm_config->rs; + ofdm_tcp = ofdm_config->tcp; + ofdm_timing_mx_thresh = ofdm_config->timing_mx_thresh; + ofdm_nc = ofdm_config->nc; + ofdm_ns = ofdm_config->ns; + ofdm_bps = ofdm_config->bps; + ofdm_m = (int)(ofdm_config->fs / ofdm_config->rs); + ofdm_ncp = (int)(ofdm_config->tcp * ofdm_config->fs); + ofdm_ftwindowwidth = ofdm_config->ftwindowwidth; + ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm); + ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps); + ofdm_samplesperframe = ofdm_get_samples_per_frame(ofdm); + ofdm_samplespersymbol = (ofdm->m + ofdm->ncp); + ofdm_max_samplesperframe = ofdm_get_max_samples_per_frame(ofdm); + ofdm_nrxbuf = ofdm->nrxbuf; + ofdm_ntxtbits = ofdm_config->txtbits; + ofdm_nuwbits = ofdm_config->nuwbits; + + int tx_bits[ofdm_samplesperframe]; + COMP tx[ofdm_samplesperframe]; /* one frame of tx samples */ + + int rx_bits[ofdm_bitsperframe]; /* one frame of rx bits */ + printf("Nc = %d ofdm_bitsperframe: %d\n", ofdm_nc, ofdm_bitsperframe); + + /* log arrays */ + + int tx_bits_log[ofdm_bitsperframe * NFRAMES]; + COMP tx_log[ofdm_samplesperframe * NFRAMES]; + COMP rx_log[ofdm_samplesperframe * NFRAMES]; + COMP rxbuf_in_log[ofdm_max_samplesperframe * NFRAMES]; + COMP rxbuf_log[ofdm_nrxbuf * NFRAMES]; + COMP rx_sym_log[(ofdm_ns + 3) * NFRAMES][ofdm_nc + 2]; + float phase_est_pilot_log[ofdm_rowsperframe * NFRAMES][ofdm_nc]; + COMP rx_np_log[ofdm_rowsperframe * ofdm_nc * NFRAMES]; + float rx_amp_log[ofdm_rowsperframe * ofdm_nc * NFRAMES]; + float foff_hz_log[NFRAMES]; + int rx_bits_log[ofdm_bitsperframe * NFRAMES]; + int timing_est_log[NFRAMES]; + int timing_valid_log[NFRAMES]; + float timing_mx_log[NFRAMES]; + float coarse_foff_est_hz_log[NFRAMES]; + int sample_point_log[NFRAMES]; + float symbol_likelihood_log[(CODED_BITSPERFRAME / ofdm_bps) * + (1 << ofdm_bps) * NFRAMES]; + float bit_likelihood_log[CODED_BITSPERFRAME * NFRAMES]; + int detected_data_log[CODED_BITSPERFRAME * NFRAMES]; + float mean_amp_log[NFRAMES]; + float snr_log[NFRAMES]; + + FILE *fout; + int f, i, j; + + /* set up LDPC code */ + + 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 = (uint16_t *)HRA_112_112_H_rows; + ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols; + + /* Main Loop + * ---------------------------------------------------------------------*/ + + for (f = 0; f < NFRAMES; f++) { + /* --------------------------------------------------------*\ + Mod + \*---------------------------------------------------------*/ + + /* See CML startup code in tofdm.m */ + + for (i = 0; i < ofdm_nuwbits; i++) { + tx_bits[i] = ofdm->tx_uw[i]; + } + for (i = ofdm_nuwbits; i < ofdm_nuwbits + ofdm_ntxtbits; i++) { + tx_bits[i] = 0; + } + + if (ldpc_enable) { + unsigned char ibits[HRA_112_112_NUMBERROWSHCOLS]; + unsigned char pbits[HRA_112_112_NUMBERPARITYBITS]; + + assert(HRA_112_112_NUMBERROWSHCOLS == ldpc.CodeLength / 2); + for (i = 0; i < ldpc.CodeLength / 2; i++) { + ibits[i] = payload_data_bits[i]; + } + encode(&ldpc, ibits, pbits); + for (j = 0, i = ofdm_nuwbits + ofdm_ntxtbits; j < ldpc.CodeLength / 2; + i++, j++) { + tx_bits[i] = ibits[j]; + } + for (j = 0; j < ldpc.CodeLength / 2; i++, j++) { + tx_bits[i] = pbits[j]; + } + assert(i == ofdm_bitsperframe); + } else { + int Npayloadbits = ofdm_bitsperframe - (ofdm_nuwbits + ofdm_ntxtbits); + uint16_t r[Npayloadbits]; + uint8_t payload_bits[Npayloadbits]; + + ofdm_rand(r, Npayloadbits); + for (i = 0; i < Npayloadbits; i++) payload_bits[i] = r[i] > 16384; + uint8_t txt_bits[ofdm_ntxtbits]; + for (i = 0; i < ofdm_ntxtbits; i++) txt_bits[i] = 0; + + uint8_t tx_bits_char[ofdm_bitsperframe]; + ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits_char, payload_bits, + txt_bits); + for (i = 0; i < ofdm_bitsperframe; i++) tx_bits[i] = tx_bits_char[i]; + } + + ofdm_mod(ofdm, (COMP *)tx, tx_bits); + + /* tx vector logging */ + + memcpy(&tx_bits_log[ofdm_bitsperframe * f], tx_bits, + sizeof(int) * ofdm_bitsperframe); + memcpy(&tx_log[ofdm_samplesperframe * f], tx, + sizeof(COMP) * ofdm_samplesperframe); + } + + /* --------------------------------------------------------*\ + Channel + \*---------------------------------------------------------*/ + + fs_offset(rx_log, tx_log, ofdm_samplesperframe * NFRAMES, + SAMPLE_CLOCK_OFFSET_PPM); + + COMP foff_phase_rect = {1.0f, 0.0f}; + + freq_shift(rx_log, rx_log, FOFF_HZ, &foff_phase_rect, + ofdm_samplesperframe * NFRAMES); + + /* --------------------------------------------------------*\ + Demod + \*---------------------------------------------------------*/ + + /* Init/pre-load rx with ideal timing so we can test with timing estimation + * disabled */ + + int Nsam = ofdm_samplesperframe * NFRAMES; + int prx = 0; + int nin = ofdm_samplesperframe + 2 * ofdm_samplespersymbol; + + int lnew; + COMP rxbuf_in[ofdm_max_samplesperframe]; + +#define FRONT_LOAD +#ifdef FRONT_LOAD + for (i = 0; i < nin; i++, prx++) { + ofdm->rxbuf[ofdm_nrxbuf - nin + i] = + rx_log[prx].real + rx_log[prx].imag * I; + } +#endif + + int nin_tot = 0; + + /* disable estimators for initial testing */ + + ofdm_set_verbose(ofdm, false); + ofdm_set_timing_enable(ofdm, true); + ofdm_set_foff_est_enable(ofdm, true); + ofdm_set_phase_est_enable(ofdm, true); + +//#define TESTING_FILE +#ifdef TESTING_FILE + FILE *fin = fopen("~/codec2-dev/octave/ofdm_test.raw", "rb"); + assert(fin != NULL); + int Nbitsperframe = ofdm_bitsperframe; + int Nmaxsamperframe = ofdm_max_samplesperframe; + short rx_scaled[Nmaxsamperframe]; +#endif + + /* start this with something sensible otherwise LDPC decode fails in tofdm.m + */ + + ofdm->mean_amp = 1.0; + + for (f = 0; f < NFRAMES; f++) { + /* For initial testing, timing est is off, so nin is always + fixed. TODO: we need a constant for rxbuf_in[] size that + is the maximum possible nin */ + + nin = ofdm_get_nin(ofdm); + assert(nin <= ofdm_max_samplesperframe); + + /* Insert samples at end of buffer, set to zero if no samples + available to disable phase estimation on future pilots on + last frame of simulation. */ + + if ((Nsam - prx) < nin) { + lnew = Nsam - prx; + } else { + lnew = nin; + } + // printf("nin: %d prx: %d lnew: %d\n", nin, prx, lnew); + for (i = 0; i < nin; i++) { + rxbuf_in[i].real = 0.0; + rxbuf_in[i].imag = 0.0; + } + + if (lnew) { + for (i = 0; i < lnew; i++, prx++) { + rxbuf_in[i] = rx_log[prx]; + } + } + assert(prx <= ofdm_max_samplesperframe * NFRAMES); + +#ifdef TESTING_FILE + fread(rx_scaled, sizeof(short), nin, fin); + + for (i = 0; i < nin; i++) { + rxbuf_in[i].real = (float)rx_scaled[i] / ASCALE; + rxbuf_in[i].imag = 0.0; + } +#endif + + /* uncoded OFDM modem ---------------------------------------*/ + + ofdm_demod(ofdm, rx_bits, rxbuf_in); + +#ifdef TESTING_FILE + int Nerrs = 0; + for (i = 0; i < Nbitsperframe; i++) { + if (test_bits_ofdm[i] != rx_bits[i]) { + Nerrs++; + } + } + printf("f: %d Nerr: %d\n", f, Nerrs); +#endif + + float symbol_likelihood[(CODED_BITSPERFRAME / ofdm_bps) * (1 << ofdm_bps)]; + float bit_likelihood[CODED_BITSPERFRAME]; + uint8_t out_char[CODED_BITSPERFRAME]; + + if (ldpc_enable) { + /* LDPC functions --------------------------------------*/ + + float EsNo = 10; + + /* 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)]; + + 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]; + + Demod2D(symbol_likelihood, ldpc_codeword_symbols, S_matrix, EsNo, + ldpc_codeword_symbol_amps, ofdm->mean_amp, + CODED_BITSPERFRAME / ofdm_bps); + Somap(bit_likelihood, symbol_likelihood, 1 << ofdm_bps, ofdm_bps, + CODED_BITSPERFRAME / ofdm_bps); + + float llr[CODED_BITSPERFRAME]; + int parityCheckCount; + + // fprintf(stderr, "\n"); + for (i = 0; i < CODED_BITSPERFRAME; i++) { + llr[i] = -bit_likelihood[i]; + // fprintf(stderr, "%f ", llr[i]); + } + + // fprintf(stderr, "\n"); + + run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount); + /* + fprintf(stderr, "iter: %d parityCheckCount: %d\n", iter, + parityCheckCount); for(i=0; i<CODED_BITSPERFRAME; i++) { fprintf(stderr, + "%d ", out_char[i]); + } + */ + } + + /* rx vector logging -----------------------------------*/ + + assert(nin_tot < ofdm_samplesperframe * NFRAMES); + memcpy(&rxbuf_in_log[nin_tot], rxbuf_in, sizeof(COMP) * nin); + nin_tot += nin; + + for (i = 0; i < ofdm_nrxbuf; i++) { + rxbuf_log[ofdm_nrxbuf * f + i].real = crealf(ofdm->rxbuf[i]); + rxbuf_log[ofdm_nrxbuf * f + i].imag = cimagf(ofdm->rxbuf[i]); + } + + for (i = 0; i < (ofdm_ns + 3); i++) { + for (j = 0; j < (ofdm_nc + 2); j++) { + rx_sym_log[(ofdm_ns + 3) * f + i][j].real = crealf(ofdm->rx_sym[i][j]); + rx_sym_log[(ofdm_ns + 3) * f + i][j].imag = cimagf(ofdm->rx_sym[i][j]); + } + } + + /* note corrected phase (rx no phase) is one big linear array for frame */ + + for (i = 0; i < ofdm_rowsperframe * ofdm_nc; i++) { + rx_np_log[ofdm_rowsperframe * ofdm_nc * f + i].real = + crealf(ofdm->rx_np[i]); + rx_np_log[ofdm_rowsperframe * ofdm_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_nc; j++) { + phase_est_pilot_log[ofdm_rowsperframe * f + i][j] = + ofdm->aphase_est_pilot_log[ofdm_nc * i + j]; + rx_amp_log[ofdm_rowsperframe * ofdm_nc * f + ofdm_nc * i + j] = + ofdm->rx_amp[ofdm_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 */ + timing_valid_log[f] = ofdm->timing_valid; + timing_mx_log[f] = ofdm->timing_mx; + coarse_foff_est_hz_log[f] = ofdm->coarse_foff_est_hz; + sample_point_log[f] = + ofdm->sample_point + 1; /* offset by 1 to match Octave */ + float EsNodB = ofdm_esno_est_calc(ofdm->rx_np, ofdm_rowsperframe * ofdm_nc); + snr_log[f] = ofdm_snr_from_esno(ofdm, EsNodB); + mean_amp_log[f] = ofdm->mean_amp; + + memcpy(&rx_bits_log[ofdm_bitsperframe * f], rx_bits, sizeof(rx_bits)); + + if (ldpc_enable) { + for (i = 0; i < (CODED_BITSPERFRAME / ofdm_bps) * (1 << ofdm_bps); i++) { + symbol_likelihood_log[(CODED_BITSPERFRAME / ofdm_bps) * + (1 << ofdm_bps) * f + + i] = symbol_likelihood[i]; + } + for (i = 0; i < CODED_BITSPERFRAME; i++) { + bit_likelihood_log[CODED_BITSPERFRAME * f + i] = bit_likelihood[i]; + detected_data_log[CODED_BITSPERFRAME * f + i] = out_char[i]; + } + } + } + + /*---------------------------------------------------------*\ + Dump logs to Octave file for evaluation + by tofdm.m Octave script + \*---------------------------------------------------------*/ + + fout = fopen("tofdm_out.txt", "wt"); + assert(fout != NULL); + fprintf(fout, "# Created by tofdm.c\n"); + octave_save_complex(fout, "pilot_samples_c", (COMP *)ofdm->pilot_samples, 1, + ofdm_samplespersymbol, ofdm_samplespersymbol); + octave_save_int(fout, "tx_bits_log_c", tx_bits_log, 1, + ofdm_bitsperframe * NFRAMES); + octave_save_complex(fout, "tx_log_c", (COMP *)tx_log, 1, + ofdm_samplesperframe * NFRAMES, + ofdm_samplesperframe * NFRAMES); + octave_save_complex(fout, "rx_log_c", (COMP *)rx_log, 1, + ofdm_samplesperframe * NFRAMES, + ofdm_samplesperframe * NFRAMES); + octave_save_complex(fout, "rxbuf_in_log_c", (COMP *)rxbuf_in_log, 1, nin_tot, + nin_tot); + octave_save_complex(fout, "rxbuf_log_c", (COMP *)rxbuf_log, 1, + ofdm_nrxbuf * NFRAMES, ofdm_nrxbuf * NFRAMES); + octave_save_complex(fout, "rx_sym_log_c", (COMP *)rx_sym_log, + (ofdm_ns + 3) * NFRAMES, ofdm_nc + 2, ofdm_nc + 2); + octave_save_float(fout, "phase_est_pilot_log_c", (float *)phase_est_pilot_log, + ofdm_rowsperframe * NFRAMES, ofdm_nc, ofdm_nc); + octave_save_float(fout, "rx_amp_log_c", (float *)rx_amp_log, 1, + ofdm_rowsperframe * ofdm_nc * NFRAMES, + ofdm_rowsperframe * ofdm_nc * NFRAMES); + octave_save_float(fout, "foff_hz_log_c", foff_hz_log, NFRAMES, 1, 1); + octave_save_int(fout, "timing_est_log_c", timing_est_log, NFRAMES, 1); + octave_save_int(fout, "timing_valid_log_c", timing_valid_log, NFRAMES, 1); + octave_save_float(fout, "timing_mx_log_c", timing_mx_log, NFRAMES, 1, 1); + octave_save_float(fout, "coarse_foff_est_hz_log_c", coarse_foff_est_hz_log, + NFRAMES, 1, 1); + octave_save_int(fout, "sample_point_log_c", sample_point_log, NFRAMES, 1); + octave_save_complex(fout, "rx_np_log_c", (COMP *)rx_np_log, 1, + ofdm_rowsperframe * ofdm_nc * NFRAMES, + ofdm_rowsperframe * ofdm_nc * NFRAMES); + octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, + ofdm_bitsperframe * NFRAMES); + octave_save_float(fout, "symbol_likelihood_log_c", symbol_likelihood_log, + (CODED_BITSPERFRAME / ofdm_bps) * (1 << ofdm_bps) * NFRAMES, + 1, 1); + octave_save_float(fout, "bit_likelihood_log_c", bit_likelihood_log, + CODED_BITSPERFRAME * NFRAMES, 1, 1); + octave_save_int(fout, "detected_data_log_c", detected_data_log, 1, + CODED_BITSPERFRAME * NFRAMES); + octave_save_float(fout, "snr_log_c", snr_log, NFRAMES, 1, 1); + octave_save_float(fout, "mean_amp_log_c", mean_amp_log, NFRAMES, 1, 1); + fclose(fout); +#ifdef TESTING_FILE + fclose(fin); +#endif + + ofdm_destroy(ofdm); + + return 0; +} |
