canair hunt
usage: canair hunt [-h] <kind> ...
[UDS+CAN] Answer 'which byte carries a signal I already know?' Choose a domain kind:
uds sweep a diagnostic PID's bytes vs a known signal (domain A).
A bare `canair hunt AAF 2181 --against …` is shorthand for this.
can sweep a raw broadcast-CAN frame ID's bytes vs a reference frame
byte in the same log (domain B), bytes labelled 0xID:rN.
Read-only: analyses captures/ only, never talks to the device.
positional arguments:
<kind>
uds Hunt a diagnostic PID's bytes vs a known signal (domain A)
can Hunt a raw broadcast-CAN frame ID's bytes vs a reference (domain
B)
options:
-h, --help show this help message and exit
canair hunt uds
usage: canair hunt uds [-h]
(--against ECU:PID:PARAM | --against-file FILE | --physical)
[--min-n N] [--top N] [--transform MODE]
[--method {pearson,spearman}] [--join-tol SECONDS]
[--fill {auto,hold,none}] [--max-hold SECONDS] [--json]
[--all-interps] [--control ECU:PID:PARAM]
[--control-file FILE] [--promote NAME] [--per-session]
[--session-gap SECONDS] [--notation NAME]
[--since WHEN] [--until WHEN] [--date YYYY-MM-DD]
[--today] [--last-sessions [N]] [--last-session]
[--state STATE] [--label SUBSTR]
[ecu] [pid]
Sweeps every byte offset of the target PID under every interpretation
(u8/i16/u24/f32/... x endianness), time-aligns each candidate against a
known reference signal on another ECU/PID (--against), and ranks them by
|Pearson r|. Each top hit reports a linear fit (y=m·x+c), the residual,
and a physical-unit guess — so you learn not just which byte, but its
scale and offset.
This automates the 'which byte tracks vehicle speed / motor RPM?' scratch
work. Use --transform delta to hunt the byte tracking the reference's
*rate* (e.g. torque vs acceleration), and --promote to write the top hit
straight into ecus/ as an enabled, unverified candidate parameter.
Read-only: analyses captures/ only, never talks to the device.
positional arguments:
ecu Target ECU to hunt on (e.g. AAF)
pid Target PID to hunt on (e.g. 2181)
options:
-h, --help show this help message and exit
--against ECU:PID:PARAM
Reference signal: a diagnostic ECU:PID:PARAM (or
ECU:PID:EXPR)
--against-file FILE Reference from an external CSV (timestamp,value)
instead of a bus signal — a calibrated meter log, GPS
track, grid-voltage export. Joined by nearest
timestamp; the file must be on the same absolute clock
as the captures (relative/zero-based logs won't align)
--physical No reference: flag bytes whose (scaled) value lands in
a named physical band (mains RMS/peak, line freq, 12V
rail, HV pack) at some scaling (/1 /10 /100 ×2 ×√2).
Finds anchorless signals by plausibility
--min-n N Min aligned points (default 10)
--top N Max hits (default 12)
--transform MODE Transform the reference before aligning (e.g. delta to
hunt the byte that tracks the reference's *rate* —
torque vs acceleration)
--method {pearson,spearman}
Ranking coefficient: pearson (linear, default) or
spearman (rank)
--json Machine-readable output
--all-interps Show every interpretation per offset (u8/i16/u24/…);
default collapses to the best interpretation per byte
offset
--control ECU:PID:PARAM
Confounder control: regress out this nuisance signal
and rank by the PARTIAL correlation (what remains
after removing the control's linear influence).
Surfaces a byte whose link to --against only shows
once the dominant driver is removed (e.g. AC voltage
behind the IR-drop current)
--control-file FILE Like --control, but the nuisance signal is an external
timestamp,value CSV (mutually exclusive with
--control)
--promote NAME Write the top hit's expression to ecus/ as an enabled,
unverified candidate param NAME (via pids upsert-
param), with the correlation evidence auto-filled into
notes
--per-session Remove each recording session's DC baseline before
ranking — makes a slowly-varying absolute-level
reference/byte (pack/12V/mains voltage, a held
temperature) rankable by --against instead of being
dominated by cross-session offsets. Ranks the in-
session *variation*, not the level
--session-gap SECONDS
With --per-session: time gap that starts a new session
(default 300.0s)
--notation NAME byte-index notation for output labels: wican
(default), isotp, torque, bix. Overrides the
display.byte_notation config key.
time joining:
--join-tol SECONDS Nearest-timestamp join window (default 5s)
--fill {auto,hold,none}
Carry a run-length (keep:changes) value forward to
reference instants it has no sample at: 'auto'
(default) fills only keep:changes sessions, 'hold'
forces it everywhere, 'none' keeps strict point
semantics
--max-hold SECONDS Cap how long a filled value may be carried (default:
until the next sample or the end of its recording
session)
scoping:
Restrict to captures within a date/time range (inclusive) and/or by session state (token-matched) or label substring. --since/--until accept a date (YYYY-MM-DD) or a timestamp (YYYY-MM-DD HH:MM[:SS[.ffffff]])
--since WHEN Only captures on or after this date/time (YYYY-MM-DD[
HH:MM:SS])
--until WHEN Only captures on or before this date/time (YYYY-MM-DD[
HH:MM:SS])
--date YYYY-MM-DD Only captures on this exact date (shorthand for
--since X --until X)
--today Only captures recorded today (shorthand for --date
<today>)
--last-sessions [N] Only the most recent N recorded sessions in scope (N
defaults to 1)
--last-session Only the most recent recorded session in scope (alias
for --last-sessions 1)
--state STATE Only captures recorded in STATE, matched by token and
widened by the profile's implies: hierarchy (--state
ready also matches DRIVING). Comma-separate
alternatives (--state ready,driving); repeat the flag
to require several at once (--state charging --state
parked)
--label SUBSTR Only captures whose session/capture label contains
SUBSTR (case-insensitive)
examples:
# which byte on AAF 2181 is vehicle speed (known on ESC 22C101)?
canair hunt AAF 2181 --against ESC:22C101:REAL_SPEED_KMH
# restrict to drive captures and only strong linear fits
canair hunt AAF 2181 --against ESC:22C101:REAL_SPEED_KMH --state driving --min-n 30
# hunt the byte that tracks the reference's *rate* (acceleration, not speed)
canair hunt MCU 2102 --against ESC:22C101:REAL_SPEED_KMH --transform delta
# rank by rank-correlation (catches quantized / saturating links)
canair hunt MCU 2102 --against ESC:22C101:REAL_SPEED_KMH --method spearman
# write the winning byte into ecus/ as an unverified candidate param
canair hunt AAF 2181 --against ESC:22C101:REAL_SPEED_KMH --promote WHEEL_SPEED_KMH
# reference an EXTERNAL log (calibrated meter / GPS / grid-voltage export),
# joined by nearest timestamp on the captures' absolute clock
canair hunt OBC 2101 --against-file grid_voltage.csv --state charging
# confounder control: which byte tracks the grid once the IR-drop current is
# regressed out? (partial correlation — surfaces links a dominant driver hides)
canair hunt OBC 2101 --against-file grid_voltage.csv --control OBC:2101:OBC_DC_A
# no reference at all: flag bytes whose scaled value lands in a physical band
# (mains RMS/peak, line freq, 12V rail, HV pack) — finds an anchorless signal
canair hunt OBC 2101 --physical --state charging
tip: --against takes a known signal ECU:PID:PARAM (or a raw ECU:PID:EXPR). Use
`canair correlate --overlap` first to find a reference that actually shares
time-aligned samples with your target.
canair hunt can
usage: canair hunt can [-h] [--can-format {auto,asc,blf,csv,log,gvret}] --id
ID --against 0xID:rN [--min-n N] [--top N]
[--transform MODE] [--method {pearson,spearman}]
[--join-tol SECONDS] [--fill {auto,hold,none}]
[--max-hold SECONDS] [--json] [--all-interps]
[--notation NAME]
FILE
Hunt on a raw broadcast-CAN frame log: sweep every byte/interpretation of --id's frames vs --against (a frame byte 0xID:rN in the same log). Hits are raw-CAN rN labels (no WiCAN expr); --promote is not supported for frames yet (frame signals are defined in signals/).
positional arguments:
FILE Path to a raw broadcast-CAN frame log
(.asc/.blf/candump .log/.trc/GVRET .csv)
options:
-h, --help show this help message and exit
--can-format {auto,asc,blf,csv,log,gvret}
Log format (default: auto-detect by extension)
--id ID The arbitration ID to hunt on (e.g. 0x220)
--against 0xID:rN Reference frame byte in the same log (e.g. 0x386:r0)
--min-n N Min aligned points (default 10)
--top N Max hits (default 12)
--transform MODE Transform the reference before aligning (e.g. delta to
hunt the byte that tracks the reference's *rate* —
torque vs acceleration)
--method {pearson,spearman}
Ranking coefficient: pearson (linear, default) or
spearman (rank)
--json Machine-readable output
--all-interps Show every interpretation per offset (u8/i16/u24/…);
default collapses to the best interpretation per byte
offset
--notation NAME byte-index notation for output labels: wican
(default), isotp, torque, bix. Overrides the
display.byte_notation config key.
time joining:
--join-tol SECONDS Nearest-timestamp join window (default 5s)
--fill {auto,hold,none}
Carry a run-length (keep:changes) value forward to
reference instants it has no sample at: 'auto'
(default) fills only keep:changes sessions, 'hold'
forces it everywhere, 'none' keeps strict point
semantics
--max-hold SECONDS Cap how long a filled value may be carried (default:
until the next sample or the end of its recording
session)