Skip to content

Commit

Permalink
Merge pull request #984 from argilo/improve-rds
Browse files Browse the repository at this point in the history
Add symbol synchronization to RDS receiver
  • Loading branch information
argilo authored Oct 3, 2021
2 parents ea89a24 + 77dfc07 commit 4be7d66
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 33 deletions.
1 change: 1 addition & 0 deletions resources/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
NEW: Added SoapyPlutoSDR to DMG release.
NEW: Preliminary support for GNU Radio 3.10.
FIXED: Compatibility with case-sensitive filesystems on MacOS.
IMPROVED: Better reception of RDS signals.


2.14.4: Released December 28, 2020
Expand Down
75 changes: 56 additions & 19 deletions src/dsp/rx_rds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* https://gqrx.dk/
*
* Copyright 2011 Alexandru Csete OZ9AEC.
*
*
* Gqrx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
Expand All @@ -31,6 +31,10 @@
#include <stdarg.h>
#include "dsp/rx_rds.h"

#if GNURADIO_VERSION >= 0x030800
#include <gnuradio/digital/timing_error_detector_type.h>
#endif

static const int MIN_IN = 1; /* Minimum number of input streams. */
static const int MAX_IN = 1; /* Maximum number of input streams. */
static const int MIN_OUT = 1; /* Minimum number of output streams. */
Expand All @@ -56,34 +60,67 @@ rx_rds::rx_rds(double sample_rate)
gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (char))),
d_sample_rate(sample_rate)
{
d_taps2 = gr::filter::firdes::low_pass(2500.0, d_sample_rate, 2400, 2000);

f_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(1, d_taps2, 57000, d_sample_rate);
if (sample_rate != 240000.0) {
throw std::invalid_argument("RDS sample rate not supported");
}

d_rsmp_tap = gr::filter::firdes::low_pass(10, d_sample_rate, 2375, 2000);
d_rsmp = gr::filter::pfb_arb_resampler_ccf::make(2375/d_sample_rate,d_rsmp_tap,32);
d_fxff_tap = gr::filter::firdes::low_pass(1, d_sample_rate, 7500, 5000);
d_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(10, d_fxff_tap, 57000, d_sample_rate);

f_rrcf = gr::filter::firdes::root_raised_cosine(1, 2375, 2375, 1, 100);
d_bpf2 = gr::filter::fir_filter_ccf::make(1, f_rrcf);
int interpolation = 19;
int decimation = 24;
#if GNURADIO_VERSION < 0x30900
float rate = (float) interpolation / (float) decimation;
d_rsmp_tap = gr::filter::firdes::low_pass(interpolation, interpolation, rate * 0.45, rate * 0.1);
d_rsmp = gr::filter::rational_resampler_base_ccf::make(interpolation, decimation, d_rsmp_tap);
#else
d_rsmp = gr::filter::rational_resampler_ccf::make(interpolation, decimation);
#endif

int n_taps = 151;
d_rrcf = gr::filter::firdes::root_raised_cosine(1, 19000, 2375, 1, n_taps);

gr::digital::constellation_sptr p_c = gr::digital::constellation_bpsk::make()->base();
d_mpsk = gr::digital::constellation_receiver_cb::make(p_c, 1*M_PI/100.0, -0.06, 0.06);

b_koin = gr::blocks::keep_one_in_n::make(sizeof(unsigned char), 2);
#if GNURADIO_VERSION < 0x030800
d_bpf = gr::filter::fir_filter_ccf::make(1, d_rrcf);

d_ddbb = gr::digital::diff_decoder_bb::make(2);
d_agc = gr::analog::agc_cc::make(2e-3, 0.585 * 1.25, 53 * 1.25);

d_sync = gr::digital::clock_recovery_mm_cc::make(8, 0.25 * 0.175 * 0.175, 0.5, 0.175, 0.005);

rds_decoder = gr::rds::decoder::make(0, 0);
rds_parser = gr::rds::parser::make(1, 0, 0);
d_koin = gr::blocks::keep_one_in_n::make(sizeof(unsigned char), 2);
#else
d_rrcf_manchester = std::vector<float>(n_taps-8);
for (int n = 0; n < n_taps-8; n++) {
d_rrcf_manchester[n] = d_rrcf[n] - d_rrcf[n+8];
}
d_bpf = gr::filter::fir_filter_ccf::make(1, d_rrcf_manchester);

d_agc = gr::analog::agc_cc::make(2e-3, 0.585, 53);

d_sync = gr::digital::symbol_sync_cc::make(gr::digital::TED_ZERO_CROSSING, 16, 0.01, 1, 1, 0.1, 1, p_c);
#endif

d_mpsk = gr::digital::constellation_receiver_cb::make(p_c, 2*M_PI/100.0, -0.002, 0.002);

d_ddbb = gr::digital::diff_decoder_bb::make(2);

/* connect filter */
connect(self(), 0, f_fxff, 0);
connect(f_fxff, 0, d_rsmp, 0);
connect(d_rsmp, 0, d_bpf2, 0);
connect(d_bpf2, 0, d_mpsk, 0);
connect(d_mpsk, 0, b_koin, 0);
connect(b_koin, 0, d_ddbb, 0);
connect(self(), 0, d_fxff, 0);
connect(d_fxff, 0, d_rsmp, 0);
connect(d_rsmp, 0, d_bpf, 0);
connect(d_bpf, 0, d_agc, 0);
connect(d_agc, 0, d_sync, 0);
connect(d_sync, 0, d_mpsk, 0);

#if GNURADIO_VERSION < 0x030800
connect(d_mpsk, 0, d_koin, 0);
connect(d_koin, 0, d_ddbb, 0);
#else
connect(d_mpsk, 0, d_ddbb, 0);
#endif

connect(d_ddbb, 0, self(), 0);
}

