% Now run demod ----------------------------------------------------------------
ch_fdm_frame_log_index = 1;
+nin = M;
f = 0;
+nin_frame = acohpsk.Nsymbrowpilot*M;
%while (ch_fdm_frame_log_index + acohpsk.Nsymbrowpilot*M+M/P) < length(ch_fdm_frame_log)
for f=1:frames;
acohpsk.frame = f;
- if sync == 0
- nin = M;
- else
- nin = M;
- if 0
- if rx_timing(1) > M/P
- nin = M + M/P;
- end
- if rx_timing(1) < -M/P
- nin = M - M/P;
- end
- end
- end
-
- nin_frame = (acohpsk.Nsymbrowpilot-1)*M + nin;
ch_fdm_frame = ch_fdm_frame_log(ch_fdm_frame_log_index:ch_fdm_frame_log_index + nin_frame - 1);
ch_fdm_frame_log_index += nin_frame;
rx_filt_log = [rx_filt_log rx_filt];
ch_symb_log = [ch_symb_log; ch_symb];
+ rx_timing_log = [rx_timing_log rx_timing];
for i=1:Nsw-1
acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);
rx_baseband_log = [rx_baseband_log rx_baseband];
rx_filt_log = [rx_filt_log rx_filt];
ch_symb_log = [ch_symb_log; ch_symb];
-
+ rx_timing_log = [rx_timing_log rx_timing];
+
for i=1:Nsw-1
acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);
end
[sync acohpsk] = sync_state_machine(acohpsk, sync, next_sync);
+ % work out how many samples we need for next time
+
+ nin = M;
+ if sync == 1
+ if rx_timing(length(rx_timing)) > M/P
+ nin = M + M/P;
+ end
+ if rx_timing(length(rx_timing)) < -M/P
+ nin = M - M/P;
+ end
+ end
+ nin_frame = (acohpsk.Nsymbrowpilot-1)*M + nin;
+ %printf("%f %d %d\n", rx_timing(length(rx_timing)), nin, nin_frame);
+
prev_tx_bits2 = prev_tx_bits;
prev_tx_bits = tx_bits;
stem_sig_and_error(10, 111, rx_bits_log_c, rx_bits_log - rx_bits_log_c, 'rx bits', [1 length(rx_bits_log) -1.5 1.5])
stem_sig_and_error(11, 111, f_est_log_c - Fcentre, f_est_log - f_est_log_c, 'f est', [1 length(f_est_log) foff-5 foff+5])
+ stem_sig_and_error(12, 111, rx_timing_log_c, rx_timing_log_c - rx_timing_log, 'rx timing', [1 length(rx_timing_log) -M M])
check(tx_bits_log, tx_bits_log_c, 'tx_bits');
check(tx_symb_log, tx_symb_log_c, 'tx_symb');
check(rx_amp_log, rx_amp_log_c, 'rx_amp_log',0.01);
check(phi_log_diff, zeros(length(phi_log_diff), Nc*Nd), 'rx_phi_log',0.05);
check(rx_symb_log, rx_symb_log_c, 'rx_symb',0.01);
+ check(rx_timing_log, rx_timing_log_c, 'rx_timing',0.001);
check(rx_bits_log, rx_bits_log_c, 'rx_bits');
check(f_est_log, f_est_log_c, 'f_est');
#define COHPSK_NC 7 /* hard coded for now */
#define COHPSK_SAMPLES_PER_FRAME 600
#define COHPSK_RS 75
-#define COHPSK_FS 7500
+#define COHPSK_FS 7500 /* note this is a wierd value to get an integer oversampling rate */
#include "comp.h"
#include "codec2_fdmdv.h"
struct COHPSK *cohpsk_create(void);
void cohpsk_destroy(struct COHPSK *coh);
void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[]);
-void cohpsk_demod(struct COHPSK *cohpsk, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[]);
+void cohpsk_demod(struct COHPSK *cohpsk, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin_frame);
#endif
coh->sync = 0;
coh->frame = 0;
coh->ratio = 0.0;
+ coh->nin = COHPSK_M;
/* clear sync window buffer */
coh->rx_filt_log_col_index = 0;
coh->ch_symb_log = NULL;
coh->ch_symb_log_r = 0;
+ coh->rx_timing_log = NULL;
+ coh->rx_timing_log_index = 0;
return coh;
}
void rate_Fs_rx_processing(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], COMP ch_fdm_frame[], float *f_est, int nsymb, int nin, int freq_track)
{
struct FDMDV *fdmdv = coh->fdmdv;
- int r, c, i;
+ int r, c, i, ch_fdm_frame_index;
COMP rx_fdm_frame_bb[COHPSK_M];
COMP rx_baseband[COHPSK_NC*ND][COHPSK_M+COHPSK_M/P];
COMP rx_filt[COHPSK_NC*ND][P+1];
float beta, g;
COMP adiff, amod_strip, mod_strip;
- assert(nin < COHPSK_M*NSYMROWPILOT);
+ ch_fdm_frame_index = 0;
for (r=0; r<nsymb; r++) {
- fdmdv_freq_shift_coh(rx_fdm_frame_bb, &ch_fdm_frame[r*COHPSK_M], -(*f_est), &fdmdv->fbb_phase_rx, nin);
+ fdmdv_freq_shift_coh(rx_fdm_frame_bb, &ch_fdm_frame[ch_fdm_frame_index], -(*f_est), &fdmdv->fbb_phase_rx, nin);
+ ch_fdm_frame_index += nin;
fdm_downconvert_coh(rx_baseband, COHPSK_NC*ND, rx_fdm_frame_bb, fdmdv->phase_rx, fdmdv->freq, nin);
rx_filter_coh(rx_filt, COHPSK_NC*ND, rx_baseband, coh->rx_filter_memory, nin);
rx_timing = rx_est_timing(rx_onesym, fdmdv->Nc, rx_filt, fdmdv->rx_filter_mem_timing, env, nin, COHPSK_M);
}
if (coh->rx_filt_log) {
- for(c=0; c<COHPSK_NC*ND; c++) {
- for(i=0; i<P; i++) {
+ for(c=0; c<COHPSK_NC*ND; c++) {
+ for(i=0; i<nin/(COHPSK_M/P); i++) {
coh->rx_filt_log[c*coh->rx_filt_log_col_sz + coh->rx_filt_log_col_index + i] = rx_filt[c][i];
}
}
- coh->rx_filt_log_col_index += P;
+ coh->rx_filt_log_col_index += nin/(COHPSK_M/P);
}
if (coh->ch_symb_log) {
}
coh->ch_symb_log_r++;
}
+
+ if (coh->rx_timing_log) {
+ coh->rx_timing_log[coh->rx_timing_log_index] = rx_timing;
+ coh->rx_timing_log_index++;
+ //printf("rx_timing_log_index: %d\n", coh->rx_timing_log_index);
+ }
+
+ /* we only allow a timing shift on one symbol per frame */
+
+ if (nin != COHPSK_M)
+ nin = COHPSK_M;
}
+ coh->rx_timing = rx_timing;
}
AUTHOR......: David Rowe
DATE CREATED: 5/4/2015
- COHPSK demodulator, takes an array of COHPSK_SAMPLES_PER_FRAME
- modulated samples, returns an array of COHPSK_BITS_PER_FRAME bits.
+ COHPSK demodulator, takes an array of (nominally) nin_frame =
+ COHPSK_SAMPLES_PER_FRAME modulated samples, returns an array of
+ COHPSK_BITS_PER_FRAME bits.
The input signal is complex to support single sided frequency shifting
before the demod input (e.g. click to tune feature).
- The number of input samples is fixed, and unlike the FDMDV modem
- doesn't change to adjust for differences in transmit and receive
- sample clocks. This means frame sync will occasionally be lost,
- however this is hardly noticable for digital voice applications.
-
- TODO: logic to check if we are still in sync, ride thru bad frames
-
\*---------------------------------------------------------------------------*/
-void cohpsk_demod(struct COHPSK *coh, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[])
+void cohpsk_demod(struct COHPSK *coh, int rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin_frame)
{
COMP ch_symb[NSW*NSYMROWPILOT][COHPSK_NC*ND];
int i, j, sync, anext_sync, next_sync, nin, r, c;
float max_ratio, f_est;
- /* store two frames of received samples so we can rewind if we get a good candidate */
+ next_sync = sync = coh->sync;
- for (i=0; i<(NSW-1)*NSYMROWPILOT*COHPSK_M; i++)
- coh->ch_fdm_frame_buf[i] = coh->ch_fdm_frame_buf[i+NSYMROWPILOT*COHPSK_M];
+ for (i=0; i<NSW*NSYMROWPILOT*COHPSK_M-*nin_frame; i++)
+ coh->ch_fdm_frame_buf[i] = coh->ch_fdm_frame_buf[i+*nin_frame];
+ //printf("nin_frame: %d i: %d i+nin_frame: %d\n", *nin_frame, i, i+*nin_frame);
for (j=0; i<NSW*NSYMROWPILOT*COHPSK_M; i++,j++)
coh->ch_fdm_frame_buf[i] = rx_fdm[j];
//printf("i: %d j: %d rx_fdm[0]: %f %f\n", i,j, rx_fdm[0].real, rx_fdm[0].imag);
- next_sync = sync = coh->sync;
- nin = COHPSK_M;
-
- /* if out of sync do Initial Freq offset estimation using NSW frames to flush out filter memories */
+ /* if out of sync do Initial Freq offset estimation using NSW frames to flush out filter memories */
if (sync == 0) {
/* we are out of sync so reset f_est and process two frames to clean out memories */
- rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, nin, 0);
+ rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, COHPSK_M, 0);
for (i=0; i<NSW-1; i++) {
update_ct_symb_buf(coh->ct_symb_buf, &ch_symb[i*NSYMROWPILOT]);
}
fprintf(stderr, " [%d] trying sync and f_est: %f\n", coh->frame, coh->f_est);
- rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, nin, 0);
+ rate_Fs_rx_processing(coh, ch_symb, coh->ch_fdm_frame_buf, &coh->f_est, NSW*NSYMROWPILOT, COHPSK_M, 0);
for (i=0; i<NSW-1; i++) {
update_ct_symb_buf(coh->ct_symb_buf, &ch_symb[i*NSYMROWPILOT]);
}
/* If in sync just do sample rate processing on latest frame */
if (sync == 1) {
- rate_Fs_rx_processing(coh, ch_symb, rx_fdm, &coh->f_est, NSYMROWPILOT, nin, 1);
+ rate_Fs_rx_processing(coh, ch_symb, rx_fdm, &coh->f_est, NSYMROWPILOT, coh->nin, 1);
frame_sync_fine_freq_est(coh, ch_symb, sync, &next_sync);
for(r=0; r<2; r++)
sync = sync_state_machine(coh, sync, next_sync);
coh->sync = sync;
+
+ /* work out how many samples we need for the next call to account
+ for differences in tx and rx sample clocks */
+
+ nin = COHPSK_M;
+ if (sync == 1) {
+ if (coh->rx_timing > COHPSK_M/P)
+ nin = COHPSK_M + COHPSK_M/P;
+ if (coh->rx_timing < -COHPSK_M/P)
+ nin = COHPSK_M - COHPSK_M/P;
+ }
+ coh->nin = nin;
+ *nin_frame = (NSYMROWPILOT-1)*COHPSK_M + nin;
+ //printf("%f %d %d\n", coh->rx_timing, nin, *nin_frame);
}
float f_est;
COMP rx_filter_memory[COHPSK_NC*ND][COHPSK_NFILTER];
COMP ct_symb_buf[NCT_SYMB_BUF][COHPSK_NC*ND];
- int ct; /* coarse timing offset in symbols */
+ int ct; /* coarse timing offset in symbols */
+ float rx_timing; /* fine timing for last symbol in frame */
+ int nin; /* number of samples to input for next symbol */
float f_fine_est;
COMP ff_rect;
COMP ff_phase;
struct FDMDV *fdmdv;
- /* optional log variables used for tetsing Octave to C port */
+ /* optional log variables used for testing Octave to C port */
- COMP *rx_baseband_log;
+ COMP *rx_baseband_log;
int rx_baseband_log_col_index;
int rx_baseband_log_col_sz;
- COMP *rx_filt_log;
+ COMP *rx_filt_log;
int rx_filt_log_col_index;
int rx_filt_log_col_sz;
- COMP *ch_symb_log;
+ COMP *ch_symb_log;
int ch_symb_log_r;
int ch_symb_log_col_sz;
+
+ float *rx_timing_log;
+ int rx_timing_log_index;
};
void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits);
float EsNo, variance;
COMP scaled_noise;
int reliable_sync_bit;
+ int ch_fdm_frame_log_index, nin_frame, tmp;
coh = cohpsk_create();
fdmdv = coh->fdmdv;
coh->ch_symb_log_col_sz = COHPSK_NC*ND;
coh->ch_symb_log = (COMP *)malloc(sizeof(COMP)*NSYMROWPILOT*FRAMESL*coh->ch_symb_log_col_sz);
+
+ coh->rx_timing_log = (float*)malloc(sizeof(float)*NSYMROWPILOT*FRAMESL);
/* init stuff */
/* Main Loop ---------------------------------------------------------------------*/
for(f=0; f<FRAMES; f++) {
- coh->frame = f;
/* --------------------------------------------------------*\
Mod
ch_fdm_frame[r] = cadd(ch_fdm_frame[r], scaled_noise);
}
-
- /* --------------------------------------------------------*\
- Demod
- \*---------------------------------------------------------*/
-
- cohpsk_demod(coh, rx_bits, &reliable_sync_bit, ch_fdm_frame);
-
- /* --------------------------------------------------------*\
- Log each vector
- \*---------------------------------------------------------*/
+ /* tx vector logging */
memcpy(&tx_bits_log[COHPSK_BITS_PER_FRAME*f], tx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME);
memcpy(&tx_fdm_frame_log[COHPSK_M*NSYMROWPILOT*f], tx_fdm_frame, sizeof(COMP)*COHPSK_M*NSYMROWPILOT);
memcpy(&ch_fdm_frame_log[COHPSK_M*NSYMROWPILOT*f], ch_fdm_frame, sizeof(COMP)*COHPSK_M*NSYMROWPILOT);
- //memcpy(&rx_fdm_frame_bb_log[M*NSYMROWPILOT*f], rx_fdm_frame_bb, sizeof(COMP)*M*NSYMROWPILOT);
-
+
for(r=0; r<NSYMROWPILOT; r++, log_r++) {
for(c=0; c<COHPSK_NC*ND; c++) {
tx_symb_log[log_r][c] = tx_symb[r][c];
}
}
+ }
+
+ nin_frame = COHPSK_SAMPLES_PER_FRAME;
+ ch_fdm_frame_log_index = 0;
+
+ for(f=0; f<FRAMES; f++) {
+ coh->frame = f;
+
+ //printf("nin_frame: %d\n", nin_frame);
+
+ /* --------------------------------------------------------*\
+ Demod
+ \*---------------------------------------------------------*/
+
+ assert(ch_fdm_frame_log_index < COHPSK_M*NSYMROWPILOT*FRAMES);
+ tmp = nin_frame;
+ cohpsk_demod(coh, rx_bits, &reliable_sync_bit, &ch_fdm_frame_log[ch_fdm_frame_log_index], &nin_frame);
+ ch_fdm_frame_log_index += tmp;
+
+ /* --------------------------------------------------------*\
+ Log each vector
+ \*---------------------------------------------------------*/
if (coh->sync == 1) {
octave_save_complex(fout, "rx_baseband_log_c", (COMP*)coh->rx_baseband_log, COHPSK_NC*ND, coh->rx_baseband_log_col_index, coh->rx_baseband_log_col_sz);
octave_save_complex(fout, "rx_filt_log_c", (COMP*)coh->rx_filt_log, COHPSK_NC*ND, coh->rx_filt_log_col_index, coh->rx_filt_log_col_sz);
octave_save_complex(fout, "ch_symb_log_c", (COMP*)coh->ch_symb_log, coh->ch_symb_log_r, COHPSK_NC*ND, COHPSK_NC*ND);
+ octave_save_float(fout, "rx_timing_log_c", (float*)coh->rx_timing_log, 1, coh->rx_timing_log_index, coh->rx_timing_log_index);
octave_save_complex(fout, "ct_symb_ff_log_c", (COMP*)ct_symb_ff_log, NSYMROWPILOT*FRAMES, COHPSK_NC*ND, COHPSK_NC*ND);
octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, log_data_r, COHPSK_NC*ND, COHPSK_NC*ND);
octave_save_float(fout, "rx_phi_log_c", (float*)rx_phi_log, log_data_r, COHPSK_NC*ND, COHPSK_NC*ND);
float EsNo, variance;
COMP scaled_noise;
float EsNodB, foff_hz;
- int fading_en, nhfdelay, ret;
+ int fading_en, nhfdelay, ret, nin;
COMP *ch_fdm_delay, aspread, aspread_2ms, delayed, direct;
FILE *ffading;
/* Main Loop ---------------------------------------------------------------------*/
+ nin = COHPSK_SAMPLES_PER_FRAME;
+
for(f=0; f<FRAMES; f++) {
/* --------------------------------------------------------*\
Demod
\*---------------------------------------------------------*/
- cohpsk_demod(coh, rx_bits, &reliable_sync_bit, ch_fdm);
+ cohpsk_demod(coh, rx_bits, &reliable_sync_bit, ch_fdm, &nin);
errors = 0;
for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {