From 37068861e710bd5c4811e4d93817f594290f3676 Mon Sep 17 00:00:00 2001 From: baobrien Date: Mon, 8 Feb 2016 16:53:20 +0000 Subject: [PATCH] Further work on fmfsk C modem, not quite done, still needs deep testing git-svn-id: https://svn.code.sf.net/p/freetel/code@2690 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/fmfsk.m | 16 ++- codec2-dev/src/CMakeLists.txt | 3 + codec2-dev/src/fmfsk.c | 59 ++++++--- codec2-dev/src/fmfsk_demod.c | 114 +++++++++++++++++ codec2-dev/src/fmfsk_mod.c | 12 +- codec2-dev/src/fsk_demod.c | 20 +-- codec2-dev/unittest/CMakeLists.txt | 3 + codec2-dev/unittest/tfmfsk.c | 196 +++++++++++++++++++++++++++++ 8 files changed, 390 insertions(+), 33 deletions(-) create mode 100644 codec2-dev/src/fmfsk_demod.c create mode 100644 codec2-dev/unittest/tfmfsk.c diff --git a/codec2-dev/octave/fmfsk.m b/codec2-dev/octave/fmfsk.m index 37f748cc..7697fd8e 100644 --- a/codec2-dev/octave/fmfsk.m +++ b/codec2-dev/octave/fmfsk.m @@ -32,16 +32,23 @@ function states = fmfsk_init(Fs,Rb) %Current fixed processing buffer size, in non-ME bits nbit = 192; + states.Rb = Rb; states.Rs = Rb*2; % Manchester-encoded bitrate states.Fs = Fs; states.Ts = Fs/states.Rs; - states.N = nbit*states.Ts; + states.N = nbit*2*states.Ts; + %states.N + %states.N = floor(states.Rs*.080)*states.Ts + %states.N states.nin = states.N; % Samples in the next demod cycle states.nstash = states.Ts*2; % How many samples to stash away between proc cycles for timing adjust states.nmem = states.N+(4*states.Ts); states.nsym = nbit*2; states.nbit = nbit; + + %tates.nsym = floor(states.Rs*.080); + %states.nbit = floor(states.Rb*.080) %Old sample memory states.oldsamps = zeros(1,states.nmem); @@ -95,16 +102,19 @@ function [rx_bits states] = fmfsk_demod(states,rx) ssamps(nold+1:nmem) = rx; states.oldsamps = ssamps; - rx_filt = zeros(1,nsym*Ts); + rx_filt = zeros(1,(nsym+1)*Ts); + length(rx_filt) %Integrate Ts input samples at every offset %This is the same thing as filtering with a filter of all ones % out to Ts. % It's implemented like this for ease of C-porting for ii=(1:(nsym+1)*Ts) st = ii; - en = st+Ts; + en = st+Ts-1; rx_filt(ii) = sum(ssamps(st:en)); end + + length(rx_filt) % Fine timing estimation ------------------------------------------------------ diff --git a/codec2-dev/src/CMakeLists.txt b/codec2-dev/src/CMakeLists.txt index 1ffbd9b3..b79d6df3 100644 --- a/codec2-dev/src/CMakeLists.txt +++ b/codec2-dev/src/CMakeLists.txt @@ -257,6 +257,9 @@ target_link_libraries(cohpsk_mod ${CMAKE_REQUIRED_LIBRARIES} codec2) add_executable(fmfsk_mod fmfsk_mod.c) target_link_libraries(fmfsk_mod ${CMAKE_REQUIRED_LIBRARIES} codec2) +add_executable(fmfsk_demod fmfsk_demod.c modem_probe.c octave.c) +target_link_libraries(fmfsk_demod ${CMAKE_REQUIRED_LIBRARIES} codec2) + add_executable(cohpsk_demod cohpsk_demod.c octave.c) target_link_libraries(cohpsk_demod ${CMAKE_REQUIRED_LIBRARIES} codec2) diff --git a/codec2-dev/src/fmfsk.c b/codec2-dev/src/fmfsk.c index 57229b4a..e9478b50 100644 --- a/codec2-dev/src/fmfsk.c +++ b/codec2-dev/src/fmfsk.c @@ -31,6 +31,8 @@ #include #include #include +#include + #include "fmfsk.h" #include "modem_probe.h" @@ -60,7 +62,7 @@ struct FMFSK * fmfsk_create(int Fs,int Rb){ fmfsk->Rs = Rb*2; fmfsk->Fs = Fs; fmfsk->Ts = Fs/fmfsk->Rs; - fmfsk->N = nbits*fmfsk->Ts; + fmfsk->N = nbits*2*fmfsk->Ts; fmfsk->nmem = fmfsk->N+(fmfsk->Ts*4); fmfsk->nsym = nbits*2; fmfsk->nbit = nbits; @@ -103,6 +105,28 @@ uint32_t fmfsk_nin(struct FMFSK *fmfsk){ * float mod_out[] - Buffer for N samples of modulated FMFSK * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits */ +//void fmfsk_mod(struct FMFSK *fmfsk, float fmfsk_out[],uint8_t bits_in[]){ +// int i,j; +// int Ts = fmfsk->Ts; +// int N = fmfsk->N; +// +// for(i=0;inbit; @@ -112,20 +136,19 @@ void fmfsk_mod(struct FMFSK *fmfsk, float fmfsk_out[],uint8_t bits_in[]){ /* Save a manchester-encoded 0 */ if(bits_in[i] == 0){ for(j=0; j0 ? 1 : 0; + lastv = currv; + mdiff = mdiff>0 ? mdiff : 0-mdiff; + //printf("md %f\n",mdiff); /* Put bit in it's stream */ - if((i&2)==1){ + if((i%2)==1){ apeven += mdiff; /* Even stream goes in LSB */ rx_bits[i>>1] |= mbit ? 0x1 : 0x0; }else{ apodd += mdiff; /* Odd in second-to-LSB */ - rx_bits[i>>1] |= mbit ? 0x2 : 0x0; + rx_bits[i>>1] = mbit ? 0x2 : 0x0; } } - if(apeven>apodd){ + fprintf(stderr,"even has it\n"); /* Zero out odd bits from output bitstream */ for(i=0;i>1; } /* Save last sample of int stream for next demod round */ - fmfsk->lodd = rx_filt[sample_offset+((nsym-1)*Ts)]; + fmfsk->lodd = lastv; modem_probe_samp_f("t_norm_rx_timing",&norm_rx_timing,1); modem_probe_samp_f("t_rx_filt",rx_filt,nsym*Ts); diff --git a/codec2-dev/src/fmfsk_demod.c b/codec2-dev/src/fmfsk_demod.c new file mode 100644 index 00000000..6bd45a80 --- /dev/null +++ b/codec2-dev/src/fmfsk_demod.c @@ -0,0 +1,114 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: fsk_demod.c + AUTHOR......: Brady O'Brien + DATE CREATED: 8 January 2016 + + C test driver for fsk_demod in fsk.c. Reads in a stream of 32 bit cpu endian + floats and writes out the detected bits + + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2016 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 . +*/ + +#include +#include "fmfsk.h" + +#define MODEMPROBE_ENABLE +#include "modem_probe.h" +#include "codec2_fdmdv.h" + +int main(int argc,char *argv[]){ + struct FMFSK *fmfsk; + int Fs,Rb; + FILE *fin,*fout; + uint8_t *bitbuf; + int16_t *rawbuf; + float *modbuf; + int i,t; + + if(argc<4){ + fprintf(stderr,"usage: %s SampleFreq BitRate InputModemRawFile OutputOneBitPerCharFile [OctaveLogFile]\n",argv[0]); + exit(1); + } + + /* Extract parameters */ + Fs = atoi(argv[1]); + Rb = atoi(argv[2]); + + /* Open files */ + if(strcmp(argv[3],"-")==0){ + fin = stdin; + }else{ + fin = fopen(argv[3],"r"); + } + + if(strcmp(argv[4],"-")==0){ + fout = stdout; + }else{ + fout = fopen(argv[4],"w"); + } + + + if(argc>4) + modem_probe_init("fmfsk2",argv[5]); + + /* set up FSK */ + fmfsk = fmfsk_create(Fs,Rb); + + if(fin==NULL || fout==NULL || fmfsk==NULL){ + fprintf(stderr,"Couldn't open test vector files\n"); + goto cleanup; + } + + /* allocate buffers for processing */ + bitbuf = (uint8_t*)alloca(sizeof(uint8_t)*fmfsk->nbit); + rawbuf = (int16_t*)alloca(sizeof(int16_t)*(fmfsk->N+fmfsk->Ts*2)); + modbuf = (float*)alloca(sizeof(float)*(fmfsk->N+fmfsk->Ts*2)); + + /* Demodulate! */ + while( fread(rawbuf,sizeof(int16_t),fmfsk_nin(fmfsk),fin) == fmfsk_nin(fmfsk) ){ + for(i=0;inbit;i++){ + t = (int)bitbuf[i]; + modem_probe_samp_i("t_d_bitout",&t,1); + } + + fwrite(bitbuf,sizeof(uint8_t),fmfsk->nbit,fout); + + if(fin == stdin || fout == stdin){ + fflush(fin); + fflush(fout); + } + } + + modem_probe_close(); + cleanup: + fclose(fin); + fclose(fout); + fmfsk_destroy(fmfsk); + exit(0); +} + diff --git a/codec2-dev/src/fmfsk_mod.c b/codec2-dev/src/fmfsk_mod.c index 69a632f7..ae739821 100644 --- a/codec2-dev/src/fmfsk_mod.c +++ b/codec2-dev/src/fmfsk_mod.c @@ -81,14 +81,14 @@ int main(int argc,char *argv[]){ while( fread(bitbuf,sizeof(uint8_t),fmfsk->nbit,fin) == fmfsk->nbit ){ fmfsk_mod(fmfsk,modbuf,bitbuf); for(i=0; iN; i++){ - rawbuf[i] = (int16_t)(modbuf[i]*(float)FDMDV_SCALE); - } + rawbuf[i] = (int16_t)(modbuf[i]*(float)FDMDV_SCALE); + } fwrite(rawbuf,sizeof(int16_t),fmfsk->N,fout); - if(fin == stdin || fout == stdin){ - fflush(fin); - fflush(fout); - } + if(fin == stdin || fout == stdin){ + fflush(fin); + fflush(fout); + } } cleanup: diff --git a/codec2-dev/src/fsk_demod.c b/codec2-dev/src/fsk_demod.c index cf0cecfc..83055b00 100644 --- a/codec2-dev/src/fsk_demod.c +++ b/codec2-dev/src/fsk_demod.c @@ -85,21 +85,21 @@ int main(int argc,char *argv[]){ /* Demodulate! */ while( fread(rawbuf,sizeof(int16_t),fsk_nin(fsk),fin) == fsk_nin(fsk) ){ - for(i=0;iNbits;i++){ - t = (int)bitbuf[i]; - modem_probe_samp_i("t_d_bitout",&t,1); - } + t = (int)bitbuf[i]; + modem_probe_samp_i("t_d_bitout",&t,1); + } fwrite(bitbuf,sizeof(uint8_t),fsk->Nbits,fout); if(fin == stdin || fout == stdin){ - fflush(fin); - fflush(fout); - } + fflush(fin); + fflush(fout); + } } modem_probe_close(); diff --git a/codec2-dev/unittest/CMakeLists.txt b/codec2-dev/unittest/CMakeLists.txt index accc7a83..732ac7d8 100644 --- a/codec2-dev/unittest/CMakeLists.txt +++ b/codec2-dev/unittest/CMakeLists.txt @@ -66,6 +66,9 @@ target_link_libraries(t16_8_short codec2) add_executable(tfsk tfsk.c ../src/kiss_fft.c ../src/kiss_fftr.c ../src/octave.c ../src/modem_probe.c) target_link_libraries(tfsk m) +add_executable(tfmfsk tfmfsk.c ../src/octave.c ../src/modem_probe.c) +target_link_libraries(tfmfsk m) + #add_executable(t48_8 t48_8.c ../src/fdmdv.c ../src/kiss_fft.c) #target_link_libraries(t48_8 codec2) diff --git a/codec2-dev/unittest/tfmfsk.c b/codec2-dev/unittest/tfmfsk.c new file mode 100644 index 00000000..877e639e --- /dev/null +++ b/codec2-dev/unittest/tfmfsk.c @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tfmfsk.c + AUTHOR......: Brady O'Brien + DATE CREATED: 8 February 2016 + + C test driver for fmfsk_mod and fmfsk_demod in fmfsk.c. Reads a file with input + bits/rf and spits out modulated/demoduladed samples and a dump of internal + state. To run unit test, see octave/tfmfsk.m + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2016 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 . +*/ + + +#define MODEMPROBE_ENABLE + +#include "modem_probe.h" +#include + +/* Note: This is a dirty hack to force fsk.c to compile with modem probing enabled */ +#include "fmfsk.c" + +#define ST_BITS 10000 +#define ST_FS 48000 +#define ST_RS 2400 +#define ST_EBNO 8 + +#define TEST_SELF_FULL 1 /* No-arg self test */ +#define TEST_MOD 2 /* Test modulator using in and out file */ +#define TEST_DEMOD 3 /* Test demodulator using in and out file */ + + +int main(int argc,char *argv[]){ + struct FMFSK *fmfsk; + int Fs,Rs; + FILE *fin,*fout; + + uint8_t *bitbuf = NULL; + float *modbuf = NULL; + uint8_t *bitbufp; + float *modbufp; + + size_t bitbufsize = 0; + size_t modbufsize = 0; + + int test_type; + + int i; + + fin = NULL; + fout = NULL; + + /* Set up full self-test */ + if(argc == 1){ + test_type = TEST_SELF_FULL; + modem_probe_init("fmfsk","fmfsk_tfmfsk_log.txt"); + Fs = ST_FS; + Rs = ST_RS; + } else if (argc<7){ + /* Not running any test */ + printf("Usage: %s [(M|D) SampleRate BitRate InputFile OutputFile OctaveLogFile]\n",argv[0]); + exit(1); + } else { + /* Running stim-drivin test */ + /* Mod test */ + if(strcmp(argv[1],"M")==0 || strcmp(argv[1],"m")==0) { + test_type = TEST_MOD; + /* Demod test */ + } else if(strcmp(argv[1],"D")==0 || strcmp(argv[1],"d")==0) { + test_type = TEST_DEMOD; + } else { + printf("Must specify mod or demod test with M or D\n"); + exit(1); + } + /* Extract parameters */ + Fs = atoi(argv[2]); + Rs = atoi(argv[3]); + + /* Open files */ + fin = fopen(argv[4],"r"); + fout = fopen(argv[5],"w"); + + if(fin == NULL || fout == NULL){ + printf("Couldn't open test vector files\n"); + exit(1); + } + /* Init modem probing */ + modem_probe_init("fmfsk",argv[6]); + + } + + srand(1); + + /* set up FSK */ + fmfsk = fmfsk_create(Fs,Rs); + /* Modulate! */ + if(test_type == TEST_MOD || test_type == TEST_SELF_FULL){ + /* Generate random bits for self test */ + if(test_type == TEST_SELF_FULL){ + bitbufsize = ST_BITS; + bitbuf = (uint8_t*) malloc(sizeof(uint8_t)*ST_BITS); + for(i=0; inbit,fin) == fmfsk->nbit){ + i++; + bitbufp+=fmfsk->nbit; + /* Make sure we don't break the buffer */ + if(i*fmfsk->nbit > bitbufsize){ + bitbuf = realloc(bitbuf,sizeof(uint8_t)*(bitbufsize+fmfsk->nbit)); + bitbufsize += fmfsk->nbit; + } + } + } + /* Allocate modulation buffer */ + modbuf = (float*)malloc(sizeof(float)*(bitbufsize/fmfsk->nbit)*fmfsk->N*4); + modbufsize = (bitbufsize/fmfsk->nbit)*fmfsk->N; + /* Do the modulation */ + modbufp = modbuf; + bitbufp = bitbuf; + while( bitbufp < bitbuf+bitbufsize){ + fmfsk_mod(fmfsk, modbufp, bitbufp); + modbufp += fmfsk->N; + bitbufp += fmfsk->nbit; + } + /* For a mod-only test, write out the result */ + if(test_type == TEST_MOD){ + fwrite(modbuf,sizeof(float),modbufsize,fout); + free(modbuf); + } + /* Free bit buffer */ + free(bitbuf); + } + + /* Add channel imp here */ + + + /* Now test the demod */ + if(test_type == TEST_DEMOD || test_type == TEST_SELF_FULL){ + free(modbuf); + modbuf = malloc(sizeof(float)*(fmfsk->N+fmfsk->Ts*2)); + bitbuf = malloc(sizeof(uint8_t)*fmfsk->nbit); + /* Demod-only test */ + if(test_type == TEST_DEMOD){ + while( fread(modbuf,sizeof(float),fmfsk_nin(fmfsk),fin) == fmfsk_nin(fmfsk) ){ + fmfsk_demod(fmfsk,bitbuf,modbuf); + fwrite(bitbuf,sizeof(uint8_t),fmfsk->nbit,fout); + } + } + /* Demod after channel imp. and mod */ + else{ + bitbufp = bitbuf; + modbufp = modbuf; + while( modbufp < modbuf + modbufsize){ + fmfsk_demod(fmfsk,bitbuf,modbuf); + modbufp += fmfsk_nin(fmfsk); + } + } + free(bitbuf); + } + + modem_probe_close(); + if(test_type == TEST_DEMOD || test_type == TEST_MOD){ + fclose(fin); + fclose(fout); + } + fmfsk_destroy(fmfsk); + exit(0); +} + -- 2.25.1