Files
STM32F4-Base/test/host/cal/cal_collect.py
T
wandering1 40a2816a99
CI / 静态门禁 (pre-commit) (push) Failing after 4m15s
CI / 主机侧单测 (MSVC) (push) Failing after 1m41s
feat(adc): UN 标定完成、标定脚本归集到 test/host/cal/
- UN 通道 5 点最小二乘标定完成:r=555.382141, b=-1, 残差 0.038%, R²=0.99999967
- UA/IA/UN 三路 VALID 置位,保护解卡
- ROM 默认值更新为当前标定值(ADC_CAL_R_Q16_VOLT=555.144958)
- UB/UC/UN 通过 104 写入 ROM 默认值,config.ini 同步
- cal_fit.py 新增 ROLD 表自动读取,不再需要手传 --r-old
- 执行卡精简至 126 行,新增 cal_collect.py 采集脚本与 ROLD 填表
- 标定脚本(cal_fit/cal_write/cal_collect)归集到 test/host/cal/
- 全库文档路径引用同步更新(8 文件)
- UN 当前态文档改写:明确零序电压 U0 语义、本台架未接线状态
- 删除已失效的外部知识底座文档链接
2026-11-13 11:26:36 +08:00

96 lines
3.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""从串口日志采集 meas: 读数并填入执行卡 CALDATA 表。
用法:
cal_collect.py --doc <执行卡路径> --sem ua --point 1 [--samples N] [--log <日志路径>]
自动读取 serial.log 最近 N 拍(默认 15),取中位数,写入 CALDATA 表对应行。
重复运行同一 --point 会覆盖旧值。
"""
import argparse
import re
import statistics
import sys
import time
from pathlib import Path
DEFAULT_LOG = ".dsh/skills/serial-assistant/scripts/state/serial.log"
SEM_FIELD = {"ua": "ua_mv", "un": "un_mv", "ia": "ia_mv"}
def read_median(log_path, sem, n_samples=15, min_val=None):
field = SEM_FIELD.get(sem)
if not field:
print("ERROR: unknown sem %r (use ua/un/ia)" % sem)
return None
text = Path(log_path).read_text(encoding="utf-8", errors="replace")
lines = text.strip().splitlines()
meas = [l for l in lines if "meas:" in l and field + "=" in l]
recent = meas[-n_samples * 2:] if len(meas) >= n_samples * 2 else meas
vals = []
for l in recent:
m = re.search(field + r"=(\d+\.?\d*)", l)
if m:
v = float(m.group(1))
if min_val is not None and v < min_val:
continue
vals.append(v)
if not vals:
return None
return round(statistics.median(vals))
def update_caldata(doc_path, sem, point, value):
text = Path(doc_path).read_text(encoding="utf-8")
m = re.search(r"(<!--\s*CALDATA:BEGIN\s*-->.*?<!--\s*CALDATA:END\s*-->)", text, re.S)
if not m:
print("ERROR: no CALDATA markers in %s" % doc_path)
return False
block = m.group(1)
pattern = r"(\|\s*%s\s*\|\s*%d\s*\|\s*)(\S*|)(\s*\|.*)" % (re.escape(sem), point)
new_block, count = re.subn(pattern, r"\g<1>%d\3" % value, block)
if count != 1:
print("ERROR: expected 1 match for %s point %d, got %d" % (sem, point, count))
return False
text = text.replace(block, new_block)
Path(doc_path).write_text(text, encoding="utf-8", newline="\n")
return True
def main():
ap = argparse.ArgumentParser(description="采集串口读数填入 CALDATA 表")
ap.add_argument("--doc", required=True, help="执行卡文档路径")
ap.add_argument("--sem", required=True, choices=["ua", "un", "ia"], help="通道")
ap.add_argument("--point", required=True, type=int, help="点序号 (1-5)")
ap.add_argument("--samples", type=int, default=15, help="采样拍数 (默认 15)")
ap.add_argument("--log", default=DEFAULT_LOG, help="串口日志路径")
ap.add_argument("--min-val", type=float, default=None,
help="过滤低于此值的读数(切换瞬态)")
ap.add_argument("--wait", type=float, default=3.0,
help="等待新数据到达的秒数 (默认 3)")
a = ap.parse_args()
if a.point < 1 or a.point > 8:
print("ERROR: point must be 1-8")
return 1
time.sleep(a.wait)
med = read_median(a.log, a.sem, a.samples, a.min_val)
if med is None:
print("ERROR: no valid %s data in last %d samples" % (a.sem, a.samples))
return 1
print("%s point %d: %d mV/mA (median of %d samples)" % (a.sem, a.point, med, a.samples))
if not update_caldata(a.doc, a.sem, a.point, med):
return 1
print("OK: updated CALDATA table in %s" % a.doc)
return 0
if __name__ == "__main__":
sys.exit(main())