diff --git a/src/applications/gqrx/dcontrols.cpp b/src/applications/gqrx/dcontrols.cpp index 11c3a14af1..4c21f37f11 100644 --- a/src/applications/gqrx/dcontrols.cpp +++ b/src/applications/gqrx/dcontrols.cpp @@ -3505,7 +3505,7 @@ c_def() .v3_config_group("receiver") .config_key("rds_gomega") .v_type(V_DOUBLE) - .def(0.) + .def(-4.3) .min(-50.) .max(1.) .step(0.1) @@ -3543,7 +3543,7 @@ c_def() .v3_config_group("receiver") .config_key("rds_gmu") .v_type(V_DOUBLE) - .def(0.) + .def(-1.4) .min(-50.) .max(1.) .step(0.1) @@ -3562,7 +3562,7 @@ c_def() .v3_config_group("receiver") .config_key("rds_agc") .v_type(V_DOUBLE) - .def(0.002) + .def(0.01) .min(0.0) .max(10.0) .step(1e-4) @@ -3598,9 +3598,9 @@ c_def() .v3_config_group("receiver") .config_key("rds_fxff_bw") .v_type(V_DOUBLE) - .def(1000.) + .def(1110.) .min(500.) - .max(1170.) + .max(2000.) .step(10.0) .frac_digits(1) , @@ -3616,7 +3616,7 @@ c_def() .v3_config_group("receiver") .config_key("rds_fxff_tw") .v_type(V_DOUBLE) - .def(500.) + .def(300.) .min(50.) .max(800.) .step(10.0) @@ -3634,7 +3634,7 @@ c_def() .v3_config_group("receiver") .config_key("rds_omega_lim") .v_type(V_DOUBLE) - .def(2.5e-4) + .def(5.0e-4) .min(1e-5) .max(1e-3) .step(1e-5) @@ -3652,12 +3652,50 @@ c_def() .v3_config_group("receiver") .config_key("rds_dll_bw") .v_type(V_DOUBLE) - .def(0.4) + .def(1.8) .min(0.01) .max(4.0) .step(0.01) .frac_digits(2) , +c_def() + .idx(C_RDS_CL_BW) + .name("RDS_CL_BW") + .title("CL BW/SNR:") + .title_placement(c_def::grid_placement(PLACE_NEXT,0)) + .placement(c_def::grid_placement(PLACE_SAME,PLACE_NEXT)) + .hint("Costas loop bandwidth log unit") + .g_type(G_DOUBLESPINBOX) + .dock(D_RDS) + .scope(S_VFO) + .v3_config_group("receiver") + .config_key("rds_cl_bw") + .v_type(V_DOUBLE) + .def(-28.) + .min(-50.) + .max(-10.) + .step(0.1) + .frac_digits(1) + , +c_def() + .idx(C_RDS_PHASE_SNR) + .name("RDS_PHASE_SNR") + .title("snr:") + .title_placement(c_def::grid_placement(PLACE_NONE,0)) + .placement(c_def::grid_placement(PLACE_SAME,PLACE_NEXT)) + .hint("SNR(phase), db") + .g_type(G_LABEL) + .dock(D_RDS) + .scope(S_VFO) + .v_type(V_DOUBLE) + .def(0.) + .min(0.) + .max(0.) + .step(0.1) + .frac_digits(4) + .writable(false) + .event(true) + , }; std::array, C_COUNT> conf_base::observers{}; diff --git a/src/applications/gqrx/dcontrols.h b/src/applications/gqrx/dcontrols.h index dc7caf4525..6b094e2b4d 100644 --- a/src/applications/gqrx/dcontrols.h +++ b/src/applications/gqrx/dcontrols.h @@ -225,6 +225,8 @@ enum c_id C_RDS_FXFF_TW, C_RDS_OMEGA_LIM, C_RDS_DLL_BW, + C_RDS_CL_BW, + C_RDS_PHASE_SNR, C_COUNT }; diff --git a/src/dsp/clock_recovery.cpp b/src/dsp/clock_recovery.cpp index 31062480aa..398d86d503 100644 --- a/src/dsp/clock_recovery.cpp +++ b/src/dsp/clock_recovery.cpp @@ -96,7 +96,6 @@ int clock_recovery_el_cc::general_work(int noutput_items, assert(d_mu <= 1.0); float mm_val = 0; - constexpr float corr_alfa=0.001f; while (oo < noutput_items && ii < ni) { @@ -170,12 +169,10 @@ int clock_recovery_el_cc::general_work(int noutput_items, } if(out1) out1[oo] = d_skip?0:1; - if(d_corr0>=d_corr180) - { - out[oo++] = d_interp.interpolate(&in[ii], d_mu); - }else{ - out[oo++] = d_interp.interpolate(&in[ci180], c_mu180); - } + gr_complex outval=(d_corr0>=d_corr180)?d_interp.interpolate(&in[ii], d_mu):d_interp.interpolate(&in[ci180], c_mu180); + out[oo++]=outval; + d_am_i+=(log10f(std::max(std::abs(real(outval)),0.00001f))-d_am_i)*corr_alfa; + d_am_q+=(log10f(std::max(std::abs(imag(outval)),0.00001f))-d_am_q)*corr_alfa; d_omega = d_omega + d_gain_omega * mm_val; d_omega = diff --git a/src/dsp/clock_recovery.h b/src/dsp/clock_recovery.h index af9ca794b0..1a82db7020 100644 --- a/src/dsp/clock_recovery.h +++ b/src/dsp/clock_recovery.h @@ -40,7 +40,8 @@ typedef std::shared_ptr sptr; gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) override; - float mu() const { return (std::abs(d_corr0)>std::abs(d_corr180))?d_corr0:-d_corr180; } + float mu() const { return (std::abs(d_corr0)>std::abs(d_corr180))?d_corr0*10.f:-d_corr180*10.f; } +// float mu() const { return (std::abs(d_corr0)>std::abs(d_corr180))?(d_am_i-d_am_q)*10.f:(d_am_q-d_am_i)*10.f; } float omega() const { return d_omega; } float gain_mu() const { return d_gain_mu; } float gain_omega() const { return d_gain_omega; } @@ -56,6 +57,8 @@ typedef std::shared_ptr sptr; void set_dllalfa(float v) { d_dllalfa=v; } private: + static constexpr float corr_alfa{0.001f}; + float d_mu; // fractional sample position [0.0, 1.0] float d_omega; // nominal frequency float d_gain_omega; // gain for adjusting omega @@ -83,6 +86,8 @@ typedef std::shared_ptr sptr; float d_corr180{0.0}; float d_dllbw{0.4f}; float d_dllalfa{0.2f}; + float d_am_i{0.f}; + float d_am_q{0.f}; gr_complex slicer_0deg(gr_complex sample) { diff --git a/src/dsp/rds/decoder_impl.cc b/src/dsp/rds/decoder_impl.cc index 0b2b5aa58b..bca415582d 100644 --- a/src/dsp/rds/decoder_impl.cc +++ b/src/dsp/rds/decoder_impl.cc @@ -139,7 +139,7 @@ unsigned int decoder_impl::calc_syndrome(unsigned long message, return (lreg & ((1<>10,16)^(grp[0]&0x3ff); const bit_locator & bl=locator[s^offset_word[0]]; @@ -160,6 +162,10 @@ int decoder_impl::process_group(unsigned * grp, int thr, unsigned char * offs_ch if(offs_chars) if(bl.w>0) offs_chars[0]='x'; + if(bl.w==1) + g1++; + if(bl.w==2) + g2++; ret+=bl.w; d_block0errs=bl.w; @@ -170,6 +176,10 @@ int decoder_impl::process_group(unsigned * grp, int thr, unsigned char * offs_ch if(offs_chars) if(bl1.w>thr) offs_chars[1]='x'; + if(bl1.w==1) + g1++; + if(bl1.w==2) + g2++; ret+=bl1.w; s=calc_syndrome(grp[2]>>10,16)^(grp[2]&0x3ff); @@ -182,6 +192,10 @@ int decoder_impl::process_group(unsigned * grp, int thr, unsigned char * offs_ch if(offs_chars) if(bl2.w>thr) offs_chars[2]='x'; + if(bl2.w==1) + g1++; + if(bl2.w==2) + g2++; ret+=bl2.w; }else{ if(offs_chars) @@ -191,6 +205,10 @@ int decoder_impl::process_group(unsigned * grp, int thr, unsigned char * offs_ch if(offs_chars) if(bl4.w>thr) offs_chars[2]='x'; + if(bl4.w==1) + g1++; + if(bl4.w==2) + g2++; ret+=bl4.w; } @@ -201,7 +219,14 @@ int decoder_impl::process_group(unsigned * grp, int thr, unsigned char * offs_ch if(offs_chars) if(bl3.w>thr) offs_chars[3]='x'; + if(bl3.w==1) + g1++; + if(bl3.w==2) + g2++; ret+=bl3.w; + + if(good_grp) + *good_grp=g1*3+g2; return ret; } @@ -300,19 +325,31 @@ int decoder_impl::work (int noutput_items, uint16_t pi = (next_grp[0]>>10)^locators[0]; if(d_block0errs<5) { - constexpr char weights[]={5,2,1,1,1}; + constexpr uint8_t weights[]={19,9,5,4,3}; d_pi_a[pi].weight+=weights[d_block0errs]; d_pi_a[pi].count++; int bit_offset=d_bit_counter-d_pi_a[pi].lastseen; d_pi_a[pi].lastseen=d_bit_counter; - if((d_pi_a[pi].weight>=10)&&(d_block0errs==0)&&((bit_offset+1)%GROUP_SIZE < 3)) + /* + if((d_pi_a[pi].weight>=22)&&(d_block0errs<3)&&((bit_offset+1)%GROUP_SIZE < 3)) + d_pi_a[pi].weight+=2; + if((d_pi_a[pi].weight>=22)&&(d_block0errs<5)&&(bit_offset%GROUP_SIZE == 0)) d_pi_a[pi].weight+=4; - if(d_pi_a[pi].weight<13) + if((d_pi_a[pi].weight>=22)&&(d_block0errs<3)&&(bit_offset%GROUP_SIZE == 0)) + d_pi_a[pi].weight+=6; + if((d_pi_a[pi].weight>=22)&&(d_block0errs==0)&&(bit_offset%GROUP_SIZE == 0)) + d_pi_a[pi].weight+=15; + */ + if((d_pi_a[pi].weight>=22)&&((bit_offset+1)%GROUP_SIZE < 3)) + d_pi_a[pi].weight+=weights[d_block0errs]>>2; + if((d_pi_a[pi].weight>=22)&&(bit_offset%GROUP_SIZE == 0)) + d_pi_a[pi].weight+=weights[d_block0errs]>>1; + if(d_pi_a[pi].weight<55) { if(d_pi_a[pi].weight>d_max_weight) { d_max_weight=d_pi_a[pi].weight; - printf("?[%04x] %d %d %d\n",pi,d_pi_a[pi].weight,d_block0errs,d_next_errs); + printf("?[%04x] %d (%d,%d) %d %d\n",pi,((bit_offset+1)%GROUP_SIZE < 3),d_pi_a[pi].weight,d_pi_a[pi].count,d_block0errs,d_next_errs); d_matches[pi].push_back(grp_array(next_grp)); prev_grp[0]=pi; prev_grp[1]=d_pi_a[pi].weight; @@ -321,7 +358,7 @@ int decoder_impl::work (int noutput_items, decode_group(prev_grp,d_next_errs); } }else{ - printf("+[%04x] %d %d %d!!\n",pi,d_pi_a[pi].weight,d_block0errs,d_next_errs); + printf("+[%04x] %d (%d,%d) %d %d!!\n",pi,((bit_offset+1)%GROUP_SIZE < 3),d_pi_a[pi].weight,d_pi_a[pi].count,d_block0errs,d_next_errs); auto & prv=d_matches[pi]; for(unsigned k=0;k>=2; - d_pi_a[jj].count>>=2; - } + if(jj==pi) + { + d_pi_a[jj].weight>>=1; + d_pi_a[jj].count>>=1; + }else{ + d_pi_a[jj].weight>>=2; + d_pi_a[jj].count>>=2; + } d_pi_bitcnt=0; - d_max_weight>>=2; - //d_state=SYNC; + d_max_weight>>=1; + d_state=SYNC; d_best_pi=pi; bit_counter=1; continue; } d_pi_bitcnt++; - if(d_pi_bitcnt>BLOCK_SIZE*100) + if(d_pi_bitcnt>BLOCK_SIZE*50) { d_pi_bitcnt=0; for(int jj=0;jj<65536;jj++) @@ -372,7 +413,7 @@ int decoder_impl::work (int noutput_items, if(d_corr) continue; } - bit_errors=process_group(good_group, ecc_max, offset_chars, locators); + bit_errors=process_group(good_group, ecc_max, offset_chars, locators, &good_grp); char sync_point='E'; if(d_state != FORCE_SYNC) { @@ -396,22 +437,34 @@ int decoder_impl::work (int noutput_items, sync_point='N'; } } - if((bit_errors > 15)&&(d_state==SYNC)) + if(d_state==SYNC) { - if(d_counter > 512) + if(good_grp>=4) { - d_state=NO_SYNC; - d_counter = 0; - printf("- NO Sync errors: %d\n",d_curr_errs); - }else - d_counter +=bit_errors; - } + d_counter>>=2; + //d_counter=0; + } + if(good_grp>=3) + { + d_counter>>=1; + } + if(bit_errors > 15) + { + if(d_counter > 512) + { + d_state=NO_SYNC; + d_counter = 0; + printf("- NO Sync errors: %d\n",d_curr_errs); + } + } } + d_counter +=bit_errors; if(d_state != SYNC) continue; }else{ d_state = SYNC; offset_chars[0]='F'; sync_point='F'; + d_counter = 0; } // if(bit_errors>5) // continue; diff --git a/src/dsp/rds/decoder_impl.h b/src/dsp/rds/decoder_impl.h index 29073e3d18..573ae78c80 100644 --- a/src/dsp/rds/decoder_impl.h +++ b/src/dsp/rds/decoder_impl.h @@ -42,8 +42,8 @@ class decoder_impl : public decoder }; struct pi_stats { - char count; - char weight; + uint8_t count; + uint8_t weight; unsigned lastseen; }; struct grp_array @@ -66,7 +66,7 @@ class decoder_impl : public decoder static unsigned int calc_syndrome(unsigned long, unsigned char); void decode_group(unsigned *, int); static std::array build_locator(); - int process_group(unsigned * grp, int thr=0, unsigned char * offs_chars=nullptr, uint16_t * loc=nullptr); + int process_group(unsigned * grp, int thr=0, unsigned char * offs_chars=nullptr, uint16_t * loc=nullptr, int * good_grp=nullptr); int bit_counter; unsigned long lastseen_offset_counter, reg; diff --git a/src/dsp/rx_rds.cpp b/src/dsp/rx_rds.cpp index d176cb474f..7a602d4288 100644 --- a/src/dsp/rx_rds.cpp +++ b/src/dsp/rx_rds.cpp @@ -141,7 +141,12 @@ typedef std::shared_ptr sptr; d_iir+=(real(b[1])-d_iir)*fv; out[k]=d_prev^tmp; d_prev=tmp; - #else + #elif 0 + auto m1_0=b[0]-b[1]-b[2]+b[3]; + auto m0_0=b[0]-b[1]+b[2]-b[3]; + int f0=std::abs(m1_0)>std::abs(m0_0); + out[k]=f0; + #else constexpr float fv=0.2f; float iir=d_iir; float p[4]; @@ -157,14 +162,27 @@ typedef std::shared_ptr sptr; int f0=std::abs(m1_0)>std::abs(m0_0); out[k]=f0; #endif + d_i_mag+=(log10f(std::max(std::abs(real(b[0])),0.0001f))*10.f-d_i_mag)*corr_alfa; + d_q_mag+=(log10f(std::max(std::abs(imag(b[0])),0.0001f))*10.f-d_q_mag)*corr_alfa; + d_i_mag+=(log10f(std::max(std::abs(real(b[1])),0.0001f))*10.f-d_i_mag)*corr_alfa; + d_q_mag+=(log10f(std::max(std::abs(imag(b[1])),0.0001f))*10.f-d_q_mag)*corr_alfa; } return noutput_items; } + float snr() const + { + return d_i_mag-d_q_mag; + } + private: + static constexpr float corr_alfa{0.001f}; + float d_iir{0.f}; int d_prev{0}; + float d_i_mag{0.f}; + float d_q_mag{0.f}; }; @@ -197,7 +215,7 @@ class soft_bpsk: public gr::digital::constellation_bpsk soft_bpsk(): constellation_bpsk() { }; - float acc{0.f}; + float acc{0.f}; }; static const int MIN_IN = 1; /* Minimum number of input streams. */ @@ -220,14 +238,15 @@ rx_rds::rx_rds(double sample_rate, bool encorr) gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (char))), d_sample_rate(sample_rate) { - if (sample_rate != 240000.0) { + constexpr int decim1=8; + if (sample_rate < 128000.0) { throw std::invalid_argument("RDS sample rate not supported"); } // d_fxff_tap = gr::filter::firdes::low_pass(1, d_sample_rate, 5500, 3500); d_fxff_tap = gr::filter::firdes::band_pass(1, d_sample_rate, 2375.0/2.0-d_fxff_bw, 2375.0/2.0+d_fxff_bw, d_fxff_tw/*,gr::filter::firdes::WIN_BLACKMAN_HARRIS*/); - d_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(10, d_fxff_tap, 57000, d_sample_rate); + d_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(decim1, d_fxff_tap, 57000, d_sample_rate); update_fxff_taps(); #if GNURADIO_VERSION < 0x030900 @@ -239,7 +258,9 @@ rx_rds::rx_rds(double sample_rate, bool encorr) #endif int n_taps = 151*5; - d_rrcf = gr::filter::firdes::root_raised_cosine(1, (d_sample_rate*float(d_interpolation))/float(d_decimation*10), 2375.0*0.95, 1, n_taps); + d_rrcf = gr::filter::firdes::root_raised_cosine(1, (d_sample_rate*float(d_interpolation))/float(d_decimation*decim1), 2375.0*0.97, 1, n_taps); +// auto tmp_rrcf=gr::filter::firdes::root_raised_cosine(1, (d_sample_rate*float(d_interpolation))/float(d_decimation*decim1), 2375.0*0.5, 1, n_taps); +// volk_32f_x2_add_32f(d_rrcf.data(),d_rrcf.data(),tmp_rrcf.data(),n_taps); d_rrcf_manchester = std::vector(n_taps-8); for (int n = 0; n < n_taps-8; n++) { d_rrcf_manchester[n] = d_rrcf[n] - d_rrcf[n+8]; @@ -247,19 +268,19 @@ rx_rds::rx_rds(double sample_rate, bool encorr) //gr::digital::constellation_sptr p_c = gr::digital::constellation_bpsk::make()->base(); gr::digital::constellation_sptr p_c = soft_bpsk::make()->base(); - auto corr=iir_corr::make((d_sample_rate*d_interpolation*104.0*2.0)/(d_decimation*23750.0),0.1); + auto corr=iir_corr::make((d_sample_rate*d_interpolation*104.0*2.0)/(d_decimation*float(2375.0*decim1)),0.1); int agc_samp = (d_sample_rate*d_interpolation*0.8f)/(d_decimation*23750.f); - d_costas_loop = gr::digital::costas_loop_cc::make(2.0*M_PI/2000.0,2); - //d_costas_loop->set_damping_factor(0.75); - d_costas_loop->set_min_freq(-0.005); - d_costas_loop->set_max_freq(0.005); + d_costas_loop = gr::digital::costas_loop_cc::make(powf(10.f,-2.8f),2); + //d_costas_loop->set_damping_factor(0.85); + d_costas_loop->set_min_freq(-0.0003*float(decim1)); + d_costas_loop->set_max_freq(0.0003*float(decim1)); #if GNURADIO_VERSION < 0x030800 d_bpf = gr::filter::fir_filter_ccf::make(1, d_rrcf); d_agc = make_rx_agc_cc(0,40, agc_samp, 0, agc_samp, 0); - d_sync = clock_recovery_el_cc::make((d_sample_rate*d_interpolation)/(d_decimation*23750.f), d_gain_omega, 0.5, d_gain_mu, d_omega_lim); + d_sync = clock_recovery_el_cc::make((d_sample_rate*d_interpolation)/(d_decimation*float(2375.f*decim1)), d_gain_omega, 0.5, d_gain_mu, d_omega_lim); d_koin = gr::blocks::keep_one_in_n::make(sizeof(unsigned char), 2); #else @@ -276,20 +297,25 @@ rx_rds::rx_rds(double sample_rate, bool encorr) /* connect filter */ connect(self(), 0, d_fxff, 0); - connect(d_fxff, 0, d_rsmp, 0); - connect(d_rsmp, 0, d_agc, 0); + if(d_decimation==d_interpolation) + { + connect(d_fxff, 0, d_agc, 0); + }else{ + connect(d_fxff, 0, d_rsmp, 0); + connect(d_rsmp, 0, d_agc, 0); + } #if 1 - connect(d_agc, 0, d_bpf, 0); - connect(d_bpf, 0, d_costas_loop, 0); + connect(d_agc, 0, d_costas_loop, 0); + connect(d_costas_loop, 0, d_bpf, 0); #else connect(d_agc, 0, d_costas_loop, 0); #endif if(encorr) { - connect(d_costas_loop, 0, corr, 0); + connect(d_bpf, 0, corr, 0); connect(corr, 0, d_sync, 0); }else - connect(d_costas_loop, 0, d_sync, 0); + connect(d_bpf, 0, d_sync, 0); // connect(d_agc, 0, d_sync, 0); #if 0 connect(d_sync, 0, d_mpsk, 0); @@ -303,10 +329,10 @@ rx_rds::rx_rds(double sample_rate, bool encorr) connect(d_ddbb, 0, self(), 0); #else - auto dm=dbpsk_det_cb::make(); - connect(d_sync, 0, dm, 0); - connect(d_sync, 1, dm, 1); - connect(dm, 0, self(), 0); + d_det=dbpsk_det_cb::make(); + connect(d_sync, 0, d_det, 0); + connect(d_sync, 1, d_det, 1); + connect(d_det, 0, self(), 0); #endif #if 0 { @@ -400,16 +426,17 @@ void rx_rds::trig() changed_value(C_RDS_CR_OMEGA, d_index, d_sync->omega()); changed_value(C_RDS_CR_MU, d_index, d_sync->mu()); changed_value(C_RDS_CL_FREQ, d_index, d_costas_loop->get_frequency()*1000.); + changed_value(C_RDS_PHASE_SNR, d_index, phase_snr()); } void rx_rds::update_fxff_taps() { //lock(); #if 0 - d_fxff_tap = gr::filter::firdes::low_pass(1, d_sample_rate, d_fxff_bw*3., d_fxff_tw); + d_fxff_tap = gr::filter::firdes::low_pass(1, d_sample_rate, d_fxff_bw+2375.f-1000.f, d_fxff_tw); #else d_fxff_tap = gr::filter::firdes::band_pass(1, d_sample_rate, - 2375.0/2.0-d_fxff_bw, 2375.0/2.0+d_fxff_bw, d_fxff_tw); + 2375.0/2.0-std::min(d_fxff_bw,1170.0f), 2375.0/2.0+std::min(d_fxff_bw,1170.0f), d_fxff_tw); #endif d_fxff->set_taps(d_fxff_tap); //unlock(); @@ -418,15 +445,19 @@ void rx_rds::update_fxff_taps() void rx_rds::set_omega_lim(float v) { d_sync->set_omega_lim(d_omega_lim=v); - return; - disconnect(d_agc, 0, d_sync, 0); - disconnect(d_sync, 0, d_mpsk, 0); - d_sync = clock_recovery_el_cc::make((d_sample_rate*d_interpolation)/(d_decimation*23750.f), d_gain_omega, 0.5, d_gain_mu, d_omega_lim=v); - connect(d_agc, 0, d_sync, 0); - connect(d_sync, 0, d_mpsk, 0); } void rx_rds::set_dll_bw(float v) { d_sync->set_dllbw(v); } + +void rx_rds::set_cl_bw(float v) +{ + d_costas_loop->set_loop_bandwidth(powf(10.f,v/10.)); +} + +float rx_rds::phase_snr() const +{ + return dynamic_cast(d_det.get())->snr(); +} diff --git a/src/dsp/rx_rds.h b/src/dsp/rx_rds.h index 93750becac..59020d49ee 100644 --- a/src/dsp/rx_rds.h +++ b/src/dsp/rx_rds.h @@ -83,6 +83,8 @@ class rx_rds : public gr::hier_block2, public conf_notifier void set_fxff_tw(float tw) {d_fxff_tw=tw; update_fxff_taps();} void set_omega_lim(float v); void set_dll_bw(float v); + void set_cl_bw(float v); + float phase_snr() const; private: void update_fxff_taps(); @@ -109,16 +111,17 @@ class rx_rds : public gr::hier_block2, public conf_notifier gr::digital::constellation_decoder_cb::sptr d_mpsk; gr::digital::diff_decoder_bb::sptr d_ddbb; gr::digital::costas_loop_cc::sptr d_costas_loop; + gr::basic_block_sptr d_det; double d_sample_rate; int d_index; - constexpr static int d_interpolation = 19; - constexpr static int d_decimation = 24; - float d_fxff_tw{500.0f}; - float d_fxff_bw{1000.0f}; - float d_gain_mu{0.175*0.2}; - float d_gain_omega{0.25 * 0.175 * 0.000175}; - float d_omega_lim{0.00040}; + constexpr static int d_interpolation = 1; + constexpr static int d_decimation = 1; + float d_fxff_tw{300.0f}; + float d_fxff_bw{950.0f}; + float d_gain_mu{powf(10.f,-1.4f)}; + float d_gain_omega{powf(10.f,-4.3f)}; + float d_omega_lim{0.00050}; }; diff --git a/src/receivers/vfo.cpp b/src/receivers/vfo.cpp index 3fc5eaa53c..14a6c006ea 100644 --- a/src/receivers/vfo.cpp +++ b/src/receivers/vfo.cpp @@ -473,6 +473,12 @@ bool vfo_s::set_rds_dll_bw(const c_def::v_union & v) return true; } +bool vfo_s::set_rds_cl_bw(const c_def::v_union & v) +{ + d_rds_cl_bw = v; + return true; +} + void vfo_s::restore_settings(vfo_s& from, bool force) { c_def::v_union v(0); @@ -554,6 +560,7 @@ void vfo_s::restore_settings(vfo_s& from, bool force) from.get_rds_ecc_max(v); set_rds_ecc_max(v); from.get_rds_omega_lim(v); set_rds_omega_lim(v); from.get_rds_dll_bw(v); set_rds_dll_bw(v); + from.get_rds_cl_bw(v); set_rds_cl_bw(v); from.get_test(v);set_test(v); } @@ -585,6 +592,7 @@ bool vfo_s::get_rds_clock(c_def::v_union &) const {return false;} bool vfo_s::get_rds_af(c_def::v_union &) const {return false;} bool vfo_s::get_rds_errors(c_def::v_union &) const {return false;} bool vfo_s::get_rds_cl_freq(c_def::v_union &) const {return false;} +bool vfo_s::get_rds_phase_snr(c_def::v_union &) const {return false;} int vfo_s::conf_initializer() { @@ -731,6 +739,7 @@ int vfo_s::conf_initializer() getters[C_RDS_ALTFREQ]=&vfo_s::get_rds_af; getters[C_RDS_BIT_ERRORS]=&vfo_s::get_rds_errors; getters[C_RDS_CL_FREQ]=&vfo_s::get_rds_cl_freq; + getters[C_RDS_PHASE_SNR]=&vfo_s::get_rds_phase_snr; getters[C_RDS_AGC]=&vfo_s::get_rds_agc; setters[C_RDS_AGC]=&vfo_s::set_rds_agc; getters[C_RDS_GMU]=&vfo_s::get_rds_gmu; @@ -747,6 +756,8 @@ int vfo_s::conf_initializer() setters[C_RDS_OMEGA_LIM]=&vfo_s::set_rds_omega_lim; getters[C_RDS_DLL_BW]=&vfo_s::get_rds_dll_bw; setters[C_RDS_DLL_BW]=&vfo_s::set_rds_dll_bw; + getters[C_RDS_CL_BW]=&vfo_s::get_rds_cl_bw; + setters[C_RDS_CL_BW]=&vfo_s::set_rds_cl_bw; return 0; } diff --git a/src/receivers/vfo.h b/src/receivers/vfo.h index 9f02a1b1ab..e38d1274db 100644 --- a/src/receivers/vfo.h +++ b/src/receivers/vfo.h @@ -202,6 +202,7 @@ typedef class vfo_s: public conf_dispatchers bool get_rds_ecc_max(c_def::v_union & v) const { v=d_rds_ecc_max; return true; } bool get_rds_omega_lim(c_def::v_union & v) const { v=d_rds_omega_lim; return true; } bool get_rds_dll_bw(c_def::v_union & v) const { v=d_rds_dll_bw; return true; } + bool get_rds_cl_bw(c_def::v_union & v) const { v=d_rds_cl_bw; return true; } //setters virtual void set_offset(int offset); @@ -292,6 +293,7 @@ typedef class vfo_s: public conf_dispatchers virtual bool get_rds_af(c_def::v_union &) const; virtual bool get_rds_errors(c_def::v_union &) const; virtual bool get_rds_cl_freq(c_def::v_union &) const; + virtual bool get_rds_phase_snr(c_def::v_union &) const; virtual bool set_rds_agc(const c_def::v_union & v); virtual bool set_rds_gmu(const c_def::v_union & v); virtual bool set_rds_gomega(const c_def::v_union & v); @@ -300,6 +302,7 @@ typedef class vfo_s: public conf_dispatchers virtual bool set_rds_ecc_max(const c_def::v_union & v); virtual bool set_rds_omega_lim(const c_def::v_union & v); virtual bool set_rds_dll_bw(const c_def::v_union & v); + virtual bool set_rds_cl_bw(const c_def::v_union & v); public: struct comp @@ -370,14 +373,15 @@ typedef class vfo_s: public conf_dispatchers bool d_rds_on; int d_testval; - float d_rds_agc{0.002f}; - float d_rds_gomega{0.f}; - float d_rds_gmu{0.f}; - float d_rds_fxff_bw{1000.f}; - float d_rds_fxff_tw{500.f}; + float d_rds_agc{0.01f}; + float d_rds_gomega{-1.6f}; + float d_rds_gmu{-0.6f}; + float d_rds_fxff_bw{950.f}; + float d_rds_fxff_tw{300.f}; int d_rds_ecc_max{0}; - float d_rds_omega_lim{2.5e-4f}; - float d_rds_dll_bw{0.4f}; + float d_rds_omega_lim{5.e-4f}; + float d_rds_dll_bw{1.8f}; + float d_rds_cl_bw{-28.f}; } vfo; diff --git a/src/receivers/wfmrx.cpp b/src/receivers/wfmrx.cpp index 69048163dc..e991765544 100644 --- a/src/receivers/wfmrx.cpp +++ b/src/receivers/wfmrx.cpp @@ -341,6 +341,12 @@ bool wfmrx::get_rds_cl_freq(c_def::v_union &to) const return true; } +bool wfmrx::get_rds_phase_snr(c_def::v_union &to) const +{ + to=rds->phase_snr(); + return true; +} + bool wfmrx::set_rds_agc(const c_def::v_union & v) { receiver_base_cf::set_rds_agc(v); @@ -351,14 +357,14 @@ bool wfmrx::set_rds_agc(const c_def::v_union & v) bool wfmrx::set_rds_gmu(const c_def::v_union & v) { receiver_base_cf::set_rds_gmu(v); - rds->set_gain_mu(powf(10.f, v)*0.175); + rds->set_gain_mu(powf(10.f, v)); return true; } bool wfmrx::set_rds_gomega(const c_def::v_union & v) { receiver_base_cf::set_rds_gomega(v); - rds->set_gain_omega(powf(10.f, v)*0.007); + rds->set_gain_omega(powf(10.f, v)); return true; } @@ -386,21 +392,20 @@ bool wfmrx::set_rds_ecc_max(const c_def::v_union & v) bool wfmrx::set_rds_omega_lim(const c_def::v_union & v) { receiver_base_cf::set_rds_omega_lim(v); - if(d_rds_on) - lock(); rds->set_omega_lim(d_rds_omega_lim); - if(d_rds_on) - unlock(); return true; } bool wfmrx::set_rds_dll_bw(const c_def::v_union & v) { receiver_base_cf::set_rds_dll_bw(v); - if(d_rds_on) - lock(); rds->set_dll_bw(d_rds_dll_bw); - if(d_rds_on) - unlock(); + return true; +} + +bool wfmrx::set_rds_cl_bw(const c_def::v_union & v) +{ + receiver_base_cf::set_rds_cl_bw(v); + rds->set_cl_bw(d_rds_cl_bw); return true; } diff --git a/src/receivers/wfmrx.h b/src/receivers/wfmrx.h index 452eeceed5..c0d0528e03 100644 --- a/src/receivers/wfmrx.h +++ b/src/receivers/wfmrx.h @@ -85,6 +85,7 @@ class wfmrx : public receiver_base_cf bool get_rds_af(c_def::v_union &) const override; bool get_rds_errors(c_def::v_union &) const override; bool get_rds_cl_freq(c_def::v_union &) const override; + bool get_rds_phase_snr(c_def::v_union &) const override; bool set_rds_agc(const c_def::v_union & v) override; bool set_rds_gmu(const c_def::v_union & v) override; bool set_rds_gomega(const c_def::v_union & v) override; @@ -93,6 +94,7 @@ class wfmrx : public receiver_base_cf bool set_rds_ecc_max(const c_def::v_union & v) override; bool set_rds_omega_lim(const c_def::v_union & v) override; bool set_rds_dll_bw(const c_def::v_union & v) override; + bool set_rds_cl_bw(const c_def::v_union & v) override; private: void start_rds_decoder();