FlexRIO 在轨图像取舍:判决要跑在数据进内存之前

摘要:拍得到和传得回是两回事------下行带宽永远不够。这篇讲判决逻辑为什么必须放进 FPGA、行流水线怎么搭、资源账怎么算,以及三个必踩的坑:跨时钟域、DMA 溢出、位宽截断。


0. 先说结论

在轨图像处理的约束不是算力,是数据一旦进了内存,带宽和时间就已经花掉了。

所以判决必须前移:在像素流还在走的时候,就把"留/丢"决定掉。

行流水线的判决延迟 = 判决涉及的行数 × 行周期。这个数字通常比"存一帧再处理"小两三个数量级------这就是为什么星上筛选基本都做在 FPGA 里。

1. 先把账算出来:为什么必须丢

以一台 4096 × 3072、12 bit 的相机为例,单帧原始数据量:

复制代码
4096 × 3072 × 12 bit / 8 ≈ 18.9 MB

按 10 fps 输出,就是约 189 MB/s。而常见的星地下行链路(S/X 波段)在几十到几百 Mbps 量级,换算下来每秒只能传几 MB 到十几 MB。

也就是说:能传下去的,通常不到能拍到的百分之一。

这个比例决定了系统设计的顺序------先设计"丢什么",再设计"存什么"。反过来做,就会得到一个"能拍很多、传不回去"的系统。

2. 为什么判决必须在 FPGA 上

方案 判决延迟 资源占用 能做的算法
存整帧 → CPU 判 一帧时间 + 搬运时间 大(整帧缓存) 任意复杂
存整帧 → RT 判 一帧时间 中 中等
FPGA 行流水线 几行时间 小(行缓存) 简单但足够

关键认知:丢帧判决本身通常不需要复杂算法。

云覆盖、曝光饱和、星点数量、梯度方差------这些全是逐像素/逐行的局部统计,FPGA 做正合适。而真正复杂的算法(目标识别、场景理解)本来也不该在星上做:星上算力有限、功耗受限、算法更新周期长。

把"简单的判决"放在最前面,把"复杂的处理"放在地面,是这类系统唯一能跑通的架构。

3. 判据怎么设计

四个常用判据可以叠加使用:

判据 计算方式 拦掉什么 FPGA 友好度
饱和度 统计 ≥ 阈值的像素占比 过曝帧 高(逐像素比较)
云覆盖 亮度均值 + 方差 全云/全黑帧 高(滑动累加)
清晰度 梯度绝对值之和 运动模糊、失焦 中(需行缓存)
星点/目标数 局部极大值计数 导航/定位帧优先 低(需二维窗口)

实用的做法是两级串联:

  • 一级粗筛:饱和度 + 云覆盖,一行就能判,不需要缓存。
  • 二级细筛:清晰度,需要 2--3 行缓存,但能拦住"看得见但没用"的模糊帧。

绝大多数废帧在第一级就被拦掉,二级的压力就小了。这个结构的好处是:一级的阈值可以设得很宽松(宁可放过),把精度压力留给二级。

4. 行流水线怎么搭

核心结构只有三段:

复制代码
像素流 → [行统计] → [判决] → [写FIFO / 丢弃]
                     ↑
                阈值(可配置)

三个要点:

(1)统计和判决分开。 统计用流水线累加器,判决用比较器,两者都不阻塞像素流。任何一个环节插入"等待",整条流水线的吞吐就掉了。

(2)判决结果延迟几行生效。 这意味着一帧的开头几行总是先写进缓冲,判完再决定要不要保留。所需缓冲深度 = 判决行数 × 行宽 × 位宽。

(3)丢弃要彻底。 判决为丢,FIFO 直接不写。让数据"先进来再删"等于没省------带宽已经花掉了。

一行统计的伪代码(对应 FPGA 上的并行实现):

复制代码
for each pixel p in line:
    sum   += p
    sumsq += p*p
    sat   += (p >= SAT_THRESH) ? 1 : 0
    grad  += abs(p - p_prev)      // 需 1 像素延迟
after line:
    mean = sum / W
    var  = sumsq / W - mean*mean
    if (sat > SAT_MAX) or (var < VAR_MIN): drop_frame()

两个静默错误的来源:

  • sumsq 的位宽。4352 个 12 bit 像素、每个平方后 24 bit,累加需要 24 + 13 = 37 bit。位宽给少了会溢出,而且溢出后结果看起来"还算正常",最难查。
  • 除法。除以 W 用移位(W 取 2 的幂),不要真的例化一个除法器------既费资源又拖时序。

5. 资源账:先算再写

以中端 Kintex-7 级别 FPGA 为例,资源大头通常是这两项:

行缓存(BRAM):

复制代码
BRAM 位数 = 判决行数 × 行宽 × 位宽
         = 3 × 4096 × 12 bit
         ≈ 147 Kbit
         ≈ 4 块 36Kb BRAM

统计乘法(DSP):逐像素平方是一路 DSP,梯度是减法 + 绝对值(LUT 即可)。流水线并行度决定 DSP 数量,通常一行 2--4 个就够。

资源 用途 估算方法 余量要求
LUT 统计 + 判决 + 接口 综合后看报告 ≥ 30%
DSP 乘法(平方、梯度) 并行度 × 2 ≥ 30%
BRAM 行缓存 + FIFO 行数 × 行宽 × 位宽 ≥ 20%
时钟 像素时钟 / 处理时钟 需跨时钟域 ---

经验:BRAM 经常比算法本身更吃资源。先算行缓存,再谈算法复杂度。

6. 三个必踩的坑

坑一:跨时钟域。

像素时钟来自相机接口,处理时钟来自板载晶振,两者不同源。直接跨域采样会偶发丢像素------频率越低越难复现,因为它依赖两个时钟的相位关系。

必须用异步 FIFO 或握手同步。这条没有捷径。

坑二:DMA FIFO 溢出。

判决放行了太多帧,主机侧读得慢,FIFO 一满就静默丢数据,现象看起来像"相机丢帧"。

处理办法:要么在 FPGA 侧限流(按最坏下行速率放行),要么把 FIFO 的满标志接进判决逻辑------满了就强制丢弃当前帧,并打一个计数器。这个计数器是排错的关键,没有它你永远不知道数据是在哪一级丢的。

坑三:位宽截断。

12 bit 像素做 8 bit 显示/存储时直接取高 8 位,暗部细节全丢;更麻烦的是统计阈值按 12 bit 定,截断之后再比就全错。

位宽必须在链路上全程标注清楚:哪一段是 12 bit 原始、哪一段是 8 bit 显示、统计用的是哪一段。这一条写进设计文档,比写在脑子里强。

7. 边界

FPGA 适合"确定性强、局部性强、延迟敏感"的判断,不适合"需要全局信息、需要迭代"的算法。

判断标准一句话:这个判决能不能只靠当前行 + 前 N 行做出来?

能,就放 FPGA;不能,就老老实实下传,或者先做降采样再判。

把目标识别硬塞进 FPGA,通常换来的是资源爆掉、精度下降、迭代周期以月计------这三个代价,没有一个能在项目后期补回来。

8. 参考资料

  • NI:FlexRIO 与 LabVIEW FPGA 的流水线设计
  • NI:FPGA 跨时钟域与异步 FIFO 的使用
  • CCSDS 图像数据压缩标准(星上数据处理的接口约定)

附:5 分钟自测,先回答这 5 个问题

  1. 判决是在像素流入内存之前做的,还是存完再判?
  2. 判决要几行缓存?BRAM 按"行数 × 行宽 × 位宽"算过吗?
  3. sumsq 的位宽按最坏情况(满像素、满行宽)算过吗?
  4. DMA FIFO 的满标志接进判决逻辑了吗?有丢帧计数器吗?
  5. 统计用的位宽和存储用的位宽,在链路图上看得到吗?

第 3 条和第 4 条是"静默错误":不报错、不崩溃,只是结果悄悄不对,或者数据悄悄少了。


拍得到和传得回是两回事。判决前移省下的带宽,通常比优化压缩算法更直接------而且它对算法精度没有要求。

相关推荐
FPGA小迷弟2 小时前
FPGA 与无线电:从软件定义无线电到 5G 基带的硬件实现之路
5g·fpga开发·架构·dsp开发·fpga·无线电
yingheceping3 小时前
2026 国产 FPGA 核心板怎么选?工控/视觉/通信/科研,四场景对板指南
fpga开发·fpga
LabVIEW开发14 小时前
PHD2000 注射泵通宵实验:LabVIEW 分段排程、堵针检测与断点续跑
串口通信·labview·仪器控制·实验室自动化
LabVIEW开发19 小时前
用 LabVIEW 做故障注入:把起落架的「危险试验」变成可重复流程
串口通信·labview·仪器控制·labview功能·labview程序
FPGA小徐1 天前
FPGA离散数列信源熵:原理、计算与硬件实现全解
fpga
FPGA小徐2 天前
【FPGA数字信号处理】离散信源香农熵计算:原理详解 + 纯Verilog可综合实现 + 全套仿真代码
fpga
LabVIEW开发2 天前
CLAD 例题精讲 2|数值与布尔:三个反直觉的地方
labview
LabVIEW开发3 天前
波音客机降噪验证系统:NI PXI 加 LabVIEW 怎么同时做到可扩展与低成本
labview·labview知识·labview功能·labview程序
LabVIEW开发3 天前
风洞 50 米/秒,LabVIEW 采哪几路信号
自动化测试·数据采集·labview