SatNOGS client V2.x / SoapyRTLSDR: setting Freq Correction (PPM)

The SATNOGS_PPM_ERROR option have no effect on the latest version of the SatNOGS client system. Previously had the opportunity to pass parameters for librtlsdr using the --dev-args ( SATNOGS_DEV_ARGS ).

Below is a screenshot for setting the Soapy Source radio parameters in Gnuradio flowgraph.

As you see, Soapy Source block have special setting 'Freq Correction" ( it works! ). The following code corresponds to it:

    self.soapy_source_0 = \
     soapy.source(1, 'rtlsdr', '', samp_rate*40, "fc32")
    self.soapy_source_0.set_frequency(0, 436.9e6)
    self.soapy_source_0.set_gain_mode(0, False)
    self.soapy_source_0.set_antenna(0, 'RX')
    self.soapy_source_0.set_dc_offset_mode(0, True)
    self.soapy_source_0.set_frequency_correction(0, 39)

SoapySDRUtil application allow to print information about the RTL-SDR.

You can see parameter:

Freq Correction [corr]: Default 0 (parts per million)

Unfortunatelly, parameter corr in SATNOGS_DEV_ARGS have no effect also (see dev_args: “corr=37” in Metadata>radio ).

Here information for my RTLSDR:


Soapy SDR – the SDR abstraction library


Probe device driver=rtlsdr

– Device identification


– Peripheral summary

Channels: 1 Rx, 0 Tx
Timestamps: YES
Time sources: sw_ticks
Other Settings:
* Direct Sampling - RTL-SDR Direct Sampling Mode
[key=direct_samp, default=0, type=string, options=(0, 1, 2)]
* Offset Tune - RTL-SDR Offset Tuning Mode
[key=offset_tune, default=false, type=bool]
* I/Q Swap - RTL-SDR I/Q Swap Mode
[key=iq_swap, default=false, type=bool]
* Digital AGC - RTL-SDR digital AGC Mode
[key=digital_agc, default=false, type=bool]

– RX Channel 0

Full-duplex: NO
Supports AGC: YES
Stream formats: CS8, CS16, CF32
Native format: CS8 [full-scale=128]
Stream args:
* Buffer Size - Number of bytes per buffer, multiples of 512 only.
[key=bufflen, units=bytes, default=262144, type=int]
* Ring buffers - Number of buffers in the ring.
[key=buffers, units=buffers, default=15, type=int]
* Async buffers - Number of async usb buffers (advanced).
[key=asyncBuffs, units=buffers, default=0, type=int]
Antennas: RX
Full gain range: [0, 0] dB
TUNER gain range: [0, 0] dB
Full freq range: [23.999, 1764] MHz
RF freq range: [24, 1764] MHz
CORR freq range: [-0.001, 0.001] MHz
Sample rates: 0.25, 1.024, 1.536, 1.792, 1.92, 2.048, 2.16, 2.56, 2.88, 3.2 MSps

Perhaps SATNOGS_PPM_ERROR is still required?

1 Like

@surligas ^^ any ideas?

Unfortunately the corr setting is available on the Soapy 0.7 AFAIK. I will search for a possible solution.

1 Like

I have uploaded soapysdr 0.7 and deps to . Let’s see how it will go…


Also worth noting here that SoapySDRUtil --probe isn’t showing the available gain range in the SDR information output, just as @pierros saw on IRC. Therefore, the instructions in may not work in all cases…

Is this maybe a case where users that rely on these settings should be warned off updating for a while? What about new users? Is this maybe a case where we should be staying with the older client until this is all resolved?

I’ve just had a go at setting up a station from scratch on a RPi4 using the new build, and SoapySDRUtil isn’t available, even after a satnogs-setup update and apply. I had to manually install this using sudo apt-get install soapysdr-tools
I can confirm that on my new install, after installing the required utilities, I do end up seeing the RTLSDR gain:

 Full gain range: [0, 49.6] dB
    TUNER gain range: [0, 49.6] dB
