% Estimate frequency offset of FDM signal using BPSK pilot. This is quite
% sensitive to pilot tone level wrt other carriers
-function foff = rx_est_freq_offset(rx_fdm, pilot, pilot_prev, nin)
+function [foff s1 s2] = rx_est_freq_offset(rx_fdm, pilot, pilot_prev, nin)
global M;
global Npilotbaseband;
global pilot_baseband1;
pilot_baseband2(Npilotbaseband-nin+i) = rx_fdm(i) * conj(pilot_prev(i));
end
- [foff1 max1 pilot_lpf1] = lpf_peak_pick(pilot_baseband1, pilot_lpf1, nin);
- [foff2 max2 pilot_lpf2] = lpf_peak_pick(pilot_baseband2, pilot_lpf2, nin);
+ [foff1 max1 pilot_lpf1 s1] = lpf_peak_pick(pilot_baseband1, pilot_lpf1, nin);
+ [foff2 max2 pilot_lpf2 s2] = lpf_peak_pick(pilot_baseband2, pilot_lpf2, nin);
if max1 > max2
foff = foff1;
% LPF and peak pick part of freq est, put in a function as we call it twice
-function [foff imax pilot_lpf] = lpf_peak_pick(pilot_baseband, pilot_lpf, nin)
+function [foff imax pilot_lpf S] = lpf_peak_pick(pilot_baseband, pilot_lpf, nin)
global M;
global Npilotlpf;
global Npilotcoeff;
pilot_lpf(1:Npilotlpf-nin) = pilot_lpf(nin+1:Npilotlpf);
j = 1;
for i = Npilotlpf-nin+1:Npilotlpf
- pilot_lpf(i) = pilot_baseband(j:j+Npilotcoeff) * pilot_coeff';
+ pilot_lpf(i) = pilot_baseband(j:j+Npilotcoeff-1) * pilot_coeff';
j++;
end
% decimate to improve DFT resolution, window and DFT
Mpilot = Fs/(2*200); % calc decimation rate given new sample rate is twice LPF freq
- s = pilot_lpf(1:Mpilot:Npilotlpf) .* hanning(Npilotlpf/Mpilot)';
+ h = hanning(Npilotlpf);
+ s = pilot_lpf(1:Mpilot:Npilotlpf) .* h(1:Mpilot:Npilotlpf)';
S = abs(fft(s, Mpilotfft));
% peak pick and convert to Hz
fclose(f);
endfunction
-
-% Saves 200Hz LPF filter coeffs to a text file in the form of a C array
-
function pilot_coeff_file(filename)
global pilot_coeff;
- global Nfilter;
+ global Npilotcoeff;
f=fopen(filename,"wt");
fprintf(f,"/* Generated by pilot_coeff_file() Octave function */\n\n");
fprintf(f,"const float pilot_coeff[]={\n");
for m=1:Npilotcoeff-1
- fprintf(f," %g,\n", pilot_coeff(m));
+ fprintf(f," %g,\n",pilot_coeff(m));
+ endfor
+ fprintf(f," %g\n};\n",pilot_coeff(Npilotcoeff));
+ fclose(f);
+endfunction
+
+% Saves hanning window coeffs to a text file in the form of a C array
+
+function hanning_file(filename)
+ global Npilotlpf;
+
+ h = hanning(Npilotlpf);
+
+ f=fopen(filename,"wt");
+ fprintf(f,"/* Generated by hanning_file() Octave function */\n\n");
+ fprintf(f,"const float hanning[]={\n");
+ for m=1:Npilotlpf-1
+ fprintf(f," %g,\n", h(m));
endfor
- fprintf(f," %g\n};\n", pilot_coeff(Npilotcoeff));
+ fprintf(f," %g\n};\n", h(Npilotlpf));
fclose(f);
endfunction
global Mpilotfft = 256;
global Npilotcoeff = 30; % number of pilot LPF coeffs
-global pilot_coeff = fir1(Npilotcoeff, 200/(Fs/2))'; % 200Hz LPF
-global Npilotbaseband = Npilotcoeff + 4*M; % number of pilot baseband samples reqd for pilot LPF
+global pilot_coeff = fir1(Npilotcoeff-1, 200/(Fs/2))'; % 200Hz LPF
+global Npilotbaseband = Npilotcoeff + M + M/P; % number of pilot baseband samples reqd for pilot LPF
global Npilotlpf = 4*M; % number of samples we DFT pilot over, pilot est window
% pilot LUT, used for copy of pilot at rx
% Main loop ----------------------------------------------------
for f=1:frames
+
% obtain nin samples of the test input signal
for i=1:nin
test_frame_sync_log = [test_frame_sync_log test_frame_sync_state];
end
-
+
% ---------------------------------------------------------------------
% Print Stats
% ---------------------------------------------------------------------
passes = fails = 0;
frames = 25;
prev_tx_symbols = ones(Nc+1,1);
+
+% Octave outputs we want to collect for comparison to C version
+
tx_bits_log = [];
tx_symbols_log = [];
tx_baseband_log = [];
tx_fdm_log = [];
+pilot_baseband1_log = [];
+pilot_baseband2_log = [];
+pilot_lpf1_log = [];
+pilot_lpf2_log = [];
+s1_log = [];
+s2_log = [];
for f=1:frames
+
+ % modulator
+
tx_bits = get_test_bits(Nc*Nb);
tx_bits_log = [tx_bits_log tx_bits];
tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, 'dqpsk');
tx_baseband_log = [tx_baseband_log tx_baseband];
tx_fdm = fdm_upconvert(tx_baseband);
tx_fdm_log = [tx_fdm_log tx_fdm];
+
+ rx_fdm = real(tx_fdm);
+
+ % demodulator
+
+ [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M);
+
+ [foff s1 s2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, M);
+
+ pilot_baseband1_log = [pilot_baseband1_log pilot_baseband1];
+ pilot_baseband2_log = [pilot_baseband2_log pilot_baseband2];
+ pilot_lpf1_log = [pilot_lpf1_log pilot_lpf1];
+ pilot_lpf2_log = [pilot_lpf2_log pilot_lpf2];
+ s1_log = [s1_log s1];
+ s2_log = [s2_log s2];
+
end
% Compare to the output from the C version
load ../unittest/tfdmdv_out.txt
-figure(1)
-subplot(211)
+% Helper functions to plot output of C verson and difference between Octave and C versions
+
+function stem_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec)
+ figure(plotnum)
+ subplot(subplotnum)
+ stem(sig);
+ hold on;
+ stem(error,'g');
+ hold off;
+ if nargin == 6
+ axis(axisvec);
+ end
+ title(titlestr);
+endfunction
+
+function plot_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec)
+ figure(plotnum)
+ subplot(subplotnum)
+ plot(sig);
+ hold on;
+ plot(error,'g');
+ hold off;
+ if nargin == 6
+ axis(axisvec);
+ end
+ title(titlestr);
+endfunction
+
+% ---------------------------------------------------------------------------------------
+% Plot output and test each C function
+% ---------------------------------------------------------------------------------------
+
+% fdmdv_get_test_bits() & bits_to_dqpsk_symbols()
+
n = 28;
-stem(tx_bits_log_c(1:n));
-hold on;
-stem(tx_bits_log(1:n) - tx_bits_log_c(1:n),'g');
-hold off;
-axis([1 n -1.5 1.5])
-title('tx bits')
-subplot(212)
-stem(real(tx_symbols_log_c(1:n/2)));
-hold on;
-stem(tx_symbols_log(1:n/2) - tx_symbols_log_c(1:n/2),'g');
-hold off;
-axis([1 n/2 -1.5 1.5])
-title('tx symbols real')
-
-figure(2)
-clf;
+stem_sig_and_error(1, 211, tx_bits_log_c(1:n), tx_bits_log(1:n) - tx_bits_log_c(1:n), 'tx bits', [1 n -1.5 1.5])
+stem_sig_and_error(1, 212, real(tx_symbols_log_c(1:n/2)), tx_symbols_log(1:n/2) - tx_symbols_log_c(1:n/2), 'tx symbols real', [1 n/2 -1.5 1.5])
+
+% tx_filter()
+
diff = tx_baseband_log - tx_baseband_log_c;
-subplot(211)
c=3;
-plot(real(tx_baseband_log_c(c,:)));
-hold on;
-plot(real(sum(diff)),'g')
-hold off;
-title('tx baseband real')
-subplot(212)
-plot(imag(tx_baseband_log_c(c,:)));
-hold on;
-plot(imag(sum(diff)),'g')
-hold off;
-title('tx baseband imag')
-
-figure(3)
-clf
-subplot(211)
-plot(real(tx_fdm_log_c));
-hold on;
-plot(real(tx_fdm_log - tx_fdm_log_c),'g');
-hold off;
-title('tx fdm real')
-subplot(212)
-plot(imag(tx_fdm_log_c));
-hold on;
-plot(imag(tx_fdm_log - tx_fdm_log_c),'g');
-hold off;
-title('tx fdm imag')
-
-figure(4)
-clf
-subplot(211)
-plot(real(pilot_lut_c));
-hold on;
-plot(real(pilot_lut - pilot_lut_c),'g');
-hold off;
-title('pilot lut real')
-subplot(212)
-plot(imag(pilot_lut_c));
-hold on;
-plot(imag(pilot_lut - pilot_lut_c),'g');
-hold off;
-title('pilot lut imag')
+plot_sig_and_error(2, 211, real(tx_baseband_log_c(c,:)), real(sum(diff)), 'tx baseband real')
+plot_sig_and_error(2, 212, imag(tx_baseband_log_c(c,:)), imag(sum(diff)), 'tx baseband imag')
+
+% fdm_upconvert()
+
+plot_sig_and_error(3, 211, real(tx_fdm_log_c), real(tx_fdm_log - tx_fdm_log_c), 'tx fdm real')
+plot_sig_and_error(3, 212, imag(tx_fdm_log_c), imag(tx_fdm_log - tx_fdm_log_c), 'tx fdm imag')
+
+% generate_pilot_lut()
+
+plot_sig_and_error(4, 211, real(pilot_lut_c), real(pilot_lut - pilot_lut_c), 'pilot lut real')
+plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(pilot_lut - pilot_lut_c), 'pilot lut imag')
+
+% rx_est_freq_offset()
+
+plot_sig_and_error(5, 211, real(pilot_baseband1_log), real(pilot_baseband1_log - pilot_baseband1_log_c), 'pilot baseband1 real' )
+plot_sig_and_error(5, 212, real(pilot_baseband2_log), real(pilot_baseband2_log - pilot_baseband2_log_c), 'pilot baseband2 real' )
+
+plot_sig_and_error(6, 211, real(pilot_lpf1_log), real(pilot_lpf1_log - pilot_lpf1_log_c), 'pilot lpf1 real' )
+plot_sig_and_error(6, 212, real(pilot_lpf2_log), real(pilot_lpf2_log - pilot_lpf2_log_c), 'pilot lpf2 real' )
+
+plot_sig_and_error(7, 211, real(s1_log), real(s1_log - s1_log_c), 's1 real' )
+plot_sig_and_error(7, 212, real(s2_log), real(s2_log - s2_log_c), 's2 real' )
+
+% ---------------------------------------------------------------------------------------
+% AUTOMATED CHECKS ------------------------------------------
+% ---------------------------------------------------------------------------------------
if sum(tx_bits_log - tx_bits_log_c) == 0
printf("fdmdv_get_test_bits..: OK\n");
fails++;
end
+[m n] = size(pilot_baseband1_log);
+if sum(pilot_baseband1_log - pilot_baseband1_log_c)/n < 1E-3
+ printf("pilot_baseband1_log..: OK\n");
+ passes++;
+else;
+ printf("pilot_baseband1_log..: FAIL\n");
+ fails++;
+end
+
+[m n] = size(pilot_baseband2_log);
+if sum(pilot_baseband2_log - pilot_baseband2_log_c)/n < 1E-3
+ printf("pilot_baseband2_log..: OK\n");
+ passes++;
+else;
+ printf("pilot_baseband2_log..: FAIL\n");
+ fails++;
+end
+
printf("\npasses: %d fails: %d\n", passes, fails);
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <math.h>
#include "fdmdv_internal.h"
#include "fdmdv.h"
#include "rn.h"
#include "test_bits.h"
+#include "pilot_coeff.h"
+#include "fft.h"
+#include "hanning.h"
/*---------------------------------------------------------------------------*\
return res;
}
+static COMP cconj(COMP a)
+{
+ COMP res;
+
+ res.real = a.real;
+ res.imag = -a.imag;
+
+ return res;
+}
+
static COMP cmult(COMP a, COMP b)
{
COMP res;
return res;
}
+static COMP fcmult(float a, COMP b)
+{
+ COMP res;
+
+ res.real = a*b.real;
+ res.imag = a*b.imag;
+
+ return res;
+}
+
static COMP cadd(COMP a, COMP b)
{
COMP res;
struct FDMDV *fdmdv_create(void)
{
struct FDMDV *f;
- int c, k;
+ int c, i, k;
float carrier_freq;
assert(FDMDV_BITS_PER_FRAME == NC*NB);
}
+ /* Set up frequency of each carrier */
+
for(c=0; c<NC/2; c++) {
carrier_freq = (-NC/2 + c)*FSEP + FCENTRE;
f->freq[c].real = cos(2.0*PI*carrier_freq/FS);
f->freq[NC].real = cos(2.0*PI*FCENTRE/FS);
f->freq[NC].imag = sin(2.0*PI*FCENTRE/FS);
+ /* Generate DBPSK pilot Look Up Table (LUT) */
+
+ generate_pilot_lut(f->pilot_lut, &f->freq[NC]);
+
+ /* Freq Offset estimation */
+
+ for(i=0; i<NPILOTBASEBAND; i++) {
+ f->pilot_baseband1[i].real = f->pilot_baseband2[i].real = 0.0;
+ f->pilot_baseband1[i].imag = f->pilot_baseband2[i].imag = 0.0;
+ }
+ f->pilot_lut_index = 0;
+ f->prev_pilot_lut_index = 3*M;
+
+ for(i=0; i<NPILOTLPF; i++) {
+ f->pilot_lpf1[i].real = f->pilot_lpf2[i].real = 0.0;
+ f->pilot_lpf1[i].imag = f->pilot_lpf2[i].imag = 0.0;
+ }
+
return f;
}
tx_fdm[i] = cmult(two, tx_fdm[i]);
}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: generate_pilot_fdm()
+ AUTHOR......: David Rowe
+ DATE CREATED: 19/4/2012
+
+ Generate M samples of DBPSK pilot signal for Freq offset estimation
+
+\*---------------------------------------------------------------------------*/
+
+void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol,
+ float *filter_mem, COMP *phase, COMP *freq)
+{
+ int i,j,k;
+ float tx_baseband[M];
+
+ /* +1 -1 +1 -1 DBPSK sync carrier, once filtered becomes (roughly)
+ two spectral lines at +/- RS/2 */
+
+ if (*bit)
+ *symbol = -*symbol;
+ else
+ *symbol = *symbol;
+ if (*bit)
+ *bit = 0;
+ else
+ *bit = 1;
+
+ /* filter DPSK symbol to create M baseband samples */
+
+ filter_mem[NFILTER-1] = (sqrt(2)/2) * *symbol;
+ for(i=0; i<M; i++) {
+ tx_baseband[i] = 0.0;
+ for(j=M-1,k=M-i-1; j<NFILTER; j+=M,k+=M)
+ tx_baseband[i] += M * filter_mem[j] * gt_alpha5_root[k];
+ }
+
+ /* shift memory, inserting zeros at end */
+
+ for(i=0; i<NFILTER-M; i++)
+ filter_mem[i] = filter_mem[i+M];
+
+ for(i=NFILTER-M; i<NFILTER; i++)
+ filter_mem[i] = 0.0;
+
+ /* upconvert */
+
+ for(i=0; i<M; i++) {
+ *phase = cmult(*phase, *freq);
+ pilot_fdm[i].real = sqrt(2)*2*tx_baseband[i] * phase->real;
+ pilot_fdm[i].imag = sqrt(2)*2*tx_baseband[i] * phase->imag;
+ }
+}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: generate_pilot_lut()
+ AUTHOR......: David Rowe
+ DATE CREATED: 19/4/2012
+
+ Generate a 4M sample vector of DBPSK pilot signal. As the pilot signal
+ is periodic in 4M samples we can then use this vector as a look up table
+ for pilot signal generation in the demod.
+
+\*---------------------------------------------------------------------------*/
+
+void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq)
+{
+ int pilot_rx_bit = 0;
+ float pilot_symbol = sqrt(2.0);
+ COMP pilot_phase = {1.0, 0.0};
+ float pilot_filter_mem[NFILTER];
+ COMP pilot[M];
+ int i,f;
+
+ for(i=0; i<NFILTER; i++)
+ pilot_filter_mem[i] = 0.0;
+
+ /* discard first 4 symbols as filter memory is filling, just keep
+ last four symbols */
+
+ for(f=0; f<8; f++) {
+ generate_pilot_fdm(pilot, &pilot_rx_bit, &pilot_symbol, pilot_filter_mem, &pilot_phase, pilot_freq);
+ if (f >= 4)
+ memcpy(&pilot_lut[M*(f-4)], pilot, M*sizeof(COMP));
+ }
+
+}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: lpf_peak_pick()
+ AUTHOR......: David Rowe
+ DATE CREATED: 20/4/2012
+
+ LPF and peak pick part of freq est, put in a function as we call it twice.
+
+\*---------------------------------------------------------------------------*/
+
+void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], COMP s[], int nin)
+{
+ int i,j,k;
+ int mpilot;
+ float mag, imax;
+ int ix;
+ float r;
+
+ /* LPF cutoff 200Hz, so we can handle max +/- 200 Hz freq offset */
+
+ for(i=0; i<NPILOTLPF-nin; i++)
+ pilot_lpf[i] = pilot_lpf[nin+i];
+ for(i=NPILOTLPF-nin, j=0; i<NPILOTLPF; i++,j++) {
+ pilot_lpf[i].real = 0.0; pilot_lpf[i].imag = 0.0;
+ for(k=0; k<NPILOTCOEFF; k++)
+ pilot_lpf[i] = cadd(pilot_lpf[i], fcmult(pilot_coeff[k], pilot_baseband[j+k]));
+ }
+
+ /* decimate to improve DFT resolution, window and DFT */
+
+ mpilot = FS/(2*200); /* calc decimation rate given new sample rate is twice LPF freq */
+ for(i=0; i<MPILOTFFT; i++) {
+ s[i].real = 0.0; s[i].imag = 0.0;
+ }
+
+ for(i=0,j=0; i<NPILOTLPF; i+=mpilot,j++) {
+ s[j] = fcmult(hanning[i], pilot_lpf[i]);
+ //s[j] = pilot_lpf[i];
+ }
+#ifdef TT
+ fft(&s[0].real, MPILOTFFT, 1);
+
+ /* peak pick and convert to Hz */
+
+ imax = 0.0;
+ ix = 0;
+ for(i=0; i<MPILOTFFT; i++) {
+ mag = s[i].real*s[i].real + s[i].imag*s[i].imag;
+ if (mag > imax) {
+ imax = mag;
+ ix = i;
+ }
+ }
+ r = 2.0*200.0/MPILOTFFT; /* maps FFT bin to frequency in Hz */
+
+ if (ix >= MPILOTFFT/2)
+ *foff = (ix - MPILOTFFT)*r;
+ else
+ *foff = (ix)*r;
+ *max = imax;
+#endif
+}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: rx_est_freq_offset()
+ AUTHOR......: David Rowe
+ DATE CREATED: 19/4/2012
+
+ Estimate frequency offset of FDM signal using BPSK pilot. Note that
+ this algorithm is quite sensitive to pilot tone level wrt other
+ carriers, so test variations to the pilot amplitude carefully.
+
+\*---------------------------------------------------------------------------*/
+
+float rx_est_freq_offset(struct FDMDV *f, float rx_fdm[], int nin)
+{
+ int i,j;
+ COMP pilot[M+M/P];
+ COMP prev_pilot[M+M/P];
+ float foff, foff1, foff2;
+ float max1, max2;
+
+ assert(nin <= M+M/P);
+
+ /* get pilot samples used for correlation/down conversion of rx signal */
+
+ for (i=0; i<nin; i++) {
+ pilot[i] = f->pilot_lut[f->pilot_lut_index];
+ f->pilot_lut_index++;
+ if (f->pilot_lut_index >= 4*M)
+ f->pilot_lut_index = 0;
+
+ prev_pilot[i] = f->pilot_lut[f->prev_pilot_lut_index];
+ f->prev_pilot_lut_index++;
+ if (f->prev_pilot_lut_index >= 4*M)
+ f->prev_pilot_lut_index = 0;
+ }
+
+ /*
+ Down convert latest M samples of pilot by multiplying by ideal
+ BPSK pilot signal we have generated locally. This peak of the
+ resulting signal is sensitive to the time shift between the
+ received and local version of the pilot, so we do it twice at
+ different time shifts and choose the maximum.
+ */
+
+ for(i=0; i<NPILOTBASEBAND-nin; i++) {
+ f->pilot_baseband1[i] = f->pilot_baseband1[i+nin];
+ f->pilot_baseband2[i] = f->pilot_baseband2[i+nin];
+ }
+
+ for(i=0,j=NPILOTBASEBAND-nin; i<nin; i++,j++) {
+ f->pilot_baseband1[j] = fcmult(rx_fdm[i], cconj(pilot[i]));
+ f->pilot_baseband2[j] = fcmult(rx_fdm[i], cconj(prev_pilot[i]));
+ }
+
+ lpf_peak_pick(&foff1, &max1, f->pilot_baseband1, f->pilot_lpf1, f->s1, nin);
+ lpf_peak_pick(&foff2, &max2, f->pilot_baseband2, f->pilot_lpf2, f->s2, nin);
+ //for(i=0; i<MPILOTFFT; i++) {
+ // printf("%f %f\n", f->s1[i].real, f->s1[i].imag);
+ //}
+
+#ifdef T
+ if (max1 > max2)
+ foff = foff1;
+ else
+ foff = foff2;
+
+ return foff;
+#endif
+ return 0;
+}
\*---------------------------------------------------------------------------*/
+#define PI 3.141592654
#define FS 8000 /* sample rate in Hz */
#define T (1.0/FS) /* sample period in seconds */
#define RS 50 /* symbol rate in Hz */
#define RB (NC*RS*NB) /* bit rate */
#define M (FS/RS) /* oversampling factor */
#define NSYM 6 /* number of symbols to filter over */
+#define NFILTER (NSYM*M) /* size of tx/rx filters at sample rate M */
+
#define FSEP 75 /* Separation between carriers (Hz) */
#define FCENTRE 1200 /* Centre frequency, Nc/2 carriers below this, Nc/2 carriers above (Hz) */
+
#define NT 5 /* number of symbols we estimate timing over */
#define P 4 /* oversample factor used for initial rx symbol filtering */
-#define NFILTER (NSYM*M) /* size of tx/rx filters at sample rate M */
#define NFILTERTIMING (M+Nfilter+M) /* filter memory used for resampling after timing estimation */
#define NTEST_BITS (NC*NB*4) /* length of test bit sequence */
-#define PI 3.141592654
+#define NPILOT_LUT (4*M) /* number of pilot look up table samples */
+#define NPILOTCOEFF 30 /* number of FIR filter coeffs in LP filter */
+#define NPILOTBASEBAND (NPILOTCOEFF+M+M/P) /* number of pilot baseband samples reqd for pilot LPF */
+#define NPILOTLPF (4*M) /* number of samples we DFT pilot over, pilot est window */
+#define MPILOTFFT 256
/*---------------------------------------------------------------------------*\
COMP tx_filter_memory[NC+1][NFILTER];
COMP phase_tx[NC+1];
COMP freq[NC+1];
+
+ COMP pilot_lut[NPILOT_LUT];
+ int pilot_lut_index;
+ int prev_pilot_lut_index;
+
+ COMP pilot_baseband1[NPILOTBASEBAND];
+ COMP pilot_baseband2[NPILOTBASEBAND];
+ COMP pilot_lpf1[NPILOTLPF];
+ COMP pilot_lpf2[NPILOTLPF];
+ COMP s1[MPILOTFFT];
+ COMP s2[MPILOTFFT];
};
/*---------------------------------------------------------------------------*\
void bits_to_dqpsk_symbols(COMP tx_symbols[], COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit);
void tx_filter(COMP tx_baseband[NC+1][M], COMP tx_symbols[], COMP tx_filter_memory[NC+1][NFILTER]);
void fdm_upconvert(COMP tx_fdm[], COMP tx_baseband[NC+1][M], COMP phase_tx[], COMP freq_tx[]);
+void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq);
+void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq);
+float rx_est_freq_offset(struct FDMDV *f, float rx_fdm[], int nin);
+void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], COMP s[], int nin);
#endif
--- /dev/null
+/* Generated by hanning_file() Octave function */
+
+const float hanning[]={
+ 0,
+ 2.4171e-05,
+ 9.66816e-05,
+ 0.000217525,
+ 0.000386689,
+ 0.000604158,
+ 0.00086991,
+ 0.00118392,
+ 0.00154616,
+ 0.00195659,
+ 0.00241517,
+ 0.00292186,
+ 0.00347661,
+ 0.00407937,
+ 0.00473008,
+ 0.00542867,
+ 0.00617507,
+ 0.00696922,
+ 0.00781104,
+ 0.00870045,
+ 0.00963736,
+ 0.0106217,
+ 0.0116533,
+ 0.0127322,
+ 0.0138581,
+ 0.0150311,
+ 0.0162509,
+ 0.0175175,
+ 0.0188308,
+ 0.0201906,
+ 0.0215968,
+ 0.0230492,
+ 0.0245478,
+ 0.0260923,
+ 0.0276826,
+ 0.0293186,
+ 0.0310001,
+ 0.032727,
+ 0.034499,
+ 0.036316,
+ 0.0381779,
+ 0.0400844,
+ 0.0420354,
+ 0.0440307,
+ 0.04607,
+ 0.0481533,
+ 0.0502802,
+ 0.0524506,
+ 0.0546643,
+ 0.056921,
+ 0.0592206,
+ 0.0615627,
+ 0.0639473,
+ 0.0663741,
+ 0.0688427,
+ 0.0713531,
+ 0.0739048,
+ 0.0764978,
+ 0.0791318,
+ 0.0818064,
+ 0.0845214,
+ 0.0872767,
+ 0.0900718,
+ 0.0929066,
+ 0.0957807,
+ 0.0986939,
+ 0.101646,
+ 0.104636,
+ 0.107665,
+ 0.110732,
+ 0.113836,
+ 0.116978,
+ 0.120156,
+ 0.123372,
+ 0.126624,
+ 0.129912,
+ 0.133235,
+ 0.136594,
+ 0.139989,
+ 0.143418,
+ 0.146881,
+ 0.150379,
+ 0.153911,
+ 0.157476,
+ 0.161074,
+ 0.164705,
+ 0.168368,
+ 0.172063,
+ 0.17579,
+ 0.179549,
+ 0.183338,
+ 0.187158,
+ 0.191008,
+ 0.194888,
+ 0.198798,
+ 0.202737,
+ 0.206704,
+ 0.2107,
+ 0.214724,
+ 0.218775,
+ 0.222854,
+ 0.226959,
+ 0.231091,
+ 0.235249,
+ 0.239432,
+ 0.243641,
+ 0.247874,
+ 0.252132,
+ 0.256414,
+ 0.260719,
+ 0.265047,
+ 0.269398,
+ 0.273772,
+ 0.278167,
+ 0.282584,
+ 0.287021,
+ 0.29148,
+ 0.295958,
+ 0.300456,
+ 0.304974,
+ 0.30951,
+ 0.314065,
+ 0.318638,
+ 0.323228,
+ 0.327835,
+ 0.332459,
+ 0.3371,
+ 0.341756,
+ 0.346427,
+ 0.351113,
+ 0.355814,
+ 0.360528,
+ 0.365256,
+ 0.369997,
+ 0.374751,
+ 0.379516,
+ 0.384293,
+ 0.389082,
+ 0.393881,
+ 0.398691,
+ 0.40351,
+ 0.408338,
+ 0.413176,
+ 0.418022,
+ 0.422876,
+ 0.427737,
+ 0.432605,
+ 0.43748,
+ 0.44236,
+ 0.447247,
+ 0.452138,
+ 0.457034,
+ 0.461935,
+ 0.466839,
+ 0.471746,
+ 0.476655,
+ 0.481568,
+ 0.486481,
+ 0.491397,
+ 0.496313,
+ 0.501229,
+ 0.506145,
+ 0.511061,
+ 0.515976,
+ 0.520889,
+ 0.5258,
+ 0.530708,
+ 0.535614,
+ 0.540516,
+ 0.545414,
+ 0.550308,
+ 0.555197,
+ 0.560081,
+ 0.564958,
+ 0.56983,
+ 0.574695,
+ 0.579552,
+ 0.584402,
+ 0.589244,
+ 0.594077,
+ 0.598901,
+ 0.603715,
+ 0.60852,
+ 0.613314,
+ 0.618097,
+ 0.622868,
+ 0.627628,
+ 0.632375,
+ 0.63711,
+ 0.641831,
+ 0.646538,
+ 0.651232,
+ 0.655911,
+ 0.660574,
+ 0.665222,
+ 0.669855,
+ 0.67447,
+ 0.679069,
+ 0.683651,
+ 0.688215,
+ 0.69276,
+ 0.697287,
+ 0.701795,
+ 0.706284,
+ 0.710752,
+ 0.7152,
+ 0.719627,
+ 0.724033,
+ 0.728418,
+ 0.73278,
+ 0.73712,
+ 0.741437,
+ 0.74573,
+ 0.75,
+ 0.754246,
+ 0.758467,
+ 0.762663,
+ 0.766833,
+ 0.770978,
+ 0.775097,
+ 0.779189,
+ 0.783254,
+ 0.787291,
+ 0.791301,
+ 0.795283,
+ 0.799236,
+ 0.80316,
+ 0.807055,
+ 0.810921,
+ 0.814756,
+ 0.81856,
+ 0.822334,
+ 0.826077,
+ 0.829788,
+ 0.833468,
+ 0.837115,
+ 0.840729,
+ 0.844311,
+ 0.847859,
+ 0.851374,
+ 0.854855,
+ 0.858301,
+ 0.861713,
+ 0.86509,
+ 0.868431,
+ 0.871737,
+ 0.875007,
+ 0.87824,
+ 0.881437,
+ 0.884598,
+ 0.887721,
+ 0.890806,
+ 0.893854,
+ 0.896864,
+ 0.899835,
+ 0.902768,
+ 0.905661,
+ 0.908516,
+ 0.911331,
+ 0.914106,
+ 0.916841,
+ 0.919536,
+ 0.92219,
+ 0.924804,
+ 0.927376,
+ 0.929907,
+ 0.932397,
+ 0.934845,
+ 0.93725,
+ 0.939614,
+ 0.941935,
+ 0.944213,
+ 0.946448,
+ 0.94864,
+ 0.950789,
+ 0.952894,
+ 0.954955,
+ 0.956972,
+ 0.958946,
+ 0.960874,
+ 0.962759,
+ 0.964598,
+ 0.966393,
+ 0.968142,
+ 0.969846,
+ 0.971505,
+ 0.973118,
+ 0.974686,
+ 0.976207,
+ 0.977683,
+ 0.979112,
+ 0.980495,
+ 0.981832,
+ 0.983122,
+ 0.984365,
+ 0.985561,
+ 0.986711,
+ 0.987813,
+ 0.988868,
+ 0.989876,
+ 0.990837,
+ 0.99175,
+ 0.992616,
+ 0.993434,
+ 0.994204,
+ 0.994927,
+ 0.995601,
+ 0.996228,
+ 0.996807,
+ 0.997337,
+ 0.99782,
+ 0.998255,
+ 0.998641,
+ 0.998979,
+ 0.999269,
+ 0.999511,
+ 0.999704,
+ 0.999849,
+ 0.999946,
+ 0.999994,
+ 0.999994,
+ 0.999946,
+ 0.999849,
+ 0.999704,
+ 0.999511,
+ 0.999269,
+ 0.998979,
+ 0.998641,
+ 0.998255,
+ 0.99782,
+ 0.997337,
+ 0.996807,
+ 0.996228,
+ 0.995601,
+ 0.994927,
+ 0.994204,
+ 0.993434,
+ 0.992616,
+ 0.99175,
+ 0.990837,
+ 0.989876,
+ 0.988868,
+ 0.987813,
+ 0.986711,
+ 0.985561,
+ 0.984365,
+ 0.983122,
+ 0.981832,
+ 0.980495,
+ 0.979112,
+ 0.977683,
+ 0.976207,
+ 0.974686,
+ 0.973118,
+ 0.971505,
+ 0.969846,
+ 0.968142,
+ 0.966393,
+ 0.964598,
+ 0.962759,
+ 0.960874,
+ 0.958946,
+ 0.956972,
+ 0.954955,
+ 0.952894,
+ 0.950789,
+ 0.94864,
+ 0.946448,
+ 0.944213,
+ 0.941935,
+ 0.939614,
+ 0.93725,
+ 0.934845,
+ 0.932397,
+ 0.929907,
+ 0.927376,
+ 0.924804,
+ 0.92219,
+ 0.919536,
+ 0.916841,
+ 0.914106,
+ 0.911331,
+ 0.908516,
+ 0.905661,
+ 0.902768,
+ 0.899835,
+ 0.896864,
+ 0.893854,
+ 0.890806,
+ 0.887721,
+ 0.884598,
+ 0.881437,
+ 0.87824,
+ 0.875007,
+ 0.871737,
+ 0.868431,
+ 0.86509,
+ 0.861713,
+ 0.858301,
+ 0.854855,
+ 0.851374,
+ 0.847859,
+ 0.844311,
+ 0.840729,
+ 0.837115,
+ 0.833468,
+ 0.829788,
+ 0.826077,
+ 0.822334,
+ 0.81856,
+ 0.814756,
+ 0.810921,
+ 0.807055,
+ 0.80316,
+ 0.799236,
+ 0.795283,
+ 0.791301,
+ 0.787291,
+ 0.783254,
+ 0.779189,
+ 0.775097,
+ 0.770978,
+ 0.766833,
+ 0.762663,
+ 0.758467,
+ 0.754246,
+ 0.75,
+ 0.74573,
+ 0.741437,
+ 0.73712,
+ 0.73278,
+ 0.728418,
+ 0.724033,
+ 0.719627,
+ 0.7152,
+ 0.710752,
+ 0.706284,
+ 0.701795,
+ 0.697287,
+ 0.69276,
+ 0.688215,
+ 0.683651,
+ 0.679069,
+ 0.67447,
+ 0.669855,
+ 0.665222,
+ 0.660574,
+ 0.655911,
+ 0.651232,
+ 0.646538,
+ 0.641831,
+ 0.63711,
+ 0.632375,
+ 0.627628,
+ 0.622868,
+ 0.618097,
+ 0.613314,
+ 0.60852,
+ 0.603715,
+ 0.598901,
+ 0.594077,
+ 0.589244,
+ 0.584402,
+ 0.579552,
+ 0.574695,
+ 0.56983,
+ 0.564958,
+ 0.560081,
+ 0.555197,
+ 0.550308,
+ 0.545414,
+ 0.540516,
+ 0.535614,
+ 0.530708,
+ 0.5258,
+ 0.520889,
+ 0.515976,
+ 0.511061,
+ 0.506145,
+ 0.501229,
+ 0.496313,
+ 0.491397,
+ 0.486481,
+ 0.481568,
+ 0.476655,
+ 0.471746,
+ 0.466839,
+ 0.461935,
+ 0.457034,
+ 0.452138,
+ 0.447247,
+ 0.44236,
+ 0.43748,
+ 0.432605,
+ 0.427737,
+ 0.422876,
+ 0.418022,
+ 0.413176,
+ 0.408338,
+ 0.40351,
+ 0.398691,
+ 0.393881,
+ 0.389082,
+ 0.384293,
+ 0.379516,
+ 0.374751,
+ 0.369997,
+ 0.365256,
+ 0.360528,
+ 0.355814,
+ 0.351113,
+ 0.346427,
+ 0.341756,
+ 0.3371,
+ 0.332459,
+ 0.327835,
+ 0.323228,
+ 0.318638,
+ 0.314065,
+ 0.30951,
+ 0.304974,
+ 0.300456,
+ 0.295958,
+ 0.29148,
+ 0.287021,
+ 0.282584,
+ 0.278167,
+ 0.273772,
+ 0.269398,
+ 0.265047,
+ 0.260719,
+ 0.256414,
+ 0.252132,
+ 0.247874,
+ 0.243641,
+ 0.239432,
+ 0.235249,
+ 0.231091,
+ 0.226959,
+ 0.222854,
+ 0.218775,
+ 0.214724,
+ 0.2107,
+ 0.206704,
+ 0.202737,
+ 0.198798,
+ 0.194888,
+ 0.191008,
+ 0.187158,
+ 0.183338,
+ 0.179549,
+ 0.17579,
+ 0.172063,
+ 0.168368,
+ 0.164705,
+ 0.161074,
+ 0.157476,
+ 0.153911,
+ 0.150379,
+ 0.146881,
+ 0.143418,
+ 0.139989,
+ 0.136594,
+ 0.133235,
+ 0.129912,
+ 0.126624,
+ 0.123372,
+ 0.120156,
+ 0.116978,
+ 0.113836,
+ 0.110732,
+ 0.107665,
+ 0.104636,
+ 0.101646,
+ 0.0986939,
+ 0.0957807,
+ 0.0929066,
+ 0.0900718,
+ 0.0872767,
+ 0.0845214,
+ 0.0818064,
+ 0.0791318,
+ 0.0764978,
+ 0.0739048,
+ 0.0713531,
+ 0.0688427,
+ 0.0663741,
+ 0.0639473,
+ 0.0615627,
+ 0.0592206,
+ 0.056921,
+ 0.0546643,
+ 0.0524506,
+ 0.0502802,
+ 0.0481533,
+ 0.04607,
+ 0.0440307,
+ 0.0420354,
+ 0.0400844,
+ 0.0381779,
+ 0.036316,
+ 0.034499,
+ 0.032727,
+ 0.0310001,
+ 0.0293186,
+ 0.0276826,
+ 0.0260923,
+ 0.0245478,
+ 0.0230492,
+ 0.0215968,
+ 0.0201906,
+ 0.0188308,
+ 0.0175175,
+ 0.0162509,
+ 0.0150311,
+ 0.0138581,
+ 0.0127322,
+ 0.0116533,
+ 0.0106217,
+ 0.00963736,
+ 0.00870045,
+ 0.00781104,
+ 0.00696922,
+ 0.00617507,
+ 0.00542867,
+ 0.00473008,
+ 0.00407937,
+ 0.00347661,
+ 0.00292186,
+ 0.00241517,
+ 0.00195659,
+ 0.00154616,
+ 0.00118392,
+ 0.00086991,
+ 0.000604158,
+ 0.000386689,
+ 0.000217525,
+ 9.66816e-05,
+ 2.4171e-05,
+ 0
+};
--- /dev/null
+/* Generated by pilot_coeff_file() Octave function */
+
+const float pilot_coeff[]={
+ 0.00204705,
+ 0.00276339,
+ 0.00432595,
+ 0.00697042,
+ 0.0108452,
+ 0.0159865,
+ 0.0223035,
+ 0.029577,
+ 0.0374709,
+ 0.045557,
+ 0.0533491,
+ 0.0603458,
+ 0.0660751,
+ 0.070138,
+ 0.0722452,
+ 0.0722452,
+ 0.070138,
+ 0.0660751,
+ 0.0603458,
+ 0.0533491,
+ 0.045557,
+ 0.0374709,
+ 0.029577,
+ 0.0223035,
+ 0.0159865,
+ 0.0108452,
+ 0.00697042,
+ 0.00432595,
+ 0.00276339,
+ 0.00204705
+};
scalarlsptest_LDADD = $(lib_LTLIBRARIES)
scalarlsptest_LDFLAGS = $(LIBS)
-tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c
+tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c ../src/fft.c ../src/kiss_fft.c
tfdmdv_LDADD = $(lib_LTLIBRARIES)
tfdmdv_LDFLAGS = $(LIBS)
interp.$(OBJEXT) pack.$(OBJEXT) $(am__objects_1)
tcodec2_OBJECTS = $(am_tcodec2_OBJECTS)
tcodec2_DEPENDENCIES =
-am_tfdmdv_OBJECTS = tfdmdv.$(OBJEXT) fdmdv.$(OBJEXT)
+am_tfdmdv_OBJECTS = tfdmdv.$(OBJEXT) fdmdv.$(OBJEXT) fft.$(OBJEXT) \
+ kiss_fft.$(OBJEXT)
tfdmdv_OBJECTS = $(am_tfdmdv_OBJECTS)
tfdmdv_DEPENDENCIES =
am_tinterp_OBJECTS = tinterp.$(OBJEXT) sine.$(OBJEXT) fft.$(OBJEXT) \
scalarlsptest_SOURCES = scalarlsptest.c ../src/quantise.c ../src/lpc.c ../src/lsp.c ../src/dump.c ../src/fft.c ../src/kiss_fft.c $(CODEBOOKS)
scalarlsptest_LDADD = $(lib_LTLIBRARIES)
scalarlsptest_LDFLAGS = $(LIBS)
-tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c
+tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c ../src/fft.c ../src/kiss_fft.c
tfdmdv_LDADD = $(lib_LTLIBRARIES)
tfdmdv_LDFLAGS = $(LIBS)
all: all-am
COMP tx_symbols[(NC+1)];
COMP tx_baseband[(NC+1)][M];
COMP tx_fdm[M];
+ float rx_fdm[M];
+ float foff;
int tx_bits_log[FDMDV_BITS_PER_FRAME*FRAMES];
COMP tx_symbols_log[(NC+1)*FRAMES];
COMP tx_baseband_log[(NC+1)][M*FRAMES];
COMP tx_fdm_log[M*FRAMES];
+ COMP pilot_baseband1_log[NPILOTBASEBAND*FRAMES];
+ COMP pilot_baseband2_log[NPILOTBASEBAND*FRAMES];
+ COMP pilot_lpf1_log[NPILOTLPF*FRAMES];
+ COMP pilot_lpf2_log[NPILOTLPF*FRAMES];
+ COMP s1_log[32*FRAMES];
+ COMP s2_log[32*FRAMES];
FILE *fout;
int f,c,i;
fdmdv = fdmdv_create();
for(f=0; f<FRAMES; f++) {
+
+ /* modulator */
+
fdmdv_get_test_bits(fdmdv, tx_bits);
bits_to_dqpsk_symbols(tx_symbols, fdmdv->prev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit);
memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(NC+1));
tx_filter(tx_baseband, tx_symbols, fdmdv->tx_filter_memory);
fdm_upconvert(tx_fdm, tx_baseband, fdmdv->phase_tx, fdmdv->freq);
-
+
+ for(i=0; i<M; i++)
+ rx_fdm[i] = tx_fdm[i].real;
+
+ /* demodulator */
+
+ foff = rx_est_freq_offset(fdmdv, rx_fdm, M);
+
/* save log of outputs */
memcpy(&tx_bits_log[FDMDV_BITS_PER_FRAME*f], tx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
for(i=0; i<M; i++)
tx_baseband_log[c][f*M+i] = tx_baseband[c][i];
memcpy(&tx_fdm_log[M*f], tx_fdm, sizeof(COMP)*M);
+ memcpy(&pilot_baseband1_log[f*NPILOTBASEBAND], fdmdv->pilot_baseband1, sizeof(COMP)*NPILOTBASEBAND);
+ memcpy(&pilot_baseband2_log[f*NPILOTBASEBAND], fdmdv->pilot_baseband2, sizeof(COMP)*NPILOTBASEBAND);
+ memcpy(&pilot_lpf1_log[f*NPILOTLPF], fdmdv->pilot_lpf1, sizeof(COMP)*NPILOTLPF);
+ memcpy(&pilot_lpf2_log[f*NPILOTLPF], fdmdv->pilot_lpf2, sizeof(COMP)*NPILOTLPF);
+ memcpy(&s1_log[f*32], fdmdv->s1, sizeof(COMP)*32);
+ memcpy(&s2_log[f*32], fdmdv->s2, sizeof(COMP)*32);
}
- codec2_destroy(fdmdv);
-
/* dump logs to Octave file for evaluation by tfdmdv.m Octave script */
fout = fopen("tfdmdv_out.txt","wt");
octave_save_complex(fout, "tx_symbols_log_c", tx_symbols_log, 1, (NC+1)*FRAMES);
octave_save_complex(fout, "tx_baseband_log_c", (COMP*)tx_baseband_log, (NC+1), M*FRAMES);
octave_save_complex(fout, "tx_fdm_log_c", (COMP*)tx_fdm_log, 1, M*FRAMES);
+ octave_save_complex(fout, "pilot_lut_c", (COMP*)fdmdv->pilot_lut, 1, NPILOT_LUT);
+ octave_save_complex(fout, "pilot_baseband1_log_c", pilot_baseband1_log, 1, NPILOTBASEBAND*FRAMES);
+ octave_save_complex(fout, "pilot_baseband2_log_c", pilot_baseband2_log, 1, NPILOTBASEBAND*FRAMES);
+ octave_save_complex(fout, "pilot_lpf1_log_c", pilot_lpf1_log, 1, NPILOTLPF*FRAMES);
+ octave_save_complex(fout, "pilot_lpf2_log_c", pilot_lpf2_log, 1, NPILOTLPF*FRAMES);
+ octave_save_complex(fout, "s1_log_c", s1_log, 1, 32*FRAMES);
+ octave_save_complex(fout, "s2_log_c", s2_log, 1, 32*FRAMES);
fclose(fout);
+ codec2_destroy(fdmdv);
+
return 0;
}