Thursday, December 11, 2025

gr-sleipnir Digital Voice Protocol - Test Results and Feedback Request


Hi GNU Radio community,

I've been developing gr-sleipnir, an open-source digital voice protocol for amateur radio using GNU Radio 3.10.  I'm sharing current test  results and would appreciate feedback on the implementation approach.

Project Overview: gr-sleipnir implements 4FSK/8FSK modulation with Opus voice codec (6-8 kbps), LDPC error correction (rates 2/3 and 3/4), and optional ChaCha20-Poly1305 encryption with ECDSA authentication. The protocol supports text messaging and multi-recipient encryption.

Test Methodology:

  • Platform: GNU Radio 3.10 simulation environment
  • Test coverage: 8,560 scenarios across SNR range (-2 to +20 dB), multiple channel conditions (AWGN, Rayleigh/Rician fading, frequency offset ±100/500/1000 Hz)
  • Performance metrics: FER, BER, WarpQ audio quality scores
  • All tests automated using Python test framework

Key Simulation Results:

  • Operational SNR (FER < 5%): 4FSK at -1 dB, 8FSK at 0 dB
  • FER floor: 4-6% at high SNR (hard-decision LDPC decoder limitation)
  • Crypto overhead: <1 dB for ChaCha20-Poly1305 + ECDSA
  • Frequency offset tolerance: ±500 Hz acceptable, ±1 kHz causes significant degradation
  • Fading: Minimal performance degradation in simulated Rayleigh/Rician channels

Technical Implementation:

  • Out-of-tree module structure with hierarchical blocks
  • Custom LDPC decoder (hard-decision, alist matrix format)
  • Integration with gr-opus for voice encoding/decoding
  • Frame structure: 40ms Opus frames with LDPC protection
  • All cryptographic operations using standard Linux kernel crypto API

Known Limitations:

  • Hard-decision LDPC decoder creates 4-6% FER floor (soft-decision implementation would improve this)
  • Frequency offset >±1 kHz requires compensation (AFC not yet implemented)
  • Results are from simulation; real-world hardware validation planned for Q1 2025

Questions for the Community:

  1. Channel modeling: Are the GNU Radio fading channel models (Rayleigh/Rician) representative of real-world mobile conditions, or should I expect different results on-air?
  2. LDPC implementation: I'm using hard-decision decoding for simplicity. For those who've implemented soft-decision LDPC in GNU Radio, what's the practical performance gain (measured, not theoretical)?
  3. Frequency offset: The ±1 kHz sensitivity is possible concerning. Has anyone implemented effective AFC for FSK in GNU Radio? Recommendations for libraries or approaches?
  4. Performance validation: How do simulation results typically compare to hardware testing in your experience? What factors cause the biggest discrepancies?

Code and Documentation: Project: https://github.com/Supermagnum/gr-sleipnir Test results and detailed analysis available in the repository.

Waiting to be tested
Complete 8FSK 'sign' crypto mode
396 tests remaining
Same matrix: 7 channels × 23 SNR × 2 data modes × 3 recipients
8FSK 'encrypt' crypto mode
0 tests completed
966 tests expected
Test matrix: 7 channels × 23 SNR × 2 data modes × 3 recipients
8FSK 'both' crypto mode
0 tests completed
966 tests expected
Test matrix: 7 channels × 23 SNR × 2 data modes × 3 recipients
Test matrix for remaining tests
Each crypto mode tests:
7 channel conditions (clean, AWGN, Rayleigh, Rician, freq_offset_100hz, freq_offset_500hz, freq_offset_1khz)
23 SNR points (-2 to +20 dB in 1 dB steps)
2 data modes (voice, voice_text)
3 recipient scenarios (single, two, multi)
Total: 7 × 23 × 2 × 3 = 966 tests per crypto mode
Summary
Currently: Finishing 8FSK 'sign' crypto (396 tests remaining)
Next: 8FSK 'encrypt' crypto (966 tests)
Then: 8FSK 'both' crypto (966 tests)
Total remaining: 2,328 tests (396 + 966 + 966)

Those will be completed around midnight local time.

Next Steps:  
I'm also considering implementing soft-decision LDPC to eliminate the FER floor.

Any feedback on the approach, implementation details, or testing methodology would be appreciated. I'm particularly interested in hearing from those who've validated GNU Radio simulations against real RF hardware.


LA1RMA


Wednesday, December 10, 2025

Re: Issues with E320 - AD9361 temperature sensor readings

Can you please submit a bug report to github.com/ettusresearch/uhd?

--M

On Tue, Dec 9, 2025 at 6:49 PM Indrajit Bhattacharyya <Indrajit.Bhattacharyya@kratosdefense.com> wrote:

Hi Marcus,

 

Sorry for writing to you directly as my query on the gnuradio discuss list has not come up with any response in the last 2-3 weeks.

 

Also, apologies for posting the above on the gnuradio list as the usrp-users list is down for some reason.

 

I needed some help identifying a rather odd issue I am facing with some new E320s we acquired as the older E310s are now not recommended for new designs.

 

When reading the temperature from the AD9361 I am consistently getting very high readings, confirmed with direct chip surface temperature measurements – typically of the order of 60-70C for Rx only streams, and 80-90C for streams with both Tx and Rx.

 

My requirements are very humble – the FPGA is not used at all – all data is processed on the main CPU.

 

Typical Sample rates are between 1.92 MHz to 30.72 MHz for Rx streams, and Tx is set to 30 kHz.

 

The Tx transmits only a CW.

 

When comparing with the old E310, the temperature difference is about 30C, with the same underlying code.

 

Any idea why this is happening or what I am doing wrong.

 

FYI, stopping the streams actually causes the temperature on the AD9361 to rise, which is very weird.

 

The sensor values are read using: usrp.get_sensor(i).to_real() – we only need the rssi and ad9361_temp sensors.

 

And the stream start / stop is effected using: self.uhd_usrp_source_0.stop(), self.uhd_usrp_source_0.start()

 

Sample rates on the receive are changed using:

        self.uhd_usrp_source_0.stop()

        self.uhd_usrp_source_0.set_samp_rate(self.rxSamp_rate)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 0)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 1)

        time.sleep(0.5)

        self.uhd_usrp_source_0.start()

 

Fundamentally, the system is used to compute the DOA using either high power noise sources or CW signals from a TE21 coupler inside the feed of an antenna.

 

UHD: 4.8.0.0

Python: 3.12.0

Windows: IOT

 

Default configuration of USRP:

 

MCR: 30.72 MHz or 16 MHz

Rx Frequency: 2G – 3G

Tx Frequency: 5G-5.5G

Tx Gain setting: 75 – 80 dB (~10 dBm output)

Rx Gain: AGC

 

All streams are carried over the 10G SFP modules. No packet losses.

 

Any help or insight would be greatly appreciated.

 

Thanks,

 

Indrajit.

 

Tuesday, December 9, 2025

Re: Issues with E320 - AD9361 temperature sensor readings

On 2025-12-09 12:48, Indrajit Bhattacharyya wrote:

Hi Marcus,

 

Sorry for writing to you directly as my query on the gnuradio discuss list has not come up with any response in the last 2-3 weeks.

 

Also, apologies for posting the above on the gnuradio list as the usrp-users list is down for some reason.

 

I needed some help identifying a rather odd issue I am facing with some new E320s we acquired as the older E310s are now not recommended for new designs.

 

When reading the temperature from the AD9361 I am consistently getting very high readings, confirmed with direct chip surface temperature measurements – typically of the order of 60-70C for Rx only streams, and 80-90C for streams with both Tx and Rx.

 

My requirements are very humble – the FPGA is not used at all – all data is processed on the main CPU.

 

Typical Sample rates are between 1.92 MHz to 30.72 MHz for Rx streams, and Tx is set to 30 kHz.

 

The Tx transmits only a CW.

 

When comparing with the old E310, the temperature difference is about 30C, with the same underlying code.

 

Any idea why this is happening or what I am doing wrong.

 

FYI, stopping the streams actually causes the temperature on the AD9361 to rise, which is very weird.

 

The sensor values are read using: usrp.get_sensor(i).to_real() – we only need the rssi and ad9361_temp sensors.

 

And the stream start / stop is effected using: self.uhd_usrp_source_0.stop(), self.uhd_usrp_source_0.start()

 

Sample rates on the receive are changed using:

        self.uhd_usrp_source_0.stop()

        self.uhd_usrp_source_0.set_samp_rate(self.rxSamp_rate)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 0)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 1)

        time.sleep(0.5)

        self.uhd_usrp_source_0.start()

 

Fundamentally, the system is used to compute the DOA using either high power noise sources or CW signals from a TE21 coupler inside the feed of an antenna.

 

UHD: 4.8.0.0

Python: 3.12.0

Windows: IOT

 

Default configuration of USRP:

 

MCR: 30.72 MHz or 16 MHz

Rx Frequency: 2G – 3G

