Open software against a calibrated front end: the boundary, and how to work across it
Open software against a calibrated front end: the boundary, and how to work across it
Software-defined radio gives an engineer every sample and no absolute reference; an instrument gives an absolute reference and, usually, no way in. This handbook is about the boundary between them: what a software-defined receiver is, what real-time analysis guarantees that a swept receiver cannot, the SoapySDR abstraction layer documented in enough detail to work from, the ICX-FieldHawk reviewed against seven requirements derived before it is named, and six GNU Radio signal chains against a calibrated front end, with the practice and quick reference an engineer needs on the bench.
RF and systems engineers building measurement or monitoring systems on open software; researchers and teaching staff who need a result that survives peer review; product architects deciding how much of a receiver to build; test engineers who want the samples underneath an analyzer they already own.
This is a reference document, entered at the section that answers the question in hand rather than read from front to back, so it is arranged in five parts that can be entered separately, and the sections that matter to each kind of reader are named here.
Table 1 is the router. Find the row that matches why you opened this document, and start where it tells you to.
| If you are | Start at | And you can skip |
|---|---|---|
| Evaluating whether an instrument can be programmed at all | Part I, sections 2 and 3, then Part II | Part III |
| Building a GNU Radio system against a calibrated front end | Part III, then section 22 | Part I, sections 2 and 3 |
| Specifying an instrument for a project | Part II, then the selection guide in section 28 | Part III |
| Trying to make an existing flowgraph produce a defensible number | Section 22, then section 26 | Parts I and IV |
| Looking for a number you already understand | Section 28, the quick reference | everything else |
Every figure in this handbook carries a tag saying what kind of evidence it is. Measured is a screenshot of a real instrument or a real host application showing real data. Derived is a chart computed from the relations in this document, with no measurement behind it. Schematic is a drawing made to explain something, and carries no data claim. Illustration, used on the cover, is a scene that sets a context and is never evidence. The tags are printed so that a reader checking a claim can weight each figure accordingly.
Five terms are used precisely in this handbook and loosely almost everywhere else, so they are fixed here before anything depends on them.
Every radio-frequency figure quoted in this handbook assumes ten minutes of warm-up and 25 °C ambient. Spur reject is in its standard setting except where a figure states otherwise, which matters for three of the four published sweep-speed values: the fastest figures are measured with spur reject bypassed, and each carries that condition in the table where it appears. Figures taken from a cold start are covered by no specification on these datasheets.
For most of the history of spectrum analysis the instrument was the measurement. A swept superheterodyne receiver moved a physical filter across a span, a detector reduced what passed through it to a trace, and the trace was the answer. The engineer chose the settings and read the result, and everything between those two acts was fixed at the factory.
Two things changed that. Converters became fast enough to digitize a useful span directly, which moved the boundary between fixed hardware and changeable processing toward the antenna. And general-purpose computers became fast enough to do the processing that used to need dedicated silicon. The result is that the interesting part of a modern receiver is software, and software can be replaced.
Instrument makers had a reason to be cautious about it, and the reason is worth understanding. An instrument's value is not that it computes a spectrum. It is that the number it reports is traceable to a standard, with a stated uncertainty, by an unbroken chain. Open the processing and the question is what happens to that chain. For most of the open ecosystem there was never a chain to break: the hardware reported a fraction of full scale and the user supplied the meaning.
That is the tension this handbook is about. It is not open against closed, or cheap against expensive. It is that the two families each solved half of the problem, and until recently a buyer had to pick which half to go without.
Every receiving instrument draws a line. On one side is hardware the user cannot change: the antenna port, the attenuator, the amplifiers, the mixers and filters, and the converter. On the other is processing that could in principle be rewritten. The history of the last thirty years is that line moving toward the antenna, and more of what falls behind it becoming the user's rather than the vendor's.
Figure 1 is worth holding in mind through the rest of Part I. Sections 3 and 5 are about what the left of that line has to deliver. Sections 6 and 7 are about how an application reaches across it.
Table 2 places the classes of hardware an engineer chooses between along that line. It is deliberately written about classes rather than named products, because the boundary moves with each generation and the classes do not.
| Class | Where the line falls | What you get | What you supply |
|---|---|---|---|
| Hobby receiver | Immediately after the converter | Samples, very cheaply, over a narrow span | Every correction, and a span that limits what can be seen at once |
| Prosumer or development board | Immediately after the converter | Wide instantaneous span, open drivers, good documentation | The entire amplitude reference, and its maintenance across gain states |
| Closed benchtop analyzer | At the far right, after the measurement | Traceable numbers with a stated uncertainty | Nothing, and you cannot reach the samples either |
| Instrument with an open sample path | After the correction, before the processing | Traceable samples that an open framework can consume | The processing you wanted to write anyway |
Figure 1 drew the down-conversion stage as a mixer, a local oscillator and an IF filter. That is one way to build it, and not the only one. How a receiver gets from RF to samples is the first decision its designer makes, and it fixes most of what the rest of the chain can achieve. Four architectures cover almost every receiver built today, and most of the rest combine them. Table 3 sets them side by side.
A superheterodyne receiver filters and converts the signal in two or more stages and digitizes it at an intermediate frequency. A bank of filters ahead of the first mixer, the preselector, rejects the image and the strong out-of-band signals that would otherwise mix into the band of interest. That is what makes the architecture the reference for crowded spectrum. It is also what makes it large: every stage is a physical component with its own size, power and cost.
A block converter performs one conversion, shifting a whole band to a range where another receiver can take it. It is usually a way to extend frequency coverage rather than a complete receiver.
A direct-sampling receiver has no mixer at all. The converter digitizes the RF input directly, and everything after it is arithmetic. That gives the widest instantaneous span and the fewest analog parts, and it hands the whole dynamic-range budget to the converter. A strong signal anywhere in the converter's input band arrives in the data, wanted or not. It is the architecture section 2 describes when it says converters became fast enough to digitize a useful span directly.
A zero-IF receiver converts straight to baseband I and Q, usually inside one integrated transceiver chip. It is the smallest and lowest-power option. Its characteristic errors are a DC offset at the center of the band, local-oscillator leakage and an image produced by I/Q imbalance. They are corrected by algorithms rather than removed by filters.
Combinations are common. A typical one puts a block converter ahead of one of the other three to reach higher frequencies.
| Architecture | What is fixed before the converter | What it is good at | What it costs | What to check on a datasheet |
|---|---|---|---|---|
| Superheterodyne | Preselector, two or more conversion stages, IF filters | Selectivity and dynamic range in crowded spectrum; wide tuning range | Size, power, complexity, cost | Image rejection and IF rejection, each with its frequency range |
| Block converter | One conversion stage | Extending another receiver's frequency coverage | Fewer points at which to optimize performance | The converter's image rejection, and the downstream receiver's own figures |
| Direct sampling | Anti-alias filtering only | Widest instantaneous span; fewest analog parts | Dynamic range limited by the converter; out-of-band energy reaches the data | Spurious-free dynamic range, and how aliased bands are filtered |
| Zero IF | Direct conversion to baseband I and Q | Smallest size and lowest power | DC offset, LO leakage and I/Q image, corrected in software | DC offset, LO leakage and image rejection at the band edges |
The lines between these architectures blur in practice. A receiver can switch between them by frequency band, and many modern instruments digitize an IF and finish the conversion in an FPGA, so the last analog stage is a design choice rather than a fixed boundary. The four are still the right starting question, because each one tells a reader which published figure to check first.
A number without a stated uncertainty and a traceable reference is a reading. A number with both is a measurement. The distinction is the reason the two families of hardware in this handbook are not interchangeable.
An uncorrected receiver reports its converter's output. That output is a fraction of full scale, and turning it into an absolute power in dBm needs a table of corrections covering every gain state and every frequency in use, built by the user against a reference source, maintained as it drifts, and re-checked when anything in the chain changes. Nothing prevents an engineer from building that table. It is a large, recurring job, and it has to be budgeted from the start.
Calibration is not a feature of the processing. It is a property of the path, and it has to be applied to the samples before any processing block sees them. A correction applied downstream of a decision that was made on uncorrected data does not recover the decision.
This is why the amplitude accuracy figure matters more than it looks. A receiver quoting plus or minus 2.0 dB is making a claim about every reading it produces under stated conditions. A board quoting nothing is not making a weaker claim; it is making no claim, and the difference between those two positions is the difference between a result that can be published and one that cannot.
The second thing that separates instrument-grade acquisition from a development board is what happens to signals that are not on all the time. A swept receiver visits each frequency in turn, and anything that happens elsewhere while it is looking here is absent from the result. The absence is silent: the trace looks the same whether the band was quiet or the receiver was pointed the other way.
A real-time receiver holds a span continuously and transforms every sample. The published relations for a gap-free engine of this kind are short, and they let a reader price any configuration rather than only the ones on a datasheet:
where
where
The factor of two in equation (2) is not a safety margin. It is the worst case for a burst that straddles a frame boundary: a burst exactly one frame long, arriving halfway through a frame, puts half its energy in each of two frames and is measured at full amplitude in neither. Guarantee full amplitude and you must guarantee that at least one whole frame falls inside the burst, which needs two frames of observation.
Table 4 evaluates both relations at four settings, two of which are published operating points and two of which are not. The second pair is the argument for publishing a relation rather than a curve: a reader can price a configuration the vendor never considered.
| Transform size N | Decimation D | Frame rate | 100 percent POI |
|---|---|---|---|
| 2,048 | 1 | 61,035 frames/s | 32.768 µs |
| 32 | 1 | 3,906,250 frames/s | 0.512 µs |
| 4,096 | 1 | 30,518 frames/s | 65.536 µs |
| 2,048 | 512 | 119 frames/s | 16.8 ms |
| Rows one and two: published operating points of the ICX-095, 200 and 400 chain on the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. Rows three and four: derived from equations (1) and (2); row three is also published for the ICX-045, 060 and 090 with option 50. | |||
The practical consequence is a number a system architect can put on a requirement. At 0.512 microseconds of guaranteed intercept, every event in the band lasting longer than about half a microsecond is measured at its true amplitude rather than glimpsed. A swept receiver at the same span offers no such boundary at all, and the arithmetic in BNC-AN-102 works through how far apart the two answers land.
Every manufacturer of software-defined radio hardware ships a programming interface, and every one of them is defensible on its own terms. The trouble is not that any single one is badly designed. It is that they disagree with each other on exactly the points an application has to commit to in its first hundred lines.
How is a device found: by scanning a bus, by reading a serial number, by opening a named handle? Is the tuner one center frequency, or a local oscillator and a digital down-converter the caller has to place separately? Is gain a scalar or a chain of named stages whose order matters? Do samples arrive as interleaved 16-bit integers, as normalized floats, or packed twelve to a word? None of those questions has a natural answer, so each vendor answered differently, and application code inherits all of the answers.
The demodulator, the synchronizer, the equalizer and the decoder are portable, and they are the expensive part to validate. The forty lines that open the radio are not portable, and they decide whether any of the rest can run. A pipeline that took months to validate becomes device-specific because of the cheapest code in it. Test pays again, because a change to acquisition is a change to the measurement, and revalidated data may no longer be comparable with the archive.
SoapySDR removes that coupling. It is an open-source, vendor-neutral hardware abstraction layer for software-defined radio: one C++ interface with C and Python bindings that an application programs against, and a plug-in mechanism through which any manufacturer can make its hardware appear behind that interface. The application asks for a device, sets a frequency, sets a rate and reads complex samples. It does not know which radio answered.
SoapySDR is not the only answer to the portability problem, and knowing what else exists is part of choosing it deliberately rather than by default.
It is open source, vendor neutral and maintained as a community project rather than by any hardware manufacturer, which matters for the reason a second source usually matters: the interface an integrator writes against does not belong to the company selling the radio. Its license and its current release are worth checking before a product commits to it, along with those of the framework and any out-of-tree modules in the chain; four independent projects appear in Part III of this handbook and each carries its own terms.
Figure 3 is worth reading as a boundary line rather than a stack. In a closed instrument the line falls high: the vendor's application owns acquisition, analysis and display, and you get what was exposed. In a bare development board it falls very low: you own everything above the converter, which is freedom and is also a great deal of unfinished work. SoapySDR does not move the line. It standardizes where the line is drawn, so the same application code meets the same boundary whatever is underneath.
One type carries most of the API. A dictionary of string key-value pairs, called Kwargs, describes a device that was found, requests a device to open, configures a stream and passes hints into a tuning call. It has a compact text form, which is why device arguments across the whole ecosystem look like a query string.
# enumerate, then open the specific unit by serial
found = SoapySDR.Device.enumerate() # one per device
sdr = SoapySDR.Device('driver=<name>,serial=01AB')Enumeration is not guaranteed to be cheap or free of side effects. Some modules open the device to interrogate it, so enumerating while another process holds the device can fail, and can occasionally disturb the process that holds it. Enumerate at startup and cache the result.
This is the most important habit in the interface. A setter in SoapySDR is a request, not an assignment. The hardware has a synthesizer step size, a clock divider tree, filters with discrete corners and a gain table with real granularity. Ask for 2.000000 MHz of sample rate and you may get 2.000000, or 1.999999, or 1.920000, depending on what the master clock divides down to.
sdr.setSampleRate(SOAPY_SDR_RX, 0, 2e6) fs = sdr.getSampleRate(SOAPY_SDR_RX, 0) # use fs, not 2e6, from here on
The interface is built on interrogation rather than a table of what devices can do. Nearly every settable quantity has a matching query: getFrequencyRange, getSampleRateRange, getGainRange return a minimum, a maximum and a step, where a step of zero means continuous. The list calls report the names a particular device recognizes. The argument-info calls return records carrying a key, a default, a display name, a unit and a permitted range, which is how a capable receiver application builds a settings panel for hardware it has never heard of.
Frequency has an overall call and a set of named tuning elements. A real receive chain rarely has one frequency-setting device in it: there is a local oscillator, and very often a digital shift after the converter that can move the band by a finer amount. Listing the elements returns them in signal order from the antenna inward, conventionally a radio-frequency element and a baseband element. Call the overall setter and the driver distributes across them, typically placing the oscillator as close as its step allows and making up the remainder digitally, so the result is exact even when the synthesizer is coarse. That is one of the better parts of the design.
Both forms accept a dictionary of hints. The commonest asks for a deliberate offset between the front-end oscillator and the requested center, so that oscillator leakage and the converter's own offset land outside the band of interest rather than in the middle of it. A hint a driver does not recognize is ignored rather than rejected.
Gain follows the same two-level pattern, and here the difference between the levels has consequences for a measurement. The overall call takes one number in decibels and lets the driver decide how to realize it. Named stages are listed in signal order and set individually.
Gain taken early improves noise figure and degrades linearity; gain taken late does the reverse. That trade is the engineering content of a receive chain. Overall gain is portable and imprecise; named stages are precise and not portable, because naming a stage requires device-specific knowledge in an interface designed to avoid it. There is no third option. Write against the overall call by default and carry a small explicit table for the devices where the distribution matters. And for any absolute amplitude work, turn automatic gain control off: the loop changes the scaling underneath your data.
These are two controls, and conflating them produces measurements that are wrong in a way nothing downstream can detect. The sample rate sets how many complex samples per second cross the boundary. The bandwidth sets the analog or digital filter in front of the converter. They are related and they are not the same, and setting one does not set the other.
Set a rate of 20 MSPS and leave the filter at 56 MHz and everything outside the 20 MHz Nyquist window folds back into the data as an alias, indistinguishable from signal. Set a filter far narrower than the rate and the band edges are attenuated by a roll-off nobody recorded. Usable bandwidth is typically about 0.8 of the sample rate, 100 MHz of 125 MSPS on this instrument, which is why a file's sample rate is not its bandwidth.
Streaming has five calls and a lifecycle. Set up a stream naming a direction, a sample format and the channels; activate it; read repeatedly into a buffer; deactivate and close. The read call returns the number of elements actually delivered, or a negative error code, along with flags and a timestamp.
rx = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0]) sdr.activateStream(rx) buff = numpy.empty(8192, numpy.complex64) sr = sdr.readStream(rx, [buff], len(buff)) # sr.ret, sr.flags, sr.timeNs sdr.deactivateStream(rx); sdr.closeStream(rx)
Two formats matter in practice. Complex 16-bit integers are what most hardware produces and move half the bytes; complex 32-bit floats are what most processing wants and cost a conversion. Ask for the format the hardware natively produces and the driver hands it over; ask for anything else and somebody converts, either in the driver or in your code. At high rates that conversion is not free, and it is the first thing to remove when a chain cannot keep up.
If the application does not read fast enough, the driver's buffers fill and samples are discarded. The stream continues and the data after the gap is still valid, so nothing crashes and nothing visibly breaks. What breaks is continuity: any measurement that assumes an unbroken time base across the gap is now wrong, and a spectrum averaged across one is quietly incorrect. Detect it in the return code rather than trusting a console character, because how overflow is reported varies between drivers.
GNU Radio is the framework this handbook works through, and it is not the only application that speaks this interface. A receiver that appears as a standard device appears to all of them. Gqrx is a general-purpose receiver and spectrum display, useful as a first sanity check that hardware works before any flowgraph exists. SDRangel and CubicSDR are multi-channel receivers with device panels built from the interface's own capability queries. welle.io is a digital radio decoder. None of these needed to know anything about this instrument in advance, which is the whole return on a standard interface, and any of them is a faster way to answer “is the hardware working” than a flowgraph is.
Table 5 is the working set. Everything an acquisition program needs is in it, grouped by what it controls, so a reader can write against the interface without leaving this page.
| Area | Calls | Note |
|---|---|---|
| Discovery and lifetime | enumerate, make, unmake | Enumerate once at startup and cache; enumeration is not guaranteed cheap |
| Channels | getNumChannels, getFullDuplex, getChannelInfo | Check rather than assume; a receive-only instrument reports zero transmit channels |
| Tuning | setFrequency, getFrequency, getFrequencyRange, listFrequencies | The named-element form reaches the oscillator and the digital shift separately |
| Gain | setGain, getGain, getGainRange, listGains, hasGainMode, setGainMode | Turn gain mode off for absolute amplitude work |
| Rate and bandwidth | setSampleRate, getSampleRate, getSampleRateRange, setBandwidth, getBandwidth, getBandwidthRange | Two different controls; set both deliberately |
| Antenna | listAntennas, setAntenna, getAntenna | Names are device-specific |
| Clock and time | listClockSources, setClockSource, listTimeSources, setTimeSource, getHardwareTime, setHardwareTime | How an external reference and a disciplined clock are selected |
| Formats | getNativeStreamFormat, getStreamFormats | The native format call also returns full scale, which is the number that turns a sample into a level, and it is the call this handbook's whole argument turns on |
| Streaming | setupStream, activateStream, readStream, deactivateStream, closeStream | Five calls, in that order; getStreamMTU sizes the read |
| Device settings | getSettingInfo, writeSetting, readSetting | Where a driver exposes anything the standard interface has no name for, including reference level on an instrument that has one |
| Sensors | listSensors, readSensor | Temperatures, lock status, whatever the device offers |
Two of this handbook's operational arguments rest on what the stream reports back, so Table 6 names the values rather than leaving them as a category. Every one is a return code or a flag from the read call.
| Value | Meaning | What to do about it |
|---|---|---|
| A positive return | the number of elements delivered, which may be fewer than asked for | Normal. Use the returned count; never assume a full buffer |
| Timeout | no samples arrived inside the timeout | Normal when idle; a persistent timeout after activation means the device is not streaming |
| Overflow | the driver discarded samples because the application did not read fast enough | Log it with a timestamp and discard the acquisition. This is the failure that leaves no gap in the delivered stream |
| Stream error | a transport or device fault | Tear the stream down and re-open it |
| Corruption | the driver detected damaged data | Discard and investigate the link before trusting anything from that session |
| Not supported | the request is outside what the device offers | Query the ranges rather than assuming them |
| Has-time flag | the returned timestamp is meaningful | Only trust a timestamp when this flag is set |
| End-of-burst flag | this read completed a burst | Use it to bound a triggered acquisition rather than counting samples |
One command-line tool answers most installation questions, and running it before anything else saves a great deal of time spent debugging a flowgraph that was never going to work.
SoapySDRUtil --info # library version, module path SoapySDRUtil --find # every device any module sees SoapySDRUtil --probe="driver=<name>" # one device
SoapySDR standardizes control and transport. It does not standardize meaning. That sentence is the hinge of this handbook, so it is worth spelling out exactly what falls outside the contract.
None of this is a defect. An abstraction that tried to standardize calibration across hardware that mostly has none would have failed to be adopted, and adoption is the whole value of an abstraction layer. But it does mean the question that decides whether an open flowgraph can produce a defensible number is a question the abstraction cannot answer, and the reader has to ask it of the hardware instead.
Sections 1 to 7 are an argument. Turned into requirements, they are what to put on a specification for a receiver that has to serve both an open flowgraph and a measurement file. Table 7 states each one with the section it comes from.
| # | Requirement | Derived from |
|---|---|---|
| R1 | Absolute amplitude accuracy stated as a bound, with its conditions, across the frequency range in use | Section 5 |
| R2 | The correction applied to samples before they cross the abstraction boundary, not offered as a table for the user to apply afterward | Sections 4 and 7 |
| R3 | Gap-free acquisition with a published intercept relation, so a minimum detectable event duration can be derived rather than assumed | Section 6 |
| R4 | Sample rate and usable bandwidth published as two separate numbers | Section 7 |
| R5 | A driver module for the abstraction layer, with the calibration installed alongside it | Sections 6 and 7 |
| R6 | The native interface still reachable, for the measurement modes the abstraction cannot express | Section 8 |
| R7 | One interface across form factors, so a routine developed on a bench unit runs unchanged on a field unit | Section 3 |
The ICX-FieldHawk is a real-time spectrum analyzer family built around one analysis engine and one host interface, SpectraCore, in three physical forms. What changes between them is packaging, environmental class and how the instrument is carried to the signal. What does not change is the measurement, which is the property that matters for R7.
Table 8 is the published family. The frequency column is what the model number encodes, and the last column divides the family into two signal chains: the ICX-045, 060 and 090 ship with 50 MHz of analysis bandwidth and a 16 ns sample interval, taking 100 MHz and 8 ns with option 50, and every other model holds 100 MHz at 8 ns as standard. Every current model is orderable with the -SDR option, which appends -SDR to the part number and ships the SoapySDR driver, the unit's calibration files and the example flowgraphs of Part III.
| Model | Form factor | Frequency | Analysis bandwidth |
|---|---|---|---|
| ICX-045, ICX-060, ICX-090 | Handheld, 10.1 in multi-touch display | 9 kHz to 4.5, 6 and 9 GHz | 50 MHz standard; 100 MHz with option 50 |
| ICX-095, ICX-200, ICX-400 | Handheld, 10.1 in multi-touch display | 9 kHz to 9.5, 20 and 40 GHz | 100 MHz |
| ICX-095R, ICX-200R, ICX-400R | IP68 tablet | 9 kHz to 9.5, 20 and 40 GHz | 100 MHz |
| ICX-200U, ICX-400U | USB (Type-C) or LAN (Gigabit Ethernet) module | 9 kHz to 20 and 40 GHz | 100 MHz |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. | |||
Figure 4 is the 40 GHz IP68 tablet. The range across the family is wider than one render shows: the published module weights are under 420 g for the USB module and under 665 g for the LAN module, against 1.5 kg for the handheld with its display and battery. The environmental classes are options rather than variants: the base class covers 0 to 50 °C, option 40 widens it to −20 to +65 °C and option 41 to −40 to +65 °C. Those classes are published on the IP68 tablet and module datasheets; the handheld publishes 0 to 50 °C operating and nothing wider.
A selection guide that names form factors has to say what they weigh and what they draw. Table 9 is the published physical data, with the IP68 tablet rows the datasheets leave unstated marked rather than guessed.
| Handheld | IP68 tablet | Modules | |
|---|---|---|---|
| Display | IPS LCD 1280 x 800, 10.1 in multi-touch | multi-touch | none; host software |
| Weight | 1.5 kg | Consult factory | < 420 g (USB); < 665 g (LAN) |
| Size | 260 x 179 x 46 mm (ICX-095, 200, 400); 260 x 185 x 46 mm (ICX-045, 060, 090) | Consult factory | 139 x 68 x 31 mm (USB); 167 x 117 x 30 mm (LAN) |
| Power | USB PD 65 W; 25 W typical (ICX-095, 200, 400), 32 W (ICX-045, 060, 090) | 10 to 16 W typical | 10 to 14 W (USB); 13 to 16 W (LAN) |
| Battery | 3 h typical (ICX-095, 200, 400); 2.5 h (ICX-045, 060, 090) | Consult factory | not applicable |
| Temperature | 0 to 50 °C operating | 0 to 50 °C; −20 to +65 °C (opt 40); −40 to +65 °C (opt 41) | same classes |
| Ingress | not published | IP68 chassis in prose; no published specification row | not published |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. | |||
The handheld datasheet describes the ICX-045, 060 and 090 as having a superheterodyne front end with up to 14 preselector filter bands, the first architecture in Table 3, with IF and image rejection above 95 dBc typical. For the other models, the datasheets publish the figures Table 3 says to check. On the ICX-400 with spur rejection on, image rejection is better than 90 dB typical to 33 GHz and better than 58 dB from 33 to 40 GHz, and IF rejection is better than 90 dB typical, except better than 68 dB from 8.2 to 21.75 GHz. Every model also brings the final IF out to an analog IF output (MMCX, 50 Ω, −25 dBm maximum): 312.5 MHz ± 50 MHz on the ICX-045, 060 and 090, and 307.2 MHz ± 50 MHz on every other model. An external recorder or processor can take the band there, alongside the digital stream.
This section is the instrument's answer to R1. Every figure below carries its condition, because a specification without its condition is not a specification.
Table 10 is the published radio-frequency performance. It is longer than a summary needs to be because a value without its condition cannot be compared with another.
| Parameter | Published value | Condition |
|---|---|---|
| Amplitude accuracy | ±2.0 dB / ±3.0 dB | 9 kHz to 9.5 GHz / 9.5 to 40 GHz |
| Displayed average noise level | −159.9 dBm/Hz (ICX-400 family); −166.3 dBm/Hz (ICX-200 family); −167.5 dBm/Hz (ICX-095 family) | 90 MHz to 3 GHz band, RBW 1 kHz, reference level −50 dBm |
| SSB phase noise | −107.5 dBc/Hz (ICX-400 family); −99.7 dBc/Hz (ICX-200 family); −101.6 dBc/Hz (ICX-095 family) | 1 GHz carrier, 10 kHz offset |
| SSB phase noise | −85.7 dBc/Hz; −90.6 dBc/Hz; −98.5 dBc/Hz | at 40, 20 and 9.5 GHz carriers, 10 kHz offset, on the ICX-400, 200 and 095 families |
| Third-order intercept | +40.3 dBm | 1 GHz, reference level +20 dBm, ICX-400 |
| Second-order intercept | +75.5 dBm | 1 GHz, reference level +20 dBm, ICX-400 |
| Display range | DANL to +20 dBm (ICX-400 family); to +23 dBm (ICX-095 and 200 families) | typical |
| Maximum CW input | +23 dBm / +10 dBm | 50 MHz and above, preamp off / below 50 MHz or preamp on |
| Image rejection | > 90 dB typical to 33 GHz; > 58 dB, 33 to 40 GHz | ICX-400 family, spur reject standard |
| IF rejection | > 90 dB typical, except > 68 dB from 8.2 to 21.75 GHz | ICX-400 family, spur reject enhanced |
| VSWR | < 2.0:1 / < 3.0:1 | 90 MHz to 16 GHz / 16 to 40 GHz on the ICX-400 family; < 2.0:1 to 9.5 or 20 GHz on the ICX-095 and 200 families |
| IF in-band flatness | ±2.0 dB | across the analysis bandwidth |
| Sweep speed | 1.0 THz/s | RBW 250 kHz, FPGA path, spur reject bypassed |
| Sweep speed | 577.5 GHz/s | RBW 250 kHz, standard |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. Standing conditions: 10 minute warm-up, 25 °C, spur reject standard. | ||
Spurious-free dynamic range is the figure much software-defined radio hardware quotes, and a reader arriving from that world will look for it first. It is the ratio between the strongest signal a receiver can handle and the largest unwanted response the receiver itself adds, and it compresses several mechanisms into one number. Table 10 publishes those mechanisms separately: the intercept points for intermodulation, image and IF rejection for the responses a superheterodyne creates, and the displayed average noise level for the floor. For the common two-tone case, a reader can estimate the figure from two of them:
where
Both terms have to be taken at the same reference level, because reference level sets the attenuation and gain distribution that move both of them. The datasheets publish IIP3 at reference levels of +20, 0 and −20 dBm, and DANL at −20 dBm and at −50 dBm (−70 dBm on the ICX-045, 060 and 090), so −20 dBm is the condition at which the estimate can be made from published figures. For the ICX-400 at 1 GHz, IIP3 is +8.7 dBm and DANL is −154.1 dBm/Hz. In a 1 kHz resolution bandwidth N is −124.1 dBm, and the SFDR is about (2/3) × 132.8, or 89 dB. The ICX-095 under the same conditions, with IIP3 +10.5 dBm and DANL −146.0 dBm/Hz, gives about (2/3) × 126.5, or 84 dB.
The estimate holds only at that condition. On the ICX-400 at 1 GHz, IIP3 is +40.3 dBm at a +20 dBm reference level and +8.7 dBm at −20 dBm, a 31.6 dB swing from one setting. An SFDR quoted without its reference level and resolution bandwidth cannot be compared with another, which is why this handbook gives it as an estimate with its conditions, alongside the published figures, and not as a headline number.
Displayed average noise level is quoted per hertz. To get the noise floor in a measurement at a given resolution bandwidth, add ten times the log of the resolution bandwidth in hertz. At −159.9 dBm/Hz and a 1 MHz resolution bandwidth that is −159.9 + 60, or −99.9 dBm, which is sixty decibels worse than the headline and is the number your signal has to clear.
The front end ends at a fixed intermediate frequency, with the band of interest centered on it. The datasheets publish that IF because every model brings it out to a connector: 312.5 MHz ± 50 MHz on the ICX-045, 060 and 090, and 307.2 MHz ± 50 MHz on every other model. An analog-to-digital converter digitizes that band, and digital down-conversion finishes the job in arithmetic. A numerically controlled oscillator and a complex mixer shift the band to zero frequency, a low-pass filter removes everything outside it, and the stream is decimated to complex I and Q samples. Figure 5 shows the chain.
The I/Q rate is not the converter rate. The datasheets publish the maximum rate of the complex I/Q stream: 125 MSPS, or 62.5 MSPS on the ICX-045, 060 and 090 without option 50. That is a different quantity from the converter's rate. A complex stream at a rate fs represents fs of bandwidth, because I and Q together carry both sides of zero frequency, while a single real converter needs more than twice the bandwidth it digitizes; the quick reference in section 28 states both rules. This handbook therefore quotes 125 MSPS as the maximum I/Q rate and never as the converter rate.
The available rates. Every rate the instrument delivers comes from one relation:
where
Each step down halves the sample rate and the data the host has to absorb. At full rate the datasheets publish the bandwidth that goes with it: 100 MHz at 125 MSPS, and 50 MHz at 62.5 MSPS on the ICX-045, 060 and 090. At 16-bit components, which section 13 notes is a conventional format, 125 MSPS is 500 Mbyte per second, and decimating by four brings it to 125 Mbyte per second.
The right rate is the smallest one that still holds the signal, and it is rarely the rate a demodulator wants. The AM chain in Part III shows the pattern: it takes the stream at 976.5625 kSPS (D = 128) and resamples by 768/15,625 to reach exactly 48 kSPS of audio. Every chain in Part III makes the same move, which is why section 21 insists the rate arithmetic closes.
What a factor of four buys. Section 13 shows that the 128 Mbyte buffer holds about 0.26 seconds at full rate. Decimate by four and the stream drops to 125 Mbyte per second, so the same buffer holds about 1.0 second: four times the duration at a quarter of the sample rate. The trade is exact, because buffer duration is memory divided by data rate, and data rate is proportional to 1/D.
Burst and continuous. Table 11 publishes burst and continuous recording as two separate figures: 100 MHz burst and 25 MHz continuous on the ICX-095, 200 and 400 and on the IP68 tablet and module, and 50 MHz burst (100 MHz with option 50) and 12.5 MHz continuous on the ICX-045, 060 and 090. Burst fills the 128 Mbyte buffer; continuous is what can be carried to a host without a gap. A system that records to disk has to be sized on the continuous figure.
This is the instrument's answer to R3, and it is the part of the specification a reader can do the most with, because the governing relations are published rather than only the results. Equations (1) and (2) in section 6 are the datasheet's own, which is what lets a reader price a configuration the datasheet never mentions.
Figure 6 carries the trade that decides a monitoring architecture. A large transform buys frequency resolution and costs time resolution, and the two are locked together by a constant product. There is no setting that improves both.
Figure 7 is also the answer to a fair objection, and it carries a second check that looks at first like a contradiction. At 4,096 points and 125 MSPS the bin spacing is 30.518 kHz, yet the screen reports a resolution bandwidth of 60.3 kHz, twice as wide. Both are right. Resolution bandwidth is bin spacing multiplied by the window's equivalent noise bandwidth, and 60.3 divided by 30.518 is 1.976, which is the equivalent noise bandwidth of a Blackman-Nuttall window to four figures. A flat-top window would give about 3.77 instead. So the screen agrees with equation (2), with the bin spacing, and with the window it was configured to use. The datasheet's own Blackman-Nuttall endpoints imply a rounded 2.00 rather than the true 1.976, so a reader checking those instead has found the rounding, not an error. The published real-time resolution bandwidth range runs from 14.73 MHz down to 3.59 kHz with a flat-top window in thirteen grades, and real-time amplitude resolution is 0.75 dB.
R2 and R4 are answered here, and the second of them is answered in a way worth noticing: the datasheet publishes burst and sustained capture as two separate numbers rather than quoting the larger one alone.
Table 11 is the IQ path, and the pair of bandwidth rows at the top is the part worth pausing on.
| Parameter | Published value |
|---|---|
| Burst recording bandwidth | up to 100 MHz |
| Continuous recording bandwidth | up to 25 MHz |
| Built-in capture memory | 128 Mbyte |
| IQ sample rate | up to 125 MSPS |
| Decimation | 1 to 4096, in powers of two |
| External trigger response | up to 500 per second |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. | |
where
At 125 MSPS, and assuming a 16-bit component width, which is a conventional interleaved format rather than a published property of this instrument, equation (5) gives 500 Mbyte per second, so the 128 Mbyte buffer holds about 0.26 seconds of gap-free 100 MHz capture. That is the number to remember, and it is worth being careful about what it does and does not combine with. The 0.512 microsecond intercept of section 6 is a property of the real-time transform engine, not of this buffer, so the two must not be multiplied together to claim a count of resolvable events in one trigger. What the buffer figure alone tells you is how long a window of unbroken wideband signal you can take away and reprocess as many times as the investigation needs.
Figure 8 is R2 on the instrument's own glass, before any host is involved. Part III is the same samples reached through an abstraction layer instead, and the question that part has to answer is whether anything is lost on the way across.
A published function list is a weak argument on its own, because length is not merit. The argument worth making from this one is about what is not withheld.
Figure 9 also carries a detail worth noticing, because it is the kind of thing a measurement is for and a summary figure would hide. The harmonics do not decay monotonically: the second is 15 dB lower than the third and 25 dB lower than the fourth, so the fourth dominates the distortion total. A single total-distortion number would report the same 0.154 percent whichever harmonic carried it, and the corrective action is different in each case. This is the argument for a measurement that reports every harmonic separately rather than collapsing them.
The second-harmonic marker is not a harmonic. It reads 2.001549444 GHz against a fundamental of 1.000000693 GHz, which is 1.548 MHz off exactly twice the fundamental, and at −88.12 dBm it stands about seven decibels above the noise. That is a peak search returning noise. Markers three and four land within 2 kHz of exact and are real. The distortion total is unaffected, because that term carries under a third of one percent of the summed power, and the point of showing it is that a display which lets you check the frequency column is a display that lets you catch this, which is the whole argument for numbers over pictures.
Figure 10 is worth reading beside Figure 9 for what the two have in common. In both cases the instrument reports a derived quantity and also reports the raw numbers it derived it from, so the reader can check the derivation without trusting the instrument. That is a design choice rather than an accident, and it is the property to look for in any measurement function: a result you cannot recompute is a result you cannot defend.
The commercial argument is that a fleet assembled from these units is uniform: a routine written against one runs against all of them, because the measurement set is not licensed function by function. That argument is made here from the published list and never from a claim about anyone else's price list, which is a claim this handbook is not in a position to verify.
R6 asks that the native interface stay reachable for the measurement modes the abstraction layer cannot express, and Table 12 is the evidence for it. This is the list the flowgraph path in Part III stands alongside rather than replaces.
| Category | Published support |
|---|---|
| Languages | C, C++, C#, Python, MATLAB, Qt, LabVIEW |
| Instrument protocol | SCPI, standard |
| Operating systems | Windows 11, 10, 8 and 7; Debian 12, 11 and 10; Ubuntu 24.04 back to 18.04 |
| Host architectures | x64 and AArch64 |
| Host application | SpectraCore, on Windows and Linux |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. | |
Use SCPI or the native language bindings when you want the instrument's own measurements: real-time density, pulse parameters, phase noise, harmonics, the measurement functions of section 14. Use the abstraction layer when you want the samples and intend to write the processing yourself. The two are not alternatives that exclude each other, and a system that uses both is normal: drive a calibrated sweep over SCPI, then stream IQ into a flowgraph for the part the instrument does not measure.
The frequency reference is accurate to better than 1 ppm with the standard temperature-compensated oscillator and with the oven-controlled option 01 alike; what the OCXO adds is stability, better than 0.15 ppm over temperature and better than 1 ppm per year of aging. Global-navigation timing is available with a 1PPS accuracy of ±100 ns as standard and ±75 ns or ±50 ns with options on the IP68 tablet and module. Those timing numbers decide what a distributed system can do, and BNC-AN-110 works the arithmetic, and it is worth doing on the page. At 0.2998 m per nanosecond, ±100 ns is 30.0 m of range uncertainty before geometry, and one assumption travels with that number: it treats the bound as the uncertainty on the arrival-time difference. If each node carries ±100 ns independently, the difference carries a factor of root two more and 30.0 m becomes 42.4 m. Geometry then multiplies that 42.4 m: at a dilution of precision of 1.5, which is a good layout, it is 63.6 m of position error, and at a marginal 3 it is 127 m. The ±50 ns option halves both. Geometry is the term with no receiver parameter in it at all, which is why a site survey moves this number further than any receiver choice does.
Parts per million describes frequency accuracy against a disciplined source. It says nothing about holdover, which is what the oscillator does after the last correction, and holdover is governed by aging and temperature coefficient rather than by the offset on the datasheet. A phase-noise plot does not answer it either: phase noise starts at offsets of hertz and holdover across a ten minute outage lives near a millihertz, several decades lower. Ask for the holdover figure separately or measure it.
The timing arithmetic above treats each unit as an independent clock and asks how far apart two of them can be. A system of several receivers needs a different question answered first: what do the units share? Two levels are published for this family, and each enables a different class of application. Table 13 sets them out.
| Level | What the units share | What it enables | ICX-FieldHawk |
|---|---|---|---|
| Frequency lock | A common 10 MHz reference | The same frequency axis on every unit, with no drift between them | Published: external 10 MHz reference clock input (MMCX). Reference clock output: 10 MHz on the AUXIO connector, or 100 MHz on MMCX on the ICX-045, 060 and 090 |
| Time synchronization | GNSS 1PPS, triggers | Time-difference-of-arrival geolocation, and recordings from different units aligned in time | Published: GNSS 1PPS at ±100 ns, and ±75 ns or ±50 ns with options on the IP68 tablet and module; external trigger input and output |
Frequency lock is the easiest level to reach and the easiest to overestimate. Two units on one reference agree on frequency, but each unit's synthesizer settles at an arbitrary phase every time it tunes, so their phase relationship is unknown and changes with every retune. That is enough for a common frequency axis.
Time synchronization is what the arithmetic earlier in this section prices. It is enough for time-difference-of-arrival geolocation, whose error budget BNC-AN-110 works through, and so for locating an emitter such as the drone controller in BNC-AN-103. In the fixed-frequency modes (IQS, DET and RTA), the trigger source can be set to GNSS1PPS, DevSyncByExt or DevSyncBy1PPS.
Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets (reference clock input and output, GNSS 1PPS accuracy, trigger input and output); the instrument manual, sections 5.9.2 and 16.1.2 (trigger sources).
Table 14 closes the spine this handbook opened. Part I derived seven requirements without naming a product; Part II has now reviewed one against them, and this is the scorecard. A reader specifying against a different receiver can use the same seven and fill the middle column differently.
| # | What it asked for | How this family answers |
|---|---|---|
| R1 | Amplitude accuracy as a bound, with conditions | Met. ±2.0 dB to 9.5 GHz, ±3.0 dB above, published with conditions |
| R2 | Correction applied before the abstraction boundary | Documented, not specified. The -SDR option datasheet states that the unit's calibration files are staged for the driver; no datasheet states that the published bound survives the boundary unchanged. Verify per section 27 |
| R3 | Gap-free acquisition with a published intercept relation | Met. Both governing relations are published, so any configuration can be priced rather than only the two on the datasheet |
| R4 | Sample rate and usable bandwidth as two numbers | Met. 125 MSPS and 100 MHz are published as separate figures, and the gap between them is visible on the instrument's own screen, where a 125 MHz span field accompanies a 100 MHz usable bandwidth |
| R5 | A driver module with the calibration installed alongside | Met. The -SDR option, orderable on every current model, ships the SoapySDR driver with the unit's calibration files staged for it |
| R6 | The native interface still reachable | Met. SCPI standard, plus C, C++, C#, Python, MATLAB, Qt and LabVIEW, on Windows and Linux, x64 and AArch64 |
| R7 | One interface across form factors | Met. The same interface serves module, handheld and IP68 tablet, so a routine moves between them unmodified |
Every requirement in section 8 that this family answers only in part is named here, together with the ones it does not answer at all. A reference document has to name its limits as well as its capabilities.
A GNU Radio flowgraph is a directed graph of signal processing blocks. Blocks are connected by edges that carry a stream of fixed-size items, and the runtime arranges for each block to be handed pointers into buffers and asked to do some work. GNU Radio Companion is a graphical editor over that idea; what it produces is a Python file, and reading that file is often faster than reading the canvas.
Every port has an item size in bytes, and the runtime enforces only that the sizes match. A complex float 32 item is eight bytes, a float is four, a byte is one. The runtime cannot tell a complex sample from a pair of floats, because both are eight bytes, which is why a type mismatch produces plausible nonsense rather than an error.
Blocks come in a few kinds and the kind determines the rate arithmetic. A sync block produces one output item per input item. A decimator produces one per M. An interpolator produces L per one. A general block declares its own relation through a forecast call and consumes its input explicitly.
A flowgraph carries three kinds of traffic, and knowing which one a problem belongs to resolves most confusion about why a block will not connect to another.
A tag is not a comment. It is a small record attached to one absolute sample index, and it carries four things: the item number it belongs to, a key, a value, and the identity of the block that produced it. Key and value are typed rather than free text, which is why reading one takes a type-specific accessor rather than a string compare.
This handbook's argument is that a calibrated instrument can hand an open framework a measurement rather than samples. Amplitude survives that boundary because the correction is applied before it. Absolute time survives it only through tags, and only if every block between the source and the consumer has a sensible propagation policy. A distributed system built on this path, of the kind BNC-AN-110 costs out, stands or falls on that chain being intact, and nothing in the interface will warn you when it is not.
Anything whose natural unit is a rate belongs on a stream; anything whose natural unit is an event belongs on a message port. The Wi-Fi chain in section 20 crosses that line exactly once, at the decoder, and everything after it is messages. Getting this wrong is what produces a design that tries to represent decoded packets as a sample stream, which works until two packets arrive close together.
Most integrations need one block that does not exist yet. The contract is small enough to state in full, and knowing it is what separates using GNU Radio from being able to extend it.
class my_block(gr.sync_block):
def __init__(self):
gr.sync_block.__init__(
self, name='my_block',
in_sig=[numpy.complex64],
out_sig=[numpy.float32])
def work(self, input_items, output_items):
out = output_items[0]
out[:] = numpy.abs(input_items[0])
return len(out) # items producedThe default scheduler gives every block its own thread, and every thread runs the same loop for the life of the graph: see how many items are available on the inputs and how much space is free on the outputs, wait if there is not enough of either, ask the block how much input it needs to fill that output, call the block's work function, then advance the read and write pointers by what was actually consumed and produced.
Every output port gets one circular buffer, allocated when the graph starts and never resized, and every consumer reading that port reads from the same buffer with its own index. That is why a branch point costs nothing: fanning one output to three destinations copies no data. It is also what explains back pressure. If a block downstream cannot keep up, its input buffer fills, the block upstream finds no free output space, and it waits. The stall propagates upstream until it reaches the source, and this is where an instrument behaves differently from a file.
The converter runs on the instrument's clock and produces samples whether anyone is listening or not. When back pressure reaches the source block, the source stops reading from the driver, the driver's queue fills, and the driver discards samples. Then the graph carries on. The stream downstream of the source has no gap in it: sample N+1 follows sample N exactly as before, because a hole would require the source to have produced something and it produced nothing. What the loss produced instead is a discontinuity in time and phase at a point no downstream block can identify. A symbol timing loop is now pointing at the wrong instant, a carrier loop's phase estimate is wrong by an arbitrary angle, and a frame in progress is destroyed. The symptom is intermittent decode failure with a spectrum that looks perfectly healthy.
Added processor speed rarely cures it. The cure is to remove work from the critical path: reduce the sample rate at the source rather than resampling it down later, cut the update rate of graphical sinks, take per-sample work out of interpreted code, and decimate as early in the chain as the measurement allows.
One block connects the instrument to everything else, and five of its fields decide whether the rest of the graph can work at all.
Table 15 lists them with the specific failure each one produces when it is wrong, which is more useful than a description of what each one does.
| Field | What it does | The failure if it is wrong |
|---|---|---|
| Device arguments | Selects which module and which physical unit answers | No device found, or the wrong unit of two identical ones |
| Sample Rate | Requests the complex sample rate at the boundary | Silent: every downstream filter is designed for a rate the stream does not have |
| Center Frequency | Tunes the channel | The signal is outside the digitized span and the spectrum looks empty |
| Bandwidth | Sets the filter in front of the converter, separately from the rate | Aliasing folded into the data, or band edges attenuated by an unrecorded roll-off |
| Gain / gain mode | Sets the front-end gain, or hands it to an automatic loop | With automatic gain on, absolute amplitude is meaningless |
The driver ships as the -SDR option. Append -SDR to any current ICX part number (ICX-400U-SDR, for example) and the unit ships with the SoapySDR driver module, its own calibration files staged for the driver, the GNU Radio source block and the example flowgraphs of this part. The diagrams in this section show the source block with its sample rate and center frequency and no device-argument row, because the driver and module names are release-managed items that may change between packages; take the current string from the package you install. Every standard measurement function of the base model stays installed.
An integration can fail before any signal processing runs, in three places that are cheap to check first. This section is short because the procedure is short.
Table 16 is the documented environment.
| Requirement | Value | Why it is not negotiable |
|---|---|---|
| Host architecture | x86_64 | The documented host environment on the -SDR option datasheet |
| Operating system | Ubuntu 22.04 or later | The documented host environment on the -SDR option datasheet |
| Framework | GNU Radio 3.9 or later | The release the -SDR option datasheet names for the source block |
| Transport | USB 3.0 cable and port | A USB 2.0 link cannot carry the sample rates in section 20; the failure looks like intermittent overflow rather than a connection error |
| Out-of-tree modules | gr-ieee802-11 for the Wi-Fi chain; gr-adsb for the 1090 MHz chain | Neither ships with GNU Radio. Both are open-source projects installed separately, and without them those two flowgraphs cannot be opened at all |
| Virtual machines | USB controller set to 3.1 or 3.2 | A virtual machine defaulting to a USB 2.0 controller enumerates the device and then cannot stream from it |
The device calibration files are not part of the driver binary. They are staged for the driver when the -SDR option is installed, and they are specific to the individual unit rather than to the model. Skip that step, or install the files for the wrong serial number, and everything still runs: the device enumerates, the stream starts, the flowgraph produces a constellation, and every amplitude it reports is wrong by an unknown offset. This is the one installation step whose omission is invisible at run time, and it is why section 27 exists. Confirm the files are in place and match the unit's serial number before the first measurement, then prove it once with a known level.
Verify in this order, and stop at the first step that fails, because every later step depends on the earlier ones:
uname -a # architecture and kernel SoapySDRUtil --info # the module directory you used? SoapySDRUtil --find # does the receiver appear? SoapySDRUtil --probe # what does it say it can do?
The probe reports the sample rates, bandwidths, gain stages and antenna names this unit offers, which is more authoritative than any table in this handbook including the ones in Part II. If a rate you intended to use is not in that list, the device will quietly give you the nearest one it has, and every filter you design afterwards will be designed for a rate you do not have.
Every chain below is described as receiving calibrated samples, so the mechanism belongs here rather than in a footnote. The device calibration files are installed alongside the driver module, so the correction is applied on the instrument side of the boundary and the flowgraph is handed corrected data rather than converter counts. That is R5 answered, and it is the single fact that separates this from every uncalibrated device the same flowgraph would also run against. The -SDR option datasheet publishes the mechanism; no datasheet states that the published amplitude accuracy applies unchanged to samples delivered this way. Treat it as a mechanism to verify rather than a bound to quote: section 27 is the half-day procedure that settles it on your own bench, and doing it once at the start of a campaign is worth more than any argument about it.
These six chains were demonstrated on a 6 GHz-class USB module that is no longer in the product line; the current modules are the ICX-200U and ICX-400U, and the -SDR option is orderable on every current model. The interface, the driver mechanism and the way calibration installs do not change with the model, so the integration result transfers; the published amplitude bounds do not follow from these captures and nothing here should be read as measuring them.
Each of the six chains below has been demonstrated end to end against this receiver with a real signal and a captured result. The diagrams are redrawn rather than reproduced, and the display-only branches are collapsed where they carry no teaching, so that what remains on the page is the processing that decides whether the chain works.
Figure 11 was demonstrated with a 1 GHz carrier at −20 dBm, modulated by a 1 kHz tone at 50 percent depth. Frequency modulation is the same topology with a wider front end, and the next section works that pair through. The lesson worth taking from it is that the topology transfers between modulations and the acquisition settings do not, because bandwidth is a property of the signal rather than of the graph.
Figure 12 is worth one habit, and it earns it by failing the test. Before trusting any demodulator, find a feature whose frequency you already know and confirm it lands where the arithmetic says. Here it does not, and the discrepancy is small, systematic and entirely explainable, which is what a reference offset looks like. A chain that produces clean audio can still be four kilohertz off, and nothing downstream of the demodulator would have told you. Lock both instruments to one reference before any measurement that depends on absolute frequency, and note that this is a frequency error rather than an amplitude error: the calibration argument of Part I is untouched by it.
The FM chain is the AM chain with the demodulator swapped, and it is worth a page of its own precisely because the swap is not the whole change. Frequency modulation at 75 kHz deviation occupies far more spectrum than an amplitude-modulated tone, so the source runs at 7.8125 MSPS rather than 976.5625 kSPS, an eight-fold increase, and the demodulator runs at 384 kSPS with an audio decimation of 8 to land on the same 48 kHz output.
Figure 13 makes a point worth carrying into any integration. Carson's rule puts the occupied bandwidth at roughly twice the sum of deviation and modulating frequency, so 2 × (75 + 3) kHz is about 156 kHz, against the roughly 200 kHz the trace shows, which is what the rule's own definition leads you to expect: it bounds the bandwidth holding about 98 percent of the power, and the sidebands beyond it are down but not absent on a display with this much dynamic range. The receiver has to be set from the signal's bandwidth rather than from the demodulator's output rate, and an FM chain set from the output rate rather than the signal bandwidth runs and produces distorted audio.
Figure 14 was demonstrated at 1 GHz with root-raised-cosine pulse shaping at a roll-off of 0.35 and four samples per symbol. Two details in it are worth transferring to any chain you build. The Gardner timing error detector is chosen because it does not require carrier phase to be recovered first, which is what makes the ordering above possible at all. And the Costas loop is fourth order because the constellation has fourfold rotational symmetry, and the loop order has to match it; setting it wrongly locks the loop to the wrong phase and produces a constellation rotated by a multiple of ninety degrees, which looks correct until the bits are wrong.
Figure 15 is also the cheapest diagnostic in this part. If a QPSK constellation shows four clusters at one radius, the chain is working. If it shows a ring, symbol timing has not locked. If it shows four clusters rotating slowly, the carrier loop has not. If the clusters are present but the bit assignment is wrong, suspect the loop order against the constellation symmetry. The picture names most failures before any log is read.
Figure 16 recovers a clean constellation at −80 dBm, which is the number worth carrying away from this section, and it is worth pricing rather than admiring. The capture's controls read a 0 dBm reference level, and the published noise floor nearest that condition is the −20 dBm reference-level row: −146.0 dBm/Hz on the ICX-095 family and −154.1 dBm/Hz on the ICX-400 family in the 90 MHz to 3 GHz band. In the 1 MHz processing bandwidth this chain uses that is −86.0 and −94.1 dBm, so −80 dBm is about 6 dB clear of the floor on one and 14 dB on the other, at a −20 dBm reference level. No noise-floor row is published at 0 dBm, and the floor rises with reference level, so the margin the capture ran at is smaller than those figures and is not established here. Read the demonstration as a working chain at a low level rather than as a sensitivity measurement; the sensitivity question is settled by the procedure in section 27 at the reference level you will use.
Figure 17 also answers a question the picture raises. A constellation is a picture, and a picture proves that a chain ran rather than that it ran correctly. The check that turns it into evidence is section 27: inject a known level, read it through the graph, and confirm the two agree inside the published bound. Do that once and every constellation afterward inherits the result.
Figure 18 and Figure 19 were demonstrated at 2.412 GHz and −40 dBm, and the chain ends in a file rather than a picture, with Figure 19 carrying the decode. One number in that demonstration does not reconcile with the rest and is worth stating rather than smoothing over. The integration document records 12 Mb/s with rate 1/2 coding, which is a 20 MHz channel; this capture runs at 3.90625 MSPS and demodulates at 5 MSPS, which is a quarter of that and corresponds to the 5 MHz channel option, where the same modulation and coding carry 3 Mb/s. The published result window's spectrum is band-limited at about 2 MHz either side of center, which agrees with the capture rate and not with a 20 MHz channel. The rate figure is the integration document's stated condition rather than something this capture demonstrates. The decoded frames leave as a packet capture that Wireshark opens, which means the analysis continues in a tool the network engineer already uses and the amplitude behind every frame remains traceable. The rate identity closes here too: 3,906,250 × 32 / 25 = 5,000,000 exactly, and 3.90625 MSPS is 125 MSPS divided by 32.
Figure 20 closes the loop the handbook opened. The constellation on that window was produced by open-source blocks that were never written for this instrument, running against a front end whose amplitude is bounded by a published specification. Neither half gave anything up to work with the other, and that is the whole claim of Part I stated as a screenshot.
Figure 21 was demonstrated against live air traffic at 1090 MHz, decoding aircraft address, callsign, altitude, speed, heading and position. The decoded messages leave over a message socket rather than into a display block, which is the pattern to copy whenever the output of a chain is data rather than a picture: it lets the visualization be a separate process that can crash, be restarted or be replaced without disturbing the acquisition.
Two of these chains touch signals that carry rules with them. Wi-Fi: decoding frames you are not a party to may be unlawful in your jurisdiction even when the frames are unencrypted and the receiver is passive; operate against your own equipment, on your own network, or with the network owner's written permission, and note that the 2.4 GHz examples here are receive-only. 1090 MHz: reception is passive and generally unrestricted, but the decoded data describes identifiable aircraft and may be personal data under privacy law depending on how it is stored and republished. Neither of these is legal advice, and both are cheaper to resolve before a capture than after one.
The diagrams above describe six chains; Table 17 is what lets you rebuild them. Every value is read off the demonstration flowgraphs. A blank means the demonstration did not record that value, and a blank is more useful than a plausible number, because a reader who fills one in has made a decision rather than inherited one.
| Chain | Source rate | Center | Resampler | Matched filter | Recovery | Output |
|---|---|---|---|---|---|---|
| AM | 976.5625 kSPS | 1 GHz | 768 / 15,625 | none | AM Demod, channel rate 48 kSPS, audio decimation 1 | Audio, 48 kHz |
| FM | 7.8125 MSPS | 1 GHz | 768 / 15,625 | none | FM Demod, channel rate 384 kSPS, audio decimation 8, deviation 75 kHz | Audio, 48 kHz |
| QPSK | 7.8125 MSPS | 1 GHz | 64 / 125 | RRC, alpha 0.35, rate 4 MSPS | Symbol Sync, Gardner, 4 samples/symbol; Costas order 4, loop BW 6.28e-3; AGC2 attack 1e-3, reference 1.0 | Constellation, 1024 points |
| 16-QAM | 976.5625 kSPS | 1 GHz | 128 / 125 | RRC, alpha 0.35, rate 1 MSPS | Symbol Sync, Gardner, 2 samples/symbol; decision-directed loop, BW 31.4e-3, damping 1, 16QAM constellation; Skip Head 100,000 | Constellation, 256 points |
| Wi-Fi OFDM | 3.90625 MSPS | 2.412 GHz | 32 / 25 | none | Delay 16, conjugate, multiply; moving averages 48 and 64; Sync Short threshold 0.500, min plateau 2; Delay 320, Sync Long 320; FFT 64 rectangular; Frame Equalizer LS, bandwidth 5 MHz | Frames to a packet capture file |
| ADS-B | 3.90625 MSPS | 1.09 GHz | 64 / 125 | none | Complex to magnitude squared; Framer at 2 MSPS, detection threshold 10e-9; Demod at 2 MSPS; Decoder, extended squitter only, error correction None | Decoded messages over a socket |
| Read from the demonstration flowgraphs. Documented rather than published. | ||||||
Table 18 is the guidance a reader actually wants after seeing six diagrams: not another picture, but which parameter on each block decides whether it works.
| Block | What it does | The parameter that matters | The failure it causes |
|---|---|---|---|
| Soapy source | Delivers calibrated complex samples from the receiver | Sample rate, and reading it back | Every downstream filter designed for a rate the stream does not have |
| Rational Resampler | Changes the rate by L over M with a polyphase filter | The ratio, and whether it reduces | A large L makes a long filter, which lands on the critical path and causes overflow |
| Root Raised Cosine Filter | Matched filter for a pulse-shaped signal | Roll-off, and that it matches the transmitter | A mismatched roll-off spreads the constellation and looks like noise |
| AGC2 | Normalizes level before timing recovery | Reference level and attack rate | Too fast an attack tracks the modulation and destroys amplitude information |
| Symbol Sync | Recovers the symbol clock | Samples per symbol, and the timing error detector | Wrong samples per symbol produces a constellation that never converges |
| Costas Loop | Recovers the carrier for phase-only modulation | Order, which must match the constellation symmetry | Wrong order locks to a rotated phase; the picture looks right and the bits are wrong |
| Decision-directed loop | Recovers the carrier for amplitude-bearing modulation | The constellation object wired into it | A blind loop on QAM acquires poorly and tracks worse |
| Skip Head | Discards items while loops acquire | Item count against loop bandwidth | Too few discarded and the first thousands of symbols are acquisition transient |
| Stream to Vector, FFT | Blocks the stream into transforms | Vector length matching the FFT size | A mismatch is an item-size error the runtime will not catch as a type error |
| File Sink | Writes to disk | The disk, and buffering | A slow disk propagates back pressure to the source and discards samples |
GNU Radio does not know your sample rate. The stream carries items, not seconds, and a block that appears to know the rate knows only the number typed into its field. Get that number wrong and the block designs a filter for the wrong rate and applies it without complaint.
where
Write equation (6) out for any flowgraph you are handed. Every block either changes the rate by a declared factor or leaves it alone. If the product does not come out to a rate the sink can accept, the graph is wrong, and it is wrong in the worst way: it produces output rather than an error.
Table 19 applies equation (6) to all six chains of section 20.
| Chain | Source rate | Resampler | Rate at the demodulator | Closes? |
|---|---|---|---|---|
| AM | 976.5625 kSPS | 768 / 15,625 | 48.000 kSPS | exactly |
| FM | 7.8125 MSPS | 768 / 15,625 | 384.000 kSPS | exactly |
| QPSK | 7.8125 MSPS | 64 / 125 | 4.000 MSPS | exactly |
| 16-QAM | 976.5625 kSPS | 128 / 125 | 1.000 MSPS | exactly |
| Wi-Fi | 3.90625 MSPS | 32 / 25 | 5.000 MSPS | exactly |
| ADS-B | 3.90625 MSPS | 64 / 125 | 2.000 MSPS | exactly |
Every filter costs taps times rate multiply-accumulates per second. Decimating at the source removes the work from every block downstream of it; resampling at the end has already paid for the samples it throws away. The published decimation range of 1 to 4096 in powers of two is the cheapest lever in the whole chain and the first one to reach for when a graph cannot keep up.
Everything so far makes a chain run. This section is about making its output survive somebody else's review, which is a different and higher bar.
Each review below is one problem, the property that decides it, and the limit worth knowing before you commit. The document number at the head of each review is where that problem is derived, with the arithmetic and the limits; this handbook is the index rather than the replacement, and none of these reviews is a summary of its note. Full titles are in the cross-reference index in section 29.
The buyer wants to build a system, not operate an instrument. The decision usually gets argued on noise figure and ends up being about whether the samples are reachable and whether the calibration reaches them with it. Everything in Parts I and III of this handbook is the long form of that argument. The limit: the abstraction layer reaches the samples and not the measurement modes, so a system that needs real-time density or pulse parameter tables uses the native interfaces for those and the flowgraph for the rest.
From the field (stated): the buyers are universities, research groups and experimenters, and what they report back is not throughput or block count. It is that the amplitude axis survives the boundary, so a plot produced by student code carries the same bound as one produced by the vendor's.
Modern monitoring systems hand identification to a trained model, which makes the receiver a sensor feeding a statistical estimator rather than a display feeding a human. The estimator inherits every property of the data it is given, and no model recovers what the front end discarded. The arithmetic is unforgiving. Take a swept receiver at 1 MHz resolution across a 40 GHz span with a 100 ms revisit: it dwells 2.5 microseconds in each resolution cell per pass, so counting the pulse width the window in which a 1 microsecond pulse can land is 3.5 microseconds per revisit, and for a 1 kHz emitter that is roughly one pulse in 28,000 arriving while the receiver is looking at that frequency. The repetition rate does not change that fraction; it sets how often you get a chance, so a 1 kHz emitter yields a catch about every 29 seconds. The limit is storage, and the right rate to quote is the sustained one. Continuous capture is published at 25 MHz on the ICX-095, 200 and 400. Carrying 25 MHz takes a complex rate of at least 25 MSPS, so at 16-bit components the stream is at least 100 Mbyte per second, or 360 Gbyte an hour. The 500 Mbyte per second figure belongs to the 125 MSPS burst case and the buffer behind it, not to anything written to disk. Either way, an architecture that does not decimate or trigger fills any disk you own.
Three properties of the capture decide whether a model trained on it will hold up in the field, and all three are set before the model sees a sample.
Completeness. A classifier learns the population it is shown. A swept receiver shows it the emitters that happened to be on air when it looked, which favors long and repeating signals and under-represents the short ones the arithmetic above says it mostly misses. A gap-free capture shows the training set and the field the same population, so a model's error rate in testing is a fair forecast of its error rate on the mast.
Calibrated amplitude. A model trained on uncorrected samples learns the receiver's gain table along with the signals. Move it to another unit, another gain state or another band and its inputs shift by an amount it was never shown. Samples corrected to dBm before they leave the instrument are the same at every gain state and on every unit within the published bound, so a model trained on one unit can be deployed on another.
Context carried with the samples. Center frequency, sample rate, gain and absolute time have to travel with every training example, or a labeled dataset cannot be reproduced or audited later. Section 17 shows how stream tags carry that context through a flowgraph. Treat it the way this handbook treats its figures: every example labeled with what it is and the conditions it was taken under.
Classification itself runs in the integrator's software, above the IQ line. The receiver's job is to make the training data and the field data comparable.
From the field (stated): systems integrators serving defense and national security customers have built exactly this architecture, buying the capture guarantee and the documented interface and writing every layer above the IQ line themselves.
The signal of interest is a frequency-hopping control link that is present for milliseconds at a time across a wide band, and the operator is found by direction-finding the uplink rather than the aircraft. Holding the control band whole is what makes the difference, because a hopping link is present in any one channel for only milliseconds at a time, so what a visiting receiver reports as empty is a function of when it happened to look. The limit, and it is a legal one: a lawful sensor detects, characterizes and direction-finds an emission. It does not demodulate the communication that emission carries.
From the field (stated): siting dominates. A mast placed well for the aircraft is a poor place from which to hear a controller near the ground behind a building line, and installations that optimize for one lose the other.
Stations are built once and maintained for years, and the deliverable is not the visit but the dated record the visit produces. An interference question arrives months later, and the commissioning archive is the timestamped, instrument-traceable record of the station's performance at acceptance, against which a later measurement is compared. One number carries the section: a block upconverter locked to a 10 MHz reference multiplies it by 1,305 to reach a 13.05 GHz local oscillator, and phase noise rises by twenty times the log of that ratio, which is 62.3 dB. A reference whose phase noise is acceptable at 10 MHz can limit the modulation order at 14 GHz.
From the field (stated): instruments of this class get specified against the maintenance workload rather than the commissioning one, which inverts what a datasheet comparison usually optimizes for.
A receiver bug that appears once an hour at one intersection cannot be bisected against an environment that never recurs, so the environment becomes a file. The governing fact is that a replay can never be cleaner than its capture: the analyzer's noise, spurs, imbalance and phase noise are burned into the file and are indistinguishable from signal to the generator. The capture instrument sets the ceiling. The limit: this needs two instruments. Vector signal generation is not an ICX capability, and a record-and-replay bench pairs an ICX capture with a separate generator.
From the field (stated): one requirement recurs often enough to name, which is two generators under a single control port rather than two separately addressable instruments. Two channels commanded separately are two instruments with two time bases.
Measuring an antenna pattern with an airborne probe replaces a range with a flight plan, and the two quantities that decide whether the result means anything are geometric. Far field begins near two aperture-squared over wavelength, and at exactly that distance the phase error across the aperture is one sixteenth of a wavelength. The limit: a pattern point is a statistic over a population of pulses, not a single reading, so the measurement wants pulse detection rather than a spectrum trace.
From the field (stated): this configuration flies commercially, and the stated motivation is simpler than any argument in the note: engineers should not have to climb antenna structures.
Exposure limits are written in field strength or power density, and a spectrum analyzer reports power at a connector, so the whole job is a conversion with an uncertainty budget behind it. The budget is where the engineering lives: rectangular contributions enter as the square of the half-width over three, and the worked example totals a variance of 2.196 for an expanded uncertainty of 2.96 dB. The limit: which quantity the limit is written in decides the antenna, and getting that wrong makes every number downstream wrong together.
From the field (stated): the instrument a safety officer carries is increasingly an integrator's product with a general-purpose receiver inside it, which puts this arithmetic on the integrator rather than on the officer.
Coexistence problems are between-standard problems, so an instrument that measures one standard at a time cannot see them. Holding 100 MHz gap-free is exactly one FR1 carrier edge to edge under one amplitude reference, which means the interferer and the victim are measured in the same acquisition against the same axis. The limit: 100 MHz is one carrier. Aggregated carriers beyond that span need either a wider instrument or a stated, recorded decision about which carrier is being observed.
From the field (stated): a wireless test vendor drew this boundary when they built a multi-radio analysis product on a receive module and wrote the protocol layer themselves, because from the customer's side a decode failure caused by a dropped sample carries the vendor's name.
Pre-compliance moves the expensive surprises earlier, and the arithmetic that decides whether a scan is a confirmation is dwell time against the intercept relation. A compliant scan over bands C and D, stepped in 60 kHz increments at 100 ms a point, takes about 27 minutes, and a one-second sweep is the search rather than the confirmation. A confirmation scan run at search speed gives an optimistic result. The limit: CISPR 16-1-1 detectors, bandwidths and limit lines are published as option 74 for the ICX-045, 060 and 090 only; on the other models the scan is built from general-purpose functions.
From the field (stated): nothing in the note rests on option 74. Every scan in it is built from general-purpose analyzer functions that are published on every model, and no deployment outcome has been reported back yet.
Radio-frequency performance decides less of this argument than time transfer and geometry do. In a distributed radio-location node the receiver's own time-delay estimation contributes under one hundredth of one percent of the position-error variance, while time transfer, inter-channel matching, enclosure temperature and site geometry contribute all of it. One nanosecond is 0.2998 m, and geometry multiplies whatever timing error survives. The limit: the ten-year cost is dominated by the calibration fixture, the traceability chain and obsolescence engineering, none of which scale down to low volumes.
From the field (stated): several independent system houses have built monitoring and direction-finding products on receive modules from this family, write their own software, and sell the result under their own name. None is in the receiver business.
This handbook rests on one principle: calibration belongs to the signal path, not to the processing that follows it. A correction applied after a decision has been made on uncorrected data cannot change that decision. Whether an open flowgraph produces a defensible measurement therefore depends less on the flowgraph itself than on whether the samples reaching it have already been corrected.
Part I set out seven requirements that follow from this principle, and Part II assessed the ICX-FieldHawk against each one. Published specifications meet six of them:
The remaining requirement, correction applied before the abstraction boundary, is documented but not specified. It can be verified on the bench with the procedure in section 27: inject a known level, read it through the flowgraph, and confirm that the two values agree within the published bound.
System designs should also account for the following limits:
Recommended first steps on the bench:
For the -SDR option, a datasheet, or the application notes listed in section 29, contact Berkeley Nucleonics at info@berkeleynucleonics.com or 800-234-7858.
None of the following depends on which analyzer you buy, and all of it decides whether the result is worth anything.
Table 20 is arranged by symptom, because a symptom is what the reader has when they open this page.
| Symptom | Probable cause | The check that discriminates | Fix |
|---|---|---|---|
| No device found | Module not on the load path, or permissions, or a USB 2.0 port | Run the info command: does it list the directory you installed into? | Correct the module path; use a USB 3.0 cable and port; set device permissions |
| Device found, stream never starts | Another process holds the device, or the requested rate was rejected | Read back the sample rate after setting it | Close the other application; request a rate the device reports as available |
| Spectrum looks empty | Tuned outside the signal, or bandwidth filter far narrower than the rate | Widen the span and look for the carrier; read back the bandwidth | Retune; set bandwidth explicitly rather than relying on a default |
| Amplitude reads plausible but wrong | Device automatic gain control is on, or a reference level was changed mid-campaign | Inject a known level from a calibrated source and compare | Turn device AGC off; fix the reference level and record it |
| Intermittent decode failure, spectrum healthy | Overflow: samples discarded at the driver, leaving no gap in the stream | Check the stream return code, not the console | Decimate at the source; cut graphical sink update rates; move per-sample work out of interpreted code |
| Constellation rotates slowly | Carrier frequency offset beyond the loop's pull-in, or a rate designed against the requested value rather than the achieved one | Compare the requested and read-back sample rates | Use the read-back rate everywhere; widen the loop bandwidth or add a coarse frequency correction |
| Constellation is a smear at all levels | Blocks out of order, most often carrier recovery before symbol timing | Read the graph in signal order against section 20 | Restore the order: matched filter, level, symbol timing, carrier |
| Chain works at low rate and fails at high rate | A conversion or a filter on the critical path | Request the format the hardware produces natively and re-measure | Remove the format conversion; decimate earlier; shorten the resampler |
Calibration crossing an abstraction boundary is a claim, and a claim is worth one afternoon of proof at the start of a campaign. The procedure is short.
Copy this into a capture log and fill it in. A capture without these entries is not reproducible, whatever else is true of it.
Everything in this section as a single program. It opens a named unit, reads back every setting it asked for, turns automatic gain off, queries the native format, handles overflow rather than ignoring it, and writes a sidecar so the capture can be defended later.
import json, numpy, SoapySDR
from SoapySDR import SOAPY_SDR_RX, SOAPY_SDR_CF32
from SoapySDR import SOAPY_SDR_OVERFLOW
RX = SOAPY_SDR_RX
sdr = SoapySDR.Device('driver=<name>,serial=01AB')# never AGC for absolute amplitude
if sdr.hasGainMode(RX, 0):
sdr.setGainMode(RX, 0, False)
sdr.setSampleRate(RX, 0, 20e6)
sdr.setBandwidth(RX, 0, 16e6) # not the rate
sdr.setFrequency(RX, 0, 2.412e9)# read back; never trust the request
state = {
'rate': sdr.getSampleRate(RX, 0),
'bw': sdr.getBandwidth(RX, 0),
'freq': sdr.getFrequency(RX, 0),
'gain': sdr.getGain(RX, 0),
'fmt': sdr.getNativeStreamFormat(RX, 0),
}rx = sdr.setupStream(RX, SOAPY_SDR_CF32, [0])
sdr.activateStream(rx)
mtu = sdr.getStreamMTU(rx)
buf = numpy.empty(mtu, numpy.complex64)
overflows, seg, written = [], 0, 0
out = open('capture-0.cf32', 'wb')
for _ in range(2000):
sr = sdr.readStream(rx, [buf], len(buf))
if sr.ret == SOAPY_SDR_OVERFLOW:
# record where, not only how many;
# new file: never average across a gap
overflows.append(written)
out.close(); seg += 1
out = open(f'capture-{seg}.cf32', 'wb')
written = 0
continue
if sr.ret > 0:
out.write(buf[:sr.ret].tobytes())
written += sr.ret
out.close()
sdr.deactivateStream(rx); sdr.closeStream(rx)
SoapySDR.Device.unmake(sdr)state['overflow_at'] = overflows # offsets
state['segments'] = seg + 1
json.dump(state, open('capture.json', 'w'),
indent=1) # the sidecarTable 21 is the page to photocopy.
| Quantity | Relation or value | Condition |
|---|---|---|
| Frame rate | 109 / (N × D × 8) frames/s | gap-free engine, sample interval 8 ns |
| Guaranteed intercept | POI = 2 N D × 8 ns | 100 percent, full amplitude |
| Bin spacing | fs / (N D) | 125 MSPS at decimation 1 |
| IQ data rate | fs × 2 × b/8 bytes/s | b = 16 for interleaved 16-bit |
| Buffer duration | 128 Mbyte / rate | 0.26 s at 125 MSPS, 16-bit |
| Rate identity | fout = fin × ∏L / ∏M | every path, every flowgraph |
| Noise floor in RBW | DANL + 10 log10(RBW in Hz) | −99.9 dBm at −159.9 dBm/Hz, 1 MHz |
| Complex Nyquist | bandwidth B needs complex rate B | not 2B; real sampling needs 2B |
| Usable bandwidth | about 0.8 of sample rate | filter transition band, typical |
| Amplitude accuracy | ±2.0 dB / ±3.0 dB | to 9.5 GHz / 9.5 to 40 GHz |
| Phase noise | −107.5 / −99.7 / −101.6 dBc/Hz | 1 GHz, 10 kHz offset, ICX-400 / 200 / 095 families |
| DANL | −159.9 / −166.3 / −167.5 dBm/Hz | 90 MHz to 3 GHz, RBW 1 kHz, reference level −50 dBm, ICX-400 / 200 / 095 families |
| Reference | < 1 ppm accuracy, TCXO or OCXO | OCXO (option 01) stability < 0.15 ppm, aging < 1 ppm/year |
| Timing | ±100 ns 1PPS standard | ±75 / ±50 ns with options on the IP68 tablet and module |
| Range to timing | Δr = c Δτ | 1 ns is 0.2998 m |
| Published values: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. Standing conditions: 10 minute warm-up, 25 °C, spur reject standard. | ||
Table 22 is the specification side of the quick reference. It exists so the photocopied page is genuinely self-contained: a reader who keeps only these two tables should not have to open a datasheet for anything this handbook argues from.
| Category | Published value | Condition or note |
|---|---|---|
| Frequency range | 9 kHz to 4.5, 6, 9, 9.5, 20 or 40 GHz | handheld: all six; IP68 tablet: 9.5, 20 and 40 GHz; module: 20 and 40 GHz |
| Analysis bandwidth | 100 MHz; 50 MHz standard on the ICX-045, 060 and 090 | 100 MHz with option 50 on the ICX-045, 060 and 090 |
| Amplitude accuracy | ±2.0 dB; ±3.0 dB | to 9.5 GHz; 9.5 to 40 GHz, on the ICX-095, 200 and 400 chain; the ICX-045, 060 and 090 publish ±1.5 dB over the full temperature range |
| DANL | −159.9 (ICX-400); −166.3 (ICX-200); −167.5 dBm/Hz (ICX-095) | 90 MHz to 3 GHz, RBW 1 kHz, reference level −50 dBm |
| Phase noise | −107.5 / −99.7 / −101.6 dBc/Hz; −85.7 / −90.6 / −98.5 dBc/Hz | 1 GHz, 10 kHz offset, ICX-400 / 200 / 095; at 40, 20 and 9.5 GHz on the same families |
| IIP3 / IIP2 | +40.3 dBm / +75.5 dBm | 1 GHz, reference level +20 dBm, ICX-400 |
| Display range | DANL to +20 dBm (ICX-400); to +23 dBm (ICX-095 and 200) | typical |
| Max CW input | +23 dBm; +10 dBm | 50 MHz and above preamp off; below 50 MHz or preamp on |
| Image rejection | > 90 dB to 33 GHz; > 58 dB, 33 to 40 GHz | ICX-400 family, spur reject standard |
| IF rejection | > 90 dB, except > 68 dB from 8.2 to 21.75 GHz | ICX-400 family, spur reject enhanced |
| VSWR | < 2.0:1; < 3.0:1 | 90 MHz to 16 GHz; 16 to 40 GHz (ICX-400); < 2.0:1 to the top of the band on the ICX-095 and 200 |
| Sweep speed | 1.0 THz/s; 577.5 GHz/s; 212.6 GHz/s; 2.6 GHz/s | 250 kHz bypass; 250 kHz standard; 50 kHz bypass; 1 kHz CPU bypass |
| RBW, swept | 1 Hz to 10 MHz | VBW the same range |
| RBW, real-time | 14.73 MHz to 3.59 kHz (flat-top); 7.81 MHz to 1.90 kHz (Blackman-Nuttall) | 13 grades |
| Power detection | 8 ns time resolution | PosPeak, NegPeak, Sample, Average, RMS, MaxPower |
| IQ capture | 125 MSPS; decimation 1 to 4096 in powers of two | 128 Mbyte memory |
| Recording bandwidth | 100 MHz burst; 25 MHz continuous | two separate figures; 50 MHz and 12.5 MHz on the ICX-045, 060 and 090 without option 50 |
| External trigger | up to 500 per second | |
| Reference | accuracy < 1 ppm, TCXO or OCXO | OCXO (option 01) stability < 0.15 ppm; aging < 1 ppm/year |
| GNSS 1PPS | ±100 ns; ±75 ns; ±50 ns | standard; with options on the IP68 tablet and module |
| Source: the ICX-FieldHawk, ICX-FieldHawk-R and ICX-Series USB/LAN datasheets. Standing conditions: 10 minute warm-up, 25 °C, spur reject standard. | ||
Table 23 collects every conversion this handbook uses, with a worked example on each row so the arithmetic can be checked rather than trusted.
| From | To | Relation | Worked example |
|---|---|---|---|
| dBm | watts | P = 10(dBm/10) / 1000 | −80 dBm is 10 pW |
| dBm/Hz | dBm in a bandwidth | add 10 log10(BW in Hz) | −159.9 dBm/Hz in 1 MHz is −99.9 dBm |
| Receiver reading in dBm | field strength in dBµV/m | add 107, then add the antenna factor in dB/m | −40 dBm + 107 + 20 = 87 dBµV/m |
| Voltage or power ratio | decibels | 20 log10 for voltage and field; 10 log10 for power | a factor of two is 6.02 dB or 3.01 dB |
| Frequency multiplication | phase noise penalty | 20 log10(N) | 10 MHz to 13.05 GHz is 62.3 dB |
| Timing | range | 0.2998 m per nanosecond | ±100 ns is ±30.0 m before geometry |
Figure 22 and the table below say the same thing in two registers, which is deliberate: a specifying engineer reads the table and a reviewer reads the tree.
Table 24 runs the decisions in the order they are made.
| If the job is | Choose | Because |
|---|---|---|
| Embedding a receiver in your own product | ICX-200U or ICX-400U module, USB or LAN | Smallest and lightest; one interface shared with every other form factor |
| Bench development, then field deployment | Develop on a module, deploy to a handheld or IP68 tablet | One interface means the validated routine moves unchanged |
| Field work in weather | ICX-095R, 200R or 400R IP68 tablet | IP68 chassis; temperature classes to −40 °C with option 41 |
| Anything above 9.5 GHz | The 20 GHz tier to 20 GHz; the 40 GHz tier beyond | Frequency range cannot be added later; above 9.5 GHz the published accuracy is ±3.0 dB on either tier |
| Work below 9 GHz with a tracking generator or CISPR pre-compliance | ICX-045, 060 or 090 handheld | Options 60 to 62 and 74 are published for these models only; 50 MHz standard, 100 MHz with option 50 |
| Distributed timing work | Add option 01 and a GNSS option | Holdover and 1PPS accuracy, not receiver noise figure, set position error |
| Pulse parameter measurement | Add option 72 | Pulse detection measures in the time domain, outside the transform path |
| Symbol | Meaning | Units |
|---|---|---|
| N | transform size | points |
| D | decimation factor | dimensionless |
| fs | complex sample rate | samples per second |
| L, M | interpolation and decimation factors of a resampler | dimensionless |
| b | bits per sample component | bits |
| r | data rate | bytes per second |
| c | speed of light, 0.2998 | m per nanosecond |
| Δτ | arrival-time difference | seconds |
| σp | one-sigma position error | meters |
| G | geometric dilution of precision | dimensionless |
| ENBW | equivalent noise bandwidth of a window | bins |
The ten application notes in this series, each with what it derives that this handbook only states. Where a subject appears in both, the note is the authority.