printf("EbNo: %f Eb: %f var No: %f EbNo (meas): %f\n",
EbNo, var(tx)*Ts/Fs, var(noise)/Fs, (var(tx)*Ts/Fs)/(var(noise)/Fs));
end
+ save fsk tx_bits rx
% Optional AFSK over FM demodulator
end
function run_fsk_single
- sim_in.fmark = 1200;
- sim_in.fspace = 2200;
- sim_in.Rs = 1200;
- sim_in.nsym = 1200;
- sim_in.EbNodB = 16;
- sim_in.fm = 1;
+ sim_in.fmark = 1000;
+ sim_in.fspace = 2000;
+ sim_in.Rs = 1000;
+ sim_in.nsym = 2000;
+ sim_in.EbNodB = 7;
+ sim_in.fm = 0;
sim_in.verbose = 1;
fsk_sim = fsk_ber_test(sim_in);
rand('state',1);
randn('state',1);
+graphics_toolkit ("gnuplot");
1;
% data and parity bits are on separate carriers
tx_symb = zeros(Nsymbrow,Nc);
-
+
for c=1:Nc
for r=1:Nsymbrow
i = (c-1)*Nsymbrow + r;
end
%tx_symb = zeros(Nsymbrow,Nc);
- % Optionally insert pilots, one every Ns data symbols
+ % insert pilots, one every Ns data symbols
tx_symb_pilot = zeros(Nsymbrowpilot, Nc);
endfunction
+function write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymrow, Npilotsframe, Nc);
+
+ filename = sprintf("../src/cohpsk_defs.h", Npilotsframe, Nc);
+ f=fopen(filename,"wt");
+ fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n");
+ fprintf(f,"#define NSYMROW %d /* number of data symbols for each row (i.e. each carrier) */\n", Nsymrow);
+ fprintf(f,"#define NS %d /* number of data symbols between pilots */\n", Ns);
+ fprintf(f,"#define NPILOTSFRAME %d /* number of pilot symbols of each row */\n", Npilotsframe);
+ fprintf(f,"#define PILOTS_NC %d /* number of carriers in coh modem */\n\n", Nc);
+ fprintf(f,"#define NSYMROWPILOT %d /* length of row after pilots inserted */\n\n", Nsymbrowpilot);
+ fclose(f);
+
+ filename = sprintf("../src/pilots_coh.h", Npilotsframe, Nc);
+ f=fopen(filename,"wt");
+ fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n");
+ fprintf(f,"float pilots_coh[][PILOTS_NC]={\n");
+ for r=1:Npilotsframe
+ fprintf(f, " {");
+ for c=1:Nc-1
+ fprintf(f, " %f,", pilot(r, c));
+ end
+ if r < Npilotsframe
+ fprintf(f, " %f},\n", pilot(r, Nc));
+ else
+ fprintf(f, " %f}\n};", pilot(r, Nc));
+ end
+ end
+ fclose(f);
+endfunction
+
+
+% Save test bits frame to a text file in the form of a C array
+
+function test_bits_coh_file(test_bits_coh)
+
+ f=fopen("test_bits_coh.h","wt");
+ fprintf(f,"/* Generated by test_bits_coh_file() Octave function */\n\n");
+ fprintf(f,"const int test_bits_coh[]={\n");
+ for m=1:length(test_bits_coh)-1
+ fprintf(f," %d,\n",test_bits_coh(m));
+ endfor
+ fprintf(f," %d\n};\n",test_bits_coh(length(test_bits_coh)));
+ fclose(f);
+
+endfunction
+
+
% init function for symbol rate processing
function sim_in = symbol_rate_init(sim_in)
% pilot sequence is used for phase and amplitude estimation, and frame sync
- pilot = 1 - 2*(rand(Npilotsframe,Nc) > 0.5);
+ pilot = 1 - 2*(rand(Npilotsframe,Nc) > 0.5)
sim_in.pilot = pilot;
sim_in.tx_pilot_buf = [pilot; pilot; pilot];
-
+ if sim_in.do_write_pilot_file
+ write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymbrow, Npilotsframe, Nc);
+ end
+
% Init LDPC --------------------------------------------------------------------
if ldpc_code
sim_in.code_param = code_param;
else
sim_in.rate = 1;
+ sim_in.code_param = [];
end
endfunction
if verbose > 2
printf("% 4.3f ", phi_(r,c))
end
- rx_symb(r,c) *= exp(-j*phi_(r,c));
+ % rx_symb(r,c) *= exp(-j*phi_(r,c));
end
if verbose > 2
sim_in.verbose = 1;
sim_in.plot_scatter = 1;
- sim_in.framesize = 576;
- sim_in.Nc = 9;
+ sim_in.framesize = 160;
+ sim_in.Nc = 4;
sim_in.Rs = 50;
sim_in.Ns = 4;
sim_in.Np = 2;
sim_in.Nchip = 1;
- sim_in.ldpc_code_rate = 0.5;
- sim_in.ldpc_code = 1;
+% sim_in.ldpc_code_rate = 0.5;
+% sim_in.ldpc_code = 1;
+ sim_in.ldpc_code_rate = 1;
+ sim_in.ldpc_code = 0;
sim_in.Ntrials = 20;
- sim_in.Esvec = 10;
- sim_in.hf_sim = 1;
+ sim_in.Esvec = 100;
+ sim_in.hf_sim = 0;
sim_in.hf_mag_only = 0;
sim_in.modulation = 'qpsk';
+ sim_in.do_write_pilot_file = 1;
+
sim_qpsk_hf = ber_test(sim_in);
fep=fopen("errors_450.bin","wb"); fwrite(fep, sim_qpsk_hf.ldpc_errors_log, "short"); fclose(fep);
sim_in.verbose = 1;
sim_in.plot_scatter = 1;
- sim_in.framesize = 576;
- sim_in.Nc = 9;
+ sim_in.framesize = 160;
+ sim_in.Nc = 4;
sim_in.Rs = 50;
sim_in.Ns = 4;
sim_in.Np = 2;
sim_in.Nchip = 1;
- sim_in.ldpc_code_rate = 0.5;
- sim_in.ldpc_code = 1;
+ sim_in.ldpc_code_rate = 1;
+ sim_in.ldpc_code = 0;
sim_in.Ntrials = 20;
sim_in.Esvec = 7;
Ascale = 2000;
figure(1);
clf;
- plot(Ascale*tx_fdm(1:800))
+ plot(Ascale*tx_fdm(1:8000))
ftx=fopen(tx_filename,"wb"); fwrite(ftx, Ascale*real(tx_fdm), "short"); fclose(ftx);
sim_in.verbose = 1;
sim_in.plot_scatter = 1;
- sim_in.framesize = 576;
- sim_in.Nc = 9;
+ sim_in.framesize = 160;
+ sim_in.Nc = 4;
sim_in.Rs = 50;
sim_in.Ns = 4;
sim_in.Np = 4;
sim_in.Nchip = 1;
- sim_in.ldpc_code_rate = 0.5;
- sim_in.ldpc_code = 1;
+ sim_in.ldpc_code_rate = 1;
+ sim_in.ldpc_code = 0;
sim_in.Ntrials = 10;
sim_in.Esvec = 40;
printf("Freq offset and coarse timing est...\n");
[f_max max_s_Fs] = test_freq_off_est(rx_filename, 1,5*6400);
- %f_max = 0; max_s_Fs = 4;
+ f_max = 0; max_s_Fs = 4;
max_s = floor(max_s_Fs/M + 6);
printf("Downconverting...\n");
errors_log = [errors_log error_positions];
Nerrs_log = [Nerrs_log Nerrs];
- % LDPC decode
+ if sim_in.ldpc_code
+ % LDPC decode
- detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ...
- rx_symb_linear, min(100,EsNo_), amp_linear);
- error_positions = xor(detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );
- Nerrs = sum(error_positions);
- ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs];
- ldpc_errors_log = [ldpc_errors_log error_positions];
- if Nerrs
- Ferrsldpc++;
+ detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ...
+ rx_symb_linear, min(100,EsNo_), amp_linear);
+ error_positions = xor(detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );
+ Nerrs = sum(error_positions);
+ ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs];
+ ldpc_errors_log = [ldpc_errors_log error_positions];
+ if Nerrs
+ Ferrsldpc++;
+ end
+ Terrsldpc += Nerrs;
+ Tbitsldpc += framesize*rate;
end
- Terrsldpc += Nerrs;
- Tbitsldpc += framesize*rate;
end
end
EsNo_av, mean(EsNo_to_SNR(10*log10(EsNo__log))),
Terrs,
Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr);
- printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f\n",
- Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials);
-
+ if sim_in.ldpc_code
+ printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f\n",
+ Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials);
+ end
+
figure(3);
clf;
scat = rx_symb_log .* exp(j*pi/4);
stem(Nerrs_log)
axis([0 Ntrials+1 0 max(Nerrs_log)+1])
title('Uncoded Errors/Frame');
- subplot(212)
- stem(ldpc_Nerrs_log)
- axis([0 Ntrials+1 0 max(ldpc_Nerrs_log)+1])
- title('Coded Errors/Frame');
+ if sim_in.ldpc_code
+ subplot(212)
+ stem(ldpc_Nerrs_log)
+ axis([0 Ntrials+1 0 max(ldpc_Nerrs_log)+1])
+ title('Coded Errors/Frame');
+ end
figure(5)
clf
snr = interp1([20 11.8 9.0 6.7 4.9 3.3 -10], [ 3 3 0 -3 -6 -9 -9], EsNo);
endfunction
+function gen_test_bits()
+ sim_in = standard_init();
+ framesize = 160;
+ tx_bits = round(rand(1,framesize));
+ test_bits_coh_file(tx_bits);
+endfunction
+
% Start simulations ---------------------------------------
more off;
%test_curves();
-%test_single();
+test_single();
%rate_Fs_tx("tx_zero.raw");
-%rate_Fs_tx("tx_950.raw");
-rate_Fs_rx("tx_-4dB.wav")
-%rate_Fs_rx("mel010.wav")
+%rate_Fs_tx("tx.raw");
+%rate_Fs_rx("tx_-4dB.wav")
+%rate_Fs_rx("tx.raw")
%test_freq_off_est("tx.raw",40,6400)
+%gen_test_bits();
+
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: cohpsk.h
+ AUTHOR......: David Rowe
+ DATE CREATED: March 2015
+
+ Functions that implement a coherent PSK FDM modem.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CODEC2_COHPSK__
+#define __CODEC2_COHPSK__
+
+#define COHPSK_BITS_PER_FRAME 160 /* hard coded for now */
+#define COHPSK_NC 4 /* hard coded for now */
+
+#include "comp.h"
+
+void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC], int tx_bits[], int framesize);
+
+#endif
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: cohpsk.c
+ AUTHOR......: David Rowe
+ DATE CREATED: March 2015
+
+ Functions that implement a coherent PSK FDM modem.
+
+ TODO:
+ [ ] matching octave function bits_to_dqpsk_symbols()
+ [ ] framework for test program and octave UT
+ [ ] testframe used by both Octave and C
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
+*/
+
+/*---------------------------------------------------------------------------*\
+
+ INCLUDES
+
+\*---------------------------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "codec2_cohpsk.h"
+#include "test_bits.h"
+#include "cohpsk_defs.h"
+#include "pilots_coh.h"
+
+static COMP qpsk_mod[] = {
+ { 1.0, 0.0},
+ { 0.0, 1.0},
+ { 0.0,-1.0},
+ {-1.0, 0.0}
+};
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTIONS
+
+\*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: bits_to_qpsk_symbols()
+ AUTHOR......: David Rowe
+ DATE CREATED: March 2015
+
+ Maps bits to parallel DQPSK symbols and inserts pilot symbols.
+
+\*---------------------------------------------------------------------------*/
+
+void bits_to_qpsk_symbols(COMP tx_symb[][PILOTS_NC], int tx_bits[], int framesize)
+{
+ COMP tx_symb_data[NSYMROW][PILOTS_NC];
+ int i, r, c, p_r, data_r;
+ short bits;
+
+ assert(COHPSK_NC == PILOTS_NC);
+ assert((NSYMROW*PILOTS_NC)/2 == framesize);
+
+ /*
+ Organise QPSK symbols into a NSYMBROWS rows by PILOTS_NC cols matrix,
+ each column is a carrier, time flows down the rows......
+
+ Note: the "& 0x1" prevents and non binary tx_bits[] screwing up
+ our lives. Call me defensive.
+ */
+
+ for(c=0; c<PILOTS_NC; c++) {
+ for(r=0; r<NSYMROW; r++) {
+ i = c*NSYMROW + r;
+ bits = (tx_bits[2*i]&0x1)<<1 | (tx_bits[2*i+1]&0x1);
+ tx_symb_data[r][c] = qpsk_mod[bits];
+ }
+ }
+
+ /* "push" in rows of Nc pilots, one row every NS data symbols */
+
+ for (r=0, p_r=0, data_r=0; p_r<NPILOTSFRAME; p_r++) {
+
+ /* row of pilots */
+
+ for(c=0; c<PILOTS_NC; c++) {
+ tx_symb[r][c].real = pilots_coh[p_r][c];
+ tx_symb[r][c].imag = 0.0;
+ }
+ r++;
+
+ /* NS rows of data symbols */
+
+ for(i=0; i<NS; data_r++,r++) {
+ for(c=0; c<PILOTS_NC; c++)
+ tx_symb[r][c] = tx_symb_data[data_r][c];
+ }
+ }
+
+ assert(p_r == NPILOTSFRAME);
+ assert(data_r == NSYMROW);
+ assert(r == NSYMROWPILOT);
+}
--- /dev/null
+/* Generated by write_pilot_file() Octave function */
+
+#define NSYMROW 20 /* number of data symbols for each row (i.e. each carrier) */
+#define NS 4 /* number of data symbols between pilots */
+#define NPILOTSFRAME 5 /* number of pilot symbols of each row */
+#define PILOTS_NC 4 /* number of carriers in coh modem */
+
+#define NSYMROWPILOT 25 /* length of row after pilots inserted */
+
if (f->current_test_bit > (f->ntest_bits-1))
f->current_test_bit = 0;
}
- }
+}
float fdmdv_get_fsep(struct FDMDV *f)
{
/*---------------------------------------------------------------------------*\
FILE........: fdmdv_internal.h
- AUTHOR......: David Rowe
+ AUTHOR......: David Rowe
DATE CREATED: April 16 2012
Header file for FDMDV internal functions, exposed via this header
--- /dev/null
+/* Generated by write_pilot_file() Octave function */
+
+float pilots_coh[][PILOTS_NC]={
+ { 1.000000, 1.000000, -1.000000, -1.000000},
+ { -1.000000, -1.000000, 1.000000, 1.000000},
+ { -1.000000, -1.000000, -1.000000, -1.000000},
+ { 1.000000, 1.000000, 1.000000, -1.000000},
+ { 1.000000, 1.000000, 1.000000, 1.000000}
+};
\ No newline at end of file
--- /dev/null
+/* Generated by test_bits_coh_file() Octave function */
+
+const int test_bits_coh[]={
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1
+};
add_executable(tfdmdv tfdmdv.c ../src/fdmdv.c ../src/kiss_fft.c ../src/octave.c)
target_link_libraries(tfdmdv codec2)
+add_executable(tcohpsk tcohpsk.c ../src/cohpsk.c ../src/octave.c)
+target_link_libraries(tcohpsk)
+
add_executable(t16_8 t16_8.c ../src/fdmdv.c ../src/kiss_fft.c)
target_link_libraries(t16_8 codec2)
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: tcopskv.c
+ AUTHOR......: David Rowe
+ DATE CREATED: March 2015
+
+ Tests for the C version of the cohernet 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
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "fdmdv_internal.h"
+#include "codec2_fdmdv.h"
+#include "codec2_cohpsk.h"
+#include "cohpsk_defs.h"
+#include "test_bits_coh.h"
+#include "octave.h"
+
+#define FRAMES 35
+#define CHANNEL_BUF_SIZE (10*M)
+
+int main(int argc, char *argv[])
+{
+ int tx_bits[COHPSK_BITS_PER_FRAME];
+ COMP tx_symbols[NSYMROWPILOT][PILOTS_NC];
+
+ int tx_bits_log[COHPSK_BITS_PER_FRAME*FRAMES];
+ COMP tx_symbols_log[NSYMROWPILOT*FRAMES][PILOTS_NC];
+
+ FILE *fout;
+ int f, r,c,rx_sym_log_r;
+
+ rx_sym_log_r=0;
+
+ for(f=0; f<FRAMES; f++) {
+
+ /* --------------------------------------------------------*\
+ Modulator
+ \*---------------------------------------------------------*/
+
+ bits_to_qpsk_symbols(tx_symbols, (int*)test_bits_coh, sizeof(test_bits_coh));
+
+ /* --------------------------------------------------------*\
+ Log each vector
+ \*---------------------------------------------------------*/
+
+ memcpy(&tx_bits_log[COHPSK_BITS_PER_FRAME*f], tx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME);
+ for(r=0; r<NSYMROWPILOT; r++, rx_sym_log_r++) {
+ for(c=0; c<PILOTS_NC; c++)
+ tx_symbols_log[rx_sym_log_r][c] = tx_symbols[r][c];
+ }
+ assert(rx_sym_log_r <= NSYMROWPILOT*FRAMES);
+ }
+
+
+ /*---------------------------------------------------------*\
+ Dump logs to Octave file for evaluation
+ by tcohpsk.m Octave script
+ \*---------------------------------------------------------*/
+
+ fout = fopen("tcohpsk_out.txt","wt");
+ assert(fout != NULL);
+ 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_symbols_log_c", (COMP*)tx_symbols_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC);
+ fclose(fout);
+
+ return 0;
+}
+