Recognise trunking control channels, and refuse to sit on them
A trunked system keeps one frequency transmitting a data stream around the clock so its radios know where each conversation has been put. There is no speech on it and it never stops, which makes it the strongest and most useless signal in the band: the scanner parked on 856.561 MHz for the full record limit, saved four minutes of buzzing, and found it again on the next sweep. Five signatures, matched against a constant-envelope stream that never pauses: 3600 baud two-level (Motorola SMARTNET/SmartZone), 9600 (EDACS), 1200 (MPT-1327), 4800 four-level (P25 or DMR Tier III), 2400 (NXDN). The first two are believed at once -- nothing else sends at those rates without pausing. The rest share their shape with a digital voice call on the same system, so they wait for the carrier to run unbroken past --control-seconds, longer than a conversation goes without a breath. Being in a trunked allocation raises confidence but is never required; trunking is licensed on business pairs all over the spectrum. One is named on screen, abandoned within a second or so, and its capture deleted. --keep-control records them for a decoder; --lockout-control writes them into the lock-out list. Three things had to be fixed to get there. The simulator's "pseudo-random" symbols were a counter: multiplying the symbol index by an odd constant and taking it modulo the level count returns the low bits, so two-level FSK came out 0,1,0,1. Every FSK test in the suite was measuring a tone. Its FSK is now shaped the way GFSK and C4FM shape a stream, too, square-edged keying being a signal no licensed transmitter would radiate. The symbol-rate estimator locked onto harmonics -- 3600 baud read as 18000 -- because a transition impulse train is a comb of equal lines; it now walks down to the fundamental. The squared envelope is no longer a candidate: it is not a transition signal, and its DC lobe made every random OOK signal measure ninety baud. The search starts at 200 Hz rather than 40, below which it was reading drift, which is how a bare carrier was awarded a symbol rate. And a clean two-level signal counted zero discriminator levels, because its modes land in the first and last histogram bin, where find_peaks cannot see them. Separately: locking out a frequency wrote to the settings file even under --no-config, which has no settings file by definition. It now writes only where it read from, and --simulate never writes at all -- an invented frequency would sit in a real config for ever, skipping whatever genuine signal happened to land near it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
This commit is contained in:
parent
ba6c925351
commit
4a272eb1d5
14 changed files with 984 additions and 53 deletions
86
README.md
86
README.md
|
|
@ -450,8 +450,13 @@ only for:
|
|||
| `cw` | a keyed carrier whose timing resolves as Morse |
|
||||
| `digital` | an identified keying scheme: discrete FSK levels, an M-PSK phase line, or on-off keying -- corroborated by a symbol rate |
|
||||
|
||||
Two more categories exist but are not accepted by default: `carrier`
|
||||
(unmodulated, real but empty) and `trunk` (a [trunking control
|
||||
channel](#trunked-systems-and-their-control-channels)).
|
||||
|
||||
Everything else -- static, hum, switch-mode power supply harmonics, clock
|
||||
spurs, bare carriers -- is discarded, and the files it wrote are deleted.
|
||||
spurs, bare carriers, trunking control channels -- is discarded, and the files
|
||||
it wrote are deleted.
|
||||
|
||||
The check runs *while* the capture is still going, so interference is dropped
|
||||
after a second or two instead of holding the receiver for the whole record
|
||||
|
|
@ -574,6 +579,62 @@ Each result carries a confidence and the reasoning behind it:
|
|||
|
||||
Low SNR reduces confidence rather than producing a confident wrong answer.
|
||||
|
||||
### Trunked systems and their control channels
|
||||
|
||||
Police, fire and most large business radio in the US runs on *trunked*
|
||||
systems. Rather than giving each department a frequency of its own, the system
|
||||
owns a pool of channels and hands one out per conversation. For that to work,
|
||||
one frequency is given over entirely to a data stream that runs day and night
|
||||
telling every radio in the fleet where to go next. That frequency is the
|
||||
**control channel**.
|
||||
|
||||
It is the worst thing a scanner can find: loud, perfectly steady, never
|
||||
silent, and with nothing on it to hear — just a harsh buzz. Left to itself a
|
||||
scanner parks on it for the whole record limit, saves the file, and finds it
|
||||
again on the next sweep, for as long as it runs.
|
||||
|
||||
bandsaunter recognises one and moves on, usually within a second or two:
|
||||
|
||||
```
|
||||
TRUNK 856.561096 MHz -- Motorola SMARTNET / SmartZone (Type I/II) control channel, 3600 baud -- skipping
|
||||
```
|
||||
|
||||
In the live display the recording panel turns yellow and says `TRUNK:` with
|
||||
the system name instead of `REC`, and the end-of-run summary lists every
|
||||
control channel found and where it was.
|
||||
|
||||
What identifies one is a constant-envelope data stream that never pauses, at a
|
||||
symbol rate belonging to a known trunking standard:
|
||||
|
||||
| Symbol rate | Levels | System |
|
||||
|---|---|---|
|
||||
| 3600 baud | 2 | Motorola SMARTNET / SmartZone (Type I/II) |
|
||||
| 9600 baud | 2 | EDACS / ProVoice |
|
||||
| 1200 baud | 2 | MPT-1327 |
|
||||
| 4800 baud | 4 | P25 or DMR Tier III |
|
||||
| 2400 baud | 4 | NXDN / NEXEDGE |
|
||||
|
||||
The first two are called immediately — nothing else transmits at those rates
|
||||
without pausing. The rest share their shape with an ordinary digital voice
|
||||
call on the same system, so they are only judged to be a control channel once
|
||||
the carrier has run unbroken for `--control-seconds` (20 s by default), which
|
||||
is longer than a real conversation goes without taking a breath. Raise it if
|
||||
digital voice is being skipped by mistake.
|
||||
|
||||
Sitting in a band where trunking is common raises confidence but is never
|
||||
required — trunking is licensed on business pairs all over the spectrum, so
|
||||
the shape of the signal has to be enough on its own.
|
||||
|
||||
```bash
|
||||
bandsaunter scan -b 800-trunked # control channels named and skipped
|
||||
bandsaunter scan -b 800-trunked --keep-control # record them (for a decoder)
|
||||
bandsaunter scan -b 800-trunked --lockout-control # never look at them again
|
||||
```
|
||||
|
||||
`--lockout-control` adds each one to the lock-out list as it is found; with
|
||||
lock-out saving on (the default) that list is written to your settings file
|
||||
and survives a restart.
|
||||
|
||||
### CW / Morse
|
||||
|
||||
Keyed carriers are decoded to text. The speed is measured from the signal, so
|
||||
|
|
@ -863,11 +924,18 @@ span is taken exactly as written, since a noisy stretch of spectrum has a
|
|||
definite width rather than a point with a guess around it. Ranges accept the
|
||||
same forms as everywhere else — `450M-455M`, `450-455M`, `88M to 108M`.
|
||||
|
||||
`--lockout-control` adds each trunking control channel to the list as it is
|
||||
found. Two runs never write anything back: `--no-config` has no settings file
|
||||
to write to, since the point of the flag is to leave the saved settings alone;
|
||||
and `--simulate` is looking at an invented band, whose frequencies would sit in
|
||||
a real settings file for ever, skipping whatever genuine signal happened to
|
||||
land near one. Both still lock out for the run in hand, and say so.
|
||||
|
||||
## Built-in help
|
||||
|
||||
Press `h` in the menus for topics covering setup, how the sweep works, why
|
||||
nothing (or too much) is being recorded, capturing conversations, where files
|
||||
go, HF reception and the keys available during a scan. Typing a setting name
|
||||
go, trunked systems, HF reception and the keys available during a scan. Typing a setting name
|
||||
there explains that setting instead.
|
||||
|
||||
From the command line, `bandsaunter config --describe <setting>` does the same,
|
||||
|
|
@ -925,8 +993,15 @@ signal type, which is also what the test suite runs against:
|
|||
|
||||
```bash
|
||||
bandsaunter scan -r 144M-148M --simulate
|
||||
bandsaunter scan -r 856.4M-856.7M --simulate # the control channel, skipped
|
||||
```
|
||||
|
||||
The demo band holds 2 m FM voice with a CTCSS tone, a repeater, a CW beacon,
|
||||
NOAA weather radio, airband AM, an FM broadcast station, P25-style digital
|
||||
voice, a POCSAG pager, a bare carrier, a 433 MHz ISM remote, and a SMARTNET
|
||||
control channel that never stops transmitting — because that last one is only
|
||||
interesting if it behaves the way the real thing does.
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
|
|
@ -946,7 +1021,12 @@ then gated into syllables and phrases -- because sine tones would not exercise
|
|||
the speech detector at all. SSB transmitters are filtered to their audio
|
||||
passband first, since that filter is what makes a signal single-sideband, and
|
||||
without it the simulated signal was several times wider than anything on the
|
||||
air.
|
||||
air. Its FSK transmitters are shaped the way GFSK and C4FM shape a symbol
|
||||
stream, because square-edged keying is a signal no licensed radio would
|
||||
radiate, and its symbols are genuinely pseudo-random: an earlier version
|
||||
multiplied the symbol index by an odd constant and took it modulo the level
|
||||
count, which returns the low bits of a counter -- 0, 1, 0, 1 -- so every FSK
|
||||
test was measuring a tone rather than data.
|
||||
|
||||
Its transmitters seed themselves deterministically, so a test that fails can be
|
||||
made to fail again -- the one thing needed to fix it.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue