RIQ Echo Extractor (pynasonde.vipir.riq.echo)¶
P
pynasonde.vipir.riq.echo — Dynasonde-style seven-parameter echo extraction for VIPIR RIQ data.
Overview¶
This module implements the echo characterisation algorithm described in Zabotin et al. (2005) "Dynasonde 21" for VIPIR RIQ raw IQ data. For each sounding frequency it fits seven physical parameters to the complex I+Q samples stored across the receiver array:
| Symbol | Parameter | Description |
|---|---|---|
| φ₀ | gross_phase_deg |
Gross (mean) phase of the echo signal |
| V* | velocity_mps |
Doppler / phase-path velocity |
| R′ | height_km |
Group range (virtual height) |
| XL | xl_km |
Eastward echolocation displacement |
| YL | yl_km |
Northward echolocation displacement |
| PP | polarization_deg |
Polarization chirality angle |
| EP | residual_deg |
Least-squares fit residual |
| A | amplitude_db |
Echo amplitude |
Classes¶
pynasonde.vipir.riq.echo.Echo
dataclass
¶
All seven Dynasonde-style physical parameters for one ionospheric echo.
An echo is a single significant return at a specific
(frequency, virtual height) point within one VIPIR pulse set.
The parameter names follow the Dynasonde 21 convention
(Zabotin et al., 2005).
Primary seven parameters¶
float
φ₀ — Mean complex phase of the pulse set, averaged over all pulses and all receivers at this gate (degrees). This is the "stationary-phase" carrier phase of the echo.
float
V* — Phase-path velocity derived from the linear temporal phase rate across the pulse set (m/s). Positive values indicate motion away from the sounder (receding layer).
float
R' — Stationary-phase group range / virtual height (km), computed from the range-gate index and the gate-step timing.
float
XL — Eastward echo echolocation (km). Derived from the spatial
least-squares fit of inter-antenna phase differences, projected along
the East axis: XL = R' · l where l is the East direction cosine.
float
YL — Northward echo echolocation (km): YL = R' · m.
float
PP — Chirality / polarization rotation (degrees). Estimated from the differential phase between quasi-orthogonally oriented antenna pairs. Returns NaN when the antenna array does not contain antennas with sufficiently different orientations.
float
EP — RMS residual of the planar-wavefront least-squares fit to all inter-antenna phase differences (degrees). Small values indicate a coherent, well-localised echo; large values suggest either multipath or a non-planar wavefront.
float
A — Coherent peak echo amplitude (dB), averaged over receivers.
Diagnostic / bookkeeping fields¶
float
Doppler frequency (Hz) from the linear phase-rate regression.
Related to V* by V* = f_d · c / (2 · f₀).
float
Coherent SNR at the echo gate relative to the median noise floor (dB).
int
Range-gate index within the pulse set (0-based).
float
Universal-time stamp of the first pulse in the set (seconds from the
file epoch, taken from PCT.pri_ut).
int
Number of receivers used in the spatial LS fit for XL/YL/EP.
float
Sounding frequency (kHz), taken from PCT.frequency.
to_dict()
¶
Return a plain dict representation of this echo.
pynasonde.vipir.riq.echo.EchoExtractor
¶
Extract Dynasonde-style echo parameters from VIPIR RIQ pulsets.
For each pulse set (one frequency step) the extractor:
- Assembles the complex IQ cube
C[pulse, gate, rx]. - Computes the coherent mean phasor over pulses:
C_mean[gate, rx]. - Estimates the noise floor from the per-gate amplitude distribution.
- Selects candidate echo gates whose coherent SNR exceeds
snr_threshold_db. - Computes all eight parameters at each qualifying gate.
Parameters¶
SctType
Sounder configuration table — must have been fully populated from a binary RIQ file. Key sub-structures used:
sct.station.rx_count— number of active receiverssct.station.rx_position—(rx_count, 3)array of[East_m, North_m, Up_m]receiver positionssct.station.rx_direction—(rx_count, 3)unit direction vectors (used for PP estimation)sct.timing.{gate_start, gate_end, gate_step}— gate timing (µs)sct.timing.pri— pulse repetition interval (µs)
list of Pulset
Grouped pulse data as produced by
:class:~pynasonde.vipir.riq.parsers.read_riq.RiqDataset.
Each element must expose a .pcts attribute that is a list of
:class:~pynasonde.vipir.riq.datatypes.pct.PctType objects, each
carrying pulse_i and pulse_q arrays of shape
(gate_count, rx_count).
float, default 3.0
Minimum coherent SNR (dB) a gate must exceed to qualify as an echo candidate. Gates below this value are silently discarded.
float, default 50.0
Minimum virtual height (km) considered for echo detection. Gates
below this threshold are skipped unconditionally. Set to 0 to
disable the filter. The default (50 km) excludes direct-wave and
near-field clutter, which can easily dominate the first few gates
and crowd out ionospheric returns when max_echoes_per_pulset is
small.
float, default 1000.0
Maximum virtual height (km) considered for echo detection. Gates above this threshold are skipped. Ionospheric echoes above ~1000 km are extremely rare; setting this avoids aliased end-of-range samples that are common in the last few percent of range gates.
int, default 3
Minimum number of receivers required to attempt the spatial least-squares fit that yields XL, YL, and EP. When fewer receivers are available those three parameters remain NaN. Set to 0 or 1 to attempt the fit even with only two antennas (only one baseline — the system will be exactly determined rather than overdetermined).
int or None, default 5
Maximum number of echo candidates retained per frequency step.
Candidates are ranked by descending amplitude before truncation.
Pass None to keep all candidates above the SNR threshold.
Examples¶
riq = RiqDataset.create_from_file("WI937_2022233235902.RIQ") extractor = EchoExtractor(riq.sct, riq.pulsets) extractor.extract() df = extractor.to_dataframe() ds = extractor.to_xarray()
echoes: List[Echo]
property
¶
Read-only list of extracted :class:Echo objects.
Raises¶
RuntimeError
If :meth:extract has not been called.
__init__(sct, pulsets, snr_threshold_db=3.0, min_height_km=50.0, max_height_km=1000.0, min_rx_for_direction=3, max_echoes_per_pulset=5)
¶
extract()
¶
Run the full extraction pipeline over all pulse sets.
Iterates every pulset, assembles the IQ cube, and accumulates
:class:Echo objects in self._echoes.
Returns¶
EchoExtractor
self, enabling method chaining (e.g.,
EchoExtractor(...).extract().to_dataframe()).
to_dataframe()
¶
to_xarray()
¶
Return all extracted echoes as an :class:xarray.Dataset.
Each :class:Echo field becomes a 1-D data variable indexed by
echo_index. CF-convention units and long_name attributes
are attached to every variable.
Returns¶
xarray.Dataset Empty Dataset when no echoes were found.
Raises¶
RuntimeError
If :meth:extract has not been called.
Quick start¶
from pynasonde.vipir.riq import RiqDataset, EchoExtractor
dataset = RiqDataset.create_from_file("WI937_2024058061501.RIQ")
ext = EchoExtractor(
sct=dataset.sct,
pulsets=dataset.pulsets,
snr_threshold_db=3.0,
min_rx_for_direction=3,
max_echoes_per_pulset=5,
).extract()
# Pandas DataFrame — one row per echo
df = ext.to_dataframe()
# CF-convention xarray Dataset
ds = ext.to_xarray()
Algorithm notes¶
- I/Q cube — for each
Pulset(fixed frequency), raw I and Q samples are assembled into a(pulse, gate, rx)complex array. - SNR gate selection — gates whose mean amplitude exceeds
snr_threshold_dbabove the noise floor are retained. - Gross phase (φ₀) —
angle(mean(I + jQ))averaged across all pulses and receivers. - Doppler / V* — phase is unwrapped along the pulse-time axis;
a linear regression yields the Doppler frequency;
V* = f_d·c / (2·f₀). - Direction (XL, YL) — inter-antenna phase differences are fit to a planar-wavefront model via least squares; the recovered direction cosines are projected to km offsets using the virtual height.
- Polarization (PP) — quasi-orthogonal antenna pairs are identified
from
rx_directiondot products; the circular-polarization ratio is converted to an angle. - Residual (EP) — the RMS residual of the planar-wavefront LS fit.
References¶
Zabotin, N. A., Wright, J. W., & Zhbankov, G. A. (2006). NeXtYZ: Three-dimensional electron density inversion for dynasonde ionograms. Radio Science, 41(6). https://doi.org/10.1029/2005RS003352