Tx Frequency: 5G-5.5G

Tx Gain setting: 75 – 80 dB (~10 dBm output)

Rx Gain: AGC

 

All streams are carried over the 10G SFP modules. No packet losses.

 

Any help or insight would be greatly appreciated.

 

Thanks,

 

Indrajit.

 

I don't have an E320 myself, but I've reached out to my colleagues to see what "normal" is for these devices.  90C seems quite excessive.  Is this happening on more than one
  unit?


Issues with E320 - AD9361 temperature sensor readings

Hi Marcus,

 

Sorry for writing to you directly as my query on the gnuradio discuss list has not come up with any response in the last 2-3 weeks.

 

Also, apologies for posting the above on the gnuradio list as the usrp-users list is down for some reason.

 

I needed some help identifying a rather odd issue I am facing with some new E320s we acquired as the older E310s are now not recommended for new designs.

 

When reading the temperature from the AD9361 I am consistently getting very high readings, confirmed with direct chip surface temperature measurements – typically of the order of 60-70C for Rx only streams, and 80-90C for streams with both Tx and Rx.

 

My requirements are very humble – the FPGA is not used at all – all data is processed on the main CPU.

 

Typical Sample rates are between 1.92 MHz to 30.72 MHz for Rx streams, and Tx is set to 30 kHz.

 

The Tx transmits only a CW.

 

When comparing with the old E310, the temperature difference is about 30C, with the same underlying code.

 

Any idea why this is happening or what I am doing wrong.

 

FYI, stopping the streams actually causes the temperature on the AD9361 to rise, which is very weird.

 

The sensor values are read using: usrp.get_sensor(i).to_real() – we only need the rssi and ad9361_temp sensors.

 

And the stream start / stop is effected using: self.uhd_usrp_source_0.stop(), self.uhd_usrp_source_0.start()

 

Sample rates on the receive are changed using:

        self.uhd_usrp_source_0.stop()

        self.uhd_usrp_source_0.set_samp_rate(self.rxSamp_rate)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 0)

        self.uhd_usrp_source_0.set_bandwidth((self.rxSamp_rate*2), 1)

        time.sleep(0.5)

        self.uhd_usrp_source_0.start()

 

Fundamentally, the system is used to compute the DOA using either high power noise sources or CW signals from a TE21 coupler inside the feed of an antenna.

 

UHD: 4.8.0.0

Python: 3.12.0

Windows: IOT

 

Default configuration of USRP:

 

MCR: 30.72 MHz or 16 MHz

Rx Frequency: 2G – 3G

Tx Frequency: 5G-5.5G

Tx Gain setting: 75 – 80 dB (~10 dBm output)

Rx Gain: AGC

 

All streams are carried over the 10G SFP modules. No packet losses.

 

Any help or insight would be greatly appreciated.

 

Thanks,

 

Indrajit.

 

[VOLK] Kernels should define if they are safe to use inplace

Example:
void volk_32fc_x2_multiply_32fc(lv_32fc_t* cVector, const lv_32fc_t* aVector, const lv_32fc_t* bVector, unsigned int num_points);

Can this be used as `out *= b` using:
    `volk_32fc_x2_multiply_32fc(out, out, b, out.size());`
?

Is is used this way in GNU Radio, in several places just for this one kernel, so even the main volk user makes this assumption.

But it seems like it's unspecified. It should be both specified, and presumably tested.

I feel like it should be fine for simple things like the above, and volk_32f_sqrt_32f, volk_32fc_s32f_atan2_32f, volk_32f_atan_32f, etc…, but maybe not for everything?

There may be aligned/unaligned complexities here, too.

This question started life as https://github.com/gnuradio/volk/issues/805, but I thought I'd bring it to the attention of the mailing list too.

--
typedef struct me_s {
 char name[]      = { "Thomas Habets" };
 char email[]     = { "thomas@habets.se" };
 char kernel[]    = { "Linux" };
 char *pgpKey[]   = { "http://www.habets.pp.se/pubkey.txt" };
 char pgp[] = { "9907 8698 8A24 F52F 1C2E  87F6 39A4 9EEA 460A 0169" };
 char coolcmd[]   = { "echo '. ./_&. ./_'>_;. ./_" };
} me_t;

Strange component at Nyquist frequency with USRP X310 and GNU Radio

