我们电赛队伍今年打算用安路FPGA做智能车,PID控制在PL里实现,电机PWM更新频率设的1kHz,但实测响应总比队友用STM32的慢,转弯时明显拖泥带水。编码器用SPI读的,没做任何滤波直接进PID。想问下是控制周期应该提到5kHz还是编码器信号需要先做中值滤波?国产FPGA的PLL输出抖动会不会也有影响?求有实战经验的大佬指点排查方向。
2026年了,FPGA大赛做智能车用国产FPGA跑PID,电机响应总慢半拍,是控制周期太长还是编码器反馈没做滤波?
4 个回答

先别急着把周期从 1kHz 提到 5kHz,你这现象更像反馈链路的问题。电赛里用国产 FPGA 跑 PID,最容易踩的坑不是算力不够,而是你从 SPI 读编码器那一步就把相位裕度吃掉了。SPI 读数据本身有建立时间,你如果是在中断里或者主状态机里直接拿最近一次的值去算 PID,相当于给反馈通道加了个不确定的延迟,这个延迟在 1kHz 下可能就占了一个周期的 20% 到 30%,电机看起来就是慢半拍。我建议你先在 PL 侧对 SPI 的读结果做两拍同步,把异步信号先打稳,然后加一个非常简单的一阶低通,比如 y = y_old + k(x – y_old),k 取 0.3 到 0.5 先试,目的是把编码器跳变沿的高频毛刺滤掉,而不是做中值滤波——中值滤波在 FPGA 里要排序,占用 LUT 不说,还会引入 3 到 5 个时钟的群延迟,反而是帮倒忙。滤波放完后,再去看控制周期。你提到队友 STM32 响应快,人家那是把控制做到 10kHz 甚至更高,但那是靠 CPU 中断直接读定时器编码器模式,硬件上就没有 SPI 这个环节。你还不能直接照搬周期,国产 FPGA 的 PLL 输出抖动在几百皮秒量级,对 1kHz 的 PID 来说完全不是问题,真正的问题是 PWM 死区设置——如果你死区设得太大,比如 2 微秒,而 PWM 周期是 1ms,那相当于每周期都有 0.2% 的时间输出是死的,电机在低速段会感觉黏滞。你可以先做一个实验:把 PID 周期提到 5kHz,同时把死区缩小到 0.5 微秒以内,看阶跃响应是否明显变硬。如果变硬了就是周期问题,如果还是软绵绵,那问题八成在编码器滤波上。还有个细节,国产 FPGA 的 IO 驱动强度默认可能是 4mA,你如果直接驱动光耦或者长线到编码器,上升沿会变缓,SPI 时钟边缘采数就容易采错位,建议把 IO 驱动强度调到 8mA 或 12mA,然后在 SPI 时钟线串一个 33 欧姆电阻做阻抗匹配。按这个顺序查:先加同步和低通,再提周期到 5kHz,最后调死区和 IO 强度,基本能定位到具体环节。你们现在用的是什么型号的安路?如果是 EG4 系列,PLL 的 IP 配置里有个 ‘lock threshold’ 参数,默认可能太保守,也会让时钟建立变慢,可以顺手查一下。”
“别折腾中值滤波,直接打两拍再算个平均值就行。1kHz 周期对 PID 来说确实低了点,提到 5kHz 你会发现新世界。PLL 抖动那点事在电机控制里根本排不上号。”
“我碰过类似情况,说个最直接的排查法:先把 PID 输出断开,手动给 PWM 一个固定占空比,然后用示波器同时看编码器 SPI 的时钟线和数据线,确认数据在时钟上升沿时是不是稳定。如果数据在边沿附近还在跳,那就是时序余量不够,跟 PID 周期没关系。这种情况常见于国产 FPGA 的 IO 输出延迟比 Altera 或 Xilinx 的大,你配置 SPI 时钟相位时多留半个周期余量就行。如果时序没问题,再把 PID 周期提到 5kHz,同时把积分项系数减半,因为周期变短后积分累积变快,容易过冲。你转弯拖泥带水还有个可能是 PWM 更新频率跟不上控制频率,如果 PID 算完没立即更新寄存器,而是等下一个 PWM 周期才生效,那就等于又加了一个周期的延迟。建议把 PWM 更新改成立即模式,或者让 PWM 周期和控制周期同步,这样能省掉一拍。至于中值滤波,个人感觉在编码器这种低噪声源上是浪费资源,你不如把精力放在检查反馈链路的确定性上。你们 SPI 是用的硬核还是自己写的逻辑?如果是自己写的,建议把状态机改成双沿采样,能有效减少毛刺误判。

先泼个冷水:你现在问的“1kHz还是5kHz”“要不要中值滤波”,大概率都不是根因。你队友的STM32如果也是1kHz跑PID,那差的就是反馈链路本身的处理方式。SPI读编码器这件事,在国产FPGA上最容易翻车的是时序约束没做——你如果直接在状态机里等SPI的done信号然后立刻取数据算PID,这个done到数据稳定之间可能有几个ns的偏差,在1kHz下看似无所谓,但实际等于给反馈通道加了一个随机的、非整数倍的延迟。转弯拖泥带水,本质是相位裕度被这个延迟吃掉了,不是增益不够。建议你先把控制周期固定成1kHz别动,在PL里做两件事:一是把SPI的sclk和cs用系统时钟打两拍,确保采样沿干净;二是对读回来的位置值做一次滑动平均,窗口取4到8个点,别用中值滤波,那东西在FPGA里要排序,LUT消耗大还没必要。做完这两步,再去看阶跃响应,如果超调还在但响应变快了,说明延迟问题缓解了,这时再提5kHz才有意义。另外,PWM死区那块你查过吗?很多国产FPGA的PWM输出默认死区时间是根据内部RC算的,跟STM32的定时器死区完全不是一个量级,如果死区设大了,电机在低速时会有一种“粘滞感”,跟慢半拍很像。最后说PLL抖动,安路的PLL输出抖动一般在几十ps量级,对1kHz到5kHz的PWM来说完全不是问题,别在这个方向上浪费时间。你先按我说的把SPI同步和滑动平均加上,跑一次阶跃响应对比波形,大概率能看出区别。顺便问一句:你现在SPI的时钟是多少?如果是10MHz以下但读一次编码器要等好几个周期,那延迟比你想的严重得多。

中值滤波在FPGA里做纯属自找麻烦,先加个一阶低通试试,k取0.3,比什么都管用。另外把PWM死区调小点,很多国产芯片默认死区大得离谱。

我建议你先别改周期,直接抓波形。把目标速度设成阶跃,同时用逻辑分析仪抓电机电流和编码器位置,看从阶跃发生到位置开始变化到底差了几个毫秒。如果这个延迟是固定的,比如总是2ms左右,那基本就是SPI读取周期加上PID计算周期的总和,这时候你把PID提到5kHz确实能缩短延迟,因为计算周期从1ms变成0.2ms,但SPI读取那部分如果还是1ms一次,瓶颈依然在。所以关键不是PID跑多快,而是编码器反馈多久更新一次。很多国产FPGA的SPI IP核默认是一次读32位,如果你只需要16位的位置数据,可以改成16位模式,把读取时间砍半。另外,检查一下你PWM的更新时机——是每个PID周期都更新占空比,还是等PWM计数器到顶才更新?后者会额外引入最多一个PWM周期的延迟,如果PWM频率是20kHz,那就是50微秒,虽然不大,但在1kHz控制周期下占了5%的相位裕度。先把反馈更新率提上去,再考虑控制周期,顺序别反了。
发表回答
登录后可在本页底部提交回答