From 50528abd718c8d5a61d34487c21f84371315e371 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 15 May 2017 21:35:58 +0200 Subject: [PATCH] Fixed CLI for timing recovery, added max_dphase for Costas --- csdr.c | 31 +- grc_tests/test_bpsk31_parts.grc | 473 +++++++++++++++++++++++++++- grc_tests/test_bpsk_costas_loop.grc | 79 ++++- libcsdr.c | 56 ++-- libcsdr.h | 11 +- 5 files changed, 587 insertions(+), 63 deletions(-) diff --git a/csdr.c b/csdr.c index c1e4b59..e04bae0 100755 --- a/csdr.c +++ b/csdr.c @@ -127,7 +127,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_f_u8 [databits [stopbits]]\n" " octave_complex_c \n" -" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave ]]] \n" +" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -136,7 +136,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ]\n" +" bpsk_costas_loop_cc [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_peak_c [window [--octave]]\n" @@ -2549,7 +2549,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [loop_gain [max_error [--add_q] [--output_error | --output_indexes | --octave ]]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [mu [max_error [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]]] \n" { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2568,11 +2568,22 @@ int main(int argc, char *argv[]) int add_q = !!(argc>=7 && !strcmp(argv[6], "--add_q")); - int debug_n = 0; + int debug_every_nth = -1; int output_error = 0; int output_indexes = 0; - if(argc+add_q>=8 && !strcmp(argv[6+add_q], "--octave")) debug_n = atoi(argv[7+add_q]); - if(debug_n<0) return badsyntax("debug_n should be >= 0"); + int octave_save = 0; + char* octave_save_path = NULL; + if(argc>=8+add_q && (!strcmp(argv[6+add_q], "--octave") || (octave_save = !strcmp(argv[6+add_q], "--octave_save")))) + { + debug_every_nth = atoi(argv[7+add_q]); + if(debug_every_nth<0) return badsyntax("debug_every_nth should be >= 0"); + } + if(octave_save) + { + if(argc>=9+add_q) octave_save_path = argv[8+add_q]; + else octave_save_path = "figs"; + } + if(debug_every_nth<0) { errhead(); fprintf(stderr, "--add_q mode on\n"); } if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; @@ -2585,17 +2596,13 @@ int main(int argc, char *argv[]) if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); - timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error); + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error, debug_every_nth, octave_save_path); - int debug_i=0; - state.debug_writefiles = 1; - state.debug_force = !!debug_n; //should remove that later FREAD_C; unsigned buffer_start_counter = 0; for(;;) { FEOF_CHECK; - if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, (int*)sampled_indexes, &state); //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); @@ -2819,9 +2826,9 @@ int main(int argc, char *argv[]) FILE* file_output_error = NULL; FILE* file_output_dphase = NULL; FILE* file_output_nco = NULL; - if(!(argc>4+decision_directed+3)) { errhead(); return badsyntax("need required parameters after --output_combined: "); } if(output_combined) { + if(!(argc>4+decision_directed+3)) { return badsyntax("need required parameters after --output_combined: "); } file_output_error = fopen(argv[4+decision_directed+1], "w"); file_output_dphase = fopen(argv[4+decision_directed+2], "w"); file_output_nco = fopen(argv[4+decision_directed+3], "w"); diff --git a/grc_tests/test_bpsk31_parts.grc b/grc_tests/test_bpsk31_parts.grc index ac3ad4d..6218910 100644 --- a/grc_tests/test_bpsk31_parts.grc +++ b/grc_tests/test_bpsk31_parts.grc @@ -257,7 +257,7 @@ commandline - csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 | csdr simple_agc_cc 0.0001 0.5 + csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 comment @@ -304,7 +304,7 @@ commandline - csdr bpsk_costas_loop_cc 48 + csdr bpsk_costas_loop_cc 0.05 0.707 comment @@ -316,7 +316,7 @@ _enabled - True + 0 _coordinate @@ -363,7 +363,7 @@ _enabled - 1 + 0 _coordinate @@ -390,6 +390,53 @@ cc + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr bandpass_fir_fft_cc $(csdr '=-(31.25)/1.5e3') $(csdr '=(31.25)/1.5e3') $(csdr '=31.25/1.5e3') | csdr simple_agc_cc 0.0001 0.5 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (568, 643) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_1 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + notebook @@ -422,7 +469,7 @@ labels - ['tab1', 'tab2', 'tab3', 'tab4'] + ['tab1', 'channel', 'tab3', 'tab4','bpf'] notebook @@ -667,7 +714,7 @@ _enabled - True + 0 fft_size @@ -742,6 +789,109 @@ 10 + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (832, 563) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_1_0 + + + notebook + nb, 4 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/32 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + window.hamming + + + y_divs + 10 + + + y_per_div + 10 + + wxgui_scopesink2 @@ -762,7 +912,7 @@ _enabled - True + 0 _coordinate @@ -849,7 +999,7 @@ _enabled - 1 + 0 _coordinate @@ -916,6 +1066,283 @@ Counts + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (832, 787) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0_0 + + + notebook + nb,4 + + + num_inputs + 1 + + + samp_rate + samp_rate/32 + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_waterfallsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + dynamic_range + 100 + + + _enabled + True + + + fft_rate + 15 + + + fft_size + 512 + + + freqvar + None + + + _coordinate + (840, 907) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_waterfallsink2_0 + + + notebook + nb,4 + + + ref_scale + 2.0 + + + ref_level + 0 + + + samp_rate + samp_rate/32 + + + title + Waterfall Plot + + + type + complex + + + win_size + + + + win + None + + + + wxgui_waterfallsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + dynamic_range + 100 + + + _enabled + True + + + fft_rate + 15 + + + fft_size + 512 + + + freqvar + None + + + _coordinate + (1120, 43) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_waterfallsink2_0_0 + + + notebook + nb,1 + + + ref_scale + 2.0 + + + ref_level + 0 + + + samp_rate + samp_rate/32 + + + title + Waterfall Plot + + + type + complex + + + win_size + + + + win + None + + audio_source_0 ha5kfu_execproc_xx_0 @@ -946,12 +1373,24 @@ 0 0 + + blocks_float_to_complex_0 + ha5kfu_execproc_xx_0_1 + 0 + 0 + blocks_float_to_complex_0 wxgui_fftsink2_0 0 0 + + blocks_float_to_complex_0 + wxgui_waterfallsink2_0_0 + 0 + 0 + ha5kfu_execproc_xx_0 blocks_deinterleave_0 @@ -982,4 +1421,22 @@ 0 0 + + ha5kfu_execproc_xx_0_1 + wxgui_fftsink2_0_1_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_1 + wxgui_scopesink2_0_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_1 + wxgui_waterfallsink2_0 + 0 + 0 + diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 6a6ec5d..a42452c 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -293,7 +293,7 @@ _enabled - True + 0 _coordinate @@ -336,7 +336,7 @@ _enabled - True + 0 _coordinate @@ -399,7 +399,7 @@ _enabled - True + 0 _coordinate @@ -446,7 +446,7 @@ _enabled - True + 0 _coordinate @@ -489,7 +489,7 @@ _enabled - True + 0 _coordinate @@ -575,6 +575,65 @@ 1 + + blocks_vector_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (32, 443) + + + _rotation + 0 + + + id + blocks_vector_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + complex + + + repeat + True + + + tags + [] + + + vlen + 1 + + + vector + (1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1) + + digital_costas_loop_cc @@ -650,7 +709,7 @@ _enabled - True + 1 _coordinate @@ -693,7 +752,7 @@ commandline - tee /s/costas_input | csdr bpsk_costas_loop_cc 0.1 0.707 --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output + tee /s/costas_input | CSDR_FIXED_BUFSIZE=1 csdr bpsk_costas_loop_cc 0.1 0.707 --dd --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output comment @@ -948,6 +1007,12 @@ 0 0 + + blocks_vector_source_x_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + digital_costas_loop_cc_0 wxgui_scopesink2_0_0_0 diff --git a/libcsdr.c b/libcsdr.c index bc3eef5..234a946 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1894,7 +1894,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, char* writefiles_path, int points_size, ...) { static int figure_output_counter = 0; int* points_z = (int*)malloc(sizeof(int)*points_size); @@ -1906,7 +1906,7 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error points_z[i] = va_arg(vl, int); points_color[i] = va_arg(vl, int); } - if(writefiles && !figure_output_counter) fprintf(stderr, "cf=figure();\n"); + if(writefiles_path && !figure_output_counter) fprintf(stderr, "cf=figure();\n"); fprintf(stderr, "N = %d;\nisig = [", signal_size); for(int i=0;i=0 to_return.last_correction_offset = 0; to_return.earlylate_ratio = 0.25; //0..0.5 + to_return.debug_writefiles_path = debug_writefiles_path; return to_return; } -void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase) -{ - state->debug_phase=debug_phase; -} - #define MTIMINGR_HDEBUG 0 void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state) @@ -1971,11 +1964,10 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float int num_samples_halfbit = state->decimation_rate / 2; int num_samples_quarterbit = state->decimation_rate / 4; int num_samples_earlylate_wing = num_samples_bit * state->earlylate_ratio; - int debug_i = state->debug_count; float error; int el_point_left_index, el_point_right_index, el_point_mid_index; int si = 0; - if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); + if(state->debug_every_nth>=0) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); { for(;;) @@ -2026,20 +2018,23 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float if(error>state->max_error) error=state->max_error; if(error<-state->max_error) error=-state->max_error; - if( state->debug_force || (state->debug_phase >= si && debug_i) ) + if(state->debug_every_nth>=0) { - debug_i--; - if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, - error, - current_bitstart_index, - correction_offset, - state->debug_writefiles, - 3, - el_point_left_index - current_bitstart_index, 'r', - el_point_right_index - current_bitstart_index, 'r', - el_point_mid_index - current_bitstart_index, 'r', - 0); + if(state->debug_every_nth==0 || state->debug_phase==0) + { + state->debug_phase = state->debug_every_nth; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + error, + current_bitstart_index, + correction_offset, + state->debug_writefiles_path, + 3, + el_point_left_index - current_bitstart_index, 'r', + el_point_right_index - current_bitstart_index, 'r', + el_point_mid_index - current_bitstart_index, 'r', + 0); + } + else state->debug_phase--; } int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; correction_offset = num_samples_halfbit * error_sign * error * state->loop_gain; @@ -2085,6 +2080,7 @@ void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; s->iir_temp = s->dphase = s->nco_phase = 0; + s->dphase_max=0.9*PI; //if it reached PI or -PI then it might actually hang and not come back } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s) @@ -2111,8 +2107,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, floa if(output_error) output_error[i]=error; s->dphase = error * s->alpha + s->iir_temp; s->iir_temp += error * s->beta; //iir_temp could be named current_freq. See Tom Rondeau's article for better understanding. - if(s->dphase>PI) s->dphase=PI; - if(s->dphase<-PI) s->dphase=-PI; + if(s->dphase>s->dphase_max) s->dphase=s->dphase_max; + if(s->dphase<-s->dphase_max) s->dphase=-s->dphase_max; if(output_dphase) output_dphase[i]=s->dphase; //fprintf(stderr, " error = %f; dphase = %f; nco_phase = %f;\n", error, s->dphase, s->nco_phase); diff --git a/libcsdr.h b/libcsdr.h index ff5810e..503d036 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -327,21 +327,19 @@ typedef struct timing_recovery_state_s int input_processed; int use_q; //use both I and Q for calculating the error int debug_phase; - int debug_count; - int debug_force; - int debug_writefiles; + int debug_every_nth; + char* debug_writefiles_path; int last_correction_offset; float earlylate_ratio; float loop_gain; float max_error; } timing_recovery_state_t; -timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q, float loop_gain, float max_error); +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q, float loop_gain, float max_error, int debug_every_nth, char* debug_writefiles_path); void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state); timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); -void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, char* writefiles_path, int points_size, ...); void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int n_psk); void duplicate_samples_ntimes_u8_u8(unsigned char* input, unsigned char* output, int input_size_bytes, int sample_size_bytes, int ntimes); complexf psk31_interpolate_sine_cc(complexf* input, complexf* output, int input_size, int interpolation, complexf last_input); @@ -372,6 +370,7 @@ typedef struct bpsk_costas_loop_state_s float iir_temp; float dphase; float nco_phase; + float dphase_max; } bpsk_costas_loop_state_t; void plain_interpolate_cc(complexf* input, complexf* output, int input_size, int interpolation);