InstroSDR#
- class InstroSDR(
- name: str,
- driver: SDRDriverBase,
- **kwargs: Any,
Bases:
InstrumentSoftware defined radio instrument that publishes IQ blocks and spectrum features.
Each IQ block publishes as one
Measurementwith paired.iand.qchannels per signal path, timestamped from the sample period the device reports.Initialize an InstroSDR.
- Parameters:
name (str)
Channel-name prefix for published data.
driver (SDRDriverBase)
Concrete vendor driver.
**kwargs
Passed to
Instrument:publishersandbackground_config,dataset_ridto attach aNominalCorePublisher, and any other keyword as a default tag.
Example
from instro.unstable.sdr import InstroSDR sdr = InstroSDR(name="sdr", driver=MyVendorSDR(...)) # any concrete SDRDriverBase sdr.open() try: sdr.set_center_freq(100e6) sdr.set_sample_rate(2.4e6) iq = sdr.measure_iq(n_samples=4096) spectrum = sdr.measure_spectrum(n_samples=4096) finally: sdr.close()
Attributes
Background daemon loop period.
Return an insertion-ordered snapshot of all published channel names.
The underlying hardware driver.
Methods
Append
methodto the daemon's call list.Register a publisher to receive this instrument's Measurement/Command data.
Stop the background daemon and close the driver.
Acquire one block and return one channel's power spectral density.
Replace all daemon functions with a single
method(called with the given args).Return the next contiguous block from the running stream and publish it.
Query the selected antenna port and publish it as
antenna.Return how many samples are waiting on the receive stream.
Query the IF or filter bandwidth and publish it as
bandwidth.Query the RF center frequency and publish it as
center_freq.Return the most recent
lengthsamples forchannel_namefrom the in-memory buffer.Query the reference oscillator correction and publish it as
freq_correction.Query the gain and publish it as
gain.Query the gain mode and publish it as
gain_mode.Query the IQ sample rate and publish it as
sample_rate.Return the most recent sample for
channel_namefrom the in-memory buffer.Report whether a stream is running.
Acquire one time-aligned IQ block and publish it as paired
.iand.qchannels.Acquire one block and publish four scalar spectrum features per channel.
Open the underlying driver.
Fan
dataout to every configured publisher;kwargspass through.Set the antenna port and publish it as
antenna.cmd.Set the IF or filter bandwidth and publish it as
bandwidth.cmd.Set the RF center frequency and publish it as
center_freq.cmd.Set the reference oscillator correction and publish it as
freq_correction.cmd.Set the gain and publish it as
gain.cmd.Hand gain to the AGC or take manual control, and publish it as
gain_mode.cmd.Set the IQ sample rate and publish it as
sample_rate.cmd.Begin continuous acquisition.
Stop the background daemon and every running hardware stream.
- close() None[source]#
Stop the background daemon and close the driver.
The driver is closed even if the daemon does not shut down cleanly; that failure is logged.
- property driver: SDRDriverBase#
The underlying hardware driver.
- Returns:
SDRDriverBase – The driver passed at construction.
- measure_iq( ) Measurement | None[source]#
Acquire one time-aligned IQ block and publish it as paired
.iand.qchannels.While a receive stream runs, the block is taken from that stream rather than the device, so it stays contiguous with the surrounding fetches and also publishes
backlogandoverflow.- Parameters:
- Returns:
Measurement | None – The published block, or
Noneif the read returned no samples.- Raises:
ValueError – If
n_samplesis not positive.
- start(
- *,
- direction: Direction = Direction.RX,
- channels: Sequence[str] = ('0',),
- background: bool = False,
- n_samples: int = 1024,
- publish_spectrum: bool = False,
Begin continuous acquisition.
With
background=Truethe daemon runsfetch_iqin a loop, which the blocking fetch paces, so blocks publish without a loop of your own.- Parameters:
direction (Direction)
Signal path,
Direction.RXorDirection.TX.channels (Sequence[str])
Channels the stream covers.
background (bool)
Hand the fetch loop to the background daemon.
n_samples (int)
Samples per channel per block, when
backgroundis set.publish_spectrum (bool)
Also publish spectrum features for each block, when
backgroundis set.
- property background_interval: float#
Background daemon loop period.
start(background=True)sets it to0:fetch_iqblocks until the radio has the samples, so it paces the loop itself.- Returns:
float – Loop period in seconds.
- stop(**kwargs: Any) None[source]#
Stop the background daemon and every running hardware stream.
- Parameters:
**kwargs
Ignored.
- fetch_iq( ) Measurement | None[source]#
Return the next contiguous block from the running stream and publish it.
Publishes the block as paired
.iand.qchannels for every channel the stream covers, plusbacklogandoverflowstream-health channels.- Parameters:
- Returns:
Measurement | None – The published block, or
Noneif the fetch returned no samples.- Raises:
ValueError – If
n_samplesis not positive.
- get_backlog() int[source]#
Return how many samples are waiting on the receive stream.
- Returns:
int – Samples per channel.
- Raises:
NotImplementedError – If the driver does not support streaming.
- is_streaming(
- *,
- direction: Direction = Direction.RX,
Report whether a stream is running.
- Parameters:
direction (Direction)
Direction to check.
- Returns:
bool –
Truewhile a stream started through this instrument is running.
- compute_psd( ) tuple[ndarray, ndarray] | None[source]#
Acquire one block and return one channel’s power spectral density. Publishes nothing.
Uses a Hann-windowed FFT. Frequencies are absolute, offset by the tuned center frequency.
- Parameters:
- Returns:
tuple[numpy.ndarray, numpy.ndarray] | None –
(frequencies_hz, power_db), frequencies in Hz and power in dB relative to one squared sample unit per Hz.Noneif the read returned no samples.- Raises:
ValueError – If
n_samplesis not positive.
- measure_spectrum( ) Measurement | None[source]#
Acquire one block and publish four scalar spectrum features per channel.
Publishes
spectrum.peak_power_db,spectrum.peak_freq_hz(Hz),spectrum.mean_power_db, andspectrum.occupied_bw_hz(Hz, the band holding 99% of total power). The spectrum array itself is not published; usecompute_psdfor it.- Parameters:
- Returns:
Measurement | None – The published features, or
Noneif the read returned no samples.- Raises:
ValueError – If
n_samplesis not positive.
- get_center_freq( ) Measurement[source]#
Query the RF center frequency and publish it as
center_freq.
- set_sample_rate( ) Command[source]#
Set the IQ sample rate and publish it as
sample_rate.cmd.- Parameters:
- Returns:
Command – The published command.
- get_sample_rate( ) Measurement[source]#
Query the IQ sample rate and publish it as
sample_rate.
- get_gain( ) Measurement[source]#
Query the gain and publish it as
gain.
- set_gain_mode( ) Command[source]#
Hand gain to the AGC or take manual control, and publish it as
gain_mode.cmd.- Parameters:
- Returns:
Command – The published command.
- get_gain_mode( ) Measurement[source]#
Query the gain mode and publish it as
gain_mode.
- get_bandwidth( ) Measurement[source]#
Query the IF or filter bandwidth and publish it as
bandwidth.
- set_freq_correction( ) Command[source]#
Set the reference oscillator correction and publish it as
freq_correction.cmd.
- get_freq_correction( ) Measurement[source]#
Query the reference oscillator correction and publish it as
freq_correction.
- set_antenna( ) Command[source]#
Set the antenna port and publish it as
antenna.cmd.- Parameters:
antenna (str)
Port name, one of the driver’s
list_antennas.direction (Direction)
Signal path,
Direction.RXorDirection.TX.channel (str)
Channel on that path, e.g.
"0".**kwargs
Tags added to the published value, on top of the instrument’s default tags.
- Returns:
Command – The published command.
- add_background_daemon_function(
- method: Callable,
- *args,
- **kwargs,
Append
methodto the daemon’s call list. Usedefine_background_daemonto replace instead.
- add_publisher(
- publisher: Publisher,
Register a publisher to receive this instrument’s Measurement/Command data.
- property channel_names: tuple[str, ...]#
Return an insertion-ordered snapshot of all published channel names.
Names are complete after one full daemon iteration: {name}.loop_time publishes every iteration, so call get_channel(“loop_time”, wait_for_new_samples=True) then read channel_names to ensure the complete set has arrived.
- Raises:
RuntimeError – No background buffer;
start()was not called.
- define_background_daemon(
- method: Callable,
- *args,
- **kwargs,
Replace all daemon functions with a single
method(called with the given args).
- get_antenna( ) Measurement[source]#
Query the selected antenna port and publish it as
antenna.
- get_channel( ) Measurement#
Return the most recent
lengthsamples forchannel_namefrom the in-memory buffer.If the channel does not exist yet, or no sample is available, the code will always block until
timeoutexpires.- Parameters:
channel_name
Name of the channel to retrieve.
length
Number of trailing samples to return.
wait_for_new_samples
Block until at least
lengthnew values arrive.timeout
Seconds to wait when insufficient data exists or
wait_for_new_samples=True.
- Raises:
RuntimeError – No background buffer;
start()was not called.ChannelNotFoundError – channel had no values and no data appeared before
timeout.wait_for_new_samples=Trueand channel did not appear withintimeout.ChannelValueTimeoutError –
wait_for_new_samples=Trueand values did not arrive withintimeout.
- get_single_channel_value(
- channel_name: str,
Return the most recent sample for
channel_namefrom the in-memory buffer.This will not wait, if data is not available then
Noneis returned.- Parameters:
channel_name
Name of the channel to retrieve.
- Raises:
RuntimeError – No background buffer;
start()was not called.
- publish(
- data: Measurement | Command,
- **kwargs,
Fan
dataout to every configured publisher;kwargspass through.