Amateur Radio Asked by Oleksandr Kravchuk on September 27, 2021
This is my first ever experience with GNU Radio. I am trying to implement a simple FM receiver shown below with its C++ API.
I seem to have pedantically deconstructed this receiver into its smallest components and implemented them with GNU Radio’s C++ API but does not work.
It runs but I hear no sound which makes me suspect I have misconfigured some component, missed to set some sort of gain, etc.
Any feedback is appreciated. Thank you.
#include <gnuradio/analog/quadrature_demod_cf.h>
#include <gnuradio/audio/sink.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/filter/fir_filter_blk.h>
#include <gnuradio/filter/firdes.h>
#include <gnuradio/filter/freq_xlating_fir_filter.h>
#include <gnuradio/filter/iir_filter_ffd.h>
#include <gnuradio/filter/pfb_arb_resampler_ccf.h>
#include <gnuradio/top_block.h>
#include <osmosdr/source.h>
#include <gnuradio/analog/simple_squelch_cc.h>
void calculate_iir_taps(double tau, float d_quad_rate);
std::vector<double> d_fftaps; /*! Feed forward taps. */
std::vector<double> d_fbtaps; /*! Feed back taps. */
using namespace gr;
int main(int argc, char** argv)
{
int sample_rate = 2.88e6; // audio card sample rate
int audio_decimation = 5;
// Build a top block that ill contain flowgraph blocks
top_block_sptr top_block = make_top_block("fm_radio");
osmosdr::source::sptr osmocom = osmosdr::source::make("rtl=0,repeat=true,throttle=true");
osmocom->set_center_freq(96.3e6);
osmocom->set_sample_rate(sample_rate);
osmocom->set_gain(20, 0);
osmocom->set_if_gain(20, 0);
osmocom->set_bb_gain(20, 0);
// Low pass filter
unsigned int flt_size = 1024;
std::vector<float> low_pass_filter = filter::firdes::low_pass(1, sample_rate, 100e3, 10e3);
filter::pfb_arb_resampler_ccf::sptr d_filter = filter::pfb_arb_resampler_ccf::make(288, low_pass_filter, flt_size);
// WBFM Receive
int max_dev = 75e3;
int quad_rate = 288e3;
float fm_demod_gain = quad_rate / (2 * M_PI * max_dev);
analog::quadrature_demod_cf::sptr d_quad = analog::quadrature_demod_cf::make(fm_demod_gain);
d_fftaps.resize(2);
d_fbtaps.resize(2);
calculate_iir_taps(50.0e-6, quad_rate);
filter::iir_filter_ffd::sptr d_deemph =
filter::iir_filter_ffd::make(d_fftaps, d_fbtaps, false);
int audio_rate = quad_rate / audio_decimation;
int width_of_transition_band = audio_rate / 32;
std::vector<float> d_pll_taps =
filter::firdes::low_pass(1, quad_rate, audio_rate / 2 - width_of_transition_band, width_of_transition_band);
filter::fir_filter_fff::sptr low_pass_filter2 =
filter::fir_filter_fff::make(1, d_pll_taps);
// Rational Resamplifier - might not be needed hence not used atm
filter::freq_xlating_fir_filter_ccf::sptr filt =
gr::filter::freq_xlating_fir_filter_ccf::make(288, {1}, 0.0, sample_rate);
audio::sink::sptr sink = audio::sink::make(48000);
top_block->connect(osmocom, 0, d_filter, 0);
top_block->connect(d_filter, 0, d_quad, 0);
top_block->connect(d_quad, 0, d_deemph, 0);
top_block->connect(d_deemph, 0, low_pass_filter2, 0);
top_block->connect(low_pass_filter2, 0, sink, 0);
top_block->run();
return 0;
}
void calculate_iir_taps(double tau, float d_quad_rate)
{
if (tau > 1.0e-9)
{
// copied from fm_emph.py in gr-analog
double w_c; // Digital corner frequency
double w_ca; // Prewarped analog corner frequency
double k, z1, p1, b0;
double fs = d_quad_rate;
w_c = 1.0 / tau;
w_ca = 2.0 * fs * tan(w_c / (2.0 * fs));
// Resulting digital pole, zero, and gain term from the bilinear
// transformation of H(s) = w_ca / (s + w_ca) to
// H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
k = -w_ca / (2.0 * fs);
z1 = -1.0;
p1 = (1.0 + k) / (1.0 - k);
b0 = -k / (1.0 - k);
d_fftaps[0] = b0;
d_fftaps[1] = -z1 * b0;
d_fbtaps[0] = 1.0;
d_fbtaps[1] = -p1;
}
else
{
d_fftaps[0] = 1.0;
d_fftaps[1] = 0.0;
d_fbtaps[0] = 0.0;
d_fbtaps[1] = 0.0;
}
}
CMakeLists.txt
for those wanting to try it out:
cmake_minimum_required(VERSION 3.8)
include_directories(
${GNURADIO_ALL_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
$ENV{HOME}/.grc_gnuradio
)
set(GR_LIBRARIES
boost_system
gnuradio-blocks
gnuradio-filter
gnuradio-analog
gnuradio-audio
gnuradio-runtime
gnuradio-pmt
gnuradio-osmosdr
log4cpp
)
add_executable(fm_radio fm_radio.cpp)
target_link_libraries(fm_radio ${GR_LIBRARIES})
There is at least one error in your code that would result in silence:
std::vector<double> d_fftaps; /*! Feed forward taps. */
std::vector<double> d_fbtaps; /*! Feed back taps. */
d_fftaps.resize(2);
d_fbtaps.resize(2);
filter::iir_filter_ffd::sptr d_deemph =
filter::iir_filter_ffd::make(d_fftaps, d_fbtaps, false);
The taps of this IIR filter are all zero (because you resize
d the vectors but did not write any values into them), so the output signal will be always zero.
As a quick test to see if this is the sole problem, you can remove the deemphasis filter block entirely; the audio frequency response will be wrong but you'll still be able to tell the difference.
You could also remove the squelch block temporarily, as one fewer thing to go wrong. The absolute minimum you need for a receiver that will pass some coherent signal is a decimating low-pass filter to select the desired signal and adapt the sample rate, and the quadrature demodulator; everything else is refinement.
Answered by Kevin Reid AG6YO on September 27, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP