3. 算法需求分析与接口设计

在工程算法开发中,最昂贵的错误往往不是代码写错,而是算法做对了数学、却做错了需求。需求分析阶段的一个歧义,可能在集成测试时才暴露,届时修改成本已是设计阶段的数十倍。本节聚焦如何把模糊的工程需求,逐步收敛为可编码、可测试、可验收的算法规格与接口契约。

一、从工程需求到算法规格的三层分解

工程需求通常以自然语言描述,例如“雷达在强杂波背景下应能稳定检测低速小目标”。这句话无法直接编码,需要经过三层分解:

  • 功能需求:算法要完成什么——检测目标、估计距离与速度、输出航迹。
  • 性能需求:达到什么指标——检测概率 Pd ≥ 0.9、虚警率 Pfa ≤ 1e-6、距离精度 σ_R ≤ 5 m。
  • 约束需求:在什么条件下——单帧处理时间 ≤ 10 ms、定点实现、内存 ≤ 2 MB。

这三层必须同时明确,否则规格不完整。例如只写“检测概率高”无法验收,只写“处理快”也无法判断是否达标。工程实践中建议用一张需求—规格追溯表,把每条工程需求映射到具体的算法指标、验证方法和验收阈值。

二、输入输出定义:接口的第一道防线

输入输出定义不是简单写“输入是信号、输出是结果”,而要精确到工程可对接的程度。以恒虚警率(CFAR)检测算法为例,其输入输出规格应包含:

项目规格说明
输入数据复数基带采样矩阵,维度 [N_range × N_pulse],double 或 int16
采样率10 MHz,距离分辨率 15 m
参考窗左右各 16 个距离单元,保护单元各 4 个
虚警率Pfa = 1e-6,对应门限因子由参考窗长度计算
输出检测标志矩阵 [N_range × N_pulse],逻辑型;附带估计信噪比
坐标系距离维沿行方向递增,脉冲维沿列方向递增

这里特别强调坐标系与方向约定:距离维是行还是列、索引从 0 还是 1 开始、单位是米还是采样点,必须在接口文档中写死。工程中大量集成故障源于“你以为是列优先,我以为是行优先”。

三、接口契约:比函数签名更重要的约定

接口契约描述调用方与被调方之间的权利与义务,包括:前置条件、后置条件、异常行为、边界处理。例如 CFAR 检测函数的契约可以写成:

前置条件:输入矩阵非空,参考窗长度 < 距离维长度
后置条件:输出检测标志与输入同维度;门限矩阵已内部计算
异常行为:输入含 NaN 时返回全零检测并置错误码 -1
边界处理:距离维两端不足参考窗时,采用单侧参考窗或补零

契约的价值在于:调用方知道“我该保证什么”,被调方知道“我必须交付什么”。当契约被违反时,责任边界清晰,排障效率大幅提升。

四、可测试性设计:让验证成为设计的一部分

可测试性不是测试阶段才考虑的事,而是设计阶段就要植入的属性。具体做法包括:

  • 可观测性:算法内部关键中间量(如噪声功率估计、门限值)应可输出,便于定位问题。
  • 可注入性:支持注入已知测试信号,例如人工构造的单目标回波,用于验证检测逻辑。
  • 确定性:相同输入必须产生相同输出,避免随机初始化或未定义行为。
  • 可分解性:算法拆分为可独立测试的子函数,如噪声估计、门限计算、比较判决。
建议为每个算法模块建立“最小可测单元”,即一个不依赖外部系统、可用固定输入复现的测试入口。这样在集成前就能完成大部分逻辑验证。

五、需求到接口的映射关系

下图展示了从工程需求出发,经过规格分解、输入输出定义、接口契约,最终落到可测试性设计的完整映射链路。图中同时标注了每层的关键交付物与验证手段,便于在实际项目中对照检查。

工程需求层 “强杂波下稳定检测低速小目标” → 功能需求 + 性能需求 + 约束需求 交付物:需求规格说明书、需求—指标追溯表 分解与量化 算法规格层 Pd ≥ 0.9,Pfa ≤ 1e-6,σ_R ≤ 5 m,单帧 ≤ 10 ms,定点实现 交付物:算法指标规格书、验收阈值定义 接口化 输入输出定义层 输入:[N_range × N_pulse] 复数矩阵,采样率 10 MHz,参考窗 16+4 输出:检测标志矩阵 + 估计信噪比;坐标系与方向约定明确 契约化 接口契约层 前置条件:输入非空、参考窗长度合法;后置条件:输出同维度 异常行为:NaN 输入返回全零 + 错误码;边界:单侧参考窗或补零 可测试性设计 • 可观测性 • 可注入性 • 确定性 • 可分解性 最小可测单元 固定输入复现 中间量输出 子函数独立测试 验证手段:单元测试 → 注入测试 → 边界测试 → 集成测试 → 指标验收

六、实操示例:CFAR 检测算法的接口规格片段

以下给出一个可直接参考的接口规格片段,用于说明如何把上述方法落到具体算法上。示例参数为教学假设,实际项目需根据雷达参数重新计算。

函数名:cfar_detect
输入:
  data      — [N_range × N_pulse] 复数矩阵,单位:归一化幅度
  guard_cell — 保护单元数,默认 4
  ref_cell   — 参考单元数,默认 16
  pfa        — 虚警率,默认 1e-6
输出:
  det_flag   — [N_range × N_pulse] 逻辑矩阵,true 表示检测到目标
  threshold  — [N_range × N_pulse] 门限矩阵,便于观测
  snr_est    — [N_range × N_pulse] 估计信噪比,单位 dB

契约:
  前置:N_range > 2*(guard_cell + ref_cell)
  后置:det_flag 与 data 同维度;threshold 已按 pfa 计算
  异常:data 含 NaN/Inf 时返回全 false,并记录错误码
  边界:距离维首尾不足参考窗时,采用单侧参考窗

注意这里把 threshold 和 snr_est 作为输出,而不是内部隐藏变量。这是可观测性设计的直接体现:当检测结果异常时,工程师可以立即查看门限是否合理、信噪比估计是否偏离预期,而不需要重新插桩或修改代码。

常见误区:把接口契约写成“函数说明”。契约的核心是可验证的承诺,每一条都应能对应一个测试用例。如果一条契约无法被测试,它就不是契约,只是注释。

七、可测试性检查清单

在设计评审时,可用以下清单快速检查算法接口是否具备可测试性:

检查项合格标准
输入边界是否明确空输入、单点输入、极值输入均有定义行为
输出是否可观测关键中间量可作为可选输出返回
是否支持注入测试可用已知信号验证检测/估计逻辑
是否确定性相同输入多次运行结果一致
是否可分解核心子步骤可独立调用与测试
异常是否可区分不同错误返回不同错误码,而非统一报错

需求分析与接口设计是算法工程化的起点。把工程需求翻译成可量化的算法规格,把算法规格固化为精确的输入输出定义,再用接口契约约束调用关系,最后以可测试性设计保证验证可行——这条链路走通,后续的编码、集成与验收才有稳固基础。