1 /*---------------------------------------------------------------------------*\
2
3 FILE........: tofdm.c
4 AUTHORS.....: David Rowe & Steve Sampson
5 DATE CREATED: June 2017
6
7 Tests for the C version of the OFDM modem. This program outputs a
8 file of Octave vectors that are loaded and automatically tested
9 against the Octave version of the modem by the Octave script tofdm.m
10
11 \*---------------------------------------------------------------------------*/
12
13 /*
14 Copyright (C) 2017 David Rowe
15
16 All rights reserved.
17
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU Lesser General Public License version 2, as
20 published by the Free Software Foundation. This program is
21 distributed in the hope that it will be useful, but WITHOUT ANY
22 WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program; if not, see <http://www.gnu.org/licenses/>.
28 */
29
30 #include <assert.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <string.h>
35 #include <math.h>
36 #include <complex.h>
37 #include <getopt.h>
38
39 #include "ofdm_internal.h"
40 #include "codec2_ofdm.h"
41 #include "octave.h"
42 #include "test_bits_ofdm.h"
43 #include "comp_prim.h"
44 #include "mpdecode_core.h"
45
46 #include "HRA_112_112.h" /* generated by ldpc_fsk_lib.m:ldpc_decode() */
47
48 #define NFRAMES 10
49 #define SAMPLE_CLOCK_OFFSET_PPM 100
50 #define FOFF_HZ 0.5f
51
52 #define ASCALE (2E5f * 1.1491f / 2.0f) /* scale from shorts back to floats */
53
54 #define CODED_BITSPERFRAME 224 /* number of LDPC codeword bits/frame */
55
56 /* QPSK constellation for symbol likelihood calculations */
57
58 static COMP S_matrix[] = {
59 { 1.0f, 0.0f},
60 { 0.0f, 1.0f},
61 { 0.0f, -1.0f},
62 {-1.0f, 0.0f}
63 };
64
65 /* constants we use a lot and don't want to have to deference all the time */
66
67 static float ofdm_tx_centre; /* TX Center frequency */
68 static float ofdm_rx_centre; /* RX Center frequency */
69 static float ofdm_fs; /* Sample rate */
70 static float ofdm_ts; /* Symbol cycle time */
71 static float ofdm_rs; /* Symbol rate */
72 static float ofdm_tcp; /* Cyclic prefix duration */
73 static float ofdm_timing_mx_thresh; /* See 700D Part 4 Acquisition blog post and ofdm_dev.m routines for how this was set */
74
75 static int ofdm_nc; /* NS-1 data symbols between pilots */
76 static int ofdm_ns;
77 static int ofdm_bps; /* Bits per symbol */
78 static int ofdm_m; /* duration of each symbol in samples */
79 static int ofdm_ncp; /* duration of CP in samples */
80
81 static int ofdm_ftwindowwidth;
82 static int ofdm_bitsperframe;
83 static int ofdm_rowsperframe;
84 static int ofdm_samplesperframe;
85 static int ofdm_samplespersymbol;
86 static int ofdm_max_samplesperframe;
87 static int ofdm_nrxbuf;
88 static int ofdm_ntxtbits; /* reserve bits/frame for auxillary text information */
89 static int ofdm_nuwbits; /* Unique word, used for positive indication of lock */
90
91 /*---------------------------------------------------------------------------*\
92
93 FUNCTION....: fs_offset()
94 AUTHOR......: David Rowe
95 DATE CREATED: May 2015
96
97 Simulates small Fs offset between mod and demod.
98 (Note: Won't work with float, works OK with double)
99
100 \*---------------------------------------------------------------------------*/
101
fs_offset(COMP out[],COMP in[],int n,float sample_rate_ppm)102 static int fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm) {
103 double f;
104 double tin = 0.0;
105 double step = 1.0 + sample_rate_ppm/1E6;
106 int t1, t2;
107 int tout = 0;
108
109 while (tin < (double) (n-1)) {
110 t1 = (int) floor(tin);
111 t2 = (int) ceil(tin);
112 assert(t2 < n);
113 f = tin - (double) t1;
114
115 out[tout].real = ((double)1.0-f)*(double)in[t1].real + f*(double)in[t2].real;
116 out[tout].imag = ((double)1.0-f)*(double)in[t1].imag + f*(double)in[t2].imag;
117
118 tin += step;
119 tout++;
120 //printf("tin: %f tout: %d f: %f\n", tin, tout, f);
121 }
122
123 return tout;
124 }
125
126 /*---------------------------------------------------------------------------*\
127
128 FUNCTION....: freq_shift()
129 AUTHOR......: David Rowe
130 DATE CREATED: 26/4/2012
131
132 Frequency shift modem signal. The use of complex input and output allows
133 single sided frequency shifting (no images).
134
135 \*---------------------------------------------------------------------------*/
136
freq_shift(COMP rx_fdm_fcorr[],COMP rx_fdm[],float foff,COMP * foff_phase_rect,int nin)137 static void freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, COMP *foff_phase_rect, int nin) {
138 float temp = (TAU * foff / ofdm_fs);
139 COMP foff_rect = { cosf(temp), sinf(temp) };
140 int i;
141
142 for (i = 0; i < nin; i++) {
143 *foff_phase_rect = cmult(*foff_phase_rect, foff_rect);
144 rx_fdm_fcorr[i] = cmult(rx_fdm[i], *foff_phase_rect);
145 }
146
147 /* normalise digital oscillator as the magnitude can drift over time */
148
149 float mag = cabsolute(*foff_phase_rect);
150 foff_phase_rect->real /= mag;
151 foff_phase_rect->imag /= mag;
152 }
153
main(int argc,char * argv[])154 int main(int argc, char *argv[])
155 {
156 int opt_Nc = 0;
157 int ldpc_enable = 1;
158 struct OFDM *ofdm;
159 struct OFDM_CONFIG *ofdm_config;
160
161 static struct option long_options[] = {
162 {"nc", required_argument, 0, 'n'},
163 {"noldpc", no_argument, 0, 'l'},
164 {0, 0, 0, 0}
165 };
166
167 int opt_index = 0; char c;
168
169 while ((c = getopt_long (argc, argv, "n:l", long_options, &opt_index)) != -1) {
170 switch (c) {
171 case 'n':
172 opt_Nc = atoi(optarg);
173 fprintf(stderr, "Nc = %d\n", opt_Nc);
174 break;
175 case 'l':
176 ldpc_enable = 0;
177 fprintf(stderr, "LDPC disabled\n");
178 break;
179 default:
180 fprintf(stderr,"usage: %s [Options]:\n [-l --noldpc]\n [-n --nc NumberoFCarriers]\n", argv[0]);
181 exit(1);
182 }
183 }
184
185 // init once to get a copy of default config params
186
187 ofdm = ofdm_create(NULL);
188 assert(ofdm != NULL);
189 struct OFDM_CONFIG ofdm_config_default;
190 memcpy(&ofdm_config_default, ofdm_get_config_param(ofdm), sizeof(struct OFDM_CONFIG));
191 ofdm_destroy(ofdm);
192
193 // now do a little customisation on default config, and re-create modem instance
194
195 if (opt_Nc)
196 ofdm_config_default.nc = opt_Nc;
197 //printf("ofdm_create() 2\n");
198 ofdm = ofdm_create(&ofdm_config_default);
199 assert(ofdm != NULL);
200 ofdm_config = ofdm_get_config_param(ofdm);
201 ofdm_set_tx_bpf(ofdm, false);
202
203 // same levels as Octave sim
204 ofdm->amp_scale = 1.0;
205
206 // make local copies for convenience
207 ofdm_tx_centre = ofdm_config->tx_centre;
208 ofdm_rx_centre = ofdm_config->rx_centre;
209 ofdm_fs = ofdm_config->fs;
210 ofdm_ts = ofdm_config->ts;
211 ofdm_rs = ofdm_config->rs;
212 ofdm_tcp = ofdm_config->tcp;
213 ofdm_timing_mx_thresh = ofdm_config->timing_mx_thresh;
214 ofdm_nc = ofdm_config->nc;
215 ofdm_ns = ofdm_config->ns;
216 ofdm_bps = ofdm_config->bps;
217 ofdm_m = (int) (ofdm_config->fs / ofdm_config->rs);
218 ofdm_ncp = (int) (ofdm_config->tcp * ofdm_config->fs);
219 ofdm_ftwindowwidth = ofdm_config->ftwindowwidth;
220 ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm);
221 ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps);
222 ofdm_samplesperframe = ofdm_get_samples_per_frame(ofdm);
223 ofdm_samplespersymbol = (ofdm->m + ofdm->ncp);
224 ofdm_max_samplesperframe = ofdm_get_max_samples_per_frame(ofdm);
225 ofdm_nrxbuf = ofdm->nrxbuf;
226 ofdm_ntxtbits = ofdm_config->txtbits;
227 ofdm_nuwbits = ofdm_config->nuwbits;
228
229 int tx_bits[ofdm_samplesperframe];
230 COMP tx[ofdm_samplesperframe]; /* one frame of tx samples */
231
232 int rx_bits[ofdm_bitsperframe]; /* one frame of rx bits */
233 printf("Nc = %d ofdm_bitsperframe: %d\n", ofdm_nc, ofdm_bitsperframe);
234
235 /* log arrays */
236
237 int tx_bits_log[ofdm_bitsperframe*NFRAMES];
238 COMP tx_log[ofdm_samplesperframe*NFRAMES];
239 COMP rx_log[ofdm_samplesperframe*NFRAMES];
240 COMP rxbuf_in_log[ofdm_max_samplesperframe*NFRAMES];
241 COMP rxbuf_log[ofdm_nrxbuf*NFRAMES];
242 COMP rx_sym_log[(ofdm_ns + 3)*NFRAMES][ofdm_nc + 2];
243 float phase_est_pilot_log[ofdm_rowsperframe*NFRAMES][ofdm_nc];
244 COMP rx_np_log[ofdm_rowsperframe*ofdm_nc*NFRAMES];
245 float rx_amp_log[ofdm_rowsperframe*ofdm_nc*NFRAMES];
246 float foff_hz_log[NFRAMES];
247 int rx_bits_log[ofdm_bitsperframe*NFRAMES];
248 int timing_est_log[NFRAMES];
249 int timing_valid_log[NFRAMES];
250 float timing_mx_log[NFRAMES];
251 float coarse_foff_est_hz_log[NFRAMES];
252 int sample_point_log[NFRAMES];
253 float symbol_likelihood_log[ (CODED_BITSPERFRAME/ofdm_bps) * (1<<ofdm_bps) * NFRAMES];
254 float bit_likelihood_log[CODED_BITSPERFRAME * NFRAMES];
255 int detected_data_log[CODED_BITSPERFRAME * NFRAMES];
256 float mean_amp_log[NFRAMES];
257 float snr_log[NFRAMES];
258
259 FILE *fout;
260 int f,i,j;
261
262 /* set up LDPC code */
263
264 struct LDPC ldpc;
265
266 ldpc.max_iter = HRA_112_112_MAX_ITER;
267 ldpc.dec_type = 0;
268 ldpc.q_scale_factor = 1;
269 ldpc.r_scale_factor = 1;
270 ldpc.CodeLength = HRA_112_112_CODELENGTH;
271 ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
272 ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
273 ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
274 ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
275 ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows;
276 ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols;
277
278 /* Main Loop ---------------------------------------------------------------------*/
279
280 for(f=0; f<NFRAMES; f++) {
281
282 /* --------------------------------------------------------*\
283 Mod
284 \*---------------------------------------------------------*/
285
286 /* See CML startup code in tofdm.m */
287
288 for(i=0; i<ofdm_nuwbits; i++) {
289 tx_bits[i] = ofdm->tx_uw[i];
290 }
291 for(i=ofdm_nuwbits; i<ofdm_nuwbits+ofdm_ntxtbits; i++) {
292 tx_bits[i] = 0;
293 }
294
295 if (ldpc_enable) {
296 unsigned char ibits[HRA_112_112_NUMBERROWSHCOLS];
297 unsigned char pbits[HRA_112_112_NUMBERPARITYBITS];
298
299 assert(HRA_112_112_NUMBERROWSHCOLS == ldpc.CodeLength/2);
300 for(i=0; i<ldpc.CodeLength/2; i++) {
301 ibits[i] = payload_data_bits[i];
302 }
303 encode(&ldpc, ibits, pbits);
304 for(j=0, i=ofdm_nuwbits+ofdm_ntxtbits; j<ldpc.CodeLength/2; i++,j++) {
305 tx_bits[i] = ibits[j];
306 }
307 for(j=0; j<ldpc.CodeLength/2; i++,j++) {
308 tx_bits[i] = pbits[j];
309 }
310 assert(i == ofdm_bitsperframe);
311 } else {
312 int Npayloadbits = ofdm_bitsperframe - (ofdm_nuwbits + ofdm_ntxtbits);
313 uint16_t r[Npayloadbits];
314 uint8_t payload_bits[Npayloadbits];
315
316 ofdm_rand(r, Npayloadbits);
317 for (i = 0; i < Npayloadbits; i++)
318 payload_bits[i] = r[i] > 16384;
319 uint8_t txt_bits[ofdm_ntxtbits];
320 for (i = 0; i < ofdm_ntxtbits; i++)
321 txt_bits[i] = 0;
322
323 uint8_t tx_bits_char[ofdm_bitsperframe];
324 ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits_char, payload_bits, txt_bits);
325 for(i=0; i<ofdm_bitsperframe; i++)
326 tx_bits[i] = tx_bits_char[i];
327 }
328
329 ofdm_mod(ofdm, (COMP*)tx, tx_bits);
330
331 /* tx vector logging */
332
333 memcpy(&tx_bits_log[ofdm_bitsperframe*f], tx_bits, sizeof(int)*ofdm_bitsperframe);
334 memcpy(&tx_log[ofdm_samplesperframe*f], tx, sizeof(COMP)*ofdm_samplesperframe);
335 }
336
337 /* --------------------------------------------------------*\
338 Channel
339 \*---------------------------------------------------------*/
340
341 fs_offset(rx_log, tx_log, ofdm_samplesperframe*NFRAMES, SAMPLE_CLOCK_OFFSET_PPM);
342
343 COMP foff_phase_rect = {1.0f, 0.0f};
344
345 freq_shift(rx_log, rx_log, FOFF_HZ, &foff_phase_rect, ofdm_samplesperframe * NFRAMES);
346
347 /* --------------------------------------------------------*\
348 Demod
349 \*---------------------------------------------------------*/
350
351 /* Init/pre-load rx with ideal timing so we can test with timing estimation disabled */
352
353 int Nsam = ofdm_samplesperframe*NFRAMES;
354 int prx = 0;
355 int nin = ofdm_samplesperframe + 2*ofdm_samplespersymbol;
356
357 int lnew;
358 COMP rxbuf_in[ofdm_max_samplesperframe];
359
360 #define FRONT_LOAD
361 #ifdef FRONT_LOAD
362 for (i=0; i<nin; i++,prx++) {
363 ofdm->rxbuf[ofdm_nrxbuf-nin+i] = rx_log[prx].real + rx_log[prx].imag * I;
364 }
365 #endif
366
367 int nin_tot = 0;
368
369 /* disable estimators for initial testing */
370
371 ofdm_set_verbose(ofdm, false);
372 ofdm_set_timing_enable(ofdm, true);
373 ofdm_set_foff_est_enable(ofdm, true);
374 ofdm_set_phase_est_enable(ofdm, true);
375
376 //#define TESTING_FILE
377 #ifdef TESTING_FILE
378 FILE *fin=fopen("~/codec2-dev/octave/ofdm_test.raw", "rb");
379 assert(fin != NULL);
380 int Nbitsperframe = ofdm_bitsperframe;
381 int Nmaxsamperframe = ofdm_max_samplesperframe;
382 short rx_scaled[Nmaxsamperframe];
383 #endif
384
385 /* start this with something sensible otherwise LDPC decode fails in tofdm.m */
386
387 ofdm->mean_amp = 1.0;
388
389 for(f=0; f<NFRAMES; f++) {
390 /* For initial testing, timing est is off, so nin is always
391 fixed. TODO: we need a constant for rxbuf_in[] size that
392 is the maximum possible nin */
393
394 nin = ofdm_get_nin(ofdm);
395 assert(nin <= ofdm_max_samplesperframe);
396
397 /* Insert samples at end of buffer, set to zero if no samples
398 available to disable phase estimation on future pilots on
399 last frame of simulation. */
400
401 if ((Nsam-prx) < nin) {
402 lnew = Nsam-prx;
403 } else {
404 lnew = nin;
405 }
406 //printf("nin: %d prx: %d lnew: %d\n", nin, prx, lnew);
407 for(i=0; i<nin; i++) {
408 rxbuf_in[i].real = 0.0;
409 rxbuf_in[i].imag = 0.0;
410 }
411
412 if (lnew) {
413 for(i=0; i<lnew; i++, prx++) {
414 rxbuf_in[i] = rx_log[prx];
415 }
416 }
417 assert(prx <= ofdm_max_samplesperframe*NFRAMES);
418
419 #ifdef TESTING_FILE
420 fread(rx_scaled, sizeof(short), nin, fin);
421
422 for(i=0; i<nin; i++) {
423 rxbuf_in[i].real = (float)rx_scaled[i]/ASCALE;
424 rxbuf_in[i].imag = 0.0;
425 }
426 #endif
427
428 /* uncoded OFDM modem ---------------------------------------*/
429
430 ofdm_demod(ofdm, rx_bits, rxbuf_in);
431
432 #ifdef TESTING_FILE
433 int Nerrs = 0;
434 for(i=0; i<Nbitsperframe; i++) {
435 if (test_bits_ofdm[i] != rx_bits[i]) {
436 Nerrs++;
437 }
438 }
439 printf("f: %d Nerr: %d\n", f, Nerrs);
440 #endif
441
442 float symbol_likelihood[ (CODED_BITSPERFRAME/ofdm_bps) * (1<<ofdm_bps) ];
443 float bit_likelihood[CODED_BITSPERFRAME];
444 uint8_t out_char[CODED_BITSPERFRAME];
445
446 if (ldpc_enable) {
447 /* LDPC functions --------------------------------------*/
448
449 float EsNo = 10;
450
451 /* first few symbols are used for UW and txt bits, find start of (224,112) LDPC codeword */
452
453 assert((ofdm_nuwbits+ofdm_ntxtbits+CODED_BITSPERFRAME) == ofdm_bitsperframe);
454
455 COMP ldpc_codeword_symbols[(CODED_BITSPERFRAME/ofdm_bps)];
456
457 for(i=0, j=(ofdm_nuwbits+ofdm_ntxtbits)/ofdm_bps; i<(CODED_BITSPERFRAME/ofdm_bps); i++,j++) {
458 ldpc_codeword_symbols[i].real = crealf(ofdm->rx_np[j]);
459 ldpc_codeword_symbols[i].imag = cimagf(ofdm->rx_np[j]);
460 }
461
462 float *ldpc_codeword_symbol_amps = &ofdm->rx_amp[(ofdm_nuwbits+ofdm_ntxtbits)/ofdm_bps];
463
464 Demod2D(symbol_likelihood, ldpc_codeword_symbols, S_matrix, EsNo, ldpc_codeword_symbol_amps, ofdm->mean_amp, CODED_BITSPERFRAME/ofdm_bps);
465 Somap(bit_likelihood, symbol_likelihood, 1<<ofdm_bps, ofdm_bps, CODED_BITSPERFRAME/ofdm_bps);
466
467 float llr[CODED_BITSPERFRAME];
468 int parityCheckCount;
469
470
471 // fprintf(stderr, "\n");
472 for(i=0; i<CODED_BITSPERFRAME; i++) {
473 llr[i] = -bit_likelihood[i];
474 // fprintf(stderr, "%f ", llr[i]);
475 }
476
477 //fprintf(stderr, "\n");
478
479 run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
480 /*
481 fprintf(stderr, "iter: %d parityCheckCount: %d\n", iter, parityCheckCount);
482 for(i=0; i<CODED_BITSPERFRAME; i++) {
483 fprintf(stderr, "%d ", out_char[i]);
484 }
485 */
486 }
487
488 /* rx vector logging -----------------------------------*/
489
490 assert(nin_tot < ofdm_samplesperframe*NFRAMES);
491 memcpy(&rxbuf_in_log[nin_tot], rxbuf_in, sizeof(COMP)*nin);
492 nin_tot += nin;
493
494 for(i=0; i<ofdm_nrxbuf; i++) {
495 rxbuf_log[ofdm_nrxbuf*f+i].real = crealf(ofdm->rxbuf[i]);
496 rxbuf_log[ofdm_nrxbuf*f+i].imag = cimagf(ofdm->rxbuf[i]);
497 }
498
499 for (i = 0; i < (ofdm_ns + 3); i++) {
500 for (j = 0; j < (ofdm_nc + 2); j++) {
501 rx_sym_log[(ofdm_ns + 3)*f+i][j].real = crealf(ofdm->rx_sym[i][j]);
502 rx_sym_log[(ofdm_ns + 3)*f+i][j].imag = cimagf(ofdm->rx_sym[i][j]);
503 }
504 }
505
506 /* note corrected phase (rx no phase) is one big linear array for frame */
507
508 for (i = 0; i < ofdm_rowsperframe*ofdm_nc; i++) {
509 rx_np_log[ofdm_rowsperframe*ofdm_nc*f + i].real = crealf(ofdm->rx_np[i]);
510 rx_np_log[ofdm_rowsperframe*ofdm_nc*f + i].imag = cimagf(ofdm->rx_np[i]);
511 }
512
513 /* note phase/amp ests the same for each col, but check them all anyway */
514
515 for (i = 0; i < ofdm_rowsperframe; i++) {
516 for (j = 0; j < ofdm_nc; j++) {
517 phase_est_pilot_log[ofdm_rowsperframe*f+i][j] = ofdm->aphase_est_pilot_log[ofdm_nc*i+j];
518 rx_amp_log[ofdm_rowsperframe*ofdm_nc*f+ofdm_nc*i+j] = ofdm->rx_amp[ofdm_nc*i+j];
519 }
520 }
521
522 foff_hz_log[f] = ofdm->foff_est_hz;
523 timing_est_log[f] = ofdm->timing_est + 1; /* offset by 1 to match Octave */
524 timing_valid_log[f] = ofdm->timing_valid;
525 timing_mx_log[f] = ofdm->timing_mx;
526 coarse_foff_est_hz_log[f] = ofdm->coarse_foff_est_hz;
527 sample_point_log[f] = ofdm->sample_point + 1; /* offset by 1 to match Octave */
528 float EsNodB = ofdm_esno_est_calc(ofdm->rx_np, ofdm_rowsperframe*ofdm_nc);
529 snr_log[f] = ofdm_snr_from_esno(ofdm, EsNodB);
530 mean_amp_log[f] = ofdm->mean_amp;
531
532 memcpy(&rx_bits_log[ofdm_bitsperframe*f], rx_bits, sizeof(rx_bits));
533
534 if (ldpc_enable) {
535 for(i=0; i<(CODED_BITSPERFRAME/ofdm_bps) * (1<<ofdm_bps); i++) {
536 symbol_likelihood_log[ (CODED_BITSPERFRAME/ofdm_bps) * (1<<ofdm_bps) * f + i] = symbol_likelihood[i];
537 }
538 for(i=0; i<CODED_BITSPERFRAME; i++) {
539 bit_likelihood_log[CODED_BITSPERFRAME*f + i] = bit_likelihood[i];
540 detected_data_log[CODED_BITSPERFRAME*f + i] = out_char[i];
541 }
542 }
543 }
544
545 /*---------------------------------------------------------*\
546 Dump logs to Octave file for evaluation
547 by tofdm.m Octave script
548 \*---------------------------------------------------------*/
549
550 fout = fopen("tofdm_out.txt","wt");
551 assert(fout != NULL);
552 fprintf(fout, "# Created by tofdm.c\n");
553 octave_save_complex(fout, "pilot_samples_c", (COMP*)ofdm->pilot_samples, 1, ofdm_samplespersymbol, ofdm_samplespersymbol);
554 octave_save_int(fout, "tx_bits_log_c", tx_bits_log, 1, ofdm_bitsperframe*NFRAMES);
555 octave_save_complex(fout, "tx_log_c", (COMP*)tx_log, 1, ofdm_samplesperframe*NFRAMES, ofdm_samplesperframe*NFRAMES);
556 octave_save_complex(fout, "rx_log_c", (COMP*)rx_log, 1, ofdm_samplesperframe*NFRAMES, ofdm_samplesperframe*NFRAMES);
557 octave_save_complex(fout, "rxbuf_in_log_c", (COMP*)rxbuf_in_log, 1, nin_tot, nin_tot);
558 octave_save_complex(fout, "rxbuf_log_c", (COMP*)rxbuf_log, 1, ofdm_nrxbuf*NFRAMES, ofdm_nrxbuf*NFRAMES);
559 octave_save_complex(fout, "rx_sym_log_c", (COMP*)rx_sym_log, (ofdm_ns + 3)*NFRAMES, ofdm_nc + 2, ofdm_nc + 2);
560 octave_save_float(fout, "phase_est_pilot_log_c", (float*)phase_est_pilot_log, ofdm_rowsperframe*NFRAMES, ofdm_nc, ofdm_nc);
561 octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, 1, ofdm_rowsperframe*ofdm_nc*NFRAMES, ofdm_rowsperframe*ofdm_nc*NFRAMES);
562 octave_save_float(fout, "foff_hz_log_c", foff_hz_log, NFRAMES, 1, 1);
563 octave_save_int(fout, "timing_est_log_c", timing_est_log, NFRAMES, 1);
564 octave_save_int(fout, "timing_valid_log_c", timing_valid_log, NFRAMES, 1);
565 octave_save_float(fout, "timing_mx_log_c", timing_mx_log, NFRAMES, 1, 1);
566 octave_save_float(fout, "coarse_foff_est_hz_log_c", coarse_foff_est_hz_log, NFRAMES, 1, 1);
567 octave_save_int(fout, "sample_point_log_c", sample_point_log, NFRAMES, 1);
568 octave_save_complex(fout, "rx_np_log_c", (COMP*)rx_np_log, 1, ofdm_rowsperframe*ofdm_nc*NFRAMES, ofdm_rowsperframe*ofdm_nc*NFRAMES);
569 octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, ofdm_bitsperframe*NFRAMES);
570 octave_save_float(fout, "symbol_likelihood_log_c", symbol_likelihood_log, (CODED_BITSPERFRAME/ofdm_bps) * (1<<ofdm_bps) * NFRAMES, 1, 1);
571 octave_save_float(fout, "bit_likelihood_log_c", bit_likelihood_log, CODED_BITSPERFRAME * NFRAMES, 1, 1);
572 octave_save_int(fout, "detected_data_log_c", detected_data_log, 1, CODED_BITSPERFRAME*NFRAMES);
573 octave_save_float(fout, "snr_log_c", snr_log, NFRAMES, 1, 1);
574 octave_save_float(fout, "mean_amp_log_c", mean_amp_log, NFRAMES, 1, 1);
575 fclose(fout);
576 #ifdef TESTING_FILE
577 fclose(fin);
578 #endif
579
580 ofdm_destroy(ofdm);
581
582 return 0;
583 }
584