Skip to content

ad9361: Add RX overload sensor - #955

Open
hgi586 wants to merge 1 commit into
EttusResearch:masterfrom
hgi586:feat/ad9361-overload-sensor
Open

hgi586 wants to merge 1 commit into
EttusResearch:masterfrom
hgi586:feat/ad9361-overload-sensor

Conversation

@hgi586

@hgi586 hgi586 commented Nov 9, 2026

Copy link
Copy Markdown

Pull Request Details

Description

On AD9361-based devices, UHD exposes the rssi, temp and lo_locked RX sensors, but nothing tells the host that the receiver overloaded. Counting full-scale samples on the host catches ADC clipping, but not an overload of the RF front end (LMT) caused by a strong signal outside the captured band. That overload can leave intermodulation products in the band with no other sign of it.

The AD9361 already reports both kinds of overload. Registers 0x2B8 (RX1) and 0x2B9 (RX2) ("Ovrg Sigs" in Analog Devices' ad9361_regs.h) hold:

Bit Signal
4 Large LMT overload
3 Small LMT overload
2 Large ADC overload
1 Small ADC overload
0 Digital saturation

UHD already programs these detectors' thresholds (0x104 to 0x108) in both gain modes, but it never reads the status.

This PR adds an overload RX sensor on each AD9361 frontend, next to rssi, read with get_rx_sensor("overload", chan). It returns the five bits as an integer. The change follows get_rssi() through ad9361_device_t, ad9361_ctrl and ad936x_manager. It also adds a short "Frontend sensors" subsection to the B200 manual, which did not list the frontend sensors so far.

ad9361_ctrl::get_overload() has a default implementation that throws not_implemented_error, so e3xx_ad9361_iface builds unchanged. Only ad936x_manager publishes the sensor, so it appears on B2xx only; E3xx sensors come from MPM and are not affected.

If you would prefer separate boolean sensors (for example adc_overload and lmt_overload) to one integer, I can change it.

I have signed the Individual CLA and am sending it to contribute@ettus.com, referencing this pull request.

For transparency: I asked for this feature and directed the work. An AI coding assistant (Claude Code) helped write the change and run the measurements, and I validated them on my hardware.

Related Issue

None. I described the proposal on the usrp-users mailing list beforehand and had no reply yet.

Which devices/areas does this affect?

  • B200/B210/B200mini/B205mini/B206mini: new overload RX sensor per frontend, read-only. Nothing is written to the AD9361, and streaming and gain control are unchanged.
  • E3xx: none. The code builds, and no sensor is added.

Testing Done

Hardware: a B210-class board (a clone with an AD9361), with UHD 4.9.0.1 built from the v4.9.0.1 tag plus this change. The same change rebased onto current master, with no conflicts, builds with the B200 target without warnings.

Check on master: with this branch, uhd_usrp_probe lists temp, rssi, overload, lo_locked on RX frontends A and B. A shorter rerun of the test below, at 3 s per gain step, gave the same behaviour:

  • No bits were set from 40 to 68 dB (max |I|,|Q| up to 2,436).
  • At 72 dB, with a max of 30,861, the large ADC, small ADC and saturation bits were set in 76 % of reads.
  • At 76 dB, with a max of 32,768, the same bits were set in 54 % of reads.
  • At 0 dB right after initialization, the ADC bits read as set, and they cleared after the first gain change.

Setup: manual gain, 30.72 MS/s at 915 MHz, receiving a nearby 1 W meter-reading transmitter in the 902-928 MHz band. A second thread polled the sensor about 9,000 times per second, with no effect on streaming. Meanwhile the host counted sc16 samples at full scale, for 5 s per gain step.

RX gain Max |I|,|Q| Samples >= 32000 Reads with bits set
40 to 72 dB 431 to 22,564 (bursty source) 0 none
76 dB, first pass 25,982 (about -2 dBFS) 0 small ADC only, 26 %
76 dB, second pass 32,768 1.07 % large ADC + small ADC + saturation, 77 %

Observations:

  • The small ADC bit sets a couple of dB below full scale, so it works as an early warning. The large ADC and digital saturation bits coincide with clipped samples.
  • The bits stay set until the next gain change: 77 % of reads were set while only 1 % of samples clipped. A slow poll therefore does not miss short bursts.
  • Right after initialization, the ADC bits read as set until the first gain change.
  • The LMT bits never set in this test, because the signal was inside the captured band and the ADC overloaded first.
  • Only chain 1 was tested on hardware; chain 2 uses the same code with register 0x2B9.

Not tested: no unit test was added, since the existing tests have no AD9361 register mock. The patch was not run through clang-format, because it was not installed. Formatting was matched by hand to the surrounding code.

Checklist

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project. See CODING.md.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes, and all previous tests pass.
  • I have checked all compat numbers if they need updating (FPGA compat,
    MPM compat, noc_shell, specific RFNoC block, ...)

🤖 Generated with Claude Code

Add an "overload" RX sensor on each AD9361 frontend, next to "rssi".
It returns the five RX overload signals of the chain, read from
registers 0x2B8 (RX1) and 0x2B9 (RX2):

  bit 4  large LMT overload
  bit 3  small LMT overload
  bit 2  large ADC overload
  bit 1  small ADC overload
  bit 0  digital saturation

UHD already programs the thresholds of these detectors (0x104 to
0x108) in both gain modes, but never read the result, so the host had
no way to know that the receiver overloaded. Counting full-scale
samples on the host catches ADC clipping, but not an overload of the
RF front end (LMT) caused by a strong signal outside the captured
band, which can leave intermodulation products in the band with no
other sign of it.

The bits are sticky: they stay set until the next gain change, so a
slow poll does not miss short bursts.

The sensor is published by ad936x_manager, so it appears on B2xx
devices. get_overload() has a default implementation in ad9361_ctrl
that throws not_implemented_error, so the E3xx RPC interface
(e3xx_ad9361_iface) builds unchanged; E3xx sensors come from MPM and
are not affected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@hgi586

hgi586 commented Nov 9, 2026

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@mbr0wn

mbr0wn commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

@hgi586 Thanks for the contribution! I agree this is a good idea. I was wondering if there's a way to disentangle the bits (i.e., not having to require the reader to mask-and-shift to identify individual sensor values), but that depends on the stickiness of that register. Do you know if reading the register clears it? If not, how is it cleared?

@hgi586

hgi586 commented Nov 13, 2026

Copy link
Copy Markdown
Author

I can report on the experimental results with the spectrum analyzer block in Cyberether using a B210 clone for a pr submitted. The clipping is a short message that appears momentarily with a number related to how frequently the clipping happened. From memory , the cyberether block (patch) has it's own counter for a given measurement period. It is intended as a message to the user to reduce the gain input on the spectrum analyzer block. As the gain is reduced , the message appears with much less frequency. The other message : adc overload is apparently reset by the Cyberether app (in the patch submitted) when the user reduces the gain (from my failing memory) . The important case of overload of the input rf stage as opposed to the a to d has not been tested yet. This monitoring applies also to any other blocks or apps that read a-d samples from that part on whatever hardware platform names that use the part.

All of the digital signal processing found in textbooks and their elaborate math implicitly assumes that the processing system is operated in a linear region. When this condition is not met , artifacts appear as a result of the non linear operation that are not covered by the linear models. So all software in whatever environment that use this Analog Device part should monitor those internal registers and warn users or change receiver settings. There are 2 other registers that appear to set the threshold of this monitoring. The current tests used the default values in uhd. There is a possibility that further testing of the overload characteristic of the rf stage require an additional patch to those default values in uhd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants