feat(parser): route BinRAW captures through RAW identification path
Reconstruct a signed pulse train from BinRAW Data_RAW demodulated bits (run-length encoded at TE-µs steps) so BinRAW files populate raw_data and flow through the existing RAW identification pipeline. Previously 0/120 BinRAW files yielded a predicted_category; now 118/120 categorize via the live SignatureMatcher engine. RAW code path is unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -182,6 +182,20 @@ class SubFileParser:
|
||||
data_hex = self.fields['Data_RAW'].replace(' ', '')
|
||||
metadata.bin_raw_data = bytes.fromhex(data_hex)
|
||||
|
||||
# Reconstruct a signed pulse train (µs) from the demodulated bit
|
||||
# stream so BinRAW captures flow through the same RAW identification
|
||||
# path as RAW_Data files. Data_RAW is the signal sampled at TE-µs
|
||||
# steps: a run of N identical bits is one pulse of N*TE µs (+high on
|
||||
# 1s, -low on 0s). This populates raw_data, which makes the
|
||||
# has_raw_data property true.
|
||||
n_bits = metadata.bin_raw_bit or metadata.bit_length
|
||||
if metadata.bin_raw_data and metadata.bin_raw_te and n_bits:
|
||||
pulses = self._binraw_to_pulses(
|
||||
metadata.bin_raw_data, n_bits, metadata.bin_raw_te)
|
||||
if pulses:
|
||||
metadata.raw_data = pulses
|
||||
metadata.pulse_count = len(pulses)
|
||||
|
||||
# Calculate duration
|
||||
if metadata.bit_length and metadata.bin_raw_te:
|
||||
metadata.duration_ms = (metadata.bit_length * metadata.bin_raw_te) / 1000.0
|
||||
@@ -190,6 +204,32 @@ class SubFileParser:
|
||||
self.errors.append(f"Error parsing BinRAW fields: {e}")
|
||||
logger.warning(f"Parse error: {e}")
|
||||
|
||||
@staticmethod
|
||||
def _binraw_to_pulses(data: bytes, n_bits: int, te: int) -> List[int]:
|
||||
"""Expand a BinRAW bit stream into a signed timing array (µs).
|
||||
|
||||
Bits are read MSB-first, truncated to ``n_bits``, then run-length
|
||||
encoded: each run of ``k`` equal bits becomes ``k*te`` µs, signed
|
||||
positive for 1s (pulse) and negative for 0s (gap).
|
||||
"""
|
||||
bits = []
|
||||
for byte in data:
|
||||
for i in range(7, -1, -1):
|
||||
bits.append((byte >> i) & 1)
|
||||
bits = bits[:n_bits]
|
||||
if not bits:
|
||||
return []
|
||||
pulses: List[int] = []
|
||||
current, run = bits[0], 1
|
||||
for b in bits[1:]:
|
||||
if b == current:
|
||||
run += 1
|
||||
else:
|
||||
pulses.append(run * te * (1 if current else -1))
|
||||
current, run = b, 1
|
||||
pulses.append(run * te * (1 if current else -1))
|
||||
return pulses
|
||||
|
||||
|
||||
def parse_sub_file(file_path: str) -> SignalMetadata:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user