From 761b3682828a2dbfb2f85ee9320944e3a05613b9 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sat, 18 Jan 2014 20:44:17 +0100 Subject: [PATCH] Set RTL AGC mode by default (no improvement), with command-line option to disable. --- NOTES.txt | 4 +--- RtlSdrSource.cc | 10 +++++++++- RtlSdrSource.h | 5 +++-- TODO.txt | 3 --- main.cc | 23 ++++++++++++++++++++--- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/NOTES.txt b/NOTES.txt index 893ec77..34a67f8 100644 --- a/NOTES.txt +++ b/NOTES.txt @@ -29,9 +29,7 @@ settings during a run. The LNA gain seems to switch between ~ 24 dB and ~ 34 dB without intermediate steps. With RTL in AGC mode, the level of the digital sample stream is normalized -to -6 dB FS. -Unknown whether this is an analog or digital gain stage. -Does this improve SNR or not? +to -6 dB FS. Unknown whether this is an analog or digital gain stage. At first I suspected that AGC mode may be a cooperation between the RTL and the Elonics tuner. I thought that the RTL would monitor the level and send diff --git a/RtlSdrSource.cc b/RtlSdrSource.cc index 4790cef..295e726 100644 --- a/RtlSdrSource.cc +++ b/RtlSdrSource.cc @@ -39,7 +39,8 @@ RtlSdrSource::~RtlSdrSource() bool RtlSdrSource::configure(uint32_t sample_rate, uint32_t frequency, int tuner_gain, - int block_length) + int block_length, + bool agcmode) { int r; @@ -78,6 +79,13 @@ bool RtlSdrSource::configure(uint32_t sample_rate, } } + // set RTL AGC mode + r = rtlsdr_set_agc_mode(m_dev, int(agcmode)); + if (r < 0) { + m_error = "rtlsdr_set_agc_mode failed"; + return false; + } + // set block length m_block_length = (block_length < 4096) ? 4096 : (block_length > 1024 * 1024) ? 1024 * 1024 : diff --git a/RtlSdrSource.h b/RtlSdrSource.h index eb3e194..0dda338 100644 --- a/RtlSdrSource.h +++ b/RtlSdrSource.h @@ -25,13 +25,14 @@ public: * * sample_rate :: desired sample rate in Hz. * frequency :: desired center frequency in Hz. - * gain :: desired tuner gain index, or -1 for auto-gain. + * tuner_gain :: desired tuner gain in 0.1 dB, or -1 for auto-gain. * block_length :: preferred number of samples per block. * * Return true for success, false if an error occurred. */ bool configure(uint32_t sample_rate, uint32_t frequency, int tuner_gain, - int block_length=default_block_length); + int block_length=default_block_length, + bool agcmode=false); /** Return current sample frequency in Hz. */ uint32_t get_sample_rate(); diff --git a/TODO.txt b/TODO.txt index 9ff5f34..c90a61a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,12 +1,9 @@ * (experiment) consider reducing IF filter bandwidth to ~ 80 kHz * (experiment) consider downsampling IF signal before FM detection -* (experiment) try if RTL AGC mode improves FM decoding * (feature) support 'M' 'k' suffixes for sample rates and tuning frequency * (feature) implement stereo pilot pulse-per-second * (speedup) maybe replace high-order FIR downsampling filter with 2nd order butterworth followed by lower order FIR filter * figure out why we sometimes lose stereo lock -* it looks like IF level sometimes varies so much that it saturates the receiver; perhaps this can be solved by dynamically managing the hardware gain in response to level measurements -* (quality) figure out if hardware gain settings can improve weak stations * (feature) implement RDS decoding * (quality) consider FM demodulation with PLL instead of phase discriminator diff --git a/main.cc b/main.cc index 92f4d96..e5b5ecb 100644 --- a/main.cc +++ b/main.cc @@ -217,6 +217,7 @@ void usage() " -d devidx RTL-SDR device index, 'list' to show device list (default 0)\n" " -s ifrate IF sample rate in Hz (default 1000000, min 900001)\n" " -r pcmrate Audio sample rate in Hz (default 48000 Hz)\n" + " -a 0 Disable RTL AGC mode (default 1 = enabled)\n" " -M Disable stereo decoding\n" " -R filename Write audio data as raw S16_LE samples\n" " use filename '-' to write to stdout\n" @@ -266,6 +267,7 @@ int main(int argc, char **argv) string filename; string alsadev("default"); double bufsecs = -1; + int agcmode = 1; fprintf(stderr, "SoftFM - Software decoder for FM broadcast radio with RTL-SDR\n"); @@ -275,6 +277,7 @@ int main(int argc, char **argv) { "dev", 1, NULL, 'd' }, { "ifrate", 1, NULL, 's' }, { "pcmrate", 1, NULL, 'r' }, + { "agc", 1, NULL, 'a' }, { "mono", 0, NULL, 'M' }, { "raw", 1, NULL, 'R' }, { "wav", 1, NULL, 'W' }, @@ -284,7 +287,7 @@ int main(int argc, char **argv) int c, longindex; while ((c = getopt_long(argc, argv, - "f:d:s:r:MR:W:P::b:", + "f:d:s:r:MR:W:P::b:a:", longopts, &longindex)) >= 0) { switch (c) { case 'f': @@ -328,13 +331,24 @@ int main(int argc, char **argv) badarg("-b"); } break; + case 'a': + if (!parse_opt(optarg, agcmode)) { + badarg("-a"); + } + break; default: usage(); - fprintf(stderr, "ERROR: Unknown option\n"); + fprintf(stderr, "ERROR: Invalid command line options\n"); exit(1); } } + if (optind < argc) { + usage(); + fprintf(stderr, "ERROR: Invalid command line options\n"); + exit(1); + } + vector devnames = RtlSdrSource::get_device_names(); if (devidx < 0 || (unsigned int)devidx >= devnames.size()) { fprintf(stderr, "ERROR: invalid device index %d\n", devidx); @@ -377,7 +391,8 @@ int main(int argc, char **argv) } // Configure RTL-SDR device and start streaming. - rtlsdr.configure(ifrate, tuner_freq, -1); + rtlsdr.configure(ifrate, tuner_freq, -1, + RtlSdrSource::default_block_length, agcmode); if (!rtlsdr) { fprintf(stderr, "ERROR: RtlSdr: %s\n", rtlsdr.error().c_str()); exit(1); @@ -389,6 +404,8 @@ int main(int argc, char **argv) ifrate = rtlsdr.get_sample_rate(); fprintf(stderr, "IF sample rate %.0f Hz\n", ifrate); + fprintf(stderr, "RTL AGC mode %s\n", agcmode ? "enabled" : "disabled"); + // Create source data queue. DataBuffer source_buffer;