40a2816a99
- 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 语义、本台架未接线状态 - 删除已失效的外部知识底座文档链接
96 lines
3.4 KiB
Python
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())
|