拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于ZYNQ的多通道船舶噪声采集与边缘AI系统设计

海试回来的那天晚上我坐在项目部的工位上把板子重新连上电源盯着串口里刷出来的“capture started, 16 channels, sync ok”愣了好一会儿。这套基于 ZYNQ 的船舶噪声采集系统从立项到最终跑通前前后后折腾了大半年中间推翻过一版纯 FPGA 方案也差点走回“FPGA 采数 工控机处理”的老路。最后定型的架构是 ARM FPGA 异构 SoC 做采集与边缘 AI 分析也就是 Xilinx ZYNQ 系列一肩挑。借着这篇东西我把整个系统的拆解思路、关键实现细节和调试过程中踩过的坑一次说清楚给正在做多通道采集、水下噪声测量或者边缘 AI 落地的朋友做个参考尤其是那些在 ZYNQ、ARM、FPGA 三块之间反复横跳的人。这套系统要解决的事情其实很直白多通道同步采集船舶水下辐射噪声数据要实时做预处理还要在设备端直接跑 AI 分析不依赖船上或者岸基的大型服务器。所谓高精度、高实时落在硬件上就是 ADC 位宽和采样率、通道间相位一致性、数据处理链路的延迟这三个硬指标。而边缘 AI 分析落到工程上就是模型选型、部署框架和处理器算力之间的平衡问题。下面我会从系统需求拆解开始一直讲到 FPGA 侧信号处理、ARM 侧 Linux 启动、AI 模型部署和最终的调试实录尽量还原当时做决策和排障的过程。1. 为什么船舶噪声采集最终落在 ZYNQ 这类平台上1.1 先把“高精度、高实时、多通道、边缘AI”翻译成硬件需求我们在项目初期拿到指标要求大概是 16 通道同步采集频率范围覆盖几十赫兹到十几千赫兹动态范围尽量高现场要能实时输出频谱特征还要用训练好的模型对噪声事件做分类识别。这几个要求单独看都不算夸张但放在同一个设备里就麻烦。先算一下采集这关。如果每通道采样率做到 128 kSPS、24 bit 精度16 通道加起来就是约 128 kSPS × 3 字节 × 16 通道 6.144 MB/s这个数据量对于存储和传输来说不大。但如果你想把采样率拉到 2.048 MSPS 去覆盖更高频的声呐信号即便用 16 bit数据率也到了 16 × 2.048 M × 2 字节 65.536 MB/s。这个速率已经不是普通串口或者 USB 能轻松扛住的了至少得上千兆网或者高速 DMA。再说“高实时”。船舶噪声分析里频谱刷新率通常希望做到每秒几十帧甚至上百帧这意味着 FFT 和特征提取要么在采集端完成要么在数据到达后几个毫秒内完成。如果走“FPGA 采数USB 传到上位机上位机做 FFT 和推理”的路线单是 USB 传输和协议栈开销就会吃掉一大截实时性而且整套系统的体积、功耗、可靠性都可能出问题。至于边缘 AI情况更麻烦。船上的环境摆在那里整机功耗和体积都有上限你不可能塞一块 GPU 进去。常见的轻量级卷积神经网络模型比如 MobileNetV2、TinyML 类的定制网络在 ARM Cortex-A53 这种级别处理器上跑一帧大概需要几十到一百多毫秒而在 FPGA 上跑 DPU 推理则可以做到几毫秒到十几毫秒。问题是谁来做采集、谁来做预处理、谁来做推理这中间的数据通路怎么设计决定了最终系统的实时性上限。1.2 纯FPGA方案、纯ARM方案各自卡在哪里我最早的想法其实很简单既然 FPGA 做并行采集和信号处理这么强那就用一片大 FPGA 把采集、FFT、AI 全包了。这个方案在理论上成立但实际做起来有几个很现实的问题。首先FPGA 上部署 AI 的生态远没有 ARM 侧成熟。虽然可以用 Vitis AI 的 DPU 在 PL 侧跑 CNN但 DPU 要占用不少 LUT 和 DSP你同时还得留资源给 16 通道的抽取滤波和 FFT资源分配会非常紧张。以 ZYNQ-7020 为例它总共只有 53200 个 LUT、220 个 DSP跑一个小型 DPU 加采集逻辑很吃力。其次设备需要对外通信、文件管理、远程升级、参数配置这些功能在 FPGA 里用状态机写一遍开发周期会成倍拉长而且远不如在 Linux 里方便。纯 ARM 方案就更不用说了。用一颗高性能 ARM 处理器或者开发板做采集和 AI 分析表面上看逻辑简单但多通道 ADC 的同步采样时钟、高速数据搬运这些活让 ARM 直接做是既不稳定也不高效。尤其当 ADC 输出是 LVDS 或者 JESD204B 这类高速串行接口时ARM 自带的接口根本接不进来必须加一片 FPGA 在前面做接口转换和缓冲。既然 FPGA 已经在了那这套系统的核心矛盾就不是“要不要 FPGA”而是“FPGA 和 ARM 之间怎么分工”。1.3 ZYNQ平台的结构优势与选型建议ZYNQ 这个平台的好处在于它把 ARM 和 FPGA 放进了同一颗芯片里两者通过片上的 AXI 总线互联而不是靠外部的 PCIe 或者并口。这样一来FPGA 侧采集和预处理完的数据可以直接通过高性能 AXI 接口搬进 DDRARM 侧的应用不用关心底层传输协议把数据当成普通内存来读就行。ZYNQ UltraScale MPSOC 这个系列更是把这种异构优势发挥到了极致它有四核 Cortex-A53还带了 GPU 和视频编解码单元PL 侧也有足够的逻辑资源去跑中等规模的信号处理链路。我们的选型逻辑是这样的如果只做 16 通道、128 kSPS、24 bit 的噪声采集ZYNQ-7010/7020 这种入门级器件已经够用成本也能压下来。但如果你需要跑 JESD204B 接口的高速 ADC比如 250 MSPS 以上的采样率或者要做比较重的边缘 AI 推理建议直接上 ZYNQ UltraScale 系列的 ZU7EV 或者 ZU9EG因为这类器件带有 GTH 高速收发器资源也更充裕。我们当时的方案因为要兼顾后期扩展到高频声呐采集最后选了 ZU7EV。提示不要把“ZYNQ 能跑 Linux”和“ZYNQ 能跑 AI”混为一谈。PS 侧 Cortex-A53 跑 Linux 处理业务逻辑很轻松但真正的低延迟信号处理和高速接口还是要靠 PL。选型时先盘点你的接口类型、数据率、AI 模型复杂度再决定器件的档位。2. 多通道采集前端的工程细节ADC、同步时钟与模拟链路2.1 按测量目标定ADC24bit/128kSPS和16bit/2.048MSPS两种典型配置多通道采集系统的第一关是 ADC 本身。船舶噪声测量按频段和用途不同ADC 配置差异很大。低频段的水下辐射噪声测量关注点在 10 Hz 到 10 kHz 附近动态范围要求高一般选用 24 bit、128 kSPS 的同步采样 ADC比如 ADS1278 这种 8 通道 24 bit 器件两片就能拼出 16 通道。这个配置的优点是位宽大、动态范围轻松做到 100 dB 以上缺点是单通道采样率受限不适合分析中高频信号。如果是用来采集声呐波形或者需要分析到几十千赫兹以上那就要上 16 bit、2 MSPS 以上、带 LVDS 或 JESD204B 接口的高速 ADC。比如 AD9652 这类双通道 16 bit ADC或者 AD9250 这类带 JESD204B 输出的器件。16 bit 听起来不如 24 bit“精度高”但在高频段这不是关键瓶颈因为背景噪声本身就比低频大得多16 bit 的动态范围已经够用而采样率和通道间同步能力反而更重要。所以“高精度”不是指位宽越高越好而是要跟测量对象的频谱特性和动态范围匹配。我当时在设计时把两种配置都留了接口PL 侧用了一个可配置的采集接口模块既能接 8 通道的 LVDS 并行 ADC也能接 JESD204B 串行 ADC这样后期换 ADC 板卡不用动主控逻辑。2.2 多通道相位一致性从时钟同步开始多通道噪声采集系统最容易被忽略、也最致命的问题是通道间的相位一致性。船舶噪声测向、波束形成这些应用对通道间相位差的要求通常在 0.1° 到 1° 之间。按 1° 相位差换算到时间上在 10 kHz 信号上是 0.28 μs在 100 kHz 信号上是 27.8 ns。也就是说系统里所有通道的采样时刻必须精确对齐误差不能超过几十纳秒。实现通道间同步的关键是所有 ADC 共用一个采样时钟而且这个时钟到达每个 ADC 的延时要尽量一致。工程上常用 LMK04828 这种时钟芯片来产生 ADC 采样时钟和 SYSREF。LMK04828 的优势在于它可以同时输出多路低抖动时钟并且各路时钟之间有明确的相位关系SYSREF 信号可以配合 JESD204B 做确定性延迟。我们在系统里用了一片 LMK04828由它给所有 ADC 提供采样时钟和 SYSREFFPGA 侧只负责对 SYSREF 做对齐检测不直接参与时钟产生。如果用的是并行 LVDS 接口 ADC没有 SYSREF 这个概念这时要保证多片 ADC 的采样时钟到各个芯片的走线等长并且在 FPGA 内部用同一位对齐逻辑来处理每路数据。我们当时在第一版 PCB 上就因为 ADC 时钟走线到两片 ADS1278 的长度不一致导致通道间相位差了大约 3°后来在 PCB 改版时做了等长处理相位差才降到 0.2° 以内。2.3 模拟增益与动态范围的取舍ADC 前端还要处理模拟增益的问题。船舶噪声的动态范围很大远处一艘商船和近处一艘大型邮轮接收到的声压级可能差几十分贝。如果模拟链路增益固定很可能会出现小信号被淹没、大信号直接削顶的情况。常见做法是前级加低噪声放大器后级用可编程增益放大器由系统根据输入电平自动调整增益或者使用多档固定增益手动切换。这里有个容易踩的坑PGA 的增益档位切换会引入瞬态噪声而且不同增益档位下通道间的相位一致性可能会有微小变化。我们当时在做增益自动切换时发现切换到某些档位后通道间相位偏差会突然变大排查了半天发现是 PGA 的建立时间不够导致数据采集窗口落在了切换瞬态上。后来我们把增益切换和采样启停逻辑做了一次联动切换增益后先等 PGA 稳定再开始采集这个问题就解决了。在指标要求特别严格的系统里也可以考虑用两路不同增益的 ADC 并行采同一路信号高增益管小信号低增益管大信号但这会成倍增加成本和布局面积一般场景没必要。3. FPGA侧信号处理LVDS接收、CIC抽取和FIR补偿的实战参数3.1 LVDS高速数据接收先过对齐这一关不管 ADC 是 24 bit 慢速还是 16 bit 高速只要它是并行 LVDS 接口FPGA 侧首先要解决的就是 LVDS 接收与位对齐。这个话题看着基础但真到了 16 通道同时跑的时候麻烦事一大堆。并行 LVDS ADC 一般把每个采样点的多位数据拆分到多根 LVDS 差分对上同时给出一根数据同步时钟。FPGA 内部要用 IBUFDS、IDELAYE2、ISERDESE2 这些原语把串行数据解出来。最关键的是 IDELAY 的调节因为芯片到 FPGA 之间的走线长度差异、温度漂移都会导致数据与时钟的相位关系变化所以一般会在 ADC 和 FPGA 之间约定一个训练序列FPGA 收到训练序列后通过调整 IDELAY 的 tap 值让采样点落在数据眼图的中间。我们当时用的是 ADS1278它的 LVDS 工作在 DDR 模式数据率不算高但多片芯片合在一起每片芯片的温度特性还不完全一样IDELAY 的 tap 值如果设成固定的偶尔会出现某一通道在高温下误码。后来我在逻辑里加了一个简单的监测模块周期性检查训练序列的检错结果一旦发现错误就自动把 IDELAY 调到眼图中心。这个机制说起来不难但很管用。如果是 JESD204B 接口的 ADCLVDS 那套做法就不适用了得走 GT 高速收发器。这时候建议先拿 Xilinx 的 IBERT 核把板级通道的眼图和误码率测一遍确认硬件没问题再去调 JESD204B 的链路层。很多 JESD204B 问题根子其实出在 PCB 走线或者参考时钟质量上这时候去翻链路寄存器是徒劳的。3.2 CICFIR抽取链路设计一个拿过来就能用的参数方案多通道噪声采集里ADC 的采样率常常远高于最终分析需要的速率。比如我们用 128 kSPS 采集但频谱分析只关心到 10 kHz那 128 kSPS 其实已经够不需要抽取但如果用 2.048 MSPS 采集而分析带宽只有 10 kHz那就必须做 64 倍抽取否则数据量白白多出 64 倍后面无论是存储还是 AI 推理都受不了。抽取最常用的就是 CIC 滤波器加 FIR 补偿滤波器。CIC 的好处是它不需要乘法器只用加法器和延迟器就能实现特别适合在 FPGA 里做高抽取比的第一级。我当时给系统里搭的抽取链路参数是这样的输入 2.048 MSPS目标 32 kSPS抽取因子 D64CIC 阶数 N5微分延迟 M1。CIC 的传递函数是 H(z) ((1 − z^(−D×M)) / (1 − z^(−1)))^N这个参数下通带内会有约几 dB 的跌落所以后面必须接一个 FIR 补偿滤波器把通带拉平同时做最后的抗混叠。FIR 补偿滤波器我们用了 64 阶通带 10 Hz 到 15 kHz带外抑制做到 60 dB 以上。注意 FIR 的系数要用定点化表示否则在 FPGA 里实现时资源消耗会高很多。16 通道并行处理时每一路都需要独立的 CIC 和 FIR 实例但 FIR 的系数是共享的。整个 16 通道的抽取滤波链路在 ZU7EV 上只占了大约 12% 的 LUT 和 6% 的 DSP非常宽裕。提示抽取滤波器一定要按“先抽取后低通”还是“先低通后抽取”想清楚。正确的做法是先抗混叠滤波再抽取。CIC 本身是抗混叠滤波器和抽取器的组合所以先过 CIC 是对的。但 FIR 补偿滤波器放在 CIC 之后、抽取已经完成的位置这个顺序不要搞错否则混叠会直接进到你后面的频谱数据里。3.3 多通道并行实现的资源估算多通道并行处理资源估算一定要提前做。以 16 通道、2.048 MSPS 的 ADC 输入为例数据到达 FPGA 后先是一级 LVDS 解串然后每通道单独走 CIC → FIR → FIFO 的链路。CIC 因为是纯加法器结构资源跟位宽和数据率直接相关5 级 CIC、单通道大概几百个 LUT16 通道合计在 5000 到 8000 LUT 左右。FIR 如果用对称系数可以把乘法器复用64 阶 FIR 每个通道大约需要 32 到 64 个 DSP 或者转成 LUT 乘法看时序约束情况。在资源分配上我的建议是给数据通路多留余量至少留出 30% 的 LUT 和 50% 的 DSP 给后期功能扩展。因为 FPGA 开发后期你大概率会加进 FFT、峰值检测、AI 预处理这些模块到时候再改资源规划就来不及了。我们当初最开始用的是 ZYNQ-7020后来因为扩展了 AI 功能和更多通道才换成 ZU7EV这个教训就是选型时资源估算一定要保守。3.4 FPGA内是否做FFT/特征提取边界划分思路数据经过抽取之后接下来就是“哪些在 FPGA 里做哪些扔给 ARM 做”的划分问题。很多人习惯把 FFT 也直接在 FPGA 里做觉得这样最实时。但 FFT 是个资源大户64K 点的 FFT 在 FPGA 里要占不少 BRAM 和 DSP而且 ARM 侧用 SIMD 优化过的 FFT 库速度也不慢尤其是数据率已经降到 32 kSPS 之后每通道每秒只需要做约 30 帧 1024 点 FFT这个负载对四核 A53 来说非常轻松。我们最后的分工是这样的FPGA 只做采集、抽取滤波、时域特征粗提取比如 RMS、峰值、过零率以及给 AI 模块的前置归一化ARM 侧负责做 FFT、存储、网络接口和 AI 推理。这样 PL 侧逻辑可以保持简洁时序收敛也容易PS 侧有 Linux 生态调试和扩展都方便。如果你非要所有信号处理都在 FPGA 里做那就要有一个非常强的理由比如对延迟的要求到了微秒级否则完全没必要。4. ARM侧Linux、交叉编译和启动加载里的硬核问题4.1 交叉编译工具链与文件系统FPGA 侧搞定了ARM 侧要跑 Linux这里面的问题同样不少。ZYNQ 的 PS 侧一般跑 PetaLinux 或者主线内核。PetaLinux 的好处是跟 Vivado 的硬件配置深度绑定不需要手改太多东西。但 PetaLinux 的定制性和编译速度都不太理想所以我更喜欢直接用 Xilinx 提供的工具链做交叉编译配合主线内核的设备树自己配。交叉编译工具链建议直接用 Linaro 的 GCC比如 gcc-linaro-7.5.0 或者更新的 aarch64 工具链。注意如果你还在折腾 ARM Compiler 5 或者 DS-5除非是老项目维护否则真没必要。ARM 官方后来推的 armclangARM Compiler 6和 Linaro GCC 都成熟很多可直接用。根文件系统这块最简单的做法是直接交叉编译一个 BusyBox再把必要的运行库和板级应用打进去做一个极简的根文件系统。BusyBox 编译本身不复杂关键是内核配置、设备树、文件系统三者要配套。我们当时踩过坑文件系统用 initramfs 方式打进内核时因为内核里 ramdisk 的压缩格式没配好启动时一直找不到根文件系统。后来改用 SD 卡 ext4 根文件系统u-boot 里用 bootargs 指定 root/dev/mmcblk0p2这些问题就少多了。4.2 设备树EMIO、SPI、中断和DMA的配置要点设备树是 ZYNQ 上 Linux 开发绕不开的一关。ZYNQ-7000 系列 PS 侧带了 54 个 MIO作为 GPIO、UART、SPI、SDIO 等功能引脚。但如果你需要更多 GPIO或者要用 PL 引脚做低速控制信号那就得用 EMIO。EMIO 的配置方法在 Vivado 的 PS-PL Configuration 里使能 GPIO把 MIO 之外的引脚通过 EMIO 引到 PL 侧然后给这些引脚分配管脚约束。设备树里 GPIO 驱动会自动给 EMIO 分配编号从 54 号开始。所以你在 Linux 里访问的第一个 EMIO 引脚可能是 gpio 54而不是 gpio 0。当时我们把几路继电器的控制信号做在了 EMIO 上调试时怎么找都找不到对应的 gpio后来查了 ZYNQ 的 GPIO 控制器驱动才意识到是编号偏移的问题。SPI 设备树的配置相对直接注意 SPI 总线的中断要在设备树里绑定好否则使用 SPI 传输时容易丢中断。我们当时采样的 ADC 有一部分是通过 SPI 配置寄存器的配置完用示波器量数据发现怎么都不对排查了半天发现是设备树里 SPI 的最大传输频率没设对寄存器写进去跑飞了。把 spi-max-frequency 调低一点之后问题解决。DMA 部分如果你要在 Linux 用户态直接访问 PL 到 PS 的数据流建议用 UIO 或者 DMA-BUF 框架把 PL 侧 DMA 引擎直接暴露给用户态通过 mmap 读取数据缓冲区。常见的 Xilinx AXI DMA IP 在 Linux 下有现成驱动但要注意缓冲区对齐和描述符的分配问题。我们当时用的是自己写的一个简单 UIO 驱动把 AXI DMA 的 MM2S 和 S2MM 通道映射出来用户态用 mmap 和轮询来处理数据完成中断。相比 VDMA 那种专门为视频流设计的 IPAXI DMA 在自定义数据采集场景下更灵活。4.3 不带DDR的ZYNQ用OCM运行的场景和方法很多人不知道 ZYNQ 可以不带 DDR 运行当磁盘空间和成本特别敏感时这会是一个不错的方案。ZYNQ 的 OCM片上内存只有 256 KB虽然小但配合 PL 侧的 BRAM也能做一些轻量级的采集任务。具体做法是在 Vivado 里把 PS 配置为 QSPI 启动把 FSBLFirst Stage Boot Loader和裸机应用编译好后由 FSBL 在启动时把裸机应用加载到 OCM 地址然后跳转执行。这里要特别注意 OCM 只有 256 KB所以应用代码和堆栈必须精简中断服务程序也别写得太大。另一个麻烦是 DDR 不存在时FSBL 要跳过 DDR 初始化否则会在初始化阶段卡死。我们当时用这个思路做了一个 4 通道、128 kSPS 的简陋采集节点PL 端把采集数据写到 BRAMPS 端裸机程序从 BRAM 读取数据并打包成以太网帧通过 PS 的 GEM 发送出去。整个系统功耗很低成本也压得下来。不过这个方案只适合功能极其简单的场景如果你要跑 Linux、跑 AI那还是老老实实配上 DDR不要折腾 OCM。4.4 数据从PL到PSDMA通道与共享内存设计数据从 PL 搬到 PS 的 DDR最常用的路径是 AXI DMA。PL 侧的信号处理模块把数据写进 AXI Stream 接口AXI DMA 把它搬到 PS 的 DDR 缓冲区然后向 PS 发起中断。PS 侧应用收到中断后通过 mmap 方式读取这些缓冲区做后续的 FFT 和 AI 推理。设计时要注意环形缓冲区的深度。比如 16 通道、每通道 32 kSPS、24 bit 格式总数据率约 1.536 MB/s。如果你希望应用有 100 ms 的处理时间余量那 DMA 缓冲区至少得设到 512 KB 左右。缓冲区设太浅会频繁丢中断设太深又会增加内存占用和延迟。我们最后用的是 8 MB 的环形缓冲区分成 64 个 block每个 block 128 KBDMA 写完一个 block 产生一次中断应用侧每次处理一个 block这样中断频率和数据延迟都比较均衡。如果你需要 PS 和 PL 之间的低延迟数据交换还可以考虑用 ZYNQ 的 AMP非对称多处理模式一个核跑 Linux另一个核跑裸机程序两者通过共享内存通信。这种模式适合对实时性要求极高的控制回路但共享内存的读写同步机制比如用硬件 mail box 或者自旋锁要设计好否则 CPU 之间互相踩数据是家常便饭。5. 边缘AI分析落地模型选择、部署框架和实测开销5.1 入门先跑一个手写数字识别理解ZYNQ上的AI部署流程这个项目之前团队里有人对“ZYNQ 跑 AI”的理解就是“在 Linux 里装个 PyTorch 然后 import 模型”。真到了 ZYNQ 上你会发现完全不是这么回事。最好从最简单的例子开始比如用 ZYNQ 实现 CNN 手写数字识别把整条链路先跑通。流程是先用 TensorFlow 或者 PyTorch 训练一个简单的 CNN 模型然后做量化或转成 ONNX再通过 Vitis AI 的量化器转成 DPU 能跑的模型最后编译成 .xmodel 在 ZYNQ 上部署。这个例子虽然小但能把训练环境、量化工具、交叉编译、运行时 API 这全套流程摸清楚。等这套流程熟了再换到船舶噪声识别模型剩下的就是数据准备和模型调参的问题。实际上Vitis AI 现在对 MobileNet、ResNet 这些常见 CNN 结构的支持已经很好量化后精度损失一般能控制在 1% 以内。我们的噪声事件分类模型最开始是一个在 PC 上训练好的简化版 ResNet用 Vitis AI 量化成 INT8 之后在 DPU 上运行精度损失大概 0.3% 左右完全可接受。5.2 模型部署的三条路线DPU、量化推理和Neon手工优化ZYNQ 上部署 AI 模型按算力需求和开发成本大致有三条路。第一条路线是用 Vitis AI DPU在 PL 侧跑加速器。DPU 是一个可以配置的 CNN 推理引擎典型配置下能跑卷积、池化、全连接这些算子吞吐量远高于 ARM 侧。代价是要占用 PL 资源和额外的 DDR 带宽而且 DPU 版本和 Vitis AI 工具的版本绑定比较死升级工具链时经常要同步升级 DPU 核。在 ZU7EV 上配一个 B4096 的 DPU跑 MobileNetV2 的 INT8 模型帧率能做到几十到上百 FPS具体取决于输入分辨率和批大小。第二条路线是在 ARM 侧用 TensorFlow Lite 或者 ONNX Runtime 做量化推理模型用 INT8 或者 FP16 量化。这条路线开发最省事跟平时在 PC 上写推理代码几乎一样缺点就是 A53 的算力有限复杂模型延迟会偏高。我们实测一个 MobileNetV2 量化模型在四核 A53 上跑一帧 224×224 输入大约需要 60 到 120 ms对于实时的噪声分类场景来说刚好够用但再复杂一点的模型就吃力了。第三条路线是直接用 ARM NEON 指令手工优化关键算子。这是我们最后在某个细分场景下采用的方案因为噪声识别模型的核心不是 CNN 而是几个特定的谱特征算子用 NEON 写好之后速度比直接跑通用推理框架快好几倍。但这条路线的开发和调试成本非常高而且可移植性差只建议在模型结构非常固定、长期不变化的情况下使用。5.3 把预处理做在FPGA里给AI省算力噪声数据的 AI 分析跟图像识别不一样输入通常不是原始波形而是频谱特征。如果直接在 ARM 上对 16 通道原始波形做 FFT、计算谱特征那算力开销会占用大量 A53 资源。更合理的做法是把归一化、加窗、FFT、谱特征计算这些固定算法尽可能往 FPGA 侧移ARM 侧只拿到浓缩后的特征向量。我们当时在 PL 侧加了一个特征提取模块对 32 kSPS 的每通道数据做 1024 点 FFT计算出 64 个频段的能量特征然后每 100 ms 打包一次通过 DMA 送给 ARM。这样 ARM 侧拿到的数据率从每通道 32 kSPS 降到了每通道 640 个特征值每秒16 通道加起来也才 10 k 特征值每秒。AI 推理就只需要处理一个非常小的特征矩阵整帧延迟低了很多模型也可以做得更小。这个设计思路其实可以推广边缘 AI 系统里AI 模型要处理的是“信息”不是“数据”。把所有跟信号处理相关的、算法固定的活儿放到 FPGA 或 DSP 里做ARM 只做智能决策这种架构是 ZYNQ 这类异构平台最合理的用法。5.4 一组实测推理开销数据上面说了这么多给一组我们实测的数据供参考。平台是 ZU7EVDDR4 2400 MT/sPS 侧四核 A53 跑 1.2 GHzPL 侧有一个 B4096 配置的 DPU。测试模型有两个一个是简易 CNN输入 64×64 的频域特征图另一个是 MobileNetV2输入 224×224 的“谱图”形式数据。模型部署方式单帧推理耗时备注简易CNN (INT8)Vitis AI DPU约 5~8 ms特征输入延迟低简易CNN (INT8)ARM TFLite约 20~30 ms单核推理MobileNetV2 (INT8)Vitis AI DPU约 15~25 ms图像级输入MobileNetV2 (INT8)ARM TFLite 4线程约 60~120 ms四核并行这组数据说明两点一是 DPU 的加速效果非常明显尤其对 CNN 这类算子二是如果你的系统里 AI 只是做一个辅助判断ARM 侧 TFLite 也够用没必要为了数字好看多花资源上 DPU。真正决定部署方案的是系统对端到端延迟和功耗的要求而不是单点算力。6. 调试实录JESD204B、DDR降速与EMIO的踩坑复盘6.1 JESD204B链路建立失败的排查顺序JESD204B 的调试是这次项目里最折磨人的一段。刚开始接上高速 ADC链路状态寄存器一直显示没同步抓波形一看复位信号和数据 lane 上根本没有有效数据。我当时的排查顺序现在复盘下来是值得分享的。第一步先确认物理层用 IBERT 核测高速收发器通道。注意 JESD204B 的 GT 参考时钟频率一定要跟 ADC 的 Lane rate 匹配比如 250 MSPS、2 字节、2 lane 的配置Lane rate 是 5 GbpsGT 参考时钟如果是 125 MHz那 QPLL 的配置就要按这个频率来。IBERT 测完通道眼图正常之后再往下查链路层。第二步查 JESD204B 的链路配置参数。L、F、K 这些参数在 ADC 和 FPGA 两端必须一致任何一个不匹配都会导致同步失败。很多问题出在 K 值上K 是每帧包含的字节数两端容易写串。第三步查 SYSREF。SYSREF 必须对齐到确定性延迟如果 LMK04828 输出的 SYSREF 相位不对接收端虽然能完成多 lane 对齐但每次上电的延迟都会变表现为“时好时坏”。第二步和第三步的问题我们当时反复横跳了很久最终通过把 LMK04828 的配置、ADC 的寄存器打印、FPGA 的 JESD204B IP 的调试端口状态一起拉出来对照才定位到是 SYSREF 的类型没配对。LMK04828 输出的 SYSREF 要跟 JESD204B IP 里设置的 “SYSREF Type” 匹配比如 Periodic 还是 One-shot不匹配就会导致链路建链不稳定。提示如果你的 JESD204B 链路时而同步时而不同步先不要急着改代码。用逻辑分析仪抓一次完整的“上电 → 配置 → SYNC~请求 → 对齐”过程看 SYSREF 和 SYNC 信号的时序关系。大多数链路不稳定问题根子都在时序关系上而不是寄存器值本身。6.2 PS端DDR4降速配置的根因与做法ZYNQ UltraScale MPSOC 的 PS 端 DDR4 控制器默认速率往往设置得很高比如 2400 MT/s 甚至更高。但在实际板卡上如果 PCB 走线没有按那么高的速率做好或者 DDR4 颗粒本身不是高速等级启动时就会不稳定现象包括u-boot 阶段直接挂掉、Linux 启动过程中随机 kernel panic、长时间运行后内存数据错误。我们当时遇到的问题是板子在跑 AI 推理时偶尔会报 page fault一开始以为是驱动写崩了内存查了好久。后来用 memtester 对 DDR 做压力测试跑几个小时就报错。排查方向转到 DDR 信号完整性用示波器看 DQS/DQ 波形发现眼图余量很小。跟硬件工程师商量后决定把 DDR4 频率从 2400 MT/s 降到 2133 MT/s在 PS 配置器的 DDR 选项里直接改掉重新生成 FSBL 和 Vivado 工程问题解决。DDR 降速不是一个丢人的事情工程上是很常见的妥协。关键是你要知道在哪里改在 Zynq UltraScale MPSoC IP 配置器中DDR4 的 Speed Bin 选项可以选择不同的速率等级比如 DDR4_2400P、DDR4_2133P、DDR4_1866P 等。改完重新生成硬件描述、FSBL 和设备树整体重新编译烧写即可。注意 u-boot 里也可能有单独的 DDR 初始化逻辑要确保 FSBL 里的 DDR 配置和 u-boot 一致。6.3 EMIO配置方法以及中断怎么接EMIO 的问题前面设备树部分提到过这里再说细一点。ZYNQ-7000 和 MPSOC 都支持把 PS 的 GPIO 扩展到 PL 引脚PC 上叫 EMIO。在 Vivado 的 PS-PL Configuration 页面使能 GPIO可以设定 MIO 之外再引出多少位 EMIO。Xilinx 的 GPIO IP 会自动把 EMIO 的索引接在 MIO 之后也就是说如果你使能了 8 位 EMIO那它们在 Linux 里对应的 GPIO 号通常是 54 到 61ZYNQ-7000 的 MIO 是 0 到 53。配置 EMIO 时有个容易被忽略的点EMIO 引脚在 PL 侧它的电气属性IO Standard、驱动强度、上下拉是在 XDC 约束文件里配置的而不是在 PS 的 MIO 配置里。也就是说你必须在 Vivado 里把 EMIO 信号引到顶层然后像约束普通 PL 引脚一样写物理引脚约束。如果漏了这一步轻则引脚悬空重则触发电平不确定。另外EMIO 的中断在设备树里不需要单独写因为 PS 的 GPIO 控制器中断是统一的驱动内部会处理 MIO 和 EMIO 的中断映射。但要注意 EMIO 引脚连接到 PL 逻辑时如果产生毛刺容易造成误中断。我当时在 EMIO 接了一个外部按钮按键抖动没消干净Linux 里每次按下会触发好几次中断后来在 PL 侧加了一个简单的消抖模块问题解决。6.4 多通道相位标定采集系统最重要的一个步骤系统最终验收时通道间相位一致性是必须给的硬指标。标定方法不复杂但一定要做而且最好在正式采集前做一次。方法一正弦波扫描法。给所有通道同时注入同一个正弦信号频率从低到高扫一遍采集后用 FFT 提取每通道在测试频率点的相位计算出相对相位差。这个方法直观但低频段相位差本来就小容易被噪声淹没所以测试频率点要覆盖工作频段的高端。方法二白噪声互相关法。给所有通道注入同一个宽带噪声源采集后做两两互相关从相关峰的偏移得到通道间时延。这个方法的好处是一次测量覆盖整个频带缺点是如果通道间差异很小互相关峰的位置分辨率受采样率限制需要插值才能看到更细的时延。我们在实际项目里是两种方法都做正弦扫描法验证绝对相位精度白噪声互相关法验证全频带的一致性。标定后如果发现个别通道有固定的相位偏差可以在 FPGA 里的每通道数据路径上加一个相位补偿寄存器用软件把测得的偏差补偿掉。实测下来经过补偿后整个系统的通道间相位差可以控制在 0.2° 以内满足绝大多数水声测量需求。7. 一个工程人的后续扩展建议系统的主体功能已经稳定运行了但作为工程项目的复盘有几件事我建议后面做类似项目的人提前考虑。存储方面虽然我们当时把降采样后的数据全部通过网络传到了岸基但有些场景需要设备端本地存储原始数据。16 通道、128 kSPS、24 bit 的原始数据大约是 6.144 MB/s一小时就是 22 GB。如果要连续记录一个月那本地存储容量至少得几十 TB。这个规模用 SD 卡肯定不行建议直接上 SATA 接口的固态硬盘ZYNQ UltraScale 的 PS 端可以扩展 SATA 控制器或者通过 PL 侧做一个 SATA 控制器 IP。注意连续写入时文件系统最好用专门为嵌入式设计的日志型文件系统避免突然断电导致数据损坏。远程升级这块如果设备布在船上、码头不可能每次升级都拆机连 JTAG。ZYNQ 的 QSPI Flash 支持 Multiboot 功能简单说就是在 Flash 里放两个镜像启动时先读主镜像主镜像校验失败就自动加载备份镜像。这个功能在 Linux 侧可以通过写 multiboot 寄存器触发实现远程切换镜像。结合 TFTP 或者 HTTP 下载新镜像再配合 A/B 分区方案可以做到比较可靠的不停机升级。我们后来在一个新项目里就实现了这个机制从 Web 端上传固件到自动切换整套流程不超过两分钟。通信这边如果后期要上 10G 网络可以研究一下 Corundum 这个开源 FPGA 网卡项目。它的思路是用 FPGA 实现完整的以太网 MAC、DMA 和 PCIe 控制逻辑ZYNQ 平台上也可以参考它把数据通路从 DDR 直接导到网络接口省掉 CPU 参与数据搬运的环节。不过 Corundum 的移植工作量和调试门槛都不低建议先把基础采集链路稳定跑通再考虑往这个方向延展。最后说一个我自己的体会。做这类异构系统最忌讳的就是把 ARM 和 FPGA 当成两个独立的领域分别开发到最后联调时才发现接口对不上、数据格式不匹配、时间预算超支。正确的做法是在项目一开始就把整个数据流图画出来明确每个模块的输入输出格式、位宽、帧结构、时序要求然后让负责 PS 和 PL 的人员在同一个文档里维护这套接口约定。ZYNQ 这个平台最大的价值就是让 ARM 和 FPGA 可以紧密协作但这个优势只在两边真正围绕同一个数据流设计时才能体现出来。做硬件的和做软件的坐在一起把数据通路上的每一段延迟、每一个缓冲区的深度都掰扯清楚这个系统才有可能真正达到“高精度、高实时、边缘 AI”这三个词同时成立。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门