feat(adc): 新增变比维 r 三维折算,录波段格式升 v2
采样板注入 Ua=5V/Ia=0.5A 读数偏小,根因是固件只输出引脚电压、 缺「端子→引脚」变比。折算改三维: 工程量 = (code + b) × k[µV/码] × 1e-6 × r k 保持 ROM 引脚 LSB,b 为零点,r 为端子变比(int32 Q16)。 变比不能并进 k:UA 端子域 k 达 1.5e5 µV/码、Q16 溢出 int32; r 单独存 Q16 不溢出。两点标定改标 r,k 仍是板级事实。 - 新开单段 [adc_cal_sec](8 键 r_ua..r_in),cfg 段数达 8/8 上限 - 一次变比复用 prot_set 四项,不新开段;r=0 表示本路不折算 - ROM 默认带台架实测变比(电压族 1000、电流族 29.4118), 烧进固件即显二次值;VALID 仍须两点标定,两者互不派生 - eng 判据改「每路要么已配变比、要么削顶不显示」,不再看 VALID - 104 地址 0x8050~0x8057 写 r,run_par_cal_r_set 写值与置脏同函数 - 录波 v2:通道表加 int32 r_q16,头 128→160、整段 5250→5282; code_to_milli 用余数分解换等价单次圆整,20 万组大整数对拍 0 不符 - 文档同步:采集与算法层/通道映射/故障录波/网络配置/配置文件/ 产品需求/内存台账,历史带日期实测数字按冻结口径不改 - 单测 13 套全绿,/keil-build 0 错误 0 警告(256024/31760/ 2080/152368),RAM 实测回填内存内容分配策略 §6.1
This commit is contained in:
@@ -11,19 +11,20 @@
|
||||
* 哨兵漏放,只有离线端能用独立推导的期望值 + 坏文件注入一次性钉死。
|
||||
*
|
||||
* 覆盖点(TC-ADCCAL-xxx;属主登记处 = 本目录,族 TC-HOST-ADCCAL):
|
||||
* TC-ADCCAL-001 init 注册两段:名称/键数/data_size/无回调/默认表指向
|
||||
* TC-ADCCAL-002 UA(TPAFE)折算:0 / 8192 / 32767 / -32768 对 10V/65536 独立推导
|
||||
* TC-ADCCAL-003 UB(STM32)折算:0 / 2048 / 4095 对 3.3V/4096
|
||||
* TC-ADCCAL-004 其余 6 路各 1 点(合计 8 通道 × ≥3 码值点,标定折算落地 DoD)
|
||||
* TC-ADCCAL-001 init 注册三段:名称/键数/data_size/无回调/默认表指向
|
||||
* TC-ADCCAL-002 UA(TPAFE)折算:0 / 8192 / 32767 / -32768,期望 = 引脚值 × 电压族变比
|
||||
* TC-ADCCAL-003 UB(STM32)折算:0 / 2048 / 4095,期望 = 引脚值 × 电压族变比
|
||||
* TC-ADCCAL-004 其余 6 路各 1 点(变比按族逐路挑:UC/UN 电压、IA/IB/IC/IN 电流)
|
||||
* TC-ADCCAL-005 TEMP 透传 + flags/k_uv 恒 0;sem 越界守卫
|
||||
* TC-ADCCAL-006 默认 flags 三态:VALID 全 0;CLIPPED = UB/UC/IB/IC/IN(0xE6)
|
||||
* TC-ADCCAL-007 k_uv 精确值:152.587890625 / 805.6640625(Q16 无舍入验证)
|
||||
* TC-ADCCAL-008 set():合法带边界含端点 / 越界拒绝 RAM 不动 / TEMP 拒绝
|
||||
* TC-ADCCAL-009 合法带哨兵回退:坏 k/坏 b → ROM 值 + 每通道一次 [ERR] +
|
||||
* flags 不报 VALID(即便位图置位)+ init 重置观测窗
|
||||
* TC-ADCCAL-014 零点 b 生效(set 路径):(code+b)×k 逐项可算
|
||||
* TC-ADCCAL-015 两点标定公式:合成数据还原 k/b + 写回往返 + 参数/斜率/
|
||||
* 零点越界(-2)守卫(两点标定的算术核,台架注入待跑)
|
||||
* TC-ADCCAL-014 零点 b 生效(set 路径):(code+b)×k×r 逐项可算
|
||||
* TC-ADCCAL-015 两点标定公式:合成 r/b 回算(独立推导、相对误差 1e-6)+
|
||||
* 写回往返(set k/b + set_ratio 后两点复现端子值)+ 参数/斜率/
|
||||
* k 合法域/v 越 ±1e9/r < 1.0(-1)/零点越界(-2)守卫
|
||||
* TC-ADCCAL-016 rail_ths 门限:TPAFE ±32112 / STM32 4013·81 / TEMP 不监视
|
||||
* TC-ADCCAL-017 init 幂等:重复调用 RAM 复位默认 + 重新注册
|
||||
* —— 以下走真实 cfg_file 引擎(标定落盘与整定入口 DoD)——
|
||||
@@ -36,6 +37,13 @@
|
||||
* 闭锁 / 两路齐第三路缺仍闭锁(全或无)/ 三路齐放行且 UB 仍无 VALID
|
||||
* (证明它是"三路"而不是 feed_eng 那个"8 路")/ 复位后立刻回闭锁
|
||||
* (现查、无自有状态可残留)
|
||||
* TC-ADCCAL-024 变比三维读数口初值 = ROM 默认(电压族 1000.0 / 电流族 29.4118),
|
||||
* ratio_configured 全 1,TEMP/越界恒 0
|
||||
* TC-ADCCAL-025 set_ratio(sem, 0) 成功路径(返 0):该路输出退化到引脚电压、
|
||||
* ratio_configured 归 0、VALID 清;再写回非 0 即恢复
|
||||
* TC-ADCCAL-026 set_ratio 拒绝面:比值 < 1.0 拒(-1,RAM 不动)、TEMP 拒、越界通道拒
|
||||
* TC-ADCCAL-027 坏文件注入 [adc_cal_sec]:r_ua=0 与 r_ua=1(< 1.0)都不折算、
|
||||
* VALID 不亮;未列键保留 ROM 变比(= 只坏一路不牵连别路)
|
||||
* —— 以下四项是"改了没落盘"的可诊断化(道G task-43 第②项;四态**定义只在
|
||||
* App/algo/adc_cal.h 一处**,本表只描述断言、不重定义)——
|
||||
* TC-ADCCAL-019 观测件不得反过来制造故障:get_stats(NULL) 静默返回、随时可读
|
||||
@@ -176,12 +184,57 @@ static int s_total = 0, s_passed = 0, s_failed = 0;
|
||||
|
||||
/* ===================== 独立推导的期望值 ===================== */
|
||||
/* 期望一律用 **double 直接除**(10/65536、3.3/4096),不引用被测的 Q16 常量,
|
||||
* 满足标定折算落地 DoD「期望值由 LSB 常数独立算得(不是抄实现)」;容差只需盖住
|
||||
* float32 中间积舍入(相对 ~1e-7)与打印粒度。 */
|
||||
static double exp_tpafe(int32_t code) { return (double)code * (10.0 / 65536.0); }
|
||||
static double exp_stm32(int32_t code) { return (double)code * (3.3 / 4096.0); }
|
||||
static double exp_q16(int32_t code, int32_t b, int32_t k_q16) {
|
||||
return ((double)code + (double)b) * ((double)k_q16 / 65536.0) / 1.0e6;
|
||||
* 满足标定折算落地 DoD「期望值由 LSB 常数独立算得(不是抄实现)」。三层口径:
|
||||
* ① 引脚域 exp_pin():按通道来源给 LSB——TPAFE 10 V 跨度 / 65536 码,
|
||||
* STM32 0~3.3 V / 4096 码;
|
||||
* ② 端子(二次)域 exp_eng():引脚值 × 该路变比。变比按族在此**独立写出十进制
|
||||
* 常量**(电压族 1000.0 V/V、电流族 29.4118 A/V = 1927532/65536 回落两位),
|
||||
* 不引 ADC_CAL_R_Q16_* 宏——引宏就等于把实现里的数抄进期望,正是 DoD 禁止的;
|
||||
* ③ 整定域 exp_q16():先按 Q16 系数还原引脚电压,再乘该路变比。
|
||||
* ⚠ 变比必须**按通道**挑,不能一刀切:TPAFE 侧 UA/UN 是电压族、IA 是电流族;
|
||||
* STM32 侧 UB/UC 是电压族、IB/IC/IN 是电流族(V0.1 双转换器分配,见
|
||||
* docs/硬件平台/ADC通道映射说明.md 与 adc_cal.c 的 ROM 表)。
|
||||
* 容差只需盖住 float32 中间积舍入(相对 ~1e-7)与打印粒度。 */
|
||||
#define EXP_R_VOLT (1000.0) /* 电压族变比 V/V */
|
||||
#define EXP_R_CURR (29.4118) /* 电流族变比 A/V(1927532/65536 的十进制口径) */
|
||||
|
||||
static double exp_ratio(adc_semantic_t sem) {
|
||||
switch (sem) {
|
||||
case ADC_SEM_UA:
|
||||
case ADC_SEM_UB:
|
||||
case ADC_SEM_UC:
|
||||
case ADC_SEM_UN:
|
||||
return EXP_R_VOLT;
|
||||
case ADC_SEM_IA:
|
||||
case ADC_SEM_IB:
|
||||
case ADC_SEM_IC:
|
||||
case ADC_SEM_IN:
|
||||
return EXP_R_CURR;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 引脚域:来源决定 LSB(TPAFE 是 16 位双极性 10 V 跨度,STM32 是单极性 3.3 V) */
|
||||
static double exp_pin(int32_t code, adc_semantic_t sem) {
|
||||
switch (sem) {
|
||||
case ADC_SEM_UA:
|
||||
case ADC_SEM_UN:
|
||||
case ADC_SEM_IA:
|
||||
return (double)code * (10.0 / 65536.0);
|
||||
default:
|
||||
return (double)code * (3.3 / 4096.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 端子域 = 引脚域 × 该路变比 */
|
||||
static double exp_eng(int32_t code, adc_semantic_t sem) {
|
||||
return exp_pin(code, sem) * exp_ratio(sem);
|
||||
}
|
||||
|
||||
/* 整定域:Q16 系数还原引脚电压,再乘该路变比(= adc_cal_apply 的三维口径) */
|
||||
static double exp_q16(adc_semantic_t sem, int32_t code, int32_t b, int32_t k_q16) {
|
||||
return ((double)code + (double)b) * ((double)k_q16 / 65536.0) / 1.0e6 * exp_ratio(sem);
|
||||
}
|
||||
static int near_d(double got, double want) {
|
||||
double d = got - want;
|
||||
@@ -222,9 +275,9 @@ static const char *vfs_get(void) { return (const char *)s_vfs; }
|
||||
|
||||
/* ===================== 用例(白盒组) ===================== */
|
||||
|
||||
/* TC-ADCCAL-001:init 注册两段(名称/键数/data_size/无回调) */
|
||||
/* TC-ADCCAL-001:init 注册三段(名称/键数/data_size/无回调) */
|
||||
static void tc_001_init_registers(void) {
|
||||
printf("[TC-ADCCAL-001] init registers [adc_cal]/[adc_cal_ofs]\n");
|
||||
printf("[TC-ADCCAL-001] init registers [adc_cal]/[adc_cal_ofs]/[adc_cal_sec]\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
CHECK(s_sections[0].used == 1u, "section slot0 used");
|
||||
@@ -236,31 +289,38 @@ static void tc_001_init_registers(void) {
|
||||
"sec1 name = adc_cal_ofs");
|
||||
CHECK(s_sections[1].key_count == 8u, "sec1 keys = 8b");
|
||||
CHECK(s_sections[1].data_size == 32u, "sec1 data_size = 32");
|
||||
CHECK(s_sections[2].used == 0u, "only two sections registered");
|
||||
CHECK(s_sections[2].used == 1u && strcmp(s_sections[2].name, "adc_cal_sec") == 0,
|
||||
"sec2 name = adc_cal_sec (ratio dimension)");
|
||||
CHECK(s_sections[2].key_count == 8u, "sec2 keys = 8r");
|
||||
CHECK(s_sections[2].data_size == 32u, "sec2 data_size = 32");
|
||||
CHECK(s_sections[2].p_cb == NULL, "sec2 no callback");
|
||||
CHECK(s_sections[3].used == 0u, "only three sections registered");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-002/003/004:8 通道 × ≥3 码值点折算,期望独立推导(标定折算落地 DoD) */
|
||||
/* TC-ADCCAL-002/003/004:8 通道 × ≥3 码值点折算,期望独立推导(标定折算落地 DoD)
|
||||
* v2.0 起输出是**二次值**(引脚值 × 该路变比):TPAFE 侧 UA/UN 走电压族 1000、
|
||||
* IA 走电流族 29.4118;STM32 侧 UB/UC 走电压族、IB/IC/IN 走电流族。 */
|
||||
static void tc_002_004_apply(void) {
|
||||
printf("[TC-ADCCAL-002] UA (TPAFE) apply\n");
|
||||
printf("[TC-ADCCAL-002] UA (TPAFE, voltage family) apply\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 0), exp_tpafe(0)), "UA code 0 = 0V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 8192), exp_tpafe(8192)), "UA 8192 = 1.25V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 32767), exp_tpafe(32767)), "UA full scale minus 1 (bipolar top code)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, -32768), exp_tpafe(-32768)), "UA -FS (bipolar)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 0), exp_eng(0, ADC_SEM_UA)), "UA code 0 = 0V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 8192), exp_eng(8192, ADC_SEM_UA)), "UA 8192 = 1.25V pin -> 1250V terminal");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 32767), exp_eng(32767, ADC_SEM_UA)), "UA full scale minus 1 (bipolar top code)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, -32768), exp_eng(-32768, ADC_SEM_UA)), "UA -FS (bipolar)");
|
||||
|
||||
printf("[TC-ADCCAL-003] UB (STM32) apply\n");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 0), exp_stm32(0)), "UB code 0 = 0V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 2048), exp_stm32(2048)), "UB mid = 1.65V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 4095), exp_stm32(4095)), "UB +FS 3.2992V");
|
||||
printf("[TC-ADCCAL-003] UB (STM32, voltage family) apply\n");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 0), exp_eng(0, ADC_SEM_UB)), "UB code 0 = 0V");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 2048), exp_eng(2048, ADC_SEM_UB)), "UB mid = 1.65V pin -> 1650V terminal");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 4095), exp_eng(4095, ADC_SEM_UB)), "UB +FS 3.2992V pin");
|
||||
|
||||
printf("[TC-ADCCAL-004] other six channels one mid point each\n");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UC, 123), exp_stm32(123)), "UC 123");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UN, -10000), exp_tpafe(-10000)), "UN -10000");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IA, 11452), exp_tpafe(11452)), "IA 11452 (bench first-frame code)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IB, 4000), exp_stm32(4000)), "IB 4000");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IC, 1), exp_stm32(1)), "IC 1");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IN, 4094), exp_stm32(4094)), "IN 4094");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UC, 123), exp_eng(123, ADC_SEM_UC)), "UC 123 (voltage family)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UN, -10000), exp_eng(-10000, ADC_SEM_UN)), "UN -10000 (voltage family)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IA, 11452), exp_eng(11452, ADC_SEM_IA)), "IA 11452 (current family, bench first-frame code)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IB, 4000), exp_eng(4000, ADC_SEM_IB)), "IB 4000 (current family)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IC, 1), exp_eng(1, ADC_SEM_IC)), "IC 1 (current family)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IN, 4094), exp_eng(4094, ADC_SEM_IN)), "IN 4094 (current family)");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-005:TEMP 透传与守卫 */
|
||||
@@ -315,7 +375,7 @@ static void tc_008_set(void) {
|
||||
adc_cal_init();
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, 10500000L, -12L) == 0, "set in-band ok");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) != 0u, "VALID set after accepted");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_q16(1000, -12, 10500000)),
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_q16(ADC_SEM_UA, 1000, -12, 10500000)),
|
||||
"apply uses accepted k/b");
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, 5000000L, 0L) == 0, "ROM/2 boundary accepted");
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, 20000000L, 0L) == 0, "ROM*2 boundary accepted");
|
||||
@@ -337,7 +397,7 @@ static void tc_009_sanitize(void) {
|
||||
adc_cal_init();
|
||||
s_kcfg.k[0] = 30000000L; /* > ROM*2:模拟坏文件/坏标定已写入 RAM */
|
||||
s_kcfg.valid |= 0x01u; /* 位图也说「已标定」——更要用哨兵兜住 */
|
||||
want = exp_tpafe(1000);
|
||||
want = exp_eng(1000, ADC_SEM_UA);
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), want), "out-of-band k falls back to ROM");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) == 0u, "VALID suppressed while k out of band");
|
||||
CHECK(g_caltest_err_count == 1, "first bad observation logs exactly one ERR");
|
||||
@@ -346,7 +406,7 @@ static void tc_009_sanitize(void) {
|
||||
CHECK(g_caltest_err_count == 1, "repeat observations do not spam ERR");
|
||||
/* b 越界同哨兵(k 合法、b 坏) */
|
||||
s_bcfg.b[1] = 99999L;
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 1000), exp_stm32(1000)), "bad b -> ROM + b=0");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 1000), exp_eng(1000, ADC_SEM_UB)), "bad b -> ROM + b=0");
|
||||
CHECK(g_caltest_err_count == 2, "bad b noted on its own channel");
|
||||
/* init 重置留痕位 = 新观测窗 */
|
||||
adc_cal_init();
|
||||
@@ -366,43 +426,66 @@ static void tc_00a_b_effect(void) {
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
CHECK(adc_cal_set(ADC_SEM_IA, 10000000L, -77L) == 0, "set IA b=-77");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IA, 1077), exp_q16(1077, -77, 10000000)),
|
||||
"IA apply = (code-77)*ROMk");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IA, 1077), exp_q16(ADC_SEM_IA, 1077, -77, 10000000)),
|
||||
"IA apply = (code-77)*ROMk*r_curr");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-015:两点标定公式 + 写回往返 */
|
||||
static void tc_00b_two_point(void) {
|
||||
int32_t kq = 0, bb = 0;
|
||||
const int32_t k0 = 10000000L;
|
||||
const int32_t b0 = -30L;
|
||||
int32_t c1 = -250, c2 = 32000;
|
||||
int32_t rq = 0, bb = 0;
|
||||
const int32_t k0 = 10000000L; /* 该路生效 k(TPAFE 152.587890625 uV/code) */
|
||||
const double r0 = 1000.0; /* 待标定的端子 vs 引脚变比(电压族量级) */
|
||||
const int32_t b0 = -30L; /* 真零点,码值 */
|
||||
const int32_t c1 = 300, c2 = 800; /* 两点码值(合端子 41 V / 117 V 量级) */
|
||||
int32_t v1, v2;
|
||||
int rc;
|
||||
|
||||
printf("[TC-ADCCAL-015] two-point formula recovers synthetic k/b\n");
|
||||
printf("[TC-ADCCAL-015] two-point formula recovers synthetic r/b\n");
|
||||
/* 合成测量:v = (c + b0) * k0/65536 µV(lround 模拟量化读数) */
|
||||
v1 = (int32_t)my_lround(((double)c1 + (double)b0) * ((double)k0 / 65536.0));
|
||||
v2 = (int32_t)my_lround(((double)c2 + (double)b0) * ((double)k0 / 65536.0));
|
||||
rc = adc_cal_two_point(c1, c2, v1, v2, &kq, &bb);
|
||||
/* 合成测量:端子 uV = (c + b0) x (k0/65536) uV/code x r0(lround 模拟量化读数) */
|
||||
v1 = (int32_t)my_lround(((double)c1 + (double)b0) * ((double)k0 / 65536.0) * r0);
|
||||
v2 = (int32_t)my_lround(((double)c2 + (double)b0) * ((double)k0 / 65536.0) * r0);
|
||||
rc = adc_cal_two_point(c1, c2, v1, v2, k0, &rq, &bb);
|
||||
CHECK(rc == 0, "two_point ok");
|
||||
CHECK(kq > (k0 - 5) && kq < (k0 + 5), "k recovered within +-5 q16");
|
||||
CHECK(((double)rq > (r0 * 65536.0 * (1.0 - 1.0e-6))) &&
|
||||
((double)rq < (r0 * 65536.0 * (1.0 + 1.0e-6))),
|
||||
"r recovered within 1e-6 relative");
|
||||
CHECK(bb > (b0 - 3) && bb < (b0 + 3), "b recovered within +-3 codes");
|
||||
/* 写回往返:set 后 apply(c2) 应还原 v2(µV 级) */
|
||||
/* 写回往返:set(k,b) 置位 + set_ratio 定量纲,两点都应复现端子值 */
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, kq, bb) == 0, "set recovered coeffs");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, c2), (double)v2 / 1.0e6), "roundtrip v(c2) = measured");
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, k0, bb) == 0, "set recovered k/b");
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_UA, rq) == 0, "set recovered ratio");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) != 0u,
|
||||
"VALID needs both writes (k/b band + ratio configured)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, c1), (double)v1 / 1.0e6),
|
||||
"roundtrip v(c_lo) = measured");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, c2), (double)v2 / 1.0e6),
|
||||
"roundtrip v(c_hi) = measured");
|
||||
|
||||
printf("[TC-ADCCAL-015] two_point guards\n");
|
||||
CHECK(adc_cal_two_point(100, 100, 0L, 100000L, &kq, &bb) == -1, "dc=0 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 50000L, 50000L, &kq, &bb) == -1, "dv=0 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 100000L, 50000L, &kq, &bb) == -1, "inverted slope rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, NULL, &bb) == -1, "NULL k rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, &kq, NULL) == -1, "NULL b rejected");
|
||||
/* 真零点 +9000 码 > B_MAX:斜率对但 b 越界 -> -2(先查前端,不用系数凑) */
|
||||
v1 = (int32_t)my_lround((100.0 + 9000.0) * ((double)k0 / 65536.0));
|
||||
v2 = (int32_t)my_lround((2000.0 + 9000.0) * ((double)k0 / 65536.0));
|
||||
CHECK(adc_cal_two_point(100, 2000, v1, v2, &kq, &bb) == -2, "b beyond +-8192 -> -2");
|
||||
CHECK(adc_cal_two_point(100, 100, 0L, 100000L, k0, &rq, &bb) == -1, "dc=0 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 50000L, 50000L, k0, &rq, &bb) == -1, "dv=0 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 100000L, 50000L, k0, &rq, &bb) == -1, "inverted slope rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, 0L, &rq, &bb) == -1, "k_q16 = 0 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, 100000001L, &rq, &bb) == -1, "k_q16 > 1e8 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, k0, NULL, &bb) == -1, "NULL r rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, k0, &rq, NULL) == -1, "NULL b rejected");
|
||||
/* v 超 +-1e9 uV(= +-1000 V):几乎必然把 mV/码值当 uV 填了 */
|
||||
CHECK(adc_cal_two_point(100, 200, 1000000000L, 1000100000L, k0, &rq, &bb) == -1,
|
||||
"v beyond +1e9 rejected");
|
||||
CHECK(adc_cal_two_point(100, 200, -1000100000L, -1000000000L, k0, &rq, &bb) == -1,
|
||||
"v beyond -1e9 rejected");
|
||||
/* 算出的变比 < 1.0(dc=100、k=1e7 时 dv 仅 1000 uV -> r 约 0.065)-> -1 */
|
||||
CHECK(adc_cal_two_point(100, 200, 0L, 1000L, k0, &rq, &bb) == -1, "computed r < 1.0 -> -1");
|
||||
/* 真零点 +9000 码 > B_MAX:斜率对(r = 1.5)但 b 越界 -> -2(先查前端,不用系数凑) */
|
||||
v1 = (int32_t)my_lround((100.0 + 9000.0) * ((double)k0 / 65536.0) * 1.5);
|
||||
v2 = (int32_t)my_lround((2000.0 + 9000.0) * ((double)k0 / 65536.0) * 1.5);
|
||||
CHECK(adc_cal_two_point(100, 2000, v1, v2, k0, &rq, &bb) == -2, "b beyond +-8192 -> -2");
|
||||
/* 真零点 +9000 码 > B_MAX:斜率对(r = 1.5)但 b 越界 -> -2(先查前端,不用系数凑) */
|
||||
v1 = (int32_t)my_lround((100.0 + 9000.0) * ((double)k0 / 65536.0) * 1.5);
|
||||
v2 = (int32_t)my_lround((2000.0 + 9000.0) * ((double)k0 / 65536.0) * 1.5);
|
||||
CHECK(adc_cal_two_point(100, 2000, v1, v2, k0, &rq, &bb) == -2, "b beyond +-8192 -> -2");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-016:贴轨门限表 */
|
||||
@@ -423,14 +506,83 @@ static void tc_00d_idempotent(void) {
|
||||
printf("[TC-ADCCAL-017] re-init restores defaults\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
(void)adc_cal_set(ADC_SEM_UA, 12345678L, 5L);
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_q16(1000, 5, 12345678)), "pre-check tuned");
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, 12345678L, 5L) == 0, "pre-check tuned");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_q16(ADC_SEM_UA, 1000, 5, 12345678)), "pre-check tuned");
|
||||
adc_cal_init(); /* 幂等重入:RAM 复位 + 再注册 */
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_tpafe(1000)), "re-init back to ROM");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 1000), exp_eng(1000, ADC_SEM_UA)), "re-init back to ROM");
|
||||
CHECK(adc_cal_flags(ADC_SEM_UA) == 0u, "re-init clears VALID too");
|
||||
}
|
||||
|
||||
/* ===================== 用例(引擎集成组,标定落盘与整定入口 DoD) ===================== */
|
||||
/* TC-ADCCAL-024:变比维读数口初值 = ROM 默认(出厂即配,不是缺省 0) */
|
||||
static void tc_024_ratio_defaults(void) {
|
||||
printf("[TC-ADCCAL-024] ratio readouts start at ROM defaults\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
/* 电压族 1000.0 V/V、电流族 29.4118 A/V——十进制口径在此独立写出,
|
||||
* Q16 原值由 比值 × 65536 就地算出(1927532 = 29.4118 x 65536 的回落) */
|
||||
CHECK(near_d((double)adc_cal_ratio(ADC_SEM_UA), EXP_R_VOLT), "UA ratio = 1000.0 V/V");
|
||||
CHECK(near_d((double)adc_cal_ratio(ADC_SEM_UN), EXP_R_VOLT), "UN ratio = 1000.0 V/V");
|
||||
CHECK(near_d((double)adc_cal_ratio(ADC_SEM_IA), EXP_R_CURR), "IA ratio = 29.4118 A/V");
|
||||
CHECK(near_d((double)adc_cal_ratio(ADC_SEM_IN), EXP_R_CURR), "IN ratio = 29.4118 A/V");
|
||||
CHECK(adc_cal_ratio_q16(ADC_SEM_UA) == (int32_t)my_lround(EXP_R_VOLT * 65536.0),
|
||||
"UA ratio q16 = 65536000 (LSB exact)");
|
||||
CHECK(adc_cal_ratio_q16(ADC_SEM_IA) == (int32_t)my_lround(EXP_R_CURR * 65536.0),
|
||||
"IA ratio q16 = 1927532 (LSB exact)");
|
||||
CHECK(adc_cal_ratio_configured(ADC_SEM_UA) == 1u, "UA ratio configured at boot");
|
||||
CHECK(adc_cal_ratio_configured(ADC_SEM_IA) == 1u, "IA ratio configured at boot");
|
||||
/* TEMP 不参与线性标定;越界通道同守卫 */
|
||||
CHECK((adc_cal_ratio(ADC_SEM_TEMP) == 0.0f) && (adc_cal_ratio_q16(ADC_SEM_TEMP) == 0) &&
|
||||
(adc_cal_ratio_configured(ADC_SEM_TEMP) == 0u), "TEMP ratio all zero");
|
||||
CHECK((adc_cal_ratio((adc_semantic_t)ADC_SEM_COUNT) == 0.0f) &&
|
||||
(adc_cal_ratio_q16((adc_semantic_t)ADC_SEM_COUNT) == 0) &&
|
||||
(adc_cal_ratio_configured((adc_semantic_t)ADC_SEM_COUNT) == 0u),
|
||||
"OOB sem ratio all zero");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-025:set_ratio(sem, 0) = 显式关掉本路折算(成功路径,不是拒绝) */
|
||||
static void tc_025_ratio_zero_disables(void) {
|
||||
printf("[TC-ADCCAL-025] set_ratio(0) disables scaling and drops VALID\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
/* 先走正规 k/b 整定把 VALID 点亮(r 出厂已配 → 三条件齐) */
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, ADC_CAL_K_Q16_TPAFE, 0L) == 0, "seed k/b accepted");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) != 0u,
|
||||
"VALID lit with ROM ratio already configured");
|
||||
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_UA, 0L) == 0, "set_ratio(0) accepted (explicit off)");
|
||||
/* 折算退化到引脚域:期望 = 码值 × 10/65536,与变比无关 */
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 8192), exp_pin(8192, ADC_SEM_UA)),
|
||||
"apply falls back to pin volts (x1000 gone)");
|
||||
CHECK((adc_cal_ratio(ADC_SEM_UA) == 0.0f) && (adc_cal_ratio_q16(ADC_SEM_UA) == 0),
|
||||
"ratio readouts report 0 (not a third out-of-band state)");
|
||||
CHECK(adc_cal_ratio_configured(ADC_SEM_UA) == 0u, "ratio_configured = 0");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) == 0u,
|
||||
"VALID cleared by r = 0 (three-condition rule)");
|
||||
|
||||
/* 写回非 0 即恢复(r 与 k/b 无先后依赖,现算三条件) */
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_UA, (int32_t)my_lround(EXP_R_VOLT * 65536.0)) == 0,
|
||||
"set_ratio back to 1000 accepted");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 8192), exp_eng(8192, ADC_SEM_UA)),
|
||||
"apply scales again");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) != 0u, "VALID back on");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-026:set_ratio 的拒绝面(比值 < 1.0 / TEMP / 越界通道;RAM 不动) */
|
||||
static void tc_026_ratio_set_guards(void) {
|
||||
float before;
|
||||
|
||||
printf("[TC-ADCCAL-026] set_ratio rejects sub-1.0 / TEMP / OOB, RAM intact\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
before = adc_cal_apply(ADC_SEM_UA, 1000);
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_UA, 60000L) == -1, "ratio 0.9155 (< 1.0) rejected");
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_UA, -65536L) == -1, "negative ratio rejected");
|
||||
CHECK(adc_cal_set_ratio(ADC_SEM_TEMP, 65536000L) == -1, "TEMP rejected");
|
||||
CHECK(adc_cal_set_ratio((adc_semantic_t)ADC_SEM_COUNT, 65536000L) == -1, "OOB sem rejected");
|
||||
CHECK(adc_cal_apply(ADC_SEM_UA, 1000) == before, "RAM untouched after all rejects");
|
||||
CHECK(adc_cal_ratio_q16(ADC_SEM_UA) == (int32_t)my_lround(EXP_R_VOLT * 65536.0),
|
||||
"UA ratio still ROM default after rejects");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-010:文件值经 load 生效 + VALID */
|
||||
static void tc_010_file_apply(void) {
|
||||
@@ -442,7 +594,7 @@ static void tc_010_file_apply(void) {
|
||||
CHECK(cfg_file_load() == 0, "load ok");
|
||||
CHECK(adc_cal_k_uv(ADC_SEM_UA) > 183.105f && adc_cal_k_uv(ADC_SEM_UA) < 183.106f,
|
||||
"UA k = 12000000 q16 = 183.10546875 uV");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 6557), exp_q16(6557, -40, 12000000)),
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 6557), exp_q16(ADC_SEM_UA, 6557, -40, 12000000)),
|
||||
"apply uses file k and negative file b");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) != 0u, "VALID from file bitmap");
|
||||
/* 未列键保留默认 */
|
||||
@@ -457,8 +609,8 @@ static void tc_011_file_bad(void) {
|
||||
adc_cal_init();
|
||||
vfs_put("[adc_cal]\r\nk_ua=999\r\nk_ub=-999\r\nvalid=7\r\n");
|
||||
CHECK(cfg_file_load() == 0, "load ok (values structurally valid INT)");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 500), exp_tpafe(500)), "UA sanitized to ROM");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 500), exp_stm32(500)), "UB sanitized to ROM");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 500), exp_eng(500, ADC_SEM_UA)), "UA sanitized to ROM");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UB, 500), exp_eng(500, ADC_SEM_UB)), "UB sanitized to ROM");
|
||||
CHECK(adc_cal_flags(ADC_SEM_UA) == 0u, "UA VALID denied despite bitmap bit (k out of band)");
|
||||
CHECK(adc_cal_flags(ADC_SEM_UB) == ADC_CAL_F_CLIPPED, "UB keeps only CLIPPED");
|
||||
CHECK(g_caltest_err_count >= 2, "both sanitizations logged");
|
||||
@@ -480,7 +632,7 @@ static void tc_012_file_corrupt(void) {
|
||||
big[sizeof(big) - 1u] = '\0';
|
||||
vfs_put(big);
|
||||
CHECK(cfg_file_load() == 0, "load survives corruption");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 4096), exp_tpafe(4096)), "corrupt -> ROM coefficients");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 4096), exp_eng(4096, ADC_SEM_UA)), "corrupt -> ROM coefficients");
|
||||
CHECK(adc_cal_flags(ADC_SEM_UA) == 0u, "corrupt -> no VALID anywhere (DoD wording)");
|
||||
CHECK(s_syslog_count >= 1, "corruption left self-test trail");
|
||||
}
|
||||
@@ -492,10 +644,44 @@ static void tc_013_section_missing(void) {
|
||||
adc_cal_init();
|
||||
vfs_put("; only a comment, no managed sections\n");
|
||||
CHECK(cfg_file_load() == 0, "load ok with unrelated file");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IN, 2048), exp_stm32(2048)), "IN still ROM");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IN, 2048), exp_eng(2048, ADC_SEM_IN)), "IN still ROM");
|
||||
CHECK(adc_cal_flags(ADC_SEM_IA) == 0u, "no VALID with missing sections");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-027:坏文件注入 [adc_cal_sec]——r 越带/为 0 都不折算、VALID 不亮 */
|
||||
static void tc_027_file_ratio_bad(void) {
|
||||
printf("[TC-ADCCAL-027] bad [adc_cal_sec] entries -> pin volts, no VALID\n");
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
/* r_ua=0:该路退回引脚域;位图与 k 都合法,挡不到它——只有变比条件能挡 */
|
||||
vfs_put("[adc_cal]\r\nk_ua=10000000\r\nvalid=1\r\n"
|
||||
"[adc_cal_sec]\r\nr_ua=0\r\n");
|
||||
CHECK(cfg_file_load() == 0, "load ok (r_ua = 0)");
|
||||
CHECK(adc_cal_ratio_q16(ADC_SEM_UA) == 0, "r_ua = 0 read back as 0");
|
||||
CHECK(adc_cal_ratio_configured(ADC_SEM_UA) == 0u, "r_ua = 0 -> not configured");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 500), exp_pin(500, ADC_SEM_UA)),
|
||||
"r_ua = 0 -> apply stays in pin domain");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) == 0u,
|
||||
"r_ua = 0 vetoes VALID even with valid bit + k in band");
|
||||
/* 未列键保留 ROM 变比:坏一路不牵连别路 */
|
||||
CHECK(near_d((double)adc_cal_ratio(ADC_SEM_IA), EXP_R_CURR), "IA ratio still ROM default");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_IA, 500), exp_eng(500, ADC_SEM_IA)),
|
||||
"IA still scales (only UA was zeroed)");
|
||||
|
||||
/* r_ua=1:比值 1/65536 < 1.0,同样不折算 + 不报 VALID */
|
||||
reset_all();
|
||||
adc_cal_init();
|
||||
vfs_put("[adc_cal]\r\nk_ua=10000000\r\nvalid=1\r\n"
|
||||
"[adc_cal_sec]\r\nr_ua=1\r\n");
|
||||
CHECK(cfg_file_load() == 0, "load ok (r_ua = 1)");
|
||||
CHECK(adc_cal_ratio_q16(ADC_SEM_UA) == 0, "sub-1.0 ratio reported as 0 (no third state)");
|
||||
CHECK(adc_cal_ratio_configured(ADC_SEM_UA) == 0u, "sub-1.0 ratio -> not configured");
|
||||
CHECK(near_d(adc_cal_apply(ADC_SEM_UA, 500), exp_pin(500, ADC_SEM_UA)),
|
||||
"sub-1.0 ratio -> apply stays in pin domain");
|
||||
CHECK((adc_cal_flags(ADC_SEM_UA) & ADC_CAL_F_VALID) == 0u, "sub-1.0 ratio vetoes VALID");
|
||||
CHECK(g_caltest_err_count >= 1, "sub-1.0 ratio left its own ERR trace");
|
||||
}
|
||||
|
||||
/* TC-ADCCAL-018:未标定闭锁判定单点(「数据可信」未标定即闭锁 / 道F task-16)
|
||||
* 为什么值得单独钉:这条谓词此前在 App/task/protect_task.c 与
|
||||
* App/app/ui_data_feed.c 各写一份,**没有任何一份被主机测到**(ui_data 套件只编
|
||||
@@ -614,6 +800,10 @@ int main(void) {
|
||||
tc_013_section_missing();
|
||||
tc_018_prot_blocked();
|
||||
tc_019_023_persist_obs();
|
||||
tc_024_ratio_defaults();
|
||||
tc_025_ratio_zero_disables();
|
||||
tc_026_ratio_set_guards();
|
||||
tc_027_file_ratio_bad();
|
||||
|
||||
printf("\n=== ADC Cal Layer Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
|
||||
Reference in New Issue
Block a user