canair decode¶
Alias: dec
usage: canair decode [-h] [--param NAME [NAME ...]] [--verified]
[--unverified] [--json] [--compact] [--changes-only]
[--stats] [--group-by FIELD] [--discriminate AXIS]
[--find-mirrors] [--bits] [--bytes] [--first N]
[--last N] [--corr PARAM] [--join-tol SECONDS]
[--fill {auto,hold,none}] [--max-hold SECONDS]
[--mirror-match FRACTION] [--allow-offset]
[--corr-transform MODE]
[--method {pearson,spearman,cramers_v,mutual_info}]
[--plot] [--try NAME[:unit]=EXPR] [--dump-bytes]
[--include-pci] [--signed] [--notation NAME]
[--since WHEN] [--until WHEN] [--date YYYY-MM-DD]
[--today] [--last-sessions [N]] [--last-session]
[--state STATE] [--label SUBSTR]
[QUERY ...]
[UDS] Decode captured UDS payloads using PID parameter definitions.
positional arguments:
QUERY ECU/PID selection (mini-language, see
canlib/query.py): 'BMS 2101', 'BMS:2101',
'BMS:2101,2102', 'BMS' (all defined PIDs), or a quoted
cross-ECU query 'MCU:2102 VCU:2101'. Multi-PID queries
are supported for the default value-range, --compact
and --json views; the analysis modes
(--corr/--plot/--stats/--discriminate/--find-
mirrors/--try/--dump-bytes) require the query to
resolve to a single PID.
options:
-h, --help show this help message and exit
--param NAME [NAME ...]
Show only specific parameters (repeatable and/or
space-separated: --param A B or --param A --param B)
--verified Show only verified parameters
--unverified Show only unverified parameters
--json Output as JSON (per-capture decoded values)
--compact One line per capture (chronological param=value pairs)
--changes-only, -c With --compact: skip rows where all shown params are
unchanged from the previous row (collapses stationary
runs)
--stats Descriptive statistics per param (n, distinct, mean,
median, stdev)
--group-by FIELD With --stats: compute statistics per session FIELD
(currently 'state') instead of pooling all captures
--discriminate AXIS Rank params/bytes by how cleanly they separate across
AXIS groups (F = between/within variance; Cramér's V
for typed params) — finds axis-dependent signals a
driving correlation misses. AXIS is 'state' (the
vehicle power state) or a cross-signal ECU:PID:PARAM
to group by (e.g. HVAC:220102:HVAC_COMPRESSOR_ON —
which byte separates on from off)
--find-mirrors Report byte positions on this PID that mirror each
other — redundant status mirrors and unit-variants.
Add --bits for bit-level, --allow-offset to accept an
offset/scale, --mirror-match to change the agreement
required
--bits With --find-mirrors: compare individual bits (Bn:k).
With --discriminate: also rank individual toggling
bits across the axis
--bytes With --discriminate: also rank every varying raw byte
(Bn), not just defined params — finds axis-dependent
bytes without a --try
--first N Only the first N matching captures (chronological)
--last N Only the last N matching captures (chronological)
--corr PARAM Correlate every param (incl. --try) against PARAM
(Pearson r). PARAM may be a local param name, or a
cross-signal reference ECU:PID:PARAM or ECU:PID:EXPR
(e.g. ESC:22C101:REAL_SPEED_KMH) which is time-aligned
by nearest timestamp.
--corr-transform MODE
Transform the --corr reference before pairing
(raw/delta/abs/cumsum/normalize/smooth) — e.g. --corr-
transform delta to test whether a signal tracks a
reference's RATE rather than its level
--method {pearson,spearman,cramers_v,mutual_info}
Coefficient for --corr: pearson (linear, default) or
spearman (rank — catches monotone-but-
nonlinear/quantized/saturating links), or the
categorical cramers_v / mutual_info (nominal
association — for mode/flag/enum references where
numeric spacing is meaningless)
--plot Interactive signal explorer: sweep byte
interpretations (u8/i16/f32/... and endianness) and
params, plot across captures, apply transforms
(delta/abs/normalize/...), zoom/pan the x-axis,
overlay a --corr signal, and flag bytes already mapped
by a param
--try NAME[:unit]=EXPR
Evaluate a candidate expression against captures
without editing YAML (repeatable; works even if the
PID has no params defined yet)
--dump-bytes Emit a timestamp × byte-offset matrix (one row per
capture) instead of decoding params — the escape hatch
for ad-hoc byte analysis. CSV by default; add --json
for JSON. PCI framing bytes are skipped unless
--include-pci. Honours --notation for column labels
and all scope flags
--include-pci With --dump-bytes: include ISO-TP PCI framing bytes
(skipped by default)
--signed With --dump-bytes: render each data byte as a signed
value (-128..127) with an Snn column header, instead
of the default unsigned Bnn (0..255). Use when a byte
is the high half of a signed value (a 0xFF near-zero
baseline correlates poorly unsigned but cleanly
signed)
--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)
mirror matching:
--mirror-match FRACTION
Fraction of compared rows that must agree (default
0.9; use 1 to demand every row, which round-robin poll
skew alone is enough to defeat)
--allow-offset Also accept a mirror at a constant offset or scale (a
== b + k, a == b × s) — real mirrors are frequently
the same quantity in different units or with a
different zero
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)
canair decode BMS 2101 # Value range of every param across captures
canair decode BMS 2101 --param SOC_BMS SOC_DISP # Only specific params
canair decode IGPM 22BC03 # Decode IGPM DID BC03
canair decode BMS 2101 --verified # Only verified parameters
canair decode BMS 2101 --unverified # Only unverified parameters (validation focus)
canair decode BMS 2101 --compact # One line per capture (value evolution)
canair decode ESC 22C101 --state 'MT->KW' --compact --changes-only # One drive, stationary runs collapsed
canair decode MCU 2102 --stats --group-by state # Per-drive-segment statistics
canair decode VCU 2101 --date 2026-07-22 --last 20 # Last 20 captures of one day
canair decode BMS 2101 --json # JSON (per-capture decoded values)
canair decode MCU 2102 --stats # Descriptive stats per param (mean/median/stdev/distinct)
canair decode MCU 2102 --corr MCU_MOTOR_RPM # Correlate every param vs a known signal
canair decode MCU 2102 --plot # sweep interpretations, find the signal
canair decode MCU 2102 --plot --corr MCU_MOTOR_RPM # overlay a known signal + live r
canair decode MCU 2102 --try "TORQUE:Nm=[S12:S13]/100" # Test a candidate expression
canair decode MCU 2102 --try "T=[S17:S18]" --corr MCU_MOTOR_RPM # Validate a candidate by correlation
canair decode MCU 21F2 --try "X=B9" --try "Y=[S10:S11]" # Multiple candidates, undefined PID OK
canair decode BMS 2101 --dump-bytes # timestamp x byte-offset matrix (CSV, PCI skipped)
canair decode BMS 2101 --dump-bytes --json # same matrix as JSON (ad-hoc analysis escape hatch)
--method cheat sheet (which coefficient when):
pearson linear correlation of two continuous signals (DEFAULT). Use for
analog values that scale together — speed vs wheel-rpm, current
vs power. Misses nonlinear/curved links. Reports signed r (±1).
spearman rank correlation — catches any MONOTONE relationship, even
nonlinear/quantized/saturating (a signal that rises then flattens,
or is coarsely stepped). Reach for it when pearson looks weak but
the plot clearly tracks. Reports signed r (±1).
cramers_v categorical association [0..1]: treats each distinct value as an
unordered CATEGORY. Use for mode/gear/flag/enum bytes where the
numeric spacing is meaningless (state 3 isn't "more" than state 1).
mutual_info categorical too — normalized mutual information [0..1]. Like
cramers_v but detects ANY statistical dependence between two
enum/flag signals, not just a table-association pattern.
Rule of thumb: numeric-and-proportional → pearson; numeric-but-curved/stepped
→ spearman; a code/mode/flag (not a magnitude) → cramers_v / mutual_info.
The two categorical methods rank by association strength only — they have no
sign (no ±direction) and no linear fit.