--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: ofdm_demod.c
+ AUTHOR......: David Rowe
+ 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.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 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 <errno.h>
+
+#include "codec2_ofdm.h"
+#include "ofdm_internal.h"
+#include "octave.h"
+#include "test_bits_ofdm.h"
+
+#define ASCALE (2E5*1.1491/2.0) /* scale from shorts back to floats */
+#define NFRAMES 100 /* just log the first 100 frames */
+
+int opt_exists(char *argv[], int argc, char opt[]) {
+ int i;
+ for (i=0; i<argc; i++) {
+ if (strcmp(argv[i], opt) == 0) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fin, *fout, *foct;
+ struct OFDM *ofdm;
+ int nin_frame;
+
+ 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 timing_est_log[NFRAMES];
+
+ int i, j, f, oct, logframes, arg, sd;
+
+ if (argc < 3) {
+ fprintf(stderr, "\n");
+ printf("usage: %s InputModemRawFile OutputFile [-o OctaveLogFile] [--sd]\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " Default output file format is one byte per bit hard decision\n");
+ fprintf(stderr, " -o Octave log file for testing\n");
+ fprintf(stderr, " --sd soft decision output, four doubles per QPSK symbol\n");
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "-") == 0) fin = stdin;
+ else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
+ fprintf(stderr, "Error opening input modem sample file: %s: %s.\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+
+ if (strcmp(argv[2], "-") == 0) fout = stdout;
+ else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
+ fprintf(stderr, "Error opening output file: %s: %s.\n",
+ argv[2], strerror(errno));
+ exit(1);
+ }
+
+ foct = NULL;
+ oct = 0;
+ if ((arg = opt_exists(argv, argc, "-o")) != 0) {
+ if ( (foct = fopen(argv[arg+1],"wt")) == NULL ) {
+ fprintf(stderr, "Error opening output Octave file: %s: %s.\n",
+ argv[4], strerror(errno));
+ exit(1);
+ }
+ oct = 1;
+ logframes = NFRAMES;
+ }
+
+ sd = 0;
+ if (opt_exists(argv, argc, "--sd")) {
+ sd = 1;
+ }
+
+ ofdm = ofdm_create(OFDM_CONFIG_700D);
+ assert(ofdm != NULL);
+
+ int Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
+ int Nmaxsamperframe = ofdm_get_max_samples_per_frame();
+
+ short rx_scaled[Nmaxsamperframe];
+ COMP rxbuf_in[Nmaxsamperframe];
+ int rx_bits[Nbitsperframe];
+ char rx_bits_char[Nbitsperframe];
+ int state, next_state;
+
+ state = OFDM_SEARCHING;
+ f = 0;
+
+ nin_frame = ofdm_get_nin(ofdm);
+ while(fread(rx_scaled, sizeof(short), nin_frame, fin) == nin_frame) {
+
+ /* scale and demod */
+
+ for(i=0; i<nin_frame; i++) {
+ rxbuf_in[i].real = (float)rx_scaled[i]/ASCALE;
+ rxbuf_in[i].imag = 0.0;
+ }
+
+ next_state = state;
+ switch(state) {
+ case OFDM_SEARCHING:
+ if (ofdm_sync_search(ofdm, rxbuf_in)) {
+ next_state = OFDM_SYNCED;
+ }
+ break;
+ case OFDM_SYNCED:
+ ofdm_demod(ofdm, rx_bits, rxbuf_in);
+ break;
+ }
+ state = next_state;
+
+ nin_frame = ofdm_get_nin(ofdm);
+
+ if (sd == 0) {
+ /* simple hard decision output for uncoded testing */
+ for(i=0; i<Nbitsperframe; i++) {
+ rx_bits_char[i] = rx_bits[i];
+ }
+ fwrite(rx_bits_char, sizeof(char), Nbitsperframe, fout);
+ }
+
+ if (oct) {
+ /* 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 */
+ if (f == (logframes-1))
+ oct = 0;
+ }
+
+ /* if this is in a pipeline, we probably don't want the usual
+ buffering to occur */
+
+ if (fout == stdout) fflush(stdout);
+ if (fin == stdin) fflush(stdin);
+
+ f++;
+ }
+
+ fclose(fin);
+ fclose(fout);
+
+ /* optionally dump Octave files */
+
+ if (foct != NULL) {
+ octave_save_float(foct, "phase_est_pilot_log_c", (float*)phase_est_pilot_log, OFDM_ROWSPERFRAME*NFRAMES, OFDM_NC, OFDM_NC);
+ octave_save_complex(foct, "rx_np_log_c", (COMP*)rx_np_log, 1, OFDM_ROWSPERFRAME*OFDM_NC*NFRAMES, OFDM_ROWSPERFRAME*OFDM_NC*NFRAMES);
+ octave_save_float(foct, "rx_amp_log_c", (float*)rx_amp_log, 1, OFDM_ROWSPERFRAME*OFDM_NC*NFRAMES, OFDM_ROWSPERFRAME*OFDM_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);
+ fclose(foct);
+ }
+
+ ofdm_destroy(ofdm);
+
+ return 0;
+}
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: ofdm_put_test_bits.c
+ AUTHOR......: David Rowe
+ DATE CREATED: Mar 2018
+
+ Slurps up a stream of test bits generated by ofdm_get_test_bits, useful for
+ testing ofdm_mod and ofdm_demod.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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 <errno.h>
+
+#include "codec2_ofdm.h"
+#include "test_bits_ofdm.h"
+
+#define LOG_FRAMES 100
+
+int opt_exists(char *argv[], int argc, char opt[]) {
+ int i;
+ for (i=0; i<argc; i++) {
+ if (strcmp(argv[i], opt) == 0) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fin;
+ int i, f, Nerrs, Terrs, Tbits, verbose;
+ float aber;
+ struct OFDM *ofdm;
+
+ if (argc < 2) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "usage: %s InputOneCharPerBitFile [-v]\n", argv[0]);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "-") == 0) fin = stdin;
+ else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
+ fprintf(stderr, "Error opening input file: %s: %s.\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+
+ verbose = 0;
+ if (opt_exists(argv, argc, "-v")) {
+ verbose = 1;
+ }
+
+ ofdm = ofdm_create(OFDM_CONFIG_700D);
+ assert(ofdm != NULL);
+ int Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
+ char rx_bits[Nbitsperframe];
+
+ f = Terrs = Tbits = 0;
+ while (fread(rx_bits, sizeof(char), Nbitsperframe, fin) == Nbitsperframe) {
+ f++;
+
+ Nerrs = 0;
+ for(i=0; i<Nbitsperframe; i++) {
+ if (test_bits_ofdm[i] != rx_bits[i]) {
+ Nerrs++;
+ }
+ }
+ aber = (float)Nerrs/Nbitsperframe;
+
+ if (aber < 0.2) {
+ Terrs += Nerrs;
+ Tbits += Nbitsperframe;
+ }
+
+ if (verbose) {
+ printf("f: %d Nerrs: %d aber: %3.2f\n", f, Nerrs, aber);
+ }
+
+ if (fin == stdin) fflush(stdin);
+ }
+
+ fclose(fin);
+ fprintf(stderr, "BER..: %5.4f Tbits: %5d Terrs: %5d\n", (float)Terrs/Tbits, Tbits, Terrs);
+
+ return 0;
+}
+