1 Like

There is an open issue about it.

This was only when the SDR was in use by an observation running (understandably).

I found in Setting.cpp (SoapyRTLSDR) that parameter ‘corr’ should be as capital letters and value should be float:

if (name == "CORR")
    ppm = (int) frequency;
    rtlsdr_set_freq_correction(dev, ppm);

Yet another problem in (gr-soapy)- incorrect support setFrequencyCorrection. ‘Frequency API’ SoapyRTLSDR::SetFrequency (Settings.cpp/SoapyRTLSDR) always get value ‘CORR’ 0ppm. The value ‘CORR’ is taken as Frequency Correction, not from ’ SATNOGS_DEV_ARGS', I believe.

Thanks @uy0ll for digging into this. Maybe this helps in finding the proper way to re-implement the frequency correction feature within the new gr-soapy-based satnogs client code.

I followed your hints and would like to add some remarks.

I don’t see an error within in gr-soapy here: The function source_impl::set_frequency_correction is a wrapper around {SoapyRTLSDR|Device}::setFrequencyCorrection and should work correctly when called. Unfortunately I don’t think it’s called with a non-zero value by the flowgraphs currently. The flowgraph template for the gr-soapy source block is calling it at soapy_source.block.yml#L371-373 using the correction0 parameter, but this parameter is always zero in all satnogs-flowgraphs (e.g. iq_receiver.grc#L402-403).

The config variable SATNOGS_DEV_ARGS is deprecated and has no effect in the new gr-soapy-based satnogs client software stack, but unfortunately wasn’t removed from satnogs-client yet. I just opened issue satnogs-client#373 to fix this. (edit 2020-03-10T20:40: SATNOGS_DEV_ARGS got a new meaning with gr-soapy, see gr-soapy#64 (comment 301344183) for its effects in gr-soapy v2.0 and earlier). It can be easily confused with the new SATNOGS_SOAPY_RX_DEVICE which serves a similar purpose now.

Sry, I think the if (name == "CORR") condition can’t be met within any SatNOGS station with latest software atm. Reason:
This code is part of SoapyRTLSDR::setFrequency,
it gets called only once by gr-soapy in
source_impl::set_frequency(size_t channel, const std::string &name, double frequency),
but in turn this gr-soapy function gets never called. And the simpler
source_impl::set_frequency(size_t channel, double frequency) is used

tl;dr: I can’t see the possibility to configure any frequency correction without modifying the flowgraphs in the latest satnogs client software stack. But it would be possible to re-implement this (lost) feature.


Please use the issue tracker of gr-soapy, cause there is heavy development on it to support the separate gains of each device and many things are subjected to changes.

Indeed I somehow missed issue gr-soapy#64 highly related to this topic.

1 Like

Has there been any progress on this? Is there an issue raised to cover it?

Setting a frequency correction value is something that’s pretty critical to a lot of stations. Kind of like being able to set gain properly on devices with more than one gain control knob (though I believe this has been fixed?)


I checked all possible options for device specific arguments in gr-soapy 2.0 explained in gr-soapy#64 (comment 301344183) mentioned previously, and by reviewing the respective code in gr-soapy, SoapyRTLSDR and SoapySDR I can conclude that the device arguments do not support any “corr/CORR” argument when using an rtl-sdr, and the set_freqeuncy_correction API is used with a hard-coded zero value by all flowgraphs as described in my previous long post.

Whether this has been fixed already I will try to answer in a future post.

