Release v0.29.0 — offset detector + false_trigger_reason + BlastMate serials (0.27.0→0.29.0) #36

Merged
serversdown merged 14 commits from dev into main 2026-09-07 15:57:38 -04:00
2 changed files with 49 additions and 8 deletions
Showing only changes of commit 9982938b0b - Show all commits
+23 -4
View File
@@ -62,12 +62,31 @@ _STEM = re.compile(r"^([B-Z])(\d{3})")
_B36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" _B36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def serial_of(name: str) -> str: _SERIAL_RE = re.compile(rb"\b([A-Z]{2}\d{3,6})\b")
"""`P036L318.C80H` -> `BE14036`. See CLAUDE.md, serial encoding."""
def serial_of(name: str, path=None) -> str:
"""Real serial for a BW file.
The filename encodes only the NUMBER: `<letter><3 digits>` where
letter = chr(ord('B') + serial // 1000). The two-letter family prefix
("BE", "BA", ...) is **not** in the filename, so it must be read out of
the file body. Four units in the DL2 archive are BA, not BE — assuming
"BE" mislabels BA9229, BA10060, BA10895 and BA15957.
"""
m = _STEM.match(name) m = _STEM.match(name)
if not m: if not m:
return "?" return "?"
return f"BE{(ord(m.group(1)) - ord('B')) * 1000 + int(m.group(2))}" num = (ord(m.group(1)) - ord("B")) * 1000 + int(m.group(2))
if path is not None:
try:
for s in _SERIAL_RE.findall(Path(path).read_bytes()):
s = s.decode()
if s[2:].lstrip("0") == str(num):
return s
except Exception:
pass
return f"BE{num}" # last-resort fallback; prefix unverified
def stem_time(name: str): def stem_time(name: str):
@@ -141,7 +160,7 @@ def scan(path_str: str):
for ch, st in stats.items(): for ch, st in stats.items():
others = [stats[o]["p5"] for o in stats if o != ch] others = [stats[o]["p5"] for o in stats if o != ch]
rows.append({ rows.append({
"serial": serial_of(p.name), "serial": serial_of(p.name, p),
"timestamp": stamp, "timestamp": stamp,
"filename": p.name, "filename": p.name,
"channel": ch, "channel": ch,
+26 -4
View File
@@ -28,9 +28,31 @@ from minimateplus.event_file_io import read_blastware_file
GEO=("Tran","Vert","Long"); K=10.0/32000.0 GEO=("Tran","Vert","Long"); K=10.0/32000.0
_WAVE=re.compile(r"\.[A-Za-z0-9]{2}0[Ww]$"); _STEM=re.compile(r"^([B-Z])(\d{3})") _WAVE=re.compile(r"\.[A-Za-z0-9]{2}0[Ww]$"); _STEM=re.compile(r"^([B-Z])(\d{3})")
def serial_of(n): _SERIAL_RE = re.compile(rb"\b([A-Z]{2}\d{3,6})\b")
m=_STEM.match(n)
return f"BE{(ord(m.group(1))-ord('B'))*1000+int(m.group(2))}" if m else "?"
def serial_of(name: str, path=None) -> str:
"""Real serial for a BW file.
The filename encodes only the NUMBER: `<letter><3 digits>` where
letter = chr(ord('B') + serial // 1000). The two-letter family prefix
("BE", "BA", ...) is **not** in the filename, so it must be read out of
the file body. Four units in the DL2 archive are BA, not BE — assuming
"BE" mislabels BA9229, BA10060, BA10895 and BA15957.
"""
m = _STEM.match(name)
if not m:
return "?"
num = (ord(m.group(1)) - ord("B")) * 1000 + int(m.group(2))
if path is not None:
try:
for s in _SERIAL_RE.findall(Path(path).read_bytes()):
s = s.decode()
if s[2:].lstrip("0") == str(num):
return s
except Exception:
pass
return f"BE{num}" # last-resort fallback; prefix unverified
def scan(ps): def scan(ps):
p=Path(ps) p=Path(ps)
@@ -48,7 +70,7 @@ def scan(ps):
mid, end = a[t:2*t], a[2*t:] mid, end = a[t:2*t], a[2*t:]
if not pre or not mid or not end: continue if not pre or not mid or not end: continue
v=[statistics.median(x)*K for x in (pre,mid,end)] v=[statistics.median(x)*K for x in (pre,mid,end)]
out.append({"serial":serial_of(p.name),"timestamp":stamp, out.append({"serial":serial_of(p.name, p),"timestamp":stamp,
"filename":p.name,"channel":ch, "filename":p.name,"channel":ch,
"pretrig_n": pre_n or 0, "pretrig_n": pre_n or 0,
"pre":round(v[0],4),"mid":round(v[1],4),"end":round(v[2],4), "pre":round(v[0],4),"mid":round(v[1],4),"end":round(v[2],4),