assert(mod(Fs,Rb*2)==0);
%Current fixed processing buffer size, in non-ME bits
- nbit = 192;
-
+ nbit = 96;
states.Rb = Rb;
states.Rs = Rb*2; % Manchester-encoded bitrate
states.Fs = Fs;
states.Ts = Fs/states.Rs;
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);
apeven = 0;
apodd = 0;
- sample_offset = (Ts/2)+Ts+rx_timing-1
+ sample_offset = (Ts/2)+Ts+rx_timing-1;
symsamp = zeros(1,nsym);
[b, a] = cheby1(4, 1, 300/Fs, 'high'); % 300Hz HPF to simulate FM radios
tx_pmod = fmfsk_mod(states, tx_bits);
- figure(10)
- plot(tx_pmod);
tx = analog_fm_mod(fm_states, tx_pmod);
tx = tx(10:length(tx));
rx = filter(filt,1,rx);
figure(4)
+ title("Spectrum of rx-ed signal after FM demod and FM radio channel");
plot(20*log10(abs(fft(rx))))
- figure(5)
+ figure(5)
+ title("Time domain of rx-ed signal after FM demod and FM radio channel");
plot(rx)
%rx = real(rx);
%b1 = fir2(100, [0 4000 5200 48000]/48000, [1 1 0.5 0.5]);
function test_stats = fmfsk_demod_xt(Fs,Rs,mod,tname,M=2)
global tfsk_location;
- size(mod)
-
%Name of executable containing the modulator
modvecfilename = sprintf('fmfsk_demod_ut_modvec_%d',getpid());
bitvecfilename = sprintf('fmfsk_demod_ut_bitvec_%d',getpid());
tvecfilename = sprintf('fmfsk_demod_ut_tracevec_%d.txt',getpid());
- delete(bitvecfilename);
- delete(modvecfilename);
- delete(tvecfilename);
-
%command to be run by system to launch the demod
- command = sprintf('%s D %d %d %s %s %s',tfsk_location,Fs,Rs,modvecfilename,bitvecfilename,tvecfilename)
+ command = sprintf('%s D %d %d %s %s %s',tfsk_location,Fs,Rs,modvecfilename,bitvecfilename,tvecfilename);
%save modulated input into a file
modvecfile = fopen(modvecfilename,'wb+');
end
%Add frequency drift
- fdrift = df/Fs
+ fdrift = df/Fs;
fshift = 2*pi*fdrift*(1:length(tx));
fshift = exp(j*(fshift.^2));
tx = tx.*fshift;
%High-pass filter to simulate the FM radios
if hpf>0
- printf("high-pass filtering!\n")
rx = filter(b,a,rx);
end
ebnodbs = length(ebnodbrange);
%Replication of other parameters for parcellfun
- timingv = repmat(timing_offset,1,ebnodbs);
- driftv = repmat(timing_offset,1,ebnodbs);
- hpfv = repmat(timing_offset,1,ebnodbs);
- deempv = repmat(timing_offset,1,ebnodbs);
- outfv = repmat(timing_offset,1,ebnodbs);
+ timingv = repmat(timing_offset ,1,ebnodbs);
+ driftv = repmat(drift ,1,ebnodbs);
+ hpfv = repmat(hpf ,1,ebnodbs);
+ deempv = repmat(deemp ,1,ebnodbs);
+ outfv = repmat(outfilt ,1,ebnodbs);
- statv = pararrayfun(floor(1.25*nproc()),@tfmfsk_run_sim,ebnodbrange,timingv,deempv,outfv,hpfv,driftv);
+ statv = pararrayfun(floor(.75*nproc()),@tfmfsk_run_sim,ebnodbrange,timingv,deempv,outfv,hpfv,driftv);
%statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv);
passv = zeros(1,length(statv));
endfunction
function pass = test_fmfsk_battery()
- pass = test_mod_horuscfg_randbits;
+ pass = test_mod_fdvbcfg_randbits;
assert(pass)
pass = pass && test_drift_var(1,1,1);
assert(pass)
endfunction
function plot_fsk_bers(M=2)
- %Range of EbNodB over which to plot
- ebnodbrange = (3:13);
-
- berc = ones(1,length(ebnodbrange));
- bero = ones(1,length(ebnodbrange));
- berinc = ones(1,length(ebnodbrange));
- ebnodbs = length(ebnodbrange)
- mode = 2;
- %Replication of other parameters for parcellfun
- modev = repmat(mode,1,ebnodbs);
- timingv = repmat(0,1,ebnodbs);
- fadingv = repmat(0,1,ebnodbs);
- dfv = repmat(0,1,ebnodbs);
- dav = repmat(1,1,ebnodbs);
- Mv = repmat(M,1,ebnodbs);
+ %Range of EbNodB over which to test
+ ebnodbrange = (8:14);
+ ebnodbs = length(ebnodbrange);
+ %Replication of other parameters for parcellfun
+ timingv = repmat(1 ,1,ebnodbs);
+ driftv = repmat(1 ,1,ebnodbs);
+ hpfv = repmat(1 ,1,ebnodbs);
+ deempv = repmat(1 ,1,ebnodbs);
+ outfv = repmat(1 ,1,ebnodbs);
- statv = pararrayfun(floor(1.25*nproc()),@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv);
+ statv = pararrayfun(nproc(),@tfmfsk_run_sim,ebnodbrange,timingv,deempv,outfv,hpfv,driftv);
%statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv);
for ii = (1:length(statv))
clf;
figure(M)
- semilogy(ebnodbrange, berinc,sprintf('r;%dFSK non-coherent theory;',M))
+ semilogy(ebnodbrange, berinc,sprintf('r;2FSK non-coherent theory;',M))
hold on;
- semilogy(ebnodbrange, bero ,sprintf('g;Octave fsk horus %dFSK Demod;',M))
- semilogy(ebnodbrange, berc,sprintf('v;C fsk horus %dFSK Demod;',M))
+ semilogy(ebnodbrange, bero ,sprintf('g;Octave ME-FM-FSK Demod;',M))
+ semilogy(ebnodbrange, berc,sprintf('v;C ME-FM-FSK Demod;',M))
hold off;
grid("minor");
axis([min(ebnodbrange) max(ebnodbrange) 1E-5 1])
#include "modem_probe.h"
#include "comp_prim.h"
-#define STD_PROC_BITS 192
+#define STD_PROC_BITS 96
/*
\*---------------------------------------------------------------------------*/
/* P oversampling rate constant -- should probably be init-time configurable */
-#define ct_P 8
+#define horus_P 8
/* Define this to enable EbNodB estimate */
/* This needs square roots, may take more cpu time than it's worth */
}
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: fsk_create_hbr
+ AUTHOR......: Brady O'Brien
+ DATE CREATED: 11 February 2016
+
+ Create and initialize an instance of the FSK modem. Returns a pointer
+ to the modem state/config struct. One modem config struct may be used
+ for both mod and demod. returns NULL on failure.
+
+\*---------------------------------------------------------------------------*/
+
+struct FSK * fsk_create_hbr(int Fs, int Rs,int P,int M, int tx_f1, int tx_fs)
+{
+ struct FSK *fsk;
+ int i;
+ int memold;
+ int Ndft = 0;
+
+ /* Number of symbols in a processing frame */
+ int nsyms = 192;
+
+ /* Check configuration validity */
+ assert(Fs > 0 );
+ assert(Rs > 0 );
+ assert(tx_f1 > 0);
+ assert(tx_fs > 0);
+ assert(P > 0);
+ /* Ts (Fs/Rs) must be an integer */
+ assert( (Fs%Rs) == 0 );
+ /* Ts/P (Fs/Rs/P) must be an integer */
+ assert( ((Fs/Rs)%P) == 0 );
+ assert( M==2 || M==4);
+
+ fsk = (struct FSK*) malloc(sizeof(struct FSK));
+ if(fsk == NULL) return NULL;
+
+
+ /* Set constant config parameters */
+ fsk->Fs = Fs;
+ fsk->Rs = Rs;
+ fsk->Ts = Fs/Rs;
+ fsk->N = fsk->Ts*nsyms;
+ fsk->P = P;
+ fsk->Nsym = nsyms;
+ fsk->Nmem = fsk->N+(2*fsk->Ts);
+ fsk->f1_tx = tx_f1;
+ fsk->fs_tx = tx_fs;
+ fsk->nin = fsk->N;
+ fsk->mode = M==2 ? MODE_2FSK : MODE_4FSK;
+ fsk->Nbits = M==2 ? fsk->Nsym : fsk->Nsym*2;
+
+ /* Find smallest 2^N value that fits Fs for efficient FFT */
+ /* It would probably be better to use KISS-FFt's routine here */
+ for(i=1; i; i<<=1)
+ if((fsk->N)&i)
+ Ndft = i;
+
+ fsk->Ndft = Ndft;
+
+ fsk->est_min = tx_f1-3*Rs;
+ if(fsk->est_min<0) fsk->est_min = 0;
+
+ fsk->est_max = (Fs/2)-Rs;
+
+ fsk->est_space = (Rs/2)-(Rs/10);
+
+ /* Set up rx state */
+ fsk->phi1_c = comp_exp_j(0);
+ fsk->phi2_c = comp_exp_j(0);
+ fsk->phi3_c = comp_exp_j(0);
+ fsk->phi4_c = comp_exp_j(0);
+
+ fsk->phi1_c.real = 0;
+ fsk->phi1_c.imag = 1;
+
+ memold = (4*fsk->Ts);
+
+ fsk->nstash = memold;
+ fsk->samp_old = (float*) malloc(sizeof(float)*memold);
+ if(fsk->samp_old == NULL){
+ free(fsk);
+ return NULL;
+ }
+
+ for(i=0;i<memold;i++)fsk->samp_old[i]=0;
+
+ fsk->fft_cfg = kiss_fftr_alloc(fsk->Ndft,0,NULL,NULL);
+ if(fsk->fft_cfg == NULL){
+ free(fsk->samp_old);
+ free(fsk);
+ return NULL;
+ }
+
+ fsk->fft_est = (float*)malloc(sizeof(float)*fsk->Ndft/2);
+ if(fsk->fft_est == NULL){
+ free(fsk->samp_old);
+ free(fsk->fft_cfg);
+ free(fsk);
+ return NULL;
+ }
+
+ for(i=0;i<fsk->Ndft/2;i++)fsk->fft_est[i] = 0;
+
+ fsk->norm_rx_timing = 0;
+
+ /* Set up tx state */
+ fsk->tx_phase_c = comp_exp_j(0);
+
+ /* Set up demod stats */
+ fsk->EbNodB = 0;
+ fsk->f1_est = 0;
+ fsk->f2_est = 0;
+ fsk->f3_est = 0;
+ fsk->f4_est = 0;
+ fsk->ppm = 0;
+
+ return fsk;
+}
+
+#define HORUS_MIN 800
+#define HORUS_MAX 2500
+#define HORUS_MIN_SPACING 200
/*---------------------------------------------------------------------------*\
assert(Rs > 0 );
assert(tx_f1 > 0);
assert(tx_fs > 0);
- assert(ct_P > 0);
+ assert(horus_P > 0);
/* Ts (Fs/Rs) must be an integer */
assert( (Fs%Rs) == 0 );
/* Ts/P (Fs/Rs/P) must be an integer */
- assert( ((Fs/Rs)%ct_P) == 0 );
+ assert( ((Fs/Rs)%horus_P) == 0 );
assert( M==2 || M==4);
fsk = (struct FSK*) malloc(sizeof(struct FSK));
if(fsk == NULL) return NULL;
-
- /* Find smallest 2^N value that fits Fs for efficient FFT */
- /* It would probably be better to use KISS-FFt's routine here */
- for(i=1; i; i<<=1)
- if(Fs&i)
- Ndft = i<<1;
Ndft = 1024;
- //Ndft = 4096;
/* Set constant config parameters */
fsk->Fs = Fs;
fsk->Rs = Rs;
fsk->Ts = Fs/Rs;
fsk->N = Fs;
- fsk->P = ct_P;
+ fsk->P = horus_P;
fsk->Nsym = fsk->N/fsk->Ts;
fsk->Ndft = Ndft;
fsk->Nmem = fsk->N+(2*fsk->Ts);
fsk->nin = fsk->N;
fsk->mode = M==2 ? MODE_2FSK : MODE_4FSK;
fsk->Nbits = M==2 ? fsk->Nsym : fsk->Nsym*2;
+ fsk->est_min = HORUS_MIN;
+ fsk->est_max = HORUS_MAX;
+ fsk->est_space = HORUS_MIN_SPACING;
/* Set up rx state */
fsk->phi1_c = comp_exp_j(0);
free(fsk);
}
-#define FEST_MIN 800
-#define FEST_MAX 2500
-#define FEST_MIN_SPACING 200
/*
* Internal function to estimate the frequencies of the two tones within a block of samples.
kiss_fft_cpx *fftout = (kiss_fft_cpx*)alloca(sizeof(kiss_fft_cpx)*(Ndft/2)+1);
fft_samps = Ndft;
- f_min = (FEST_MIN*Ndft)/Fs;
- f_max = (FEST_MAX*Ndft)/Fs;
- f_zero = (FEST_MIN_SPACING*Ndft)/(2*Fs);
+ f_min = (fsk->est_min*Ndft)/Fs;
+ f_max = (fsk->est_max*Ndft)/Fs;
+ f_zero = (fsk->est_space*Ndft)/(2*Fs);
int fft_loops = nin/Ndft;
for(j=0; j<fft_loops; j++){
for(i=0; i<M; i++){
freqs[i] = (float)(freqi[i])*((float)Fs/(float)Ndft);
}
-
-
-
}
void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
int f1_tx; /* f1 for modulator */
int fs_tx; /* Space between TX freqs for modulatosr */
int mode; /* 2FSK or 4FSK */
+ int est_min; /* Minimum frequency for freq. estimator */
+ int est_max; /* Maximum frequency for freq. estimaotr */
+ int est_space; /* Minimum frequency spacing for freq. estimator */
/* Parameters used by demod */
COMP phi1_c;
* int Fs - Sample frequency
* int Rs - Symbol rate
* int tx_f1 - '0' frequency
- * int tx_f2 - '1' frequency
+ * int tx_fs - frequency spacing
*/
-struct FSK * fsk_create(int Fs, int Rs,int M, int tx_f1,int tx_fs);
+struct FSK * fsk_create(int Fs, int Rs, int M, int tx_f1, int tx_fs);
+
+/*
+ * Create an FSK config/state struct from a set of config parameters
+ *
+ * int Fs - Sample frequency
+ * int Rs - Symbol rate
+ * int tx_f1 - '0' frequency
+ * int tx_fs - frequency spacing
+ */
+struct FSK * fsk_create_hbr(int Fs, int Rs, int P, int M, int tx_f1, int tx_fs);
/*
* Destroy an FSK state struct and free it's memory
int main(int argc,char *argv[]){
struct FSK *fsk;
- int Fs,Rs,M;
+ int Fs,Rs,M,P;
+ int hbr = 0;
FILE *fin,*fout;
uint8_t *bitbuf;
int16_t *rawbuf;
float *modbuf;
int i,t;
- if(argc<6){
- fprintf(stderr,"usage: %s Mode SampleFreq SymbolFreq InputModemRawFile OutputOneBitPerCharFile [OctaveLogFile]\n",argv[0]);
+ if(argc<7){
+ fprintf(stderr,"usage: %s Mode P SampleFreq SymbolFreq InputModemRawFile OutputOneBitPerCharFile [OctaveLogFile]\n",argv[0]);
exit(1);
}
/* Extract parameters */
- M = atoi(argv[1]);
- Fs = atoi(argv[2]);
- Rs = atoi(argv[3]);
+ P = atoi(argv[2]);
+ Fs = atoi(argv[3]);
+ Rs = atoi(argv[4]);
/* Open files */
- if(strcmp(argv[4],"-")==0){
- fin = stdin;
- }else{
- fin = fopen(argv[4],"r");
- }
+ if(strcmp(argv[5],"-")==0){
+ fin = stdin;
+ }else{
+ fin = fopen(argv[5],"r");
+ }
- if(strcmp(argv[5],"-")==0){
- fout = stdout;
- }else{
- fout = fopen(argv[5],"w");
- }
+ if(strcmp(argv[6],"-")==0){
+ fout = stdout;
+ }else{
+ fout = fopen(argv[6],"w");
+ }
+ /* Handle high-bit-rate special cases */
+ if(strcmp(argv[1],"2X")==0){
+ M = 2;
+ hbr = 1;
+ }else if(strcmp(argv[1],"4X")==0){
+ M = 4;
+ hbr = 1;
+ }else {
+ M = atoi(argv[1]);
+ }
- if(argc>6)
- modem_probe_init("fsk2",argv[6]);
+ if(argc>7)
+ modem_probe_init("fsk2",argv[7]);
/* set up FSK */
- fsk = fsk_create(Fs,Rs,M,1200,400);
+ if(!hbr)
+ fsk = fsk_create(Fs,Rs,M,1200,400);
+ else
+ fsk = fsk_create_hbr(Fs,Rs,P,M,1200,400);
+
if(fin==NULL || fout==NULL || fsk==NULL){
fprintf(stderr,"Couldn't open test vector files\n");
}
}
+
modem_probe_close();
cleanup:
fclose(fin);
FILE *fout;
uint8_t *bitbuf;
- /* Seed the RNG with some constant */
- srand(158324);
if(argc != 3){
fprintf(stderr,"usage: %s OutputBitsOnePerByte FrameCount\n",argv[0]);
bitbuf = (uint8_t*)alloca(sizeof(uint8_t)*FSK_FRAME_SIZE);
/* Write out sync frame and sequence */
- for(i=0; i<FSK_FRAME_SIZE; i++){
- bitbuf[i++] = 0;
- bitbuf[i++] = 0;
- bitbuf[i++] = 0;
- bitbuf[i++] = 1;
- bitbuf[i++] = 1;
- bitbuf[i++] = 0;
- bitbuf[i++] = 1;
- bitbuf[i ] = 1;
- }
- for(i=0;i<sizeof(init);i++){
- bitbuf[FSK_FRAME_SIZE-sizeof(init)+i]=init[i];
+ for(i=0; i<FSK_FRAME_SIZE; i){
+ bitbuf[i++] = rand()&0x1;
+ }
+ for(i=0;i<sizeof(init);i++){
+ bitbuf[FSK_FRAME_SIZE-sizeof(init)+i]=init[i];
+ }
+ fwrite(bitbuf,sizeof(uint8_t),FSK_FRAME_SIZE,fout);
+
+
+ /* Seed the RNG with some constant */
+ srand(158324);
+ for(i=0; i<bitcnt; i++){
+ for(j=0; j<FSK_FRAME_SIZE; j++){
+ bitbuf[j] = rand()&0x1;
}
fwrite(bitbuf,sizeof(uint8_t),FSK_FRAME_SIZE,fout);
- for(i=0; i<bitcnt; i++){
- for(j=0; j<FSK_FRAME_SIZE; j++){
- bitbuf[j] = rand()&0x1;
- }
- fwrite(bitbuf,sizeof(uint8_t),FSK_FRAME_SIZE,fout);
- if(fout == stdout){
- fflush(fout);
- }
+ if(fout == stdout){
+ fflush(fout);
}
+ }
cleanup:
fclose(fout);