
在做VLSI的人基本都绕不开数字信号处理DSP这一关尤其是滤波器、变换这两个词几乎是所有通信、音频、雷达、图像处理芯片里的常驻模块。我自己在流片项目里调过不少FIR、IIR和DCT/FFT核回头再看《VLSI数字信号处理系统》这本经典教材里关于“算法强度缩减”strength reduction的这一章感触比当年上课时深得多。简单说算法强度缩减不是让算法变“弱”恰恰相反它是在保证输入输出数学关系不变的前提下用更少的乘法器、更短的延迟线、更小的寄存器堆和更低的功耗去实现同一个数字信号处理功能。这篇文章就把我在滤波器设计和变换结构上的实操经验结合强度缩减的思路拆开揉碎了讲一遍。适合看这篇文章的人我大概圈一下正在做FPGA/ASIC滤波器和变换模块的工程师被时序收敛逼疯的RTL设计人员还有刚接触VLSI方向研究生课程、想搞懂“为什么教材里那么多等价变换”的学生。这里面不会只讲理论更多是“哪个结构省几个乘法器、哪个变换能少几级流水、什么情况下别为了省面积把系统稳定性做没了”这类实战问题。给的学习路径也很直接先理解强度缩减的本质再跟着滤波器、变换两条主线看具体手法最后是落地时容易踩的坑。1. 算法强度缩减是什么——先从“省乘法器”这个问题说起1.1 强度缩减的源头从编译器优化到VLSI结构再设计算法强度缩减这个词最早是从软件编译器那边流行起来的。比如x * 4这种表达式编译器会自动改成x 2因为移位比乘法快得多这条规则就叫strength reduction。在软件里这只是个小优化但到了VLSI数字信号处理领域这个概念被放大成了一整套设计哲学同一个数学运算可以映射到完全不同的硬件拓扑上计算代价差异可能是数量级的。举一个最经典的例子有限脉冲响应FIR滤波器的直接型结构每进来一个样本需要N次乘法和N-1次加法。N等于16的时候还好F103和IP核都能兜住但在宽带通信系统里如果滤波器阶数走到128甚至256直接型结构占用的DSP48资源、乘法器面积和功耗都会非常难看。而强度缩减的思路就是这个滤波器一定要用N个乘法器吗不一定。你可以用系数对称性把它减半可以用分布式算法用查表替代乘法可以引入多相结构让部分乘法器在工作在更低的时钟频率上。这些方法都是“结构级强度缩减”。我在实际项目里理解最深的点是强度缩减并不仅仅是把乘法改成加法这么简单它是一个覆盖算法、架构、电路三个层次的等价变换集合。算法层变换的是计算顺序比如FFT的分治架构层变换的是数据流拓扑比如流水线与并行化重组电路层则体现在用加法和移位去拼乘法器。真正要在VLSI里做强度缩减靠单一技巧是不够的最常见的成功路径是把这几层手法组合起来用。1.2 为什么强度缩减在ASIC和FPGA里特别值钱很多人都知道“面积、功耗、延迟”是VLSI设计的三个核心指标但未必清楚乘法器在这三个指标里处于什么地位。看一组工程经验值在典型CMOS工艺下实现一个16bit × 16bit乘法器消耗的逻辑门大约是一个16bit加法器的8到10倍乘法器的输入到输出延迟大约是同级加法器的3到4倍。所以在DSP芯片里乘法器子树往往就是时序收敛的关键路径它的开关功耗也占系统动态功耗的很大一部分。动态功耗公式P αCV²f里α 是翻转率。乘法器内部部分积的求和网络恰恰是翻转最密集的地方因为数据每次变化几乎都会引起大量内部节点翻转。所以当你用强度缩减把一个滤波器里的乘法次数从原来的 N 降到 N/3你省的不仅是几个单元而是整条关键路径上的翻转次数和那部分核心的接插电容。用我自己的话说“省一个乘法器比省三个加法器更让人安心。”这是从VLSI角度论述强度缩减最重要的原因。再加上ASIC和FPGA实现中DSP48、乘法器块都是稀缺硬核资源硬件乘法器数量经常直接决定你能不能在一片小尺寸FPGA上把设计放下去。这个背景下强度缩减就成了DSP系统能否落地的一个先决条件。2. 滤波器实现中的强度缩减从直接型到多阶的实战优化2.1 FIR滤波器的系数对称与公共子表达式共享FIR滤波器的核心计算是卷积y[n] Σ_{k0}^{N-1} h[k] · x[n-k]在VLSI里最干净的第一个强度缩减手段就是利用线性相位FIR的系数对称性。线性相位条件要求冲激响应满足h[k] h[N-1-k]比如一个标准的低通滤波器抽头系数是中间对称的。这样一来我可以先把滤波器输入的两个对称样本先加起来再乘系数假设N为偶数 y[n] Σ_{k0}^{N/2-1} h[k] · (x[n-k] x[n-(N-1-k)])这一个变形乘法器直接减半加法器增加了N/2个。由于加法器比乘法器便宜一个数量级这个交换几乎总是划算的。而且这个预加操作只需要在输入数据通路上增加一级加法器不会把关键路径变长多少。第二个强度缩减手法是公共子表达式共享Common Subexpression Elimination, CSE这个在VLSI实现里非常实用。原理是这样的滤波器的系数在二进制表示下通常只有少数几个比特是1。比如某个系数 h[k] 0.101001011₂这个二进制数包含的1比较多但两个系数之间可能共享类似“101”或“1001”的子模式。既然0.101001011₂ 0.1₂ 0.001₂ 0.000001₂ 0.000000011₂这种分解我就可以先把输入x[n]的右移1位、3位、6位、9位分别算好然后根据所有系数的比特模式去复用这些移位版本作为部分积再用一个加法器树把它们累加到一起。这样所有系数的乘法都可以通过移位与加法的共享网络实现整个滤波器里可以完全没有乘法器。我自己实现过一个16阶线性相位FIR用CSE做下来乘法器从8个直接压缩到2个代价是多了一棵预加和移位加法树整体面积大概省了40%。不过有个注意点CSE需要提前做系数的二进制模式匹配工具软件能自动做但在RTL里手动做时一定要先把系数写干净不要留有太多低位冗余。2.2 IIR滤波器的结构级强度缩减四阶巴特沃斯的正确实现姿势IIR滤波器因为有反馈回路强度缩减的重点又不一样。直接II型实现一个四阶巴特沃斯低通滤波器看起来只需要5个乘法系数比FIR的抽头数少多了。但如果直接把差分方程写成这样y[n] b0·x[n] b1·x[n-1] b2·x[n-2] b3·x[n-3] b4·x[n-4] - a1·y[n-1] - a2·y[n-2] - a3·y[n-3] - a4·y[n-4]在VLSI里这种直接型结构会出大问题。系统对系数a1~a4极其敏感系数只要量化误差稍微大一点极点就可能漂出单位圆滤波器直接震荡。这也是为什么教材里总在强调“高阶IIR要拆成二阶节级联”。把四阶巴特沃斯分解成两个二阶节级联Biquad级联每个二阶节只有两个极点系数敏感性大大降低。这个拆分本身就是一种强度缩减你用两个稳定性好的二阶节去替代一个实现脆弱的高阶块代价不过是多了一级寄存器组和几个加法器但换来了可量化的系数精度和稳定性。更进一步的强度缩减体现在对二阶节的系数归一化处理上。标准直接I型Biquad的差分方程是y[n] b0·x[n] b1·x[n-1] b2·x[n-2] - a1·y[n-1] - a2·y[n-2]我可以把等式右侧提取公因子把传递函数分解成“先零后极”或者“先极后零”两种级联形式再通过分配增益来让每级的中间信号不要过大。用四阶巴特沃斯举例通常取截止频率为采样率的四分之一两级Biquad分别配置不同的零极点对然后中间插入一个增益调整级。这个调整不是随便做的它背后是定点实现的动态范围优化如果中间信号溢出你再怎么剪乘法器都是白搭。我在FPGA里实现过采样率96kHz的四阶巴特沃斯用级联Biquad 移位增益调整系数位宽做到16bit实测SNR能做到80dB以上整个滤波器只用了2个DSP48。如果换成直接型结构16bit系数可能就只够到60dB还会时不时毛刺。2.3 滑动窗口滤波器的延迟优化从逐点卷积到增量更新有些滤波器很特殊它的系数全部相等比如求M点滑窗平均。之前我一直用标准的FIR结构去实现y[n] (1/M) · Σ_{k0}^{M-1} x[n-k]这个结构每来一个样本要做M次乘加。后来做实时传感器数据处理窗口长度要开到1024直接型根本跑不动。这时强度缩减的思路就是变换计算结构输出y[n]和y[n-1]之间只差“新进来的样本”和“滑出去的样本”y[n] y[n-1] ( x[n] - x[n-M] ) / M这样一来不管窗口多长每次迭代只做1次减法、1次乘法和1次加法。一个1024点的滑窗平均乘法器数量从1024降到1。这个差分更新的思路在实际工程里极其常见不只是均值滤波很多“滑窗型”的操作比如滑动DFT滑动方差都能用类似增量更新实现。实现增量更新时要注意两个坑。第一除法放在反馈环里会影响时序所以更聪明的做法是先维护窗口累加和s[n] s[n-1] x[n] - x[n-M]把除法放到输出端输出y[n] s[n] / M。在硬件上除以M可以用移位实现只要M取2的幂次。第二累加和s[n]的位宽要仔细算窗口长度M是1024时s需要比输入多大约 log2(M) 位否则会溢出。我见过有同事在这里少算了一位结果窗口一满输出直接翻成负数。2.4 模拟滤波器里的“强度缩减”Sallen-Key结构的启示很多人觉得强度缩减是数字VLSI专用概念其实模拟滤波器里也有等价思想。比如Sallen-Key结构它把一个单位增益的二阶低通滤波器用单个运放加四个阻容元件实现相比直接级联两个一阶RC滤波器省掉了一个运放。在芯片面积上一个运放可比四个阻容值钱多了这就是模拟域的“面积强度缩减”。从VLSI数字系统设计的角度看这个例子提醒我的是强度缩减的本质不局限于“数的运算”而是“系统结构的再组织”。在数字域也一样你未必非要囚禁在教科书给的直接型、转置型、级联型里只要差分方程不变、频率响应满足要求你可以自定义内部信号流。这里的关键是系统级的权衡不要只盯着单元电路。3. 变换中的强度缩减DCT、FFT、Z变换与小波包3.1 DCT/FFT的分解复用把大矩阵拆成稀疏矩阵连乘数字信号处理里的变换本质上是矩阵乘法。比如N点离散余弦变换DCT的输出X[k] Σ_{n0}^{N-1} x[n] · cos( π(2n1)k / (2N) )直接计算N点DCT需要N²次乘法和N(N-1)次加法。N8时64次乘法还能接受N1024时上百万次乘法这在VLSI里完全不可行。所以工程里都会对变换矩阵做分解把DCT矩阵拆成多个稀疏矩阵的乘积每个矩阵只有很少的非零元素这样总乘法次数可以大幅下降。以8点DCT为例Chen分解算法可以把直接计算所需的64次乘法降到13次左右。这个结果是通过多级分解、蝶形运算复用得出来的。FFT采用同样的思想——N点FFT的复杂度是O(N log N)就是通过把大DFT拆成两个N/2点DFT递归实现。在VLSI里这套递归结构映射成多级蝶形运算单元每一级只需要N/2个复数乘法器复数乘法器里又可以共享旋转因子的实部虚部运算。我还想强调一点FFT/DCT在硬件里的强度缩减并不仅仅是“计算量减少”更重要的是把规则化、模块化的结构给提炼了出来。蝴蝶运算单元完全一致方便做成脉动阵列每一级的存储和索引规律清晰方便安排流水线旋转因子的对称性也可以用来缩减ROM表的大小。这些对VLSI实现的好处比单单省几个乘法器还要大。3.2 Z变换与重定时用延迟单元玩转流水线Z变换在VLSI数字信号处理里更像是一个工程工具而不只是教科书里的数学公式。它在硬件上的扮演者是寄存器延迟单元z^{-1}。一个FIR滤波器的直接型结构本质上就是把一串z^{-1}延迟单元串起来形成输入信号的延迟线。而Z变换域的操作可以用来实现“重定时”retiming这是VLSI数字信号处理里非常经典的强度缩减手段。重定时的思路是在不改变系统传递函数的前提下把寄存器在数据流图里重新分配位置通过减少关键路径上的组合逻辑延迟来提升时钟频率。举一个具体例子。一个3阶FIR滤波器若直接实现y[n] h0·x[n] h1·x[n-1] h2·x[n-2] h3·x[n-3]三个乘法器的输出要进同一个加法树加法树的组合逻辑延迟就是关键路径。如果我利用z变换的恒等式把加法器进位保存结构换成两级“先乘后加”再“加延迟”的流水线比如这样重组d0 h0·x[n] h1·x[n-1] // 第一级流水 y[n] d0 d1[n-1] // 其中d1[n-1]是上一拍的h2·x[n-2] h3·x[n-3]寄存器从纯延迟线中被抽取出来嵌到运算单元之间关键路径就大大缩短了。这个过程就是通过z变换分析系统的延迟平衡来完成的非常实用。在FPGA上如果时序报红第一反应就是看关键路径落在哪个运算单元上然后用重定时在运算中间插入寄存器效果立竿见影。3.3 小波包变换与多分辨分析滤波器组里的计算复用小波包变换Wavelet Packet Transform, WPT也是热搜词里出现频率很高的内容。它本质上是一个多通道滤波器组输入信号经过不同尺度的低通和高通滤波器反复再分解最后得到时频分析的结果。VLSI实现小波包变换天然适合做强度缩减因为不同尺度的分解滤波器其实用的是同一组滤波器核。以两层小波包分解为例第一层需要一组低通h0和高通h1得到两个逼近信号第二层再分别对这两个信号做一次h0和h1滤波。如果不做优化需要6个滤波器实例如果复用同一个滤波器核的硬件用时分复用的方式轮询处理各通道数据只需要2个滤波器实例配上多路选择器和缓冲寄存器。这种“计算核复用”的强度缩减在面积敏感的多通道信号处理系统里价值巨大。小波包变换相比离散小波变换DWT计算量更大因为高频子带也要继续分解。但实数小波包变换和FFT不一样它不需要复数乘法系数也通常很整适合定点乘法。在VLSI里实现时我一般会把小波滤波器系数设计成短整数形式比如Daubechies系的整数近似然后用移位加法网络代替乘法器这又回到了第二节中CSE的套路。整体做下来一个支持3层分解的小波包处理核面积大约只比单层DWT大1.5倍而不是3倍。3.4 坐标变换中的强度缩减Park/Clarke变换的多种实现路径坐标变换在电机控制、并网逆变器领域到处都是Clarke变换把abc三相静止坐标变成αβ两相静止坐标Park变换再把αβ变成dq旋转坐标。这些变换的数学本质是旋转矩阵乘法和常数矩阵乘法。Clarke变换的标准形式[ Xα ] [ 1 -1/2 -1/2 ] [ Xa ] [ Xβ ] [ 0 √3/2 -√3/2 ] [ Xb ]直接实现需要4个乘法。但如果我利用矩阵元素的重复性把行向量的公共部分先提出来比如Xα的表达式是 Xa - (XbXc)/2我可以先算XbXc再乘1/2变成1次乘法和2次加法。乘1/2又可以变成右移1位。所以Clarke变换可以被缩减成纯加减法和一个移位。Park变换更直接公式里包含sin和cos乘法常规实现是4次乘法加2次加法乘法系数还要从ROM里查出来。在VLSI里常见的强度缩减路径有两种一种是把旋转坐标转换算法CORDIC嵌入进来用迭代移位加减替代sin/cos与乘法这样完全不需要乘法器另一种是用角度增量预测和查表插值来减少ROM大小。对于角度变化较快、精度要求1度以内的应用CORDIC是更省面积的方案。每次迭代只需要移位和加减迭代个数和位宽决定精度实测做到16bit精度大约需要16次迭代。坐标变换这个例子的启发是不要看见某个公式里有三角函数就默认必须用乘法器和函数发生器先想想能不能用代数恒等式、移位、查表、CORDIC重新表达。4. VLSI落地从算法强度缩减到RTL实现的关键细节4.1 位宽优化与截断误差控制别把SNR省没了强度缩减在变换结构时会影响系统的噪声性能尤其是在定点实现里。许多工程师把算法模型从浮点换成定点后发现SNR掉了二三十dB第一反应就是把所有信号位宽都加大结果面积又上去了强度缩减省下的资源又被位宽吞回去一个典型的“省了芝麻丢了西瓜”。正确的做法是分模块做位宽预算。先计算出每一级输出信号的动态范围考虑滤波器增益、变换级增益和数据相关性逐级确定整数位。比如一个增益为2.5的低通滤波器输出位宽至少要比输入多1位整数位否则峰值必溢出。小数位则可以通过定点模型仿真来逐次逼近以目标SNR为约束取满足SNR的最小位宽。IIR滤波器里的小数位宽要特别小心。反馈环路里的截断误差会不断累积形成极限环甚至死带。一个避免极限环的常用经验是反馈支路的中间结果比主信号路径多保留2~3个低比特位或者采用幅度截断的量化方式实现方式比加减1的舍入简单但可以有效收敛振荡。这个我在四阶巴特沃斯定点化时专门验证过多保留3位低位极限环振幅直接降为零。4.2 加法器树与流水线重组关键路径才是真正的敌人做强度缩减时乘法器减少了但加法的数量往往会增加加法器树就可能成为新的关键路径。所以设计时永远要同时审视乘法器和加法器两侧的延迟。加法器树本身的强度缩减也很有技巧。比如多输入加法树与其串成一个长链不如组成平衡树结构把N个输入相加的延迟从O(N)降到O(log N)。在FPGA里用进位链结构的加法器LUT可以在同一拍内完成多位宽的三输入加法所以合法的平衡树分支数不是2而是3甚至4。有些工程师还在用老式二叉树去综合三输入加法白白多了一级延迟。再进一步对于加法器树级联到乘法器的场景我会直接把第一个加法级的输出寄存器放在乘法器之前而不是之后。因为加法器结果位宽比乘法器输入位宽更大在加法后寄存的话寄存器位宽小。而如果先寄存再乘寄存器位宽增加但乘法器的输入路径变长了。实际操作中我用流水线切割时优先切乘法器组合逻辑最重的位置然后通过重定时自动将剩余寄存器在数据流图中前移或后移直到关键路径缩短到时钟约束之内。在Verilog/SystemVerilog里我一般会把这种结构写成参数化可配置的加法器树避免手动用一堆二进制加法器一层层拼。比如用generate块按照log2深度自动生成平衡树后续改位宽或分支数都很方便代码审查的时候也好讲清楚。4.3 从算法矩阵到资源面积估算先算账再动手动手写RTL之前我会先在纸上做一个快速资源估算避免写到一半发现方案根本放不进目标器件。估算公式大致是这样乘法器数量 每时钟周期并行需要的乘法次数 加法器数量 所有并行加法的操作数总和折算成等价2输入加法器数量 寄存器数量 流水线级数 × 每级数据通路的位宽和并行度比如一个128阶并行FIR滤波器如果我把系数对称和CSE都用上算出需要4个乘法器如果使用全并行结构也许需要64个乘法器两者面积差异是10倍以上的量级。把这些数字乘以单元面积和功耗系数就可以在早期评估出大概用什么等级的FPGA或者多大规模的ASIC进而决定架构方案。我做过一个表格化的粗估16bit数据通路的场景下一个DSP48可以替代大约128个LUT加寄存器组合。如果只是做中等速度低功耗的音频滤波器用LUT移位加法实现乘法可能更划算但如果速度要求上到几百MHzDSP48或硬核乘法器才是稳妥的。强度缩减的正确目标不是“把乘法器个数降到0”而是“在满足时序和精度的前提下把总成本最小化”。4.4 一个分布式算法的完整实现思路举例分布式算法Distributed Arithmetic, DA是我非常推荐的强度缩减实现方案特别适合FIR滤波器。它的核心思想是提前把滤波器系数的部分和partial sum做成查找表把乘累加操作转化为查表和累加操作。以8阶FIR为例假设输入是12bit无符号数那么可以把每个输入样本的每一位拆开y[n] Σ_{b0}^{11} 2^b · ( Σ_{k0}^{7} h[k] · x_k[n-k][b] )内层的括号是一个8输入1输出的逻辑函数预计算成一张256项的查找表输入是8个系数在某个位上的bit组合输出是对应的部分和。然后对12个bit位依次查表把查表结果按位权累加就得到了滤波输出。这套结构完全不需要乘法器只需要1个LUT和1个累加器。用SystemVerilog实现时大概是这样伪代码描述always_ff (posedge clk) begin if (rst) begin acc 0; shift_reg 0; end else begin shift_reg {new_sample, shift_reg[7:1]}; // 8级延迟线 sum 0; for (int bit 0; bit 12; bit) begin addr {shift_reg[0][bit], shift_reg[1][bit], shift_reg[2][bit], ..., shift_reg[7][bit]}; sum sum (lut[addr] bit); end y sum; end end实际上会把循环展开并流水化但原理就是这个。DA结构的优点是资源占用极其规则一个N阶滤波器需要一张深度2^N的LUT。N太大时LUT会爆炸所以实际中通常会把N拆成4或5一组的多块LUT再对多块结果求和。这个拆分就是DA和CSE组合的强度缩减。我用DA实现过一个16阶FIR在Spartan-6上只用了不到400个LUT跑100MHz没压力对比直接用乘法器节省超过60%的逻辑资源。5. 常见问题与排查技巧实录5.1 定点仿真与浮点模型对不上先查这四处做数字信号处理VLSI最让人头痛的就是浮点模型跑得好好的定点实现一出来全乱了。我遇到这类问题排查顺序基本固定第一查系数量化误差。滤波器系数从浮点转定点时如果系数位宽不够频率响应会偏移。这个影响最容易观察把定点系数和浮点系数各自的频率响应曲线叠加画出来一眼就能看出偏差。解决方式是增加系数位宽或者在强度缩减时保留系数的共享子表达式精度。第二查中间信号溢出。定点仿真时如果出现瞬间的大幅信号整数位不够就会溢出表现是输出波形在峰值处被削了或者符号跳变。这类问题用ModelSim/QuestaSim看波形非常直观找到输出异常的时间点再往回追踪各级信号基本能在半个小时内定位到是哪个加法器或乘法器输出变了。解决方式是扩展整数位或者在乘法器和加法器输出端插入饱和逻辑。第三查截断误差累积。IIR滤波器更容易出这个问题因为反馈环会把每级的量化噪声不断加起来输出会出现低频漂移或极限环。解决办法在前面也说过反馈支路多留低位或者对累计寄存器做噪声整形。第四查时序仿真与RTL行为不一致。这个问题往往出现在流水线重定时之后寄存器被移动了位置但仿真testbench里对延迟的假设没有同步更新。解决办法是把延迟线设计成参数化配置每次重定时后自动调整输出对齐窗口别用固定周期数去采样输出。5.2 时序不收敛关键路径定位的三个招数FPGA上时序报红最常见的场景就是“乘法器后面接了一长串加法器树”。这时候三个招数可以试第一招重定时。把组合逻辑均匀切割把某些寄存器从数据延迟线搬到加法器树中间去。这招效果最直接但需要保证系统传递函数不变建议用专业的重定时工具自动做手工移动容易出错。第二招改成进位保存加法和超前进位加法混合。长数据宽度的加法链很慢可以把多个部分积压缩到两个向量再用一个快速加法器统一求和。在Xilinx FPGA上就是利用CARRY8进位链可以把多位宽加法延迟压得很低。第三招改并行度为流水线。如果数据率不高完全可以用串行或者半并行的方式用多个时钟周期完成一组运算而不是要求一个时钟周期算完所有乘法。这个需要接受输出延迟变大但很多DSP系统对延迟并不敏感。5.3 强度缩减实施前先问自己四个问题这篇文章篇幅有限最后我把经验收敛成一个自检清单每次做强度缩减方案之前我都会过一遍第一数学上等效吗变换前后系统的传递函数、频率响应、群延迟特性是不是在可接受误差范围内一致不一致的话后面所有优化都是空中楼阁。第二误差分配合理吗量化误差、截断误差、舍入误差在各级的预算是否留够了尤其是反馈结构务必单独分析稳定性。第三时序和硬件资源真省了吗有些变换省了乘法器但大幅增加了路由或寄存器导致布线拥塞得不偿失。评估要看到最终布局布线后的数据不能只看行为级综合报告。第四可维护性和可扩展性怎么样花两周写的高度优化代码如果以后换了一个滤波系数就要重写一大片那要慎重考虑。参数化设计和生成脚本可以在一定程度上缓解这个问题。我在实际项目里的体会是算法强度缩减本身不难理解难的是知道何时该停下来。拼命压榨乘法器、把结构改得面目全非换来可能不到10%的面积收益却让设计和验证成本翻倍这种优化就不划算。成熟的工程师会拿着面积、功耗、时序、精度和开发周期五本账一起算最后选择那个“够用又稳”的方案而不是纸面上最优的方案。滤波器和变换里的强度缩减说到底是一个关于成本和收益的工程判断而这一课只有真正流片或者做完物尽其用的FPGA设计之后才会记得特别牢。