void cohpsk_set_verbose(struct COHPSK *coh, int verbose);
void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]);
void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
- int *bit_errors, char rx_bits[]);
+ int *bit_errors, char rx_bits[], int channel);
int cohpsk_error_pattern_size(void);
void cohpsk_set_frame(struct COHPSK *coh, int frame);
void fdmdv_freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs,
COMP *foff_phase_rect, int nin);
+
+/* used for accessing upper and lower bits before diversity combination */
+
+float *cohpsk_get_rx_bits_lower(struct COHPSK *coh);
+float *cohpsk_get_rx_bits_upper(struct COHPSK *coh);
+
#endif
/* test frames */
- coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+ coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx[0] = coh->ptest_bits_coh_rx[1] = (int*)test_bits_coh;
coh->ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int);
return coh;
i = c*NSYMROW + r;
rx_bits[2*i+1] = rot.real;
rx_bits[2*i] = rot.imag;
+
+ /* demodulate bits from upper and lower carriers separately for test purposes */
+
+ assert(ND == 2);
+
+ i = c*NSYMROW + r;
+ rot = cmult(coh->rx_symb[r][c], pi_on_4);
+ coh->rx_bits_lower[2*i+1] = rot.real;
+ coh->rx_bits_lower[2*i] = rot.imag;
+ rot = cmult(coh->rx_symb[r][c + COHPSK_NC], pi_on_4);
+ coh->rx_bits_upper[2*i+1] = rot.real;
+ coh->rx_bits_upper[2*i] = rot.imag;
}
}
Accepts bits from demod and attempts to sync with the known
test_bits sequence. When synced measures bit errors.
+ Has states to track two separate received test sequences based on
+ channel 0 or 1.
+
\*---------------------------------------------------------------------------*/
void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
- int *bit_errors, char rx_bits_char[])
+ int *bit_errors, char rx_bits_char[], int channel)
{
int i, next_state, anerror;
int rx_bits[COHPSK_BITS_PER_FRAME];
+ assert((channel == 0) || (channel == 1));
+ int *ptest_bits_coh_rx = coh->ptest_bits_coh_rx[channel];
+
for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
rx_bits[i] = rx_bits_char[i];
}
*bit_errors = 0;
for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
- anerror = (rx_bits[i] & 0x1) ^ coh->ptest_bits_coh_rx[i];
+ anerror = (rx_bits[i] & 0x1) ^ ptest_bits_coh_rx[i];
if ((anerror < 0) || (anerror > 1)) {
- fprintf(stderr, "i: %d rx_bits: %d ptest_bits_coh_rx: %d\n", i, rx_bits[i], coh->ptest_bits_coh_rx[i]);
+ fprintf(stderr, "i: %d rx_bits: %d ptest_bits_coh_rx: %d\n", i, rx_bits[i], ptest_bits_coh_rx[i]);
}
*bit_errors += anerror;
error_pattern[i] = anerror;
if (*state == 0) {
if (*bit_errors < 4) {
next_state = 1;
- coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
- if (coh->ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
- coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+ ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
+ if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
+ ptest_bits_coh_rx = (int*)test_bits_coh;
}
}
}
}
if (*state > 0) {
- coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
- if (coh->ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
- coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+ ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
+ if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
+ ptest_bits_coh_rx = (int*)test_bits_coh;
}
}
//fprintf(stderr, "state: %d next_state: %d bit_errors: %d\n", *state, next_state, *bit_errors);
*state = next_state;
+ coh->ptest_bits_coh_rx[channel] = ptest_bits_coh_rx;
}
+
int cohpsk_error_pattern_size(void) {
return COHPSK_BITS_PER_FRAME;
}
+float *cohpsk_get_rx_bits_lower(struct COHPSK *coh) {
+ return coh->rx_bits_lower;
+}
+
+
+float *cohpsk_get_rx_bits_upper(struct COHPSK *coh) {
+ return coh->rx_bits_upper;
+}
+
}
cohpsk = cohpsk_create();
- cohpsk_set_verbose(cohpsk, 1);
+ cohpsk_set_verbose(cohpsk, 0);
if (oct) {
logframes = LOG_FRAMES;
struct COHPSK {
COMP ch_fdm_frame_buf[NSW*NSYMROWPILOT*COHPSK_M]; /* buffer of several frames of symbols from channel */
float pilot2[2*NPILOTSFRAME][COHPSK_NC];
- float phi_[NSYMROW][COHPSK_NC*ND]; /* phase estimates for this frame of rx data symbols */
+ float phi_[NSYMROWPILOT][COHPSK_NC*ND]; /* phase estimates for this frame of rx data symbols */
float amp_[NSYMROW][COHPSK_NC*ND]; /* amplitude estimates for this frame of rx data symbols */
- COMP rx_symb[NSYMROW][COHPSK_NC*ND]; /* demodulated symbols */
+ COMP rx_symb[NSYMROWPILOT][COHPSK_NC*ND]; /* demodulated symbols */
float f_est;
COMP rx_filter_memory[COHPSK_NC*ND][COHPSK_NFILTER];
COMP ct_symb_buf[NCT_SYMB_BUF][COHPSK_NC*ND];
int verbose;
int *ptest_bits_coh_tx;
- int *ptest_bits_coh_rx;
+ int *ptest_bits_coh_rx[2];
int *ptest_bits_coh_end;
+ /* counting bit errors using pilots */
+
+ int npilotbits;
+ int npilotbiterrors;
+
/* optional log variables used for testing Octave to C port */
COMP *rx_baseband_log;
float *rx_timing_log;
int rx_timing_log_index;
+
+ /* demodulated bits before diversity combination for test/instrumentation purposes */
+
+ float rx_bits_lower[COHPSK_BITS_PER_FRAME];
+ float rx_bits_upper[COHPSK_BITS_PER_FRAME];
};
void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits);
state = 0; nbits = 0; nerrors = 0;
while (fread(rx_bits, sizeof(char), COHPSK_BITS_PER_FRAME, fin) == COHPSK_BITS_PER_FRAME) {
- cohpsk_put_test_bits(coh, &state, error_pattern, &bit_errors, rx_bits);
+ cohpsk_put_test_bits(coh, &state, error_pattern, &bit_errors, rx_bits, 0);
if (state == 1) {
for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
error_positions_hist[i] += error_pattern[i];
f->sz_error_pattern = cohpsk_error_pattern_size();
}
#endif
- if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)){
+ if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) {
/* Set up the C2 mode */
codec2_mode = CODEC2_MODE_1300;
}
+ f->test_frames_diversity = 1;
f->test_frame_sync_state = 0;
+ f->test_frame_sync_state_upper = 0;
f->total_bits = 0;
f->total_bit_errors = 0;
nout = f->n_speech_samples;
}
else {
- short error_pattern[COHPSK_BITS_PER_FRAME];
- int bit_errors;
-
- /* test data, lets see if we can sync to the test data sequence */
-
- char rx_bits_char[COHPSK_BITS_PER_FRAME];
- for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
- rx_bits_char[i] = rx_bits[i] < 0.0;
- cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits_char);
- if (f->test_frame_sync_state) {
- f->total_bit_errors += bit_errors;
- f->total_bits += COHPSK_BITS_PER_FRAME;
- if (f->freedv_put_error_pattern != NULL) {
- (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
+ //fprintf(stderr, " freedv_api: f->test_frames_diversity: %d\n", f->test_frames_diversity);
+
+ if (f->test_frames_diversity) {
+ /* normal operation - error pattern on frame after diveristy combination */
+ short error_pattern[COHPSK_BITS_PER_FRAME];
+ int bit_errors;
+
+ /* test data, lets see if we can sync to the test data sequence */
+
+ char rx_bits_char[COHPSK_BITS_PER_FRAME];
+ for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
+ rx_bits_char[i] = rx_bits[i] < 0.0;
+ cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits_char, 0);
+ if (f->test_frame_sync_state) {
+ f->total_bit_errors += bit_errors;
+ f->total_bits += COHPSK_BITS_PER_FRAME;
+ if (f->freedv_put_error_pattern != NULL) {
+ (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
+ }
+ }
+ }
+ else {
+ /* calculate error pattern on uncombined carriers - test mode to spot any carrier specific issues like
+ tx passband filtering */
+
+ short error_pattern[2*COHPSK_BITS_PER_FRAME];
+ char rx_bits_char[COHPSK_BITS_PER_FRAME];
+ int bit_errors_lower, bit_errors_upper;
+
+ /* lower group of carriers */
+
+ float *rx_bits_lower = cohpsk_get_rx_bits_lower(f->cohpsk);
+ for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
+ rx_bits_char[i] = rx_bits_lower[i] < 0.0;
+ }
+ cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors_lower, rx_bits_char, 0);
+
+ /* upper group of carriers */
+
+ float *rx_bits_upper = cohpsk_get_rx_bits_upper(f->cohpsk);
+ for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
+ rx_bits_char[i] = rx_bits_upper[i] < 0.0;
+ }
+ cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state_upper, &error_pattern[COHPSK_BITS_PER_FRAME], &bit_errors_upper, rx_bits_char, 1);
+ // fprintf(stderr, " freedv_api: f->test_frame_sync_state: %d f->test_frame_sync_state_upper: %d\n",
+ // f->test_frame_sync_state, f->test_frame_sync_state_upper);
+
+ /* combine total errors and call callback */
+
+ if (f->test_frame_sync_state && f->test_frame_sync_state_upper) {
+ f->total_bit_errors += bit_errors_lower + bit_errors_upper;
+ f->total_bits += 2*COHPSK_BITS_PER_FRAME;
+ if (f->freedv_put_error_pattern != NULL) {
+ (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, 2*COHPSK_BITS_PER_FRAME);
+ }
}
+
}
*valid = 0;
// Set integers
void freedv_set_test_frames (struct freedv *f, int val) {f->test_frames = val;}
+void freedv_set_test_frames_diversity (struct freedv *f, int val) {f->test_frames_diversity = val;}
void freedv_set_squelch_en (struct freedv *f, int val) {f->squelch_en = val;}
void freedv_set_total_bit_errors (struct freedv *f, int val) {f->total_bit_errors = val;}
void freedv_set_total_bits (struct freedv *f, int val) {f->total_bits = val;}
-void freedv_set_clip (struct freedv *f, int val) {f->clip = val;}
+void freedv_set_clip (struct freedv *f, int val) {f->clip = val;}
void freedv_set_varicode_code_num (struct freedv *f, int val) {varicode_set_code_num(&f->varicode_dec_states, val);}
// Set floats
int freedv_get_n_nom_modem_samples (struct freedv *f) {return f->n_nom_modem_samples;}
int freedv_get_total_bits (struct freedv *f) {return f->total_bits;}
int freedv_get_total_bit_errors (struct freedv *f) {return f->total_bit_errors;}
-int freedv_get_sync (struct freedv *f) {return f->stats.sync;}
-int freedv_get_sz_error_pattern (struct freedv *f) {return f->sz_error_pattern;}
+int freedv_get_sync (struct freedv *f) {return f->stats.sync;}
+
+int freedv_get_sz_error_pattern(struct freedv *f)
+{
+ if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) {
+ /* if diversity disabled callback sends error pattern for upper and lower carriers */
+ return f->sz_error_pattern * (2 - f->test_frames_diversity);
+ }
+ else {
+ return f->sz_error_pattern;
+ }
+}
+
// Get floats
struct CODEC2 *freedv_get_codec2 (struct freedv *f){return f->codec2;}
void freedv_set_callback_protocol (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
void freedv_set_test_frames (struct freedv *freedv, int test_frames);
+void freedv_set_test_frames_diversity (struct freedv *freedv, int test_frames_diversity);
void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols);
void freedv_set_squelch_en (struct freedv *freedv, int squelch_en);
void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh);
int *ptest_bits_coh_end;
int test_frames; // set this baby for 1 to tx/rx test frames to look at bit error stats
+ int test_frames_diversity; // 1 -> used combined carriers for error counting on 700 waveforms
int test_frame_sync_state;
+ int test_frame_sync_state_upper; // when test_frames_diveristy==0 we need extra states for upper carriers
int test_frame_count;
int total_bits;
int total_bit_errors;