Expand Down
45 changes: 31 additions & 14 deletions src/dsp/rx_rds.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,24 @@
#include <gnuradio/hier_block2.h>

#if GNURADIO_VERSION < 0x030800
#include <gnuradio/filter/fir_filter_ccc.h>
#include <gnuradio/filter/fir_filter_ccf.h>
#include <gnuradio/filter/fir_filter_fff.h>
#include <gnuradio/filter/freq_xlating_fir_filter_fcf.h>
#include <gnuradio/filter/freq_xlating_fir_filter_ccf.h>
#include <gnuradio/digital/clock_recovery_mm_cc.h>
#else
#include <gnuradio/filter/fir_filter_blk.h>
#include <gnuradio/filter/freq_xlating_fir_filter.h>
#include <gnuradio/digital/symbol_sync_cc.h>
#endif
#include <gnuradio/filter/pfb_arb_resampler_ccf.h>

#if GNURADIO_VERSION < 0x30800
#include <gnuradio/filter/rational_resampler_base_ccf.h>
#elif GNURADIO_VERSION < 0x30900
#include <gnuradio/filter/rational_resampler_base.h>
#else
#include <gnuradio/filter/rational_resampler.h>
#endif

#include <gnuradio/analog/agc_cc.h>
#include <gnuradio/digital/constellation_receiver_cb.h>
#include <gnuradio/blocks/keep_one_in_n.h>
#include <gnuradio/digital/diff_decoder_bb.h>
Expand Down Expand Up @@ -83,24 +90,34 @@ class rx_rds : public gr::hier_block2
{

public:
rx_rds(double sample_rate=96000.0);
rx_rds(double sample_rate=240000.0);
~rx_rds();

void set_param(double low, double high, double trans_width);

private:
std::vector<gr_complex> d_taps;
std::vector<float> d_taps2;
std::vector<float> d_fxff_tap;
std::vector<float> d_rsmp_tap;
gr::filter::fir_filter_ccf::sptr d_bpf2;
gr::filter::freq_xlating_fir_filter_fcf::sptr f_fxff;
gr::filter::pfb_arb_resampler_ccf::sptr d_rsmp;
std::vector<float> f_rrcf;
gr::filter::fir_filter_ccf::sptr d_bpf;
gr::filter::freq_xlating_fir_filter_fcf::sptr d_fxff;

#if GNURADIO_VERSION < 0x030900
gr::filter::rational_resampler_base_ccf::sptr d_rsmp;
#else
gr::filter::rational_resampler_ccf::sptr d_rsmp;
#endif

std::vector<float> d_rrcf;
std::vector<float> d_rrcf_manchester;
gr::analog::agc_cc::sptr d_agc;
#if GNURADIO_VERSION < 0x030800
gr::digital::clock_recovery_mm_cc::sptr d_sync;
gr::blocks::keep_one_in_n::sptr d_koin;
#else
gr::digital::symbol_sync_cc::sptr d_sync;
#endif
gr::digital::constellation_receiver_cb::sptr d_mpsk;
gr::blocks::keep_one_in_n::sptr b_koin;
gr::digital::diff_decoder_bb::sptr d_ddbb;
gr::rds::decoder::sptr rds_decoder;
gr::rds::parser::sptr rds_parser;

double d_sample_rate;
};
Expand Down

0 comments on commit 4be7d66

Please sign in to comment.