Scope / Waterfall¶
Spectrum and waterfall data from the radio's scope display.
Overview¶
Icom radios with spectrum scope (IC-7610, IC-7300, IC-705, etc.) stream real-time spectrum data over the CI-V protocol as unsolicited 0x27 0x00 packets. The icom-lan library reassembles these multi-sequence bursts and delivers complete frames via callback.
Quick Start¶
from icom_lan import create_radio, LanBackendConfig
from icom_lan.scope import ScopeFrame
async def main():
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
frames = []
def on_frame(frame: ScopeFrame):
frames.append(frame)
print(f"{frame.start_freq_hz/1e6:.3f}–{frame.end_freq_hz/1e6:.3f} MHz "
f"({len(frame.pixels)} px)")
radio.on_scope_data(on_frame)
await radio.enable_scope()
# ... frames will arrive via callback ...
await radio.disable_scope()
radio.on_scope_data(None) # unregister
Classes¶
ScopeFrame¶
A complete spectrum scope frame, assembled from a burst of CI-V sequences.
| Attribute | Type | Description |
|---|---|---|
receiver |
int |
0=MAIN, 1=SUB |
mode |
int |
0=center, 1=fixed, 2=scroll-C, 3=scroll-F |
start_freq_hz |
int |
Lower edge frequency in Hz |
end_freq_hz |
int |
Upper edge frequency in Hz |
pixels |
bytes |
Amplitude values, each 0x00–0xA0 (0–160) |
out_of_range |
bool |
True if scope data is out of range |
IC-7610 parameters: - Up to 689 pixels per frame - 15 sequences per burst (SpectrumSeqMax=15) - Amplitude range 0–160 (SpectrumAmpMax=200, but data range is 0x00–0xA0) - Dual receiver support (main + sub independently)
ScopeAssembler¶
Low-level assembler that reconstructs ScopeFrame objects from raw CI-V 0x27 0x00 payloads. Maintains independent state for main and sub receivers.
asm = ScopeAssembler()
frame = asm.feed(raw_payload, receiver=0) # payload after receiver byte
if frame is not None:
process(frame)
Most users should use radio.on_scope_data() (on the Radio returned by create_radio) instead of ScopeAssembler directly.
Scope Command Builders¶
Low-level CI-V command builders for scope control. All accept optional to_addr and from_addr parameters.
| Function | CI-V | Description |
|---|---|---|
scope_on() |
0x27 0x10 0x01 |
Enable scope display |
scope_off() |
0x27 0x10 0x00 |
Disable scope display |
scope_data_output(on) |
0x27 0x11 |
Enable/disable wave data output |
scope_data_output_on() |
0x27 0x11 0x01 |
Shortcut: enable data output |
scope_data_output_off() |
0x27 0x11 0x00 |
Shortcut: disable data output |
scope_main_sub(receiver) |
0x27 0x12 |
Select scope receiver (0=MAIN, 1=SUB) |
scope_single_dual(dual) |
0x27 0x13 |
Single/dual scope mode |
scope_set_mode(mode) |
0x27 0x14 |
Set scope mode (0–3) |
scope_set_span(span) |
0x27 0x15 |
Set scope span (0–7) |
scope_set_edge(edge) |
0x27 0x16 |
Set scope edge (1–4) |
scope_set_hold(on) |
0x27 0x17 |
Scope hold on/off |
scope_set_ref(ref) |
0x27 0x19 |
Set reference level in dB (-30.0 to +10.0) |
scope_set_speed(speed) |
0x27 0x1A |
Set speed (0=fast, 1=mid, 2=slow) |
scope_set_vbw(narrow) |
0x27 0x1D |
Video bandwidth (narrow/wide) |
scope_set_rbw(rbw) |
0x27 0x1F |
Resolution bandwidth (0=wide, 1=mid, 2=narrow) |
Protocol Details¶
The radio sends spectrum data as a burst of CI-V frames:
- Sequence 1: Metadata — mode, start/end frequency (5-byte BCD each), out-of-range flag
- Sequences 2..N-1: Pixel amplitude data (50 pixels per sequence)
- Sequence N: Final pixel chunk, frame complete
In center mode, the radio sends center frequency and half-span; the assembler expands these to actual edge frequencies.
Scope data arrives unsolicited mixed with normal CI-V traffic. The library processes it as a side-effect in the CI-V receive loop without blocking command responses.
Capture Helpers¶
capture_scope_frame()¶
Enable scope and capture one complete frame. Does NOT disable scope after.
capture_scope_frames()¶
Enable scope and capture count complete frames. Returns list oldest-first.
Raises: TimeoutError if fewer than count frames arrive within timeout.
Rendering (optional, requires Pillow)¶
render_spectrum()¶
from icom_lan.scope_render import render_spectrum
img = render_spectrum(frame, width=800, height=200, theme="classic")
img.save("spectrum.png")
Renders a single ScopeFrame as a spectrum plot (amplitude vs frequency) with grid lines and frequency labels.
render_waterfall()¶
from icom_lan.scope_render import render_waterfall
img = render_waterfall(frames, width=800, height=400, theme="classic")
Renders multiple frames as a waterfall display. Newest frame at top, color encodes amplitude.
render_scope_image()¶
from icom_lan.scope_render import render_scope_image
img = render_scope_image(frames, output="scope.png", theme="classic")
Combined image: spectrum on top, waterfall below.
| Parameter | Type | Default | Description |
|---|---|---|---|
frames |
list[ScopeFrame] |
required | Frames (oldest first) |
width |
int |
800 |
Image width |
spectrum_height |
int |
200 |
Spectrum section height |
waterfall_height |
int |
400 |
Waterfall section height |
theme |
str |
"classic" |
"classic" or "grayscale" |
output |
str \| Path \| None |
None |
Save path (PNG) |
Color Themes¶
classic — WSJT-X inspired: dark blue (noise) → blue → cyan → yellow → red (max)
grayscale — black (noise) → white (max)
Custom themes can be added to scope_render.THEMES dict with anchor points for linear interpolation.