endfunction
-function check(a, b, test_name)
+function check(a, b, test_name, tol)
global passes;
global fails;
+ if nargin == 3
+ tol = 1E-3;
+ end
+
[m n] = size(a);
printf("%s", test_name);
for i=1:(25-length(test_name))
end
printf(": ");
- e = sum(abs(a - b))/n;
- if e < 1E-3
+ e = sum(sum(abs(a - b))/n);
+ if e < tol
printf("OK\n");
passes++;
else
end
end
+ for c=1:Nc+1
+ mag = abs(phase_rx(c));
+ phase_rx(c) /= mag;
+ end
+
fdmdv.phase_rx = phase_rx;
endfunction
rx_power_dB = 10*log10(rx_power);
figure;
subplot(211)
- plot(rx_filt(1000:5*Fs));
+ plot(rx_filt(1000:length(rx_filt)));
title('GMSK Power (narrow filter)');
subplot(212)
plot(rx_power_dB);
printf("Estimated S: %3.1f N: %3.1f Nbw: %4.0f Hz SNR: %3.1f CNo: %3.1f EbNo: %3.1f BER theory: %f\n",
signal, noise, Fs*noise_bw, snr, CNo, EbNo, ber_theory);
- end
% FM signal is centred on 12 kHz and 16 kHz wide so lets also work out noise there
grid("minor")
legend("boxoff");
title('FM C/No');
+ end
% spectrum of a chunk of GMSK signal just after preamble
%gmsk_rx("ssb25db.wav")
%gmsk_rx("~/Desktop/ssb_fm_gmsk_high.wav")
%gmsk_rx("~/Desktop/test_gmsk_28BER.raw")
-gmsk_rx("~/Desktop/gmsk_rec1.wav")
+gmsk_rx("~/Desktop/gmsk_rec_reverse.wav")
rx_filt_log = [];
rx_fdm_filter_log = [];
rx_baseband_log = [];
+rx_fdm_log = [];
fbb_phase_rx = 1;
-% frame of just pilots ofr coarse sync
+% frame of just pilots for coarse sync
tx_bits = zeros(1,framesize);
[tx_symb_pilot tx_bits prev_tx_sym] = bits_to_qpsk_symbols(sim_in, tx_bits, [], []);
ct_symb_buf = zeros(2*sim_in.Nsymbrowpilot, sim_in.Nc);
+prev_tx_bits = [];
% main loop --------------------------------------------------------------------
for i=1:frames
end
tx_fdm_log = [tx_fdm_log tx_fdm_frame];
+ %
+ % Demod ----------------------------------------------------------------------
+ %
+
nin = M;
% shift frame down to complex baseband
end
mag = abs(fbb_phase_rx);
fbb_phase_rx /= mag;
+ rx_fdm_log = [rx_fdm_log rx_fdm_frame_bb];
ch_symb = zeros(sim_in.Nsymbrowpilot, Nc);
for r=1:sim_in.Nsymbrowpilot
end
prev_tx_bits2 = prev_tx_bits;
prev_tx_bits = tx_bits;
+
end
stem_sig_and_error(1, 111, 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(2, 211, real(tx_symb_log_c(1:n)), real(tx_symb_log(1:n) - tx_symb_log_c(1:n)), 'tx symb re', [1 n -1.5 1.5])
stem_sig_and_error(2, 212, imag(tx_symb_log_c(1:n)), imag(tx_symb_log(1:n) - tx_symb_log_c(1:n)), 'tx symb im', [1 n -1.5 1.5])
-stem_sig_and_error(3, 211, real(ch_symb_log_c(1:n)), real(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb re', [1 n -1.5 1.5])
-stem_sig_and_error(3, 212, imag(ch_symb_log_c(1:n)), imag(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb im', [1 n -1.5 1.5])
-stem_sig_and_error(4, 211, rx_amp_log_c(1:n), rx_amp_log(1:n) - rx_amp_log_c(1:n), 'Amp Est', [1 n -1.5 1.5])
-stem_sig_and_error(4, 212, rx_phi_log_c(1:n), rx_phi_log(1:n) - rx_phi_log_c(1:n), 'Phase Est', [1 n -4 4])
-stem_sig_and_error(5, 211, real(rx_symb_log_c(1:n)), real(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb re', [1 n -1.5 1.5])
-stem_sig_and_error(5, 212, imag(rx_symb_log_c(1:n)), imag(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb im', [1 n -1.5 1.5])
-stem_sig_and_error(6, 111, rx_bits_log_c(1:n), rx_bits_log(1:n) - rx_bits_log_c(1:n), 'rx bits', [1 n -1.5 1.5])
+
+stem_sig_and_error(3, 211, real(tx_fdm_log_c(1:n)), real(tx_fdm_log(1:n) - tx_fdm_log_c(1:n)), 'tx fdm re', [1 n -10 10])
+stem_sig_and_error(3, 212, imag(tx_fdm_log_c(1:n)), imag(tx_fdm_log(1:n) - tx_fdm_log_c(1:n)), 'tx fdm im', [1 n -10 10])
+
+stem_sig_and_error(4, 211, real(ch_symb_log_c(1:n)), real(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb re', [1 n -2 2])
+stem_sig_and_error(4, 212, imag(ch_symb_log_c(1:n)), imag(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb im', [1 n -2 2])
+stem_sig_and_error(5, 211, rx_amp_log_c(1:n), rx_amp_log(1:n) - rx_amp_log_c(1:n), 'Amp Est', [1 n -1.5 1.5])
+stem_sig_and_error(5, 212, rx_phi_log_c(1:n), rx_phi_log(1:n) - rx_phi_log_c(1:n), 'Phase Est', [1 n -4 4])
+stem_sig_and_error(6, 211, real(rx_symb_log_c(1:n)), real(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb re', [1 n -1.5 1.5])
+stem_sig_and_error(6, 212, imag(rx_symb_log_c(1:n)), imag(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb im', [1 n -1.5 1.5])
+stem_sig_and_error(7, 111, rx_bits_log_c(1:n), rx_bits_log(1:n) - rx_bits_log_c(1:n), 'rx bits', [1 n -1.5 1.5])
check(tx_bits_log, tx_bits_log_c, 'tx_bits');
check(tx_symb_log, tx_symb_log_c, 'tx_symb');
+check(tx_fdm_log, tx_fdm_log_c, 'tx_fdm');
+check(rx_fdm_log, rx_fdm_log_c, 'rx_fdm');
+check(rx_baseband_log, rx_baseband_log_c, 'rx_baseband',0.01);
+check(rx_filt_log, rx_filt_log_c, 'rx_filt');
+check(ch_symb_log, ch_symb_log_c, 'ch_symb',0.01);
check(rx_amp_log, rx_amp_log_c, 'rx_amp_log');
check(rx_phi_log, rx_phi_log_c, 'rx_phi_log');
check(rx_symb_log, rx_symb_log_c, 'rx_symb');
AUTHOR......: David Rowe
DATE CREATED: 13 August 2014
- Given Nc*NB bits construct M samples (1 symbol) of Nc+1 filtered
- symbols streams.
+ Given Nc symbols construct M samples (1 symbol) of Nc+1 filtered
+ and upconverted symbols.
\*---------------------------------------------------------------------------*/
assert(nin <= (M+M/P));
- /* Nc/2 tones below centre freq */
+ /* downconvert */
- for (c=0; c<Nc/2; c++)
- for (i=0; i<nin; i++) {
- phase_rx[c] = cmult(phase_rx[c], freq[c]);
- rx_baseband[c][i] = cmult(rx_fdm[i], cconj(phase_rx[c]));
- }
-
- /* Nc/2 tones above centre freq */
-
- for (c=Nc/2; c<Nc; c++)
+ for (c=0; c<Nc+1; c++)
for (i=0; i<nin; i++) {
phase_rx[c] = cmult(phase_rx[c], freq[c]);
rx_baseband[c][i] = cmult(rx_fdm[i], cconj(phase_rx[c]));
}
- /* centre pilot tone */
-
- c = Nc;
- for (i=0; i<nin; i++) {
- phase_rx[c] = cmult(phase_rx[c], freq[c]);
- rx_baseband[c][i] = cmult(rx_fdm[i], cconj(phase_rx[c]));
- }
-
/* normalise digital oscilators as the magnitude can drift over time */
for (c=0; c<Nc+1; c++) {
/*---------------------------------------------------------------------------*\
- FILE........: tcopskv.c
+ FILE........: tcohpsk.c
AUTHOR......: David Rowe
DATE CREATED: March 2015
- Tests for the C version of the cohernet PSK FDM modem. This program
+ Tests for the C version of the coherent PSK FDM modem. This program
outputs a file of Octave vectors that are loaded and automatically
tested against the Octave version of the modem by the Octave script
tcohpsk.m
#include "test_bits_coh.h"
#include "octave.h"
#include "comp_prim.h"
-#include "noise_samples.h"
+//#include "noise_samples.h"
#define FRAMES 35
#define RS 50
struct COHPSK *coh;
int tx_bits[COHPSK_BITS_PER_FRAME];
COMP tx_symb[NSYMROWPILOT][PILOTS_NC];
+ COMP tx_fdm[M*NSYMROWPILOT];
+ COMP rx_fdm[M*NSYMROWPILOT];
COMP ch_symb[NSYMROWPILOT][PILOTS_NC];
int rx_bits[COHPSK_BITS_PER_FRAME];
int tx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES];
COMP tx_symb_log[NSYMROWPILOT*FRAMES][PILOTS_NC];
+ COMP tx_fdm_log[M*NSYMROWPILOT*FRAMES];
+ COMP rx_fdm_log[M*NSYMROWPILOT*FRAMES];
COMP ch_symb_log[NSYMROWPILOT*FRAMES][PILOTS_NC];
float rx_amp_log[NSYMROW*FRAMES][PILOTS_NC];
int rx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES];
FILE *fout;
- int f, r, c, log_r, log_data_r, noise_r;
+ int f, r, c, log_r, log_data_r, noise_r, i;
COMP phase, freq;
int *ptest_bits_coh, *ptest_bits_coh_end;
+ float freq_hz;
+
+ struct FDMDV *fdmdv;
+ COMP rx_baseband[PILOTS_NC][M+M/P];
+ int nin;
+ COMP rx_filt[PILOTS_NC][P+1];
+ COMP rx_filt_log[PILOTS_NC][(P+1)*NSYMROWPILOT*FRAMES];
+ int rx_filt_log_col_index = 0;
+ float env[NT*P];
+ COMP rx_filter_memory[PILOTS_NC][NFILTER];
+ float rx_timing;
+ COMP tx_onesym[PILOTS_NC];
+ COMP rx_onesym[PILOTS_NC];
+ int rx_baseband_log_col_index = 0;
+ COMP rx_baseband_log[PILOTS_NC][(M+M/P)*NSYMROWPILOT*FRAMES];
coh = cohpsk_create();
assert(coh != NULL);
phase.real = 1.0; phase.imag = 0.0;
freq.real = cos(2.0*M_PI*FOFF/RS); freq.imag = sin(2.0*M_PI*FOFF/RS);
+ /* set up fdmdv states so we can use those modem functions */
+
+ fdmdv = fdmdv_create(PILOTS_NC - 1);
+ for(c=0; c<PILOTS_NC; c++) {
+ fdmdv->phase_tx[c].real = 1.0;
+ fdmdv->phase_tx[c].imag = 0.0;
+
+ freq_hz = fdmdv->fsep*( -PILOTS_NC/2 - 0.5 + c + 1.0 );
+ fdmdv->freq[c].real = cosf(2.0*M_PI*freq_hz/FS);
+ fdmdv->freq[c].imag = sinf(2.0*M_PI*freq_hz/FS);
+ fdmdv->freq_pol[c] = 2.0*M_PI*freq_hz/FS;
+
+ //printf("c: %d %f %f\n",c,freq_hz,fdmdv->freq_pol[c]);
+ for(i=0; i<NFILTER; i++) {
+ rx_filter_memory[c][i].real = 0.0;
+ rx_filter_memory[c][i].imag = 0.0;
+ }
+ }
+
+ /* Main Loop ---------------------------------------------------------------------*/
+
for(f=0; f<FRAMES; f++) {
/* --------------------------------------------------------*\
- Modem
+ Mod
\*---------------------------------------------------------*/
memcpy(tx_bits, ptest_bits_coh, sizeof(int)*COHPSK_BITS_PER_FRAME);
ptest_bits_coh = (int*)test_bits_coh;
bits_to_qpsk_symbols(tx_symb, (int*)tx_bits, COHPSK_BITS_PER_FRAME);
+ for(r=0; r<NSYMROWPILOT; r++) {
+ for(c=0; c<PILOTS_NC; c++)
+ tx_onesym[c] = tx_symb[r][c];
+ tx_filter_and_upconvert(&tx_fdm[r*M], fdmdv->Nc , tx_onesym, fdmdv->tx_filter_memory,
+ fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect);
+ }
+
+ #ifdef TMP
for(r=0; r<NSYMROWPILOT; r++,noise_r++) {
phase = cmult(phase,freq);
for(c=0; c<PILOTS_NC; c++) {
}
}
phase = fcmult(1.0/cabsolute(phase), phase);
+ #endif
+
+ memcpy(rx_fdm, tx_fdm, sizeof(COMP)*M*NSYMROWPILOT);
+ /* --------------------------------------------------------*\
+ Demod
+ \*---------------------------------------------------------*/
+
+ nin = M;
+ for (r=0; r<NSYMROWPILOT; r++) {
+ fdmdv_freq_shift(&rx_fdm[r*M], &rx_fdm[r*M], -FDMDV_FCENTRE, &fdmdv->fbb_phase_rx, nin);
+ fdm_downconvert(rx_baseband, fdmdv->Nc, &rx_fdm[r*M], fdmdv->phase_rx, fdmdv->freq, nin);
+ rx_filter(rx_filt, fdmdv->Nc, rx_baseband, rx_filter_memory, nin);
+ rx_timing = rx_est_timing(rx_onesym, fdmdv->Nc, rx_filt, fdmdv->rx_filter_mem_timing, env, nin);
+
+ for(c=0; c<PILOTS_NC; c++) {
+ ch_symb[r][c] = rx_onesym[c];
+ }
+
+ for(c=0; c<PILOTS_NC; c++) {
+ for(i=0; i<nin; i++) {
+ rx_baseband_log[c][rx_baseband_log_col_index + i] = rx_baseband[c][i];
+ }
+ }
+ rx_baseband_log_col_index += nin;
+
+ //if (f == 3)
+ // exit(0);
+ for(c=0; c<PILOTS_NC; c++) {
+ for(i=0; i<P; i++) {
+ rx_filt_log[c][rx_filt_log_col_index + i] = rx_filt[c][i];
+ }
+ }
+ rx_filt_log_col_index += P;
+
+ }
qpsk_symbols_to_bits(coh, rx_bits, ch_symb);
-
+
/* --------------------------------------------------------*\
Log each vector
\*---------------------------------------------------------*/
memcpy(&tx_bits_log[COHPSK_BITS_PER_FRAME*f], tx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME);
+ memcpy(&tx_fdm_log[M*NSYMROWPILOT*f], tx_fdm, sizeof(COMP)*M*NSYMROWPILOT);
+ memcpy(&rx_fdm_log[M*NSYMROWPILOT*f], rx_fdm, sizeof(COMP)*M*NSYMROWPILOT);
+
for(r=0; r<NSYMROWPILOT; r++, log_r++) {
for(c=0; c<PILOTS_NC; c++) {
tx_symb_log[log_r][c] = tx_symb[r][c];
assert(log_data_r <= NSYMROW*FRAMES);
}
+
/*---------------------------------------------------------*\
Dump logs to Octave file for evaluation
by tcohpsk.m Octave script
fprintf(fout, "# Created by tcohpsk.c\n");
octave_save_int(fout, "tx_bits_log_c", tx_bits_log, 1, COHPSK_BITS_PER_FRAME*FRAMES);
octave_save_complex(fout, "tx_symb_log_c", (COMP*)tx_symb_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC);
+ octave_save_complex(fout, "tx_fdm_log_c", (COMP*)tx_fdm_log, 1, M*NSYMROWPILOT*FRAMES, M*NSYMROWPILOT*FRAMES);
+ octave_save_complex(fout, "rx_fdm_log_c", (COMP*)rx_fdm_log, 1, M*NSYMROWPILOT*FRAMES, M*NSYMROWPILOT*FRAMES);
+ octave_save_complex(fout, "rx_baseband_log_c", (COMP*)rx_baseband_log, PILOTS_NC, rx_baseband_log_col_index, (M+M/P)*FRAMES*NSYMROWPILOT);
+ octave_save_complex(fout, "rx_filt_log_c", (COMP*)rx_filt_log, PILOTS_NC, rx_filt_log_col_index, (P+1)*FRAMES*NSYMROWPILOT);
octave_save_complex(fout, "ch_symb_log_c", (COMP*)ch_symb_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC);
octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC);
octave_save_float(fout, "rx_phi_log_c", (float*)rx_phi_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC);
octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, COHPSK_BITS_PER_FRAME*FRAMES);
fclose(fout);
+ fdmdv_destroy(fdmdv);
cohpsk_destroy(coh);
return 0;
fprintf(fout, "# Created by tfdmdv.c\n");
octave_save_int(fout, "tx_bits_log_c", tx_bits_log, 1, FDMDV_BITS_PER_FRAME*FRAMES);
octave_save_complex(fout, "tx_symbols_log_c", tx_symbols_log, 1, (FDMDV_NC+1)*FRAMES, (FDMDV_NC+1)*FRAMES);
-octave_save_complex(fout, "tx_fdm_log_c", (COMP*)tx_fdm_log, 1, M*FRAMES, M*FRAMES);
+ octave_save_complex(fout, "tx_fdm_log_c", (COMP*)tx_fdm_log, 1, M*FRAMES, M*FRAMES);
octave_save_complex(fout, "pilot_lut_c", (COMP*)fdmdv->pilot_lut, 1, NPILOT_LUT, NPILOT_LUT);
octave_save_complex(fout, "pilot_baseband1_log_c", pilot_baseband1_log, 1, NPILOTBASEBAND*FRAMES, NPILOTBASEBAND*FRAMES);
octave_save_complex(fout, "pilot_baseband2_log_c", pilot_baseband2_log, 1, NPILOTBASEBAND*FRAMES, NPILOTBASEBAND*FRAMES);