From 44826f32891d3214883e801b1c925202316f334b Mon Sep 17 00:00:00 2001 From: drowe67 Date: Tue, 1 May 2012 02:05:46 +0000 Subject: [PATCH] first pass at C demod test program, untested git-svn-id: https://svn.code.sf.net/p/freetel/code@386 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/README_fdmdv.txt | 6 +- codec2-dev/octave/fdmdv.m | 10 ++ codec2-dev/octave/fdmdv_demod.m | 6 +- codec2-dev/src/Makefile.am | 7 +- codec2-dev/src/Makefile.in | 23 +++- codec2-dev/src/fdmdv.c | 43 ++++++- codec2-dev/src/fdmdv.h | 17 +-- codec2-dev/src/fdmdv_demod.c | 184 +++++++++++++++++++++++++++++ codec2-dev/src/fdmdv_internal.h | 26 +++- codec2-dev/src/fdmdv_mod.c | 7 +- 10 files changed, 295 insertions(+), 34 deletions(-) create mode 100644 codec2-dev/src/fdmdv_demod.c diff --git a/codec2-dev/octave/README_fdmdv.txt b/codec2-dev/octave/README_fdmdv.txt index a845678e..8adae6db 100644 --- a/codec2-dev/octave/README_fdmdv.txt +++ b/codec2-dev/octave/README_fdmdv.txt @@ -8,7 +8,7 @@ TODO [ ] consider moving this file to root [ ] sep SVN repo, automake etc? -[ ] list each fdmdv.m script (ut, mod, demod) and Cprogram/src and what it does +[ ] list each fdmdv.m script (ut, mod, demod) and C program/src and what it does [ ] example usage [ ] repair fdmdv_ut and mod/demod after new statres exposed and var renames [X] Get file based mod and demod working again @@ -33,6 +33,10 @@ TODO [ ] test with freq offsets [ ] measure execution speed [ ] document use of fdmdv_ut and fdmdv_demod + PathSim +[ ] more positibe form of sync reqd for DV frames? + + like using track/acquire bit +[ ] more robust track/acquite state machine? + + e.g. hang on thr fades? [ ] block diagram [ ] maybe in ascii art [ ] blog posts(s) diff --git a/codec2-dev/octave/fdmdv.m b/codec2-dev/octave/fdmdv.m index f7d44dae..1a5ba6ee 100644 --- a/codec2-dev/octave/fdmdv.m +++ b/codec2-dev/octave/fdmdv.m @@ -760,6 +760,7 @@ function pilot_coeff_file(filename) fclose(f); endfunction + % Saves hanning window coeffs to a text file in the form of a C array function hanning_file(filename) @@ -778,6 +779,15 @@ function hanning_file(filename) endfunction +function png_file(fig, pngfilename) + figure(fig); + + pngname = sprintf("%s.png",pngfilename); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_large.png",pngfilename); + print(pngname, '-dpng', "-S800,600") +endfunction + % Initialise ---------------------------------------------------- global pilot_bit; diff --git a/codec2-dev/octave/fdmdv_demod.m b/codec2-dev/octave/fdmdv_demod.m index 2ba10437..791ca03b 100644 --- a/codec2-dev/octave/fdmdv_demod.m +++ b/codec2-dev/octave/fdmdv_demod.m @@ -8,7 +8,7 @@ % Version 2 % -function fdmdv_demod(rawfilename, nbits) +function fdmdv_demod(rawfilename, nbits, pngname) fdmdv; % include modem code @@ -58,7 +58,7 @@ function fdmdv_demod(rawfilename, nbits) % frequency offset estimation and correction [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); - foff_coarse = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin); + [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin); if track == 0 foff = foff_coarse; end @@ -199,4 +199,6 @@ function fdmdv_demod(rawfilename, nbits) axis([0 secs 0 1.5]); title('Test Frame Sync') + + endfunction diff --git a/codec2-dev/src/Makefile.am b/codec2-dev/src/Makefile.am index 5bf5d9d2..96586716 100644 --- a/codec2-dev/src/Makefile.am +++ b/codec2-dev/src/Makefile.am @@ -122,7 +122,7 @@ libcodec2_la_LDFLAGS = $(LIBS) library_includedir = $(prefix)/include library_include_HEADERS = codec2.h -bin_PROGRAMS = c2demo c2enc c2dec c2sim fdmdv_mod +bin_PROGRAMS = c2demo c2enc c2dec c2sim fdmdv_mod fdmdv_demod c2demo_SOURCES = c2demo.c c2demo_LDADD = $(lib_LTLIBRARIES) @@ -140,5 +140,8 @@ c2sim_SOURCES = c2sim.c c2sim_LDADD = $(lib_LTLIBRARIES) c2sim_LDFLAGS = $(LIBS) -fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c octave.c +fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c fdmdv_mod_LDFLAGS = $(LIBS) + +fdmdv_demod_SOURCES = fdmdv_demod.c fdmdv.c fft.c kiss_fft.c octave.c +fdmdv_demod_LDFLAGS = $(LIBS) diff --git a/codec2-dev/src/Makefile.in b/codec2-dev/src/Makefile.in index a37bb30d..bc5269d6 100644 --- a/codec2-dev/src/Makefile.in +++ b/codec2-dev/src/Makefile.in @@ -40,7 +40,7 @@ build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = generate_codebook$(EXEEXT) genlspdtcb$(EXEEXT) bin_PROGRAMS = c2demo$(EXEEXT) c2enc$(EXEEXT) c2dec$(EXEEXT) \ - c2sim$(EXEEXT) fdmdv_mod$(EXEEXT) + c2sim$(EXEEXT) fdmdv_mod$(EXEEXT) fdmdv_demod$(EXEEXT) subdir = src DIST_COMMON = $(library_include_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in @@ -87,8 +87,12 @@ c2enc_DEPENDENCIES = $(am__DEPENDENCIES_1) am_c2sim_OBJECTS = c2sim.$(OBJEXT) c2sim_OBJECTS = $(am_c2sim_OBJECTS) c2sim_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_fdmdv_mod_OBJECTS = fdmdv_mod.$(OBJEXT) fdmdv.$(OBJEXT) \ +am_fdmdv_demod_OBJECTS = fdmdv_demod.$(OBJEXT) fdmdv.$(OBJEXT) \ fft.$(OBJEXT) kiss_fft.$(OBJEXT) octave.$(OBJEXT) +fdmdv_demod_OBJECTS = $(am_fdmdv_demod_OBJECTS) +fdmdv_demod_LDADD = $(LDADD) +am_fdmdv_mod_OBJECTS = fdmdv_mod.$(OBJEXT) fdmdv.$(OBJEXT) \ + fft.$(OBJEXT) kiss_fft.$(OBJEXT) fdmdv_mod_OBJECTS = $(am_fdmdv_mod_OBJECTS) fdmdv_mod_LDADD = $(LDADD) generate_codebook_SOURCES = generate_codebook.c @@ -109,11 +113,12 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libcodec2_la_SOURCES) $(c2dec_SOURCES) $(c2demo_SOURCES) \ - $(c2enc_SOURCES) $(c2sim_SOURCES) $(fdmdv_mod_SOURCES) \ - generate_codebook.c genlspdtcb.c + $(c2enc_SOURCES) $(c2sim_SOURCES) $(fdmdv_demod_SOURCES) \ + $(fdmdv_mod_SOURCES) generate_codebook.c genlspdtcb.c DIST_SOURCES = $(libcodec2_la_SOURCES) $(c2dec_SOURCES) \ $(c2demo_SOURCES) $(c2enc_SOURCES) $(c2sim_SOURCES) \ - $(fdmdv_mod_SOURCES) generate_codebook.c genlspdtcb.c + $(fdmdv_demod_SOURCES) $(fdmdv_mod_SOURCES) \ + generate_codebook.c genlspdtcb.c library_includeHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(library_include_HEADERS) ETAGS = etags @@ -316,8 +321,10 @@ c2dec_LDFLAGS = $(LIBS) c2sim_SOURCES = c2sim.c c2sim_LDADD = $(lib_LTLIBRARIES) c2sim_LDFLAGS = $(LIBS) -fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c octave.c +fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c fdmdv_mod_LDFLAGS = $(LIBS) +fdmdv_demod_SOURCES = fdmdv_demod.c fdmdv.c fft.c kiss_fft.c octave.c +fdmdv_demod_LDFLAGS = $(LIBS) all: all-am .SUFFIXES: @@ -427,6 +434,9 @@ c2enc$(EXEEXT): $(c2enc_OBJECTS) $(c2enc_DEPENDENCIES) c2sim$(EXEEXT): $(c2sim_OBJECTS) $(c2sim_DEPENDENCIES) @rm -f c2sim$(EXEEXT) $(LINK) $(c2sim_LDFLAGS) $(c2sim_OBJECTS) $(c2sim_LDADD) $(LIBS) +fdmdv_demod$(EXEEXT): $(fdmdv_demod_OBJECTS) $(fdmdv_demod_DEPENDENCIES) + @rm -f fdmdv_demod$(EXEEXT) + $(LINK) $(fdmdv_demod_LDFLAGS) $(fdmdv_demod_OBJECTS) $(fdmdv_demod_LDADD) $(LIBS) fdmdv_mod$(EXEEXT): $(fdmdv_mod_OBJECTS) $(fdmdv_mod_DEPENDENCIES) @rm -f fdmdv_mod$(EXEEXT) $(LINK) $(fdmdv_mod_LDFLAGS) $(fdmdv_mod_OBJECTS) $(fdmdv_mod_LDADD) $(LIBS) @@ -448,6 +458,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c2enc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c2sim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdmdv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdmdv_demod.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdmdv_mod.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fft.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate_codebook.Po@am__quote@ diff --git a/codec2-dev/src/fdmdv.c b/codec2-dev/src/fdmdv.c index 5cc256f5..51348920 100644 --- a/codec2-dev/src/fdmdv.c +++ b/codec2-dev/src/fdmdv.c @@ -222,7 +222,7 @@ struct FDMDV *fdmdv_create(void) \*---------------------------------------------------------------------------*/ -void codec2_destroy(struct FDMDV *fdmdv) +void fdmdv_destroy(struct FDMDV *fdmdv) { assert(fdmdv != NULL); free(fdmdv); @@ -1089,9 +1089,7 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm COMP rx_fdm_fcorr[M+M/P]; COMP rx_baseband[NC+1][M+M/P]; COMP rx_filt[NC+1][P+1]; - float rx_timing; float env[NT*P]; - COMP rx_symbols[NC+1]; /* freq offset estimation and correction */ @@ -1104,9 +1102,9 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm fdm_downconvert(rx_baseband, rx_fdm_fcorr, fdmdv->phase_rx, fdmdv->freq, *nin); rx_filter(rx_filt, rx_baseband, fdmdv->rx_filter_memory, *nin); - rx_timing = rx_est_timing(rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, *nin); - foff_fine = qpsk_to_bits(rx_bits, sync_bit, fdmdv->prev_rx_symbols, rx_symbols); - memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1)); + fdmdv->rx_timing = rx_est_timing(fdmdv->rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, *nin); + foff_fine = qpsk_to_bits(rx_bits, sync_bit, fdmdv->prev_rx_symbols, fdmdv->rx_symbols); + memcpy(fdmdv->prev_rx_symbols, fdmdv->rx_symbols, sizeof(COMP)*(NC+1)); /* freq offset estimation state machine */ @@ -1114,3 +1112,36 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm fdmdv->foff -= TRACK_COEFF*foff_fine; } +/*---------------------------------------------------------------------------*\ + + FUNCTION....: fdmdv_get_demod_stats() + AUTHOR......: David Rowe + DATE CREATED: 1 May 2012 + + Fills a structure with a bunch of demod information. + +\*---------------------------------------------------------------------------*/ + +void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct FDMDV_STATS *fdmdv_stats) +{ + COMP pi_on_4; + int c; + + pi_on_4.real = cos(PI/4.0); + pi_on_4.imag = sin(PI/4.0); + + fdmdv_stats->snr = 0.0; /* TODO - implement SNR estimation */ + fdmdv_stats->fest_coarse_fine = fdmdv->coarse_fine; + fdmdv_stats->foff = fdmdv->foff; + fdmdv_stats->rx_timing = fdmdv->rx_timing/M; + fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ + + /* adjust for phase offset to make suitable for scatter plot */ + + assert((NC+1) == FDMDV_NSYM); + + for(c=0; crx_symbols[c] = cmult(cmult(fdmdv->rx_symbols[c], cconj(fdmdv->prev_rx_symbols[c])), pi_on_4); + +} + diff --git a/codec2-dev/src/fdmdv.h b/codec2-dev/src/fdmdv.h index ecb02594..5f9e9458 100644 --- a/codec2-dev/src/fdmdv.h +++ b/codec2-dev/src/fdmdv.h @@ -11,7 +11,7 @@ References: - [1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf + [1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf \*---------------------------------------------------------------------------*/ @@ -44,16 +44,17 @@ extern "C" { #define FDMDV_BITS_PER_FRAME 28 /* odd/even frames 56 bits, 1400 bit/s */ #define FDMDV_SAMPLES_PER_FRAME 160 /* 8000 Hz sample rate */ #define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */ +#define FDMDV_NSYM 15 struct FDMDV; struct FDMDV_STATS { - float snr; /* estimated SNR of rx signal in dB */ - COMP *rx_symbols; /* NC+1 latest received symbols, for scatter plot */ - int fest_track; /* == 0, freq est in acquire mode, == 1 in track mode */ - float foff; /* estimated freq offset in Hz */ - float timing; /* timing offset 0..1 as fraction of symbol period */ - float clock_offset; /* Estimated tx/rx sample clock offset in ppm */ + float snr; /* estimated SNR of rx signal in dB */ + COMP rx_symbols[FDMDV_NSYM]; /* latest received symbols, for scatter plot */ + int fest_coarse_fine; /* freq est state, 0-coarse 1-fine */ + float foff; /* estimated freq offset in Hz */ + float rx_timing; /* timing offset -1..1 as fraction of symbol period */ + float clock_offset; /* Estimated tx/rx sample clock offset in ppm */ }; struct FDMDV *fdmdv_create(void); @@ -65,7 +66,7 @@ void fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], int *sync_bi void fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]); void fdmdv_put_test_bits(struct FDMDV *f, int *sync, int *bit_errors, int rx_bits[]); -float fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats); +void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats); void fdmdv_get_waterfall_line(struct FDMDV *fdmdv_state, float magnitudes[], int *magnitude_points); #endif diff --git a/codec2-dev/src/fdmdv_demod.c b/codec2-dev/src/fdmdv_demod.c new file mode 100644 index 00000000..996d2fea --- /dev/null +++ b/codec2-dev/src/fdmdv_demod.c @@ -0,0 +1,184 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: fdmdv_demod.c + AUTHOR......: David Rowe + DATE CREATED: April 30 2012 + + Given an input raw file (8kHz, 16 bit shorts) of FDMDV modem samples + outputs a file of bits. The output file is assumed to be arranged + as codec frames of 56 bits (7 bytes) which are received as two 28 + bit modem frames. + +\*---------------------------------------------------------------------------*/ + + +/* + Copyright (C) 2012 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 . +*/ + +#include +#include +#include +#include +#include +#include + +#include "fdmdv.h" +#include "octave.h" + +#define BITS_PER_CODEC_FRAME (2*FDMDV_BITS_PER_FRAME) +#define BYTES_PER_CODEC_FRAME (BITS_PER_CODEC_FRAME/8) + +/* lof of information we want to sump to Octave */ + +#define MAX_FRAMES 50*60 + +void dump_to_octave(struct FDMDV *fdmdv, FILE *f); + +int main(int argc, char *argv[]) +{ + FILE *fin, *fout; + struct FDMDV *fdmdv; + char packed_bits[BYTES_PER_CODEC_FRAME]; + int rx_bits[FDMDV_BITS_PER_FRAME]; + int codec_bits[2*FDMDV_BITS_PER_FRAME]; + float rx_fdm[FDMDV_SAMPLES_PER_FRAME]; + short rx_fdm_scaled[FDMDV_SAMPLES_PER_FRAME]; + int i, bit, byte, c; + int nin; + int sync_bit; + int state, next_state; + + int frames; + FILE *foct; + struct FDMDV_STATS stats; + COMP rx_symbols_log[FDMDV_NSYM][MAX_FRAMES]; + int coarse_fine_log[MAX_FRAMES]; + float rx_timing_log[MAX_FRAMES]; + float foff_log[MAX_FRAMES]; + + if (argc < 3) { + printf("usage: %s InputModemRawFile OutputBitFile [OctaveDumpFile]\n", argv[0]); + printf("e.g %s hts1a_fdmdv.raw hts1a.c2\n", argv[0]); + 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 bit file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + fdmdv = fdmdv_create(); + frames = 0; + state = 0; + nin = FDMDV_SAMPLES_PER_FRAME; + + while(fread(rx_fdm_scaled, sizeof(short), nin, fin) == nin) + { + for(i=0; i #include "fdmdv.h" -#include "octave.h" #define BITS_PER_CODEC_FRAME (2*FDMDV_BITS_PER_FRAME) #define BYTES_PER_CODEC_FRAME (BITS_PER_CODEC_FRAME/8) @@ -49,7 +48,7 @@ int main(int argc, char *argv[]) char packed_bits[BYTES_PER_CODEC_FRAME]; int tx_bits[2*FDMDV_BITS_PER_FRAME]; COMP tx_fdm[2*FDMDV_SAMPLES_PER_FRAME]; - short tx_fdm_scaled[FDMDV_SAMPLES_PER_FRAME]; + short tx_fdm_scaled[2*FDMDV_SAMPLES_PER_FRAME]; int frames; int i, bit, byte; int sync_bit; @@ -117,7 +116,7 @@ int main(int argc, char *argv[]) fclose(fin); fclose(fout); - codec2_destroy(fdmdv); + fdmdv_destroy(fdmdv); return 0; } -- 2.25.1