Hello everyone,
I am using an USRP X310 with two TwinRX daughterboards for an Direction of Arrival application. I have a very simple GNU Radio flowgraph with just two blocks, an UHD USRP Source and a QT GUI Frequency Sink.
I have configured a sampling rate of 100 Msps and try to receive the four channels in a sync manner (there is no overflows issues since I have two SFP+ 10 GbEthrnet cables).
However, when I plot the spectrum of the receive signal it happens that at -50 and 50 MHz (half the sampling rate, i.e., the Nyquist frequency) there is the presence of some tones higher than the noise floor. I don't see this effect if I configure, for example, a rate of 50 Msps. This happens receiving signal from the air, with antennas, and also with a wired connection.
To make a basic test, we connected four matched loads to the RX inputs, and we see this effect too.
I will show you this graphically.
Spectrum capturing with sampling rate of 100 Msps in 2440 MHz. The high power at the Nyquist frequencies can be observed. The same happens for a capture in the 5500 MHz band.

If I use a sampling rate of 200 Msps a curios effect appears. In a capture at 2450 MHz band an important tone with high power appears at -50 MHz. And its power changes with time (the golden trace is the Max hold).

And if I capture with 200 Msps in the 5500 MHz band, a similar high power tone appears but at the right side (at +50 MHz)

Do you know if this beahviour is normal or can occur due the existance of some kind of damage in SDR or the daughterboard?
If this is normal, I guess that a digital low pass filter with a cut off frequency of 40 MHz could solve this (actually the analog bandwidth of the USRP X310 with TwinRX is 80 MHz). Is this correct?
Thanks in advance for you time.


PD. I tried to make a post in the list usrp-users but the mail was rejected.



Anxo Tato Arias
Enxeñeiro - Investigador Senior · Área de Comunicacións Avanzadas
Senior Researcher - Engineer · Advanced Communications Department
(+34) 986 120 430
atato@gradiant.org
Take care of the environment. Try not to print this email.
The information contained in this email message may be confidential information and may also be the subject of legal professional privilege. If you are not the intended recipient, any use, interference with, disclosure or copying of this material is unauthorized and prohibited. Please inform us immediately and destroy the email. Thank you for your cooperation.

Thursday, December 4, 2025

Re: Endian-ness of USRP x410 device

Thankyou Marcus and Martin for the replies. Ok probably that's why I can't send it to the usrp-users.

As you suggested, I looked at some other Rfnoc blocks in the repo but I couldn't really find anything in particular. Maybe I am looking at it wrong. So, in the meantime, I setup an ILA (again thanks Martin for the one reply where you detailed out how to set it up to another user), and I see that the data coming from the nocshell (m_in_axis_tdata) is a unrecognizable to the data I sent via TX streamer in gnuradio. I added some debug prints along the way - one on the block preceding the TX streamer, in the send() (in TX streamer in UHD) and ILA in the FPGA. I also checked if its just the IQ change that is mentioned in the Rnoc Spec pdf, but thats not it either.
For my configuration, I use item_w=32, chdr_w=64, cpu_format=sc16 and otw=sc16. So theoretically this shouldnt do any other conversions right? Or maybe I am missing something?

-J

On Thu, 27 Nov 2025 at 12:00, Martin Braun <martin.braun@ettus.com> wrote:
Hey Jons,

our mailing list server is having some issues. Our maintainer knows about this, but I can't give you a timeline for when it'll be up again.

Like Marcus says, don't worry about the network endianness. We have a bunch of things going on to flip bytes around (among other things, it saves us some CPU load when receiving data), but you need to worry about the Noc-Shell interface. I recommend looking at some of our existing blocks as examples.

--M

On Wed, Nov 26, 2025 at 4:01 PM Marcus Müller <mmueller@gnuradio.org> wrote:
Hi Jons,

On 2025-11-26 9:17 AM, Jons wrote:
> Hi all,
> This is a specific question about USRP devices and I am posting it here because I am
> unable to send it to the usrp-users mail chain.

Uh, I'm not with Ettus anymore, but that's no good. All you should need to do is send an
email from your email address to usrp-users-join@lists.ettus.com ; after you've gotten a
confirmation email and confirmed, you should be able to post there.

> I am trying to integrate a custom noc
> block into the x410 device and when going through the email archive and a doc in the
> github repo I saw that the OTW data transmission is in Big Endian.

I'll go with: that's a time-honoured tradition :D

> Can someone help me out
> in understanding how it will affect a noc block?

Not at all – you're not interfacing with the network directly, but with your nocshell, and
your verilog module / VHDL arch sees the sample data as sample-wide array (CHDR_W is the
naming convention for the width parameter, if you want to look through the source code of
Ettus' blocks), typically.

Best,
Marcus