It’s being worked on. In the gr-soapy master branch the device, stream & channel settings API was redesigned by @surligas (gr-soapy!116 (merged)) and satnogs-flowgraphs was updated to support this new API (satnogs-flowgraphs!11 (merged)). Exposing the new device/stream/channel/tune settings through satnogs-client, satnogs-config & satnogs-client-ansible is a ToDo (satnogs-client#374, satnogs-client-ansible#72 & satnogs-config#19).
Once those issues are resolved, setting the gain properly should be possible with the full granularity offered by SoapySDR (given there are no bugs in the device-specific soapy modules).

The missing frequency correction support is not fixed yet, but tracked in satnogs-flowgraphs#7 now.

The progress / explanation:

Frequency Correction in Soapy[RTL]SDR

Some confusion about this fact was caused by the SoapySDR wiki page showing the device argument corr until today (archive):

Freq Correction [corr]: Default 0 (parts per million)

In fact, this device argument was removed before the first release of SoapyRTLSDR in SoapyRTLSDR@6bfc9a9, but remained in the wiki until I updated the wiki page today.

Frequency Correction in gr-soapy

gr-soapy is supporting the Soapy Frontend Corrections API correctly since it’s first release (see gr-soapy@v1.0.1:/lib/source_impl.h#L198-203).

Frequency Correction in satnogs-flowgraphs

satnogs-flowgraphs is using a hardcoded correction value of zero as described in an earlier post in this thread. This bug is tracked in satnogs-flowgraphs#7.

Everything were installed latest from git, unfortunately still no effect:

Are you sure about that?

Looking at some of your other observations, it looks OK.

For example: - GOMX-1 looks fairly well centred

I also see you are running a fork of gr-satnogs?

1 Like

I use gr-satnogs supplemented by the direwolf_agc for the better reception AFSK1200 and also have to use the PPM value set manually in Settings.cpp (Soapy RTL SDR):

void SoapyRTLSDR::setFrequency(
const int direction,
const size_t channel,
const std::string &name,
const double frequency,
const SoapySDR::Kwargs &args)
if (name == “RF”)
centerFrequency = (uint32_t) frequency;
resetBuffer = true;
rtlsdr_set_center_freq(dev, centerFrequency);

if (name == "CORR")
SoapySDR_logf(SOAPY_SDR_WARNING, "SoapyRTLSDR::setFrequency: get \"CORR\"= '%f'", frequency);
    ppm = (int) frequency;
   ppm = 60;
 SoapySDR_logf(SOAPY_SDR_WARNING, "SoapyRTLSDR:setFrequency: set manually PPM= '%d'", ppm);
    rtlsdr_set_freq_correction(dev, ppm);

Here is how it works:

Mar 25 05:23:17 SatNOGS satnogs-client[7310]: satnogsclient.scheduler.tasks - WARNING - Script:
Mar 25 05:23:23 SatNOGS satnogs-client[7310]: Found Rafael Micro R820T tuner
Mar 25 05:23:23 SatNOGS satnogs-client[7310]: Found Rafael Micro R820T tuner
Mar 25 05:23:24 SatNOGS satnogs-client[7310]: [R82XX] PLL not locked!
Mar 25 05:23:24 SatNOGS satnogs-client[7310]: [INFO] Using format CF32.
Mar 25 05:23:24 SatNOGS satnogs-client[7310]: [WARNING] SoapyRTLSDR::setFrequency: get “CORR”= ‘0.000000’
Mar 25 05:23:24 SatNOGS satnogs-client[7310]: [WARNING] SoapyRTLSDR:setFrequency: set manually PPM= ‘60’

Well I guess the point there is… if you are using your own fork of gr-satnogs, how are you expecting to be able to test the new PPM correction setting?

I did not make any changes to the source code of any of their gr-satnogs modules. A separate an out-of-tree module direwolf_agc was added to the library, which is included only in the unique flowgraph satnogs_afsk1200.grc (example above is for STRAND-1).

The problem is obviously in the Device.cpp (SoapySDR):

this->setFrequency(direction, channel, “CORR”, value);

but appropriate API is empty:

void SoapySDR::Device::setFrequency(const int, const size_t, const std::string &, const double, const Kwargs &)

It is not clear how the PPM parameter can be passed to SoapyRTLSDR.

Paging @surligas I guess…