Skip to content

Commit b9fe590

Browse files
committed
Fixed resampling.
1 parent 8ce380b commit b9fe590

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ add_library(auto_sdr_libs STATIC ${SOURCES})
4545
add_executable(auto_sdr "sources/main.cpp")
4646
target_link_libraries(auto_sdr
4747
auto_sdr_libs
48+
gnuradio::gnuradio-analog
4849
gnuradio::gnuradio-blocks
4950
gnuradio::gnuradio-fft
5051
gnuradio::gnuradio-filter
@@ -60,6 +61,7 @@ add_executable(auto_sdr_test ${TEST_SOURCES} "tests/test_main.cpp")
6061
target_link_libraries(auto_sdr_test
6162
gtest
6263
auto_sdr_libs
64+
gnuradio::gnuradio-analog
6365
gnuradio::gnuradio-blocks
6466
gnuradio::gnuradio-fft
6567
gnuradio::gnuradio-filter

sources/config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
constexpr auto INITIAL_DELAY = std::chrono::milliseconds(1000); // delay after first start sdr device to start processing
1414
constexpr auto PERFORMANCE_LOGGER_INTERVAL = 1000; // print stats every n frames
1515
constexpr auto RECORDER_FLUSH_INTERVAL = std::chrono::milliseconds(100); // flush recordings to mqtt every 2 * n bytes
16-
constexpr auto RESAMPLER_THRESHOLD = 125; // max interpolation or decimation factor of RESAMPLER
1716
constexpr auto TRANSMISSION_MAX_TIME = std::chrono::minutes(10); // break transmission if longer that
1817

1918
// SCANNING SETTINGS
@@ -33,6 +32,9 @@ constexpr auto SPECTROGRAM_PREFERRED_MAX_STEP = 1000; //
3332
constexpr auto SPECTROGRAM_MAX_FFT = 16384; // spectrogram fft limit
3433
constexpr auto SPECTROGRAM_SEND_INTERVAL = std::chrono::milliseconds(1000); // send spectrogram data interval
3534

35+
// RECORDER SETTINGS
36+
constexpr auto RECORDER_SAMPLE_RATE_DECIMATOR = 2000000;
37+
3638
// SOURCE AND RECORDING NAMES
3739
constexpr auto GAIN_TESTER_SOURCE_NAME = "gain tester";
3840
constexpr auto GAIN_TESTER_RECORDING_NAME = "auto";

sources/radio/recorder.cpp

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
#include "recorder.h"
22

33
#include <config.h>
4+
#include <gnuradio/analog/agc2_cc.h>
45
#include <gnuradio/blocks/complex_to_interleaved_char.h>
56
#include <gnuradio/blocks/file_sink.h>
67
#include <gnuradio/blocks/stream_to_vector.h>
8+
#include <gnuradio/filter/fir_filter.h>
9+
#include <gnuradio/filter/fir_filter_blk.h>
10+
#include <gnuradio/filter/firdes.h>
11+
#include <gnuradio/filter/freq_xlating_fir_filter.h>
12+
#include <gnuradio/filter/pfb_arb_resampler_ccf.h>
713
#include <gnuradio/filter/rational_resampler.h>
814
#include <gnuradio/zeromq/sub_source.h>
915
#include <logger.h>
@@ -13,6 +19,35 @@
1319

1420
constexpr auto LABEL = "recorder";
1521

22+
// most blocks based on
23+
// https://github.com/gqrx-sdr/gqrx/blob/master/src/applications/gqrx/receiver.cpp
24+
25+
Block buildDecimator(Frequency sampleRate, Frequency shift, int decim) {
26+
if (1 < decim) {
27+
const auto filter = gr::filter::freq_xlating_fir_filter_ccf::make(decim, {1}, 0.0, sampleRate);
28+
const auto outRate = sampleRate / decim;
29+
const auto lpf_cutoff = 120e3;
30+
filter->set_center_freq(shift);
31+
filter->set_taps(gr::filter::firdes::low_pass(1.0, sampleRate, lpf_cutoff, outRate - 2 * lpf_cutoff, gr::fft::window::WIN_BLACKMAN_HARRIS));
32+
return filter;
33+
} else {
34+
auto shiftBlock = gr::blocks::rotator_cc::make();
35+
shiftBlock->set_phase_inc(2.0l * M_PIl * (static_cast<double>(shift) / static_cast<float>(sampleRate)));
36+
return shiftBlock;
37+
}
38+
}
39+
40+
Block buildResampler(Frequency inputRate, Frequency outputRate) {
41+
const auto rate = static_cast<double>(outputRate) / inputRate;
42+
const auto cutoff = rate > 1.0f ? 0.4 : 0.4 * (double)rate;
43+
const auto trans_width = rate > 1.0f ? 0.2 : 0.2 * (double)rate;
44+
const auto flt_size = 32;
45+
const auto d_taps = gr::filter::firdes::low_pass(flt_size, flt_size, cutoff, trans_width);
46+
auto resampler = gr::filter::pfb_arb_resampler_ccf::make(rate, d_taps, flt_size);
47+
resampler->set_output_multiple(4096);
48+
return resampler;
49+
}
50+
1651
Recorder::Recorder(const Config& config, const Device& device, const std::string& zeromq, Frequency sampleRate, const Recording& recording, std::function<void(const nlohmann::json&)> send)
1752
: m_config(config), m_sampleRate(sampleRate), m_recording(recording), m_send(send), m_tb(gr::make_top_block("recorder")), m_connector(m_tb) {
1853
Logger::info(
@@ -26,18 +61,14 @@ Recorder::Recorder(const Config& config, const Device& device, const std::string
2661

2762
auto source = gr::zeromq::sub_source::make(sizeof(gr_complex), 1, const_cast<char*>(zeromq.c_str()));
2863
std::vector<Block> blocks;
29-
m_shiftBlock = gr::blocks::rotator_cc::make();
3064
blocks.push_back(source);
31-
blocks.push_back(m_shiftBlock);
32-
33-
Block lastResampler;
34-
for (const auto& [factor1, factor2] : getResamplersFactors(m_sampleRate, m_recording.bandwidth, RESAMPLER_THRESHOLD)) {
35-
Logger::debug(LABEL, "rational resampler factors: {}, {}", colored(GREEN, "{}", factor1), colored(GREEN, "{}", factor2));
36-
lastResampler = gr::filter::rational_resampler<gr_complex, gr_complex, gr_complex>::make(factor1, factor2);
37-
blocks.push_back(lastResampler);
38-
}
65+
const auto decim = std::max(1, static_cast<int>(sampleRate / RECORDER_SAMPLE_RATE_DECIMATOR));
66+
blocks.push_back(buildDecimator(m_sampleRate, m_recording.shift(), decim));
67+
blocks.push_back(buildResampler(sampleRate / decim, m_recording.bandwidth));
68+
auto raw = blocks.back();
3969

4070
const auto samplesSize = roundUp(m_recording.bandwidth * RECORDER_FLUSH_INTERVAL.count() / 1000, 4096);
71+
blocks.push_back(gr::analog::agc2_cc::make(2e-3, 2e-3, 0.585, 53));
4172
blocks.push_back(gr::blocks::complex_to_interleaved_char::make(true, 127.0));
4273
blocks.push_back(gr::blocks::stream_to_vector::make(sizeof(SimpleComplex), samplesSize));
4374
m_buffer = std::make_shared<Buffer<SimpleComplex>>("RecorderBuffer", samplesSize);
@@ -46,12 +77,11 @@ Recorder::Recorder(const Config& config, const Device& device, const std::string
4677

4778
if (config.dumpRecording()) {
4879
const auto fileName = getRawFileName(config.workDir(), device, "recording", "fc", m_recording.recordingFrequency, m_recording.bandwidth);
49-
m_connector.connect<Block>(lastResampler, gr::blocks::file_sink::make(sizeof(gr_complex), fileName.c_str()));
80+
m_connector.connect<Block>(raw, gr::blocks::file_sink::make(sizeof(gr_complex), fileName.c_str()));
5081
}
5182

5283
m_firstDataTime = getTime();
5384
m_lastDataTime = m_firstDataTime;
54-
m_shiftBlock->set_phase_inc(2.0l * M_PIl * (static_cast<double>(-m_recording.shift()) / static_cast<float>(m_sampleRate)));
5585
m_tb->start();
5686
}
5787

sources/radio/recorder.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ class Recorder {
3232
const std::function<void(const nlohmann::json&)> m_send;
3333

3434
std::shared_ptr<gr::top_block> m_tb;
35-
std::shared_ptr<gr::blocks::rotator_cc> m_shiftBlock;
3635
std::shared_ptr<Buffer<SimpleComplex>> m_buffer;
3736
Connector m_connector;
3837
std::chrono::milliseconds m_firstDataTime;

0 commit comments

Comments
 (0)