diff --git a/Makefile b/Makefile index dfe3df2..905bf3a 100644 --- a/Makefile +++ b/Makefile @@ -98,3 +98,5 @@ emcc-beautify: bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi' codequality: @bash -c 'if [ `cat csdr.c | grep badsyntax | grep -v return | wc -l` -ne 1 ]; then echo "error at code quality check: badsyntax() used in csdr.c without return."; exit 1; else exit 0; fi' +v: + vim csdr.c libcsdr.c diff --git a/csdr.c b/csdr.c index feff244..2951d8f 100755 --- a/csdr.c +++ b/csdr.c @@ -124,7 +124,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_u8_u8\n" " octave_complex_c \n" -" timing_recovery_cc [--add_q [--output_error | --output_indexes | --octave ]] \n" +" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave ]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -133,7 +133,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc \n" +" bpsk_costas_loop_cc [--dd | --decision_directed]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_resonator_c [window [--octave]]\n" @@ -148,6 +148,7 @@ char usage[]= " add_n_zero_samples_at_beginning_f \n" " generic_slicer_f_u8 \n" " plain_interpolate_cc \n" +" add_const_cc \n" " ?\n" " =\n" " \n" @@ -396,7 +397,7 @@ int main(int argc, char *argv[]) clone_(the_bufsize); //After sending the buffer size out, just copy stdin to stdout } - if(!strcmp(argv[1],"clone")) + if(!strcmp(argv[1],"clone") || !strcmp(argv[1],"REM")) { if(!sendbufsize(initialize_buffers())) return -2; clone_(the_bufsize); @@ -2525,7 +2526,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --output_indexes | --octave ]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [loop_gain [max_error [--add_q] [--output_error | --output_indexes | --octave ]]] { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2536,26 +2537,32 @@ int main(int argc, char *argv[]) sscanf(argv[3],"%d",&decimation); if(decimation<=4 || decimation&3) return badsyntax("decimation factor should be a positive integer divisible by 4"); - int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + float loop_gain = 0.5; + if(argc>4) sscanf(argv[4],"%f",&loop_gain); + + float max_error = 2; + if(argc>5) sscanf(argv[5],"%f",&max_error); + + int add_q = !!(argc>=7 && !strcmp(argv[6], "--add_q")); int debug_n = 0; int output_error = 0; int output_indexes = 0; - if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); + 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"); - if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; + if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); - if(argc>=6 && !strcmp(argv[5], "--output_indexes")) output_indexes = 1; + if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_indexes")) output_indexes = 1; unsigned* sampled_indexes = NULL; if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); - timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error); int debug_i=0; state.debug_writefiles = 1; @@ -2756,14 +2763,24 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] { - float samples_per_bits; - if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); - sscanf(argv[2],"%f",&samples_per_bits); - if(samples_per_bits<=0) return badsyntax("samples_per_bits should be > 0"); + float loop_bandwidth; + if(argc<=2) return badsyntax("need required parameter (loop_bandwidth)"); + sscanf(argv[2],"%f",&loop_bandwidth); - bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); + float damping_factor; + if(argc<=3) return badsyntax("need required parameter (damping_factor)"); + sscanf(argv[3],"%f",&damping_factor); + + float gain; + if(argc<=4) return badsyntax("need required parameter (gain)"); + sscanf(argv[4],"%f",&gain); + + int decision_directed = !!(argc>5 && (!strcmp(argv[5], "--dd") || !strcmp(argv[5], "--decision_directed"))); + + bpsk_costas_loop_state_t state; + init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth, gain); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); @@ -3083,13 +3100,17 @@ int main(int argc, char *argv[]) return 0; } + int output_size=0; + FREAD_C; for(;;) { FEOF_CHECK; - FREAD_C; - apply_real_fir_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, taps, num_taps); - FWRITE_C; + output_size = apply_real_fir_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, taps, num_taps); + fwrite(output_buffer, sizeof(complexf), output_size, stdout); + //fprintf(stderr, "os = %d, is = %d, num_taps = %d\n", output_size, the_bufsize, num_taps); TRY_YIELD; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+output_size,(the_bufsize-output_size)*sizeof(complexf)); + fread(((complexf*)input_buffer)+(the_bufsize-output_size), sizeof(complexf), output_size, stdin); } } @@ -3128,6 +3149,26 @@ int main(int argc, char *argv[]) return 0; } + if(!strcmp(argv[1], "add_const_cc")) // + { + complexf x; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%f",&iofv(x)); + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%f",&qofv(x)); + + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_C; + add_const_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, x); + FWRITE_C; + TRY_YIELD; + } + return 0; + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 9d2262e..0abca69 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -89,7 +89,7 @@ _coordinate - (480, 3) + (416, 3) _rotation @@ -207,7 +207,7 @@ _coordinate - (712, 571) + (32, 275) _rotation @@ -235,7 +235,7 @@ notebook - nb, 1 + num_steps @@ -270,7 +270,54 @@ value - 2**18 + 2**13 + + + + analog_const_source_x + + alias + + + + comment + + + + const + 0 + + + affinity + + + + _enabled + True + + + _coordinate + (288, 203) + + + _rotation + 0 + + + id + analog_const_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + float @@ -293,7 +340,7 @@ _coordinate - (16, 187) + (40, 147) _rotation @@ -325,7 +372,7 @@ type - byte + int repeat @@ -333,7 +380,7 @@ - blocks_complex_to_float + blocks_add_const_vxx alias @@ -343,51 +390,8 @@ - affinity - - - - _enabled - 0 - - - _coordinate - (960, 265) - - - _rotation - 0 - - - id - blocks_complex_to_float_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - - - blocks_interleave - - alias - - - - blocksize - 1 - - - comment - + const + -1 affinity @@ -395,11 +399,11 @@ _enabled - 0 + True _coordinate - (1168, 265) + (336, 131) _rotation @@ -407,7 +411,7 @@ id - blocks_interleave_0 + blocks_add_const_vxx_0 type @@ -421,17 +425,13 @@ minoutbuf 0 - - num_streams - 2 - vlen 1 - blocks_multiply_const_vxx + blocks_float_to_complex alias @@ -440,10 +440,6 @@ comment - - const - amplitude - affinity @@ -454,7 +450,7 @@ _coordinate - (496, 155) + (496, 161) _rotation @@ -462,11 +458,7 @@ id - blocks_multiply_const_vxx_0 - - - type - complex + blocks_float_to_complex_0 maxoutbuf @@ -481,6 +473,53 @@ 1 + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (200, 131) + + + _rotation + 0 + + + id + blocks_int_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 0.5 + + + vlen + 1 + + blocks_throttle @@ -501,7 +540,7 @@ _coordinate - (488, 211) + (496, 355) _rotation @@ -556,7 +595,7 @@ _coordinate - (928, 537) + (864, 345) _rotation @@ -587,73 +626,6 @@ False - - digital_psk_mod - - alias - - - - comment - - - - affinity - - - - differential - True - - - _enabled - True - - - excess_bw - 0.35 - - - _coordinate - (208, 179) - - - _rotation - 0 - - - mod_code - "none" - - - id - digital_psk_mod_0 - - - log - False - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - constellation_points - 2 - - - samples_per_symbol - 2 - - - verbose - False - - freq_xlating_fir_filter_xxx @@ -662,7 +634,7 @@ center_freq - -freq_add + freq_add comment @@ -678,11 +650,11 @@ _enabled - 1 + True _coordinate - (688, 251) + (232, 331) _rotation @@ -713,41 +685,6 @@ ccc - - ha5kfu_execproc_sink_f - - alias - - - - commandline - zsh -c \"csdr timing_recovery_cc GARDNER 16 --add_q --octave 1 1>/dev/null 2> >(octave -i)\" - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (976, 379) - - - _rotation - 0 - - - id - ha5kfu_execproc_sink_f_0 - - ha5kfu_execproc_xx @@ -756,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc 16 + csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 1 comment @@ -772,7 +709,7 @@ _coordinate - (128, 411) + (840, 163) _rotation @@ -795,286 +732,6 @@ cc - - ha5kfu_execproc_xx - - alias - - - - commandline - csdr timing_recovery_cc GARDNER 16 --add_q | csdr fir_interpolate_cc 8 - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (400, 411) - - - _rotation - 0 - - - id - ha5kfu_execproc_xx_0_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - type - cc - - - - notebook - - alias - - - - comment - - - - _enabled - True - - - _coordinate - (16, 83) - - - _rotation - 0 - - - grid_pos - - - - id - nb - - - labels - ['1', '2'] - - - notebook - - - - style - wx.NB_TOP - - - - wxgui_fftsink2 - - avg_alpha - 0 - - - average - False - - - baseband_freq - 0 - - - alias - - - - comment - - - - affinity - - - - _enabled - 0 - - - fft_size - 1024 - - - freqvar - None - - - _coordinate - (960, 59) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_fftsink2_0 - - - notebook - - - - peak_hold - False - - - ref_level - 0 - - - ref_scale - 2.0 - - - fft_rate - 15 - - - samp_rate - samp_rate - - - title - FFT Plot - - - type - complex - - - win_size - - - - win - None - - - y_divs - 10 - - - y_per_div - 10 - - - - wxgui_scopesink2 - - ac_couple - False - - - alias - - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (632, 379) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_scopesink2_0 - - - notebook - - - - num_inputs - 1 - - - samp_rate - (samp_rate/256)*8 - - - t_scale - 0 - - - title - After timing recovery - - - trig_mode - wxgui.TRIG_MODE_AUTO - - - type - complex - - - v_offset - 0 - - - v_scale - 0 - - - win_size - - - - xy_mode - True - - - y_axis_label - Counts - - wxgui_scopesink2 @@ -1099,7 +756,7 @@ _coordinate - (432, 507) + (1104, 123) _rotation @@ -1115,7 +772,7 @@ notebook - nb, 0 + num_inputs @@ -1123,7 +780,7 @@ samp_rate - (samp_rate/256)*8 + samp_rate t_scale @@ -1131,7 +788,7 @@ title - BPSK modulated signal after Costas Loop + After Costas Loop (csdr) trig_mode @@ -1186,7 +843,7 @@ _coordinate - (1112, 491) + (1112, 299) _rotation @@ -1200,93 +857,6 @@ id wxgui_scopesink2_0_0_0 - - notebook - nb, 1 - - - num_inputs - 1 - - - samp_rate - (samp_rate/256)*8 - - - t_scale - 0 - - - title - After Costas Loop - - - trig_mode - wxgui.TRIG_MODE_AUTO - - - type - complex - - - v_offset - 0 - - - v_scale - 0 - - - win_size - - - - xy_mode - True - - - y_axis_label - Counts - - - - wxgui_scopesink2 - - ac_couple - False - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (688, 11) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_scopesink2_0_1 - notebook @@ -1305,7 +875,7 @@ title - BPSK modulated signal with frequency offset + After Costas Loop (GNU Radio) trig_mode @@ -1329,7 +899,7 @@ xy_mode - False + True y_axis_label @@ -1337,38 +907,44 @@ - analog_random_source_x_0 - digital_psk_mod_0 + analog_const_source_x_0 + blocks_float_to_complex_0 0 - 0 - - - blocks_complex_to_float_0 - blocks_interleave_0 - 1 1 - blocks_complex_to_float_0 - blocks_interleave_0 + analog_random_source_x_0 + blocks_int_to_float_0 0 0 - blocks_interleave_0 - ha5kfu_execproc_sink_f_0 + blocks_add_const_vxx_0 + blocks_float_to_complex_0 0 0 - blocks_multiply_const_vxx_0 - blocks_throttle_0 + blocks_float_to_complex_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + + + blocks_int_to_float_0 + blocks_add_const_vxx_0 0 0 blocks_throttle_0 - freq_xlating_fir_filter_xxx_0 + digital_costas_loop_cc_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 0 0 @@ -1378,45 +954,9 @@ 0 0 - - digital_psk_mod_0 - blocks_multiply_const_vxx_0 - 0 - 0 - freq_xlating_fir_filter_xxx_0 - blocks_complex_to_float_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - digital_costas_loop_cc_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - ha5kfu_execproc_xx_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - wxgui_fftsink2_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - wxgui_scopesink2_0_1 - 0 - 0 - - - ha5kfu_execproc_xx_0 - ha5kfu_execproc_xx_0_0 + blocks_throttle_0 0 0 @@ -1426,10 +966,4 @@ 0 0 - - ha5kfu_execproc_xx_0_0 - wxgui_scopesink2_0 - 0 - 0 - diff --git a/libcsdr.c b/libcsdr.c index 15a147b..d06bb5d 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -114,6 +114,16 @@ float (*firdes_get_window_kernel(window_t window))(float) |___/ */ +void normalize_fir_f(float* input, float* output, int length) +{ + //Normalize filter kernel + float sum=0; + for(int i=0;i2) error=2; - if(error<-2) error=-2; + 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) ) { debug_i--; @@ -2033,7 +2035,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float 0); } int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; - correction_offset = num_samples_halfbit * error_sign * (error/2); + correction_offset = num_samples_halfbit * error_sign * error * state->loop_gain; current_bitstart_index += num_samples_bit + correction_offset; if(si>=input_size) { @@ -2067,6 +2069,45 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } +void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth, float gain) +{ + float bandwidth_omega = 2*M_PI*bandwidth; + s->alpha = (damping_factor*2*bandwidth_omega)/gain; + float sampling_rate = 1; //the bandwidth is normalized to the sampling rate + s->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*gain); + s->iir_temp = s->dphase = s->nco_phase = 0; +} + +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* s) +{ + for(int i=0;inco_phase); + cmult(&output[i], &input[i], &nco_sample); + float error = 0; + if(s->decision_directed) + { + float output_phase = atan2(qof(output,i),iof(output,i)); + if (fabs(output_phase)PI) error -= 2*PI; + } + } + else error = iof(output,i)*qof(output,i); + s->dphase = error * s->alpha + s->iir_temp; + s->iir_temp += error * s->beta; + + //step NCO + s->nco_phase += s->dphase; + while(s->nco_phase>2*PI) s->nco_phase-=2*PI; + } +} + +#if 0 bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) { bpsk_costas_loop_state_t state; @@ -2088,7 +2129,7 @@ bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) return state; } -void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) +void bpsk_costas_loop_c1mc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) { int debug = 0; if(debug) fprintf(stderr, "costas:\n"); @@ -2122,6 +2163,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk } } +#endif + void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain) { float rate_1minus=1-rate; @@ -2205,8 +2248,8 @@ int apply_real_fir_cc(complexf* input, complexf* output, int input_size, float* float acci = 0, accq = 0; for(int ti=0;ti