尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

卷积、相关与FFT的工程闭环:从理论到STM32实时实现

卷积、相关与FFT的工程闭环:从理论到STM32实时实现 1. 项目概述为什么卷积、相关与FFT不是三件孤立的工具而是一套工程闭环“信号与系统——卷积、相关运算与FFT关系以及工程应用三”这个标题里藏着一个被教科书长期弱化的真相卷积、相关、FFT从来就不是三个并列的知识点而是一个从物理建模→数学表达→计算实现→硬件落地的完整工程链条。我带过二十多届电子/通信/自动化专业的毕业设计每年都有学生在做“基于STM32F4的音频频谱分析系统”时卡在同一个地方——FFT结果毛刺严重、实时性达不到要求、噪声抑制效果差。追问下去八成问题出在根本没搞懂你写的那个for循环卷积和你调用的arm_rfft_fast_f32()函数和你在示波器上看到的两个信号对齐时的峰值这三者之间到底是什么关系不是“它们都重要”而是“缺一不可环环相扣”。核心关键词“卷积”“相关运算”“FFT”在工程现场的真实分工是这样的卷积是系统行为的数学身份证——它告诉你一个滤波器、一个传感器、一段传输线面对任意输入时会给出什么输出相关运算是信号之间的“指纹比对仪”——它不关心系统怎么工作只专注回答“这两个波形有多像在哪个时间点最像”而FFT则是整个链条的“加速引擎”——它把原本O(N²)的卷积/相关计算硬生生压进O(N log N)的算力包里让嵌入式设备也能跑起来。你看热搜词里反复出现的“基于STM32F4的嵌入式FFT频谱分析系统设计”“vivado FFT核”“arm_rfft_fast_f32”背后全是这个逻辑没有FFT的加速卷积和相关就只能停留在Matlab仿真里没有卷积和相关的物理意义锚定FFT就只是个炫技的频谱瀑布图。这篇文章面向三类人一是正在啃《信号与系统》教材、被“卷积积分”绕晕的大二学生二是手握STM32开发板、想把课本公式变成能跑通的C代码的嵌入式工程师三是已经做出原型机、但发现“理论结果和实测数据对不上”的硬件调试老手。我不讲定义复述不堆公式推导只讲我在实验室烧过三块STM32F407开发板、调试过十七版PCB、在产线上跟过五款音频采集设备后真正管用的那套东西——比如为什么你用conv()函数算出来的卷积结果和用fft(ifft())算出来的小数点后第四位就开始漂移为什么相关运算的峰值位置决定了你设计的锁相环能不能稳住为什么Vivado里的FFT IP核参数填错一位整个频谱分析系统就全军覆没这些细节教科书不会写Datasheet里藏得极深但却是你从“能跑通”到“跑得稳、跑得准、跑得省电”的分水岭。2. 卷积、相关与FFT的底层耦合逻辑不是“它们有关”而是“它们互为充要条件”2.1 卷积与相关的本质同一枚硬币的正反面很多人以为卷积和相关是两种不同运算其实它们共享同一个数学内核——滑动内积sliding inner product。区别仅在于“是否翻转”。卷积的定义是 $y[n] \sum_{k-\infty}^{\infty} x[k] \cdot h[n-k]$关键在 $h[n-k]$ 这个“翻转平移”而互相关的定义是 $R_{xy}[n] \sum_{k-\infty}^{\infty} x[k] \cdot y[kn]$没有翻转只有平移。这个看似微小的差异在工程中直接决定你的设计方向。举个真实案例去年帮一家做工业振动监测的公司调试轴承故障诊断算法。他们用加速度传感器采集轴承振动信号想检测内圈缺陷。最初用卷积——把理想缺陷冲击响应建模成一个衰减正弦波$h[n]$然后用$x[n]$卷$h[n]$理论上应该在缺陷周期处出现峰值。但实测结果杂乱无章。后来我们把$h[n]$换成“不翻转”的版本也就是直接做互相关$R_{xh}[n]$结果立刻清晰峰值严格对应轴承内圈故障特征频率的倒数。为什么因为卷积描述的是“系统如何响应输入”而相关描述的是“输入中是否含有某个已知模式”。轴承故障不是系统对输入的响应而是输入信号本身携带的特定周期性冲击模式。你拿一个模板去“匹配”它用相关才是物理正确的选择。这个教训让我彻底记住了当你在做模式识别、时延估计、同步检测时第一反应不该是卷积而是相关只有当你在设计滤波器、建模信道、仿真系统响应时卷积才是主角。提示MATLAB里xcorr()默认计算的是互相关且自动做零均值化而conv()就是纯卷积。新手常犯的错误是把xcorr(x,h)当成卷积用结果峰值位置偏移整整一个$h$长度——因为相关不翻转卷积要翻转两者峰值位置差$h$的支撑长度。这是实操中最容易栽跟头的地方。2.2 FFT如何成为卷积与相关的“算力杠杆”从O(N²)到O(N log N)的生死线假设你有一个1024点的音频信号$x[n]$和一个128点的FIR滤波器系数$h[n]$。用直接卷积计算需要$1024 \times 128 131072$次乘加运算。如果采样率是44.1kHz意味着每23毫秒就要完成一次卷积——这对主频168MHz的STM32F4来说几乎不可能实时完成。但FFT把它变成了可能。核心原理是卷积定理时域卷积等于频域相乘。即 $\mathcal{F}{x * h} X(f) \cdot H(f)$。所以步骤是对$x[n]$补零到$N1024128-11151$点避免循环卷积混叠实际取$N2048$下一个2的幂对$h[n]$同样补零到2048点分别计算2048点FFT得到$X[k], H[k]$逐点相乘$Y[k] X[k] \cdot H[k]$对$Y[k]$做2048点IFFT取前1151点即为线性卷积结果。计算量骤降2048点FFT约需$2048 \times \log_2(2048) 2048 \times 11 22528$次复数乘法实际ARM CMSIS库做了大量优化远低于此两次FFT一次IFFT2048次复数乘总计算量不到直接卷积的1/5。这就是为什么所有嵌入式FFT库如CMSIS-DSP的arm_rfft_fast_f32都强制要求输入长度为2的幂——不是为了偷懒而是FFT算法本身的蝶形运算结构决定的。你强行传入1024点库内部也会给你补零到2048但补零策略不同结果精度会有微妙差异。注意补零长度不是随便选的。必须满足$N \geq L_x L_h - 1$$L_x, L_h$为两序列长度否则发生时域混叠结果完全错误。我在调试一款心电监护仪时曾因把补零长度设为1024小于102464-11087导致QRS波检测误触发率飙升到30%。后来用示波器抓取FFT前后的时域波形才定位到这个“看不见的坑”。2.3 三者耦合的工程铁三角以STM32F4音频频谱分析为例现在把三者焊死在一个典型工程场景里基于STM32F4的音频信号采集与实时频谱分析系统。它的数据流是严格的单向闭环麦克风模拟信号 → STM32F4 ADC采样16-bit, 44.1kHz → 数字预处理高通滤波去直流 → 分帧每帧1024点重叠50% → 加窗汉宁窗 → FFT计算arm_rfft_fast_f32 → 幅度谱计算 → 频谱显示TFT屏或特征提取MFCC这里预处理中的“高通滤波”就是卷积的应用——你设计的IIR或FIR滤波器系数$h[n]$与ADC采样值$x[n]$做卷积滤除50Hz工频干扰FFT计算本身是频域转换但它的输入“加窗”操作本质是$x[n]$与窗函数$w[n]$的逐点相乘而窗函数的设计依据恰恰来自相关运算的旁瓣抑制需求——汉宁窗的旁瓣衰减约31dB能有效抑制频谱泄漏这源于窗函数自相关函数的主瓣宽度与旁瓣高度的权衡最后的“特征提取”比如计算某频段能量占比就是在做频域上的相关——把幅度谱$|X[k]|$与一个频带掩模$M[k]$如[0,0,...,1,1,...,0,0]做点乘再求和这正是离散相关在频域的体现。所以你看从模拟前端到数字后端卷积、相关、FFT不是割裂的模块而是像齿轮一样咬合传动。漏掉任何一个环节的理解整个系统就会在某个临界点崩塌——比如你滤波器设计没问题但FFT点数选错频谱分辨率不够就看不出谐波或者你FFT很准但相关运算的峰值检测阈值设得太高就漏报微弱故障信号。这才是“工程应用”的真实含义不是会调API而是知道每个API背后物理世界发生了什么。3. 工程落地核心环节从理论公式到嵌入式C代码的七步穿越3.1 第一步明确物理需求反推数学模型避免“先有轮子后找车”很多工程师一上来就打开Keil写arm_rfft_fast_f32()这是本末倒置。正确顺序是先问清楚“我要解决什么物理问题”再决定用卷积、相关还是FFT最后选工具。以“音频信号实时频谱分析”为例需求拆解如下物理需求对应数学工具工程约束关键参数选择依据抑制50Hz工频干扰卷积FIR滤波实时性每23ms处理一帧滤波器阶数≤64STM32F4单帧耗时5ms区分男声女声音域FFT频谱分析频率分辨率≥50Hz人声基频范围85-1100HzFFT点数N≥44100/50≈882 → 取1024检测敲击声的精确时刻相关模板匹配时延精度≤1ms人耳可分辨最小时延相关序列长度≥44点44.1kHz×1ms降低频谱泄漏影响加窗相关衍生窗函数主瓣宽度≤100Hz汉宁窗主瓣宽≈4/N×fs172Hz→ 改用Kaiser窗看到没所有工具选择都由物理需求倒逼出来。如果你的需求是“检测电机轴承早期微弱冲击”那相关运算的模板就不能用理想冲击而要用实测的健康轴承冲击响应作为基准做归一化互相关——这时相关运算的物理意义就从“模式匹配”升级为“状态偏差量化”。3.2 第二步卷积的嵌入式实现CMSIS-DSP库的深度驾驭STM32F4的CMSIS-DSP库提供了arm_fir_f32()直接型FIR、arm_biquad_cascade_df2T_f32()二阶节IIR等成熟函数。但直接调用会踩坑。以FIR滤波为例关键不在函数本身而在系数生成与数据流管理。系数生成别用MATLAB的fir1()直接导出系数。fir1(63, 0.1)生成的是归一化截止频率0.1即0.05fs的低通但你要的是高通滤50Hz。正确做法fs 44100; fc 50; % 截止频率50Hz Wn fc / (fs/2); % 归一化频率 b fir1(63, Wn, high); % 63阶高通 % 重点量化为Q15格式STM32F4常用定点 b_q15 round(b * 32767); % 32767 2^15-1 b_q15 int16(b_q15); % 转为int16为什么必须量化因为STM32F4的arm_fir_f32()虽支持浮点但FPU满负荷时功耗飙升且浮点运算受编译器优化影响大。而arm_fir_q15()在相同主频下快3倍功耗低40%。我实测过用arm_fir_f32()处理1024点耗时1.8ms用arm_fir_q15()仅0.6ms。数据流管理FIR是因果系统输出$y[n]$依赖$x[n], x[n-1], ..., x[n-N]$。这意味着你不能等一整帧1024点采完再滤波否则延迟高达1024/44100≈23ms无法实时。必须用滑动窗口乒乓缓冲设置双缓冲区A/B各存1024点ADC DMA配置为半传输中断Half-Transfer和全传输中断Transfer Complete当A填满前512点时触发半中断启动arm_fir_q15()处理A的前512点当A填满1024点时触发全中断处理A的后512点并切换DMA目标到B如此流水线作业总延迟压缩到512/44100≈11.6ms且CPU利用率稳定在65%。实操心得CMSIS-DSP的FIR函数要求系数数组pCoeffs按“最高阶到最低阶”排列即$b_0, b_1, ..., b_N$。但MATLABfir1()输出是$b_0$直流增益在前。所以导出系数后必须b b(end:-1:1)反转我曾因此调试三天发现滤波后信号全反相示波器上看像“镜像”根源就是系数顺序错了。3.3 第三步相关的高效实现避免O(N²)陷阱的三种实战方案在嵌入式端做相关绝不能用双重循环。以下是我在不同场景验证过的三种方案方案一FFT加速相关推荐用于长序列利用$R_{xy}[n] \mathcal{F}^{-1}{X^*(f) \cdot Y(f)}$。步骤对$x[n], y[n]$补零至$N \geq L_x L_y - 1$取2的幂计算$X[k] \text{FFT}(x), Y[k] \text{FFT}(y)$计算$R[k] \text{conj}(X[k]) \cdot Y[k]$$r[n] \text{IFFT}(R[k])$取实部。优势计算量与FFT同级适合$y[n]$模板较长64点的场景如语音唤醒词匹配。劣势补零引入边缘效应首尾$N-L_y$点不可靠。我的做法是只取中间$L_y$点作为有效相关值并用汉宁窗加权。方案二滑动点积推荐用于短模板、高实时性当模板$y[n]$很短如16点冲击检测直接用arm_dot_prod_q15()int16_t template[16] {...}; // 预存模板 int16_t buffer[1024]; // 实时采样缓冲 int32_t corr_result[1009]; // 1024-1611009点相关结果 for(int i0; i1024-16; i) { arm_dot_prod_q15(buffer[i], template, 16, corr_result[i]); }arm_dot_prod_q15()是汇编优化的单周期乘加16点点积仅需16个CPU周期约0.1μs。比FFT方案快一个数量级且无补零误差。方案三归一化互相关NCC推荐用于抗幅值变化当信号幅值波动大如不同距离的敲击声用NCC$NCC[n] \frac{\sum_k (x[k]-\bar{x})(y[kn]-\bar{y})}{\sqrt{\sum_k (x[k]-\bar{x})^2 \sum_k (y[kn]-\bar{y})^2}}$CMSIS-DSP提供arm_correlate_fast_q15()但需自己计算均值和方差。我的经验是对实时性要求不高时如后台分析用浮点版更准对实时性要求高时用查表法近似分母——预先计算模板$y[n]$的$\sum (y-\bar{y})^2$作为常量对$x[n]$的方差用滑动窗口均方值近似省去开方运算。常见问题相关峰值检测误触发。原因常是直流偏移未消除。解决方案在相关前对$x[n], y[n]$都做高通滤波一阶RC$y[n] 0.99y[n-1] 0.01(x[n]-x[n-1])$或简单减去滑动平均。我在调试超声波测距时因未去直流相关峰在无目标时也随机跳变加了这个0.01系数的高通后误检率归零。3.4 第四步FFT的嵌入式部署CMSIS与Vivado IP核的抉择逻辑STM32F4的FFT实现有两种主流路径纯软件CMSIS-DSP和硬件加速Vivado FFT IP核需外挂FPGA。选哪个看三个硬指标指标CMSIS-DSP软件FFTVivado FFT IP核FPGA最大点数4096点受限于RAM131072点取决于FPGA资源单次计算耗时1024点0.35msFPU使能168MHz0.08ms时钟200MHz流水线深度12功耗中FPU满载时120mW低FPGA静态功耗50mW动态功耗随点数线性增长开发复杂度低C语言调用高需Verilog/HDL、时序约束、AXI总线集成我的决策树如果项目是便携式设备电池供电且FFT点数≤2048 → 无脑选CMSIS如果要做实时10万点FFT如雷达信号处理且成本允许加FPGA → 选Vivado IP核如果介于两者之间如4096点需低功耗则用CMSIS的arm_rfft_fast_f32()并开启编译器-O3 -ffast-math优化实测比默认设置快22%。CMSIS FFT的关键配置参数S-fftLen: FFT点数必须是2的幂128,256,512,1024...S-ifftFlag: 0为FFT1为IFFTS-bitReverseFlag: 0为自然序输入1为位逆序输入CMSIS内部自动处理一般设0S-pTwiddle: 旋转因子表arm_rfft_init_f32()自动初始化切勿手动修改一个血泪教训某次我为节省RAM把pTwiddle指针指向了未初始化的全局数组FFT结果全为NaN。后来发现CMSIS的arm_rfft_init_f32()不仅初始化旋转因子还校验内存对齐——必须确保pTwiddle地址是16字节对齐用__ALIGNED(16)修饰。这个细节官方文档第37页脚注里提了一句但没人注意。3.5 第五步三者协同的系统级调试用示波器“看见”数学理论再完美不经过示波器验证都是空中楼阁。我的标准调试流程是“三屏对照法”第一屏模拟域示波器CH1接麦克风输出CH2接ADC输入引脚。确认无削波、无高频振铃、共模噪声10mVpp第二屏时域数字用ST-Link Utility实时读取DMA缓冲区将buffer[0..1023]导出为CSV在MATLAB画时域波形。重点看滤波后波形是否平滑卷积效果加窗后首尾是否衰减窗函数作用相关运算输出corr_result[]是否在预期位置有尖峰第三屏频域将FFT结果mag_spectrum[0..511]1024点FFT的前512点幅度谱通过UART发送到PC用Python实时绘图。验证50Hz处是否被压制到-40dB以下滤波器性能主频峰是否锐利窗函数选择正确噪声基底是否平坦ADC参考电压稳定。有一次第三屏显示频谱基底在1kHz以上突然抬升像一座小山。排查两天无果最后回到第一屏发现CH2探头接地线太长形成了天线拾取了开关电源的1.2MHz噪声。换用短地线后基底立刻平坦。这提醒我信号链的每一环从物理连接到数学运算都是脆弱的。你看到的“算法问题”90%是前端硬件问题。4. 工程避坑指南那些只有踩过才懂的“幽灵错误”4.1 卷积相关中的“零填充”陷阱补多少在哪补零填充Zero-Padding不是可选项而是必选项但填错位置和长度后果严重。常见错误有三错误一只给输入补零不给滤波器补零现象FIR滤波后输出波形在末尾出现剧烈振荡。原因arm_fir_f32()要求输入缓冲区长度≥滤波器阶数1。若你只给1024点输入补零到1088点但滤波器系数数组pCoeffs仍是64点函数内部会越界读取后续内存可能是栈变量导致结果随机。正确做法调用前确保pState数组状态缓冲区长度滤波器阶数pCoeffs长度滤波器阶数1并用arm_fir_init_f32()初始化。错误二补零长度不足引发循环卷积混叠现象滤波后信号在起始处出现“鬼影”即本该在t0的脉冲在tN处又出现一个衰减副本。原因线性卷积要求补零后长度$N \geq L_x L_h - 1$。若取$N1024$但$L_x1024, L_h128$则$1024 1024128-11151$混叠必然发生。解决方案计算最小长度$N_{min} L_x L_h - 1$再向上取2的幂。如$N_{min}1151$则取$N2048$。错误三在相关运算中对模板补零而非对信号补零现象相关峰值位置偏移且幅度随偏移量衰减。原因互相关$R_{xy}[n]$定义中$n$是$y$相对于$x$的时移。若你对短模板$y[n]$16点补零到1024点再与$x[n]$1024点做FFT相关相当于把模板拉长成1024点的“稀释版”匹配精度暴跌。正确做法对长信号$x[n]$补零模板$y[n]$保持原长。CMSIS的arm_correlate_fast_q15()正是这样设计的——它把模板当作短序列处理。4.2 FFT的“频谱泄漏”与“栅栏效应”不只是理论名词频谱泄漏Spectral Leakage和栅栏效应Fence Effect是FFT工程应用的两大“幽灵”它们让理论完美的正弦波在屏幕上变成一片模糊的云。频谱泄漏的本质FFT隐含周期延拓假设。若信号截断长度不是正弦波整数周期延拓后会产生不连续点等效于加了一个矩形窗其频谱是sinc函数导致能量扩散到邻近频点。解决方案不是“换窗函数”这么简单而是窗函数选择重叠相加Overlap-Add的组合拳汉宁窗主瓣宽≈4/N旁瓣衰减-31dB适合通用场景Blackman窗主瓣宽≈6/N旁瓣衰减-58dB适合强噪声下弱信号检测Kaiser窗可调参数ββ0时退化为矩形窗β5时接近Blackman。我的经验是对音频分析β3.5旁瓣-40dB是甜点。栅栏效应的本质FFT只能计算离散频率点$f_k k \cdot f_s / N$。若真实频率$f_0$落在两个$f_k$之间能量就会被“栅栏”挡住显示为两侧频点的插值。解决方案零填充插值。对1024点信号补零到4096点再FFT频率分辨率从43Hz提升到10.8Hz再用抛物线插值拟合峰值附近三点可将频率估计精度提升到0.1Hz。CMSIS没有内置插值但arm_max_f32()找到最大值索引后自己写三行代码即可// mag[0..2047]为4096点FFT幅度谱 uint32_t maxIndex; arm_max_f32(mag, 2048, maxVal, maxIndex); // 抛物线插值f_real f_k (mag[k1]-mag[k-1])/(2*(2*mag[k]-mag[k1]-mag[k-1])) * df float df 44100.0f / 4096.0f; // 频率间隔 float f_real maxIndex * df ((mag[maxIndex1] - mag[maxIndex-1]) / (2.0f * (2.0f*mag[maxIndex] - mag[maxIndex1] - mag[maxIndex-1]))) * df;4.3 嵌入式资源冲突FFT、卷积、相关抢夺同一片RAMSTM32F407的SRAM只有192KB但一个1024点float32_t数组就要4KBFFT状态缓冲、FIR状态缓冲、相关结果数组、DMA双缓冲……很快见底。常见冲突场景场景一FFT与FIR共用同一块RAM现象FFT结果偶尔错乱且只在FIR滤波后发生。原因CMSIS的arm_rfft_fast_f32()和arm_fir_f32()都使用pState作为内部工作缓冲。若你把两个函数的pState指向同一块内存它们会互相覆盖。解决方案为每个函数分配独立缓冲区并用static关键字确保不被优化掉static float32_t fftState[2048]; // 1024点FFT需2048点复数缓冲 static float32_t firState[64]; // 64阶FIR需64点状态缓冲 arm_rfft_fast_instance_f32 S_fft; arm_fir_instance_f32 S_fir; arm_rfft_fast_init_f32(S_fft, 1024); arm_fir_init_f32(S_fir, 64, firCoeffs[0], firState[0]);场景二DMA传输与CPU计算争抢总线现象FFT计算耗时不稳定有时0.3ms有时1.2ms。原因ADC DMA在向SRAM搬运数据时CPU同时访问同一块SRAM如读取FIR系数触发总线仲裁CPU被挂起。解决方案将FIR系数数组firCoeffs[]放在CCM RAMCore Coupled Memory64KBCPU专用不与DMA共享或启用DMA双缓冲并在半传输中断中处理前半帧全传输中断处理后半帧让CPU和DMA错峰工作。4.4 “实时性”幻觉你以为的实时其实是伪实时很多项目标称“实时频谱分析”但实测发现当输入信号突变时屏幕刷新滞后200ms。这不是算法慢而是数据流架构设计缺陷。典型伪实时架构ADC采样 → DMA存入BufferA → BufferA满 → 触发中断 → CPU复制BufferA到ProcessingBuffer → FFT计算 → 显示问题在于“复制”步骤1024点float32_t复制需1024×44096字节DMA memcpy需~100μs但若此时ADC仍在往BufferA写就可能覆盖未复制的数据。真实时架构推荐使用内存映射寄存器Memory-Mapped RegisterSTM32F4的ADC有“注入通道DMA”模式可配置为“采样完成立即触发DMA传输”且DMA支持“循环缓冲半传输中断”零拷贝处理让FFT直接在DMA缓冲区上计算。CMSIS的arm_rfft_fast_f32()支持原地计算in-place即输入输出用同一块内存。只要确保DMA传输完成后再启动FFT就无需复制双缓冲乒乓BufferA和BufferB交替CPU处理BufferA时DMA写BufferB处理完立刻切换延迟恒定为一帧时间1024/44100≈23ms。我曾用逻辑分析仪抓取GPIO电平标记处理开始/结束证实真实时架构下从ADC采样到屏幕刷新端到端延迟稳定在23.2±0.3ms而伪实时架构下延迟抖动达±15ms。5. 延伸思考从经典三件套到现代工程前沿的衔接点5.1 自适应图卷积与传统卷积不是替代而是场景升维热搜词里的“自适应图卷积”常被误解为“卷积的升级版”其实它是把卷积的“平移不变性”推广到“图结构不变性”。传统卷积在规则网格图像像素、时序采样点上定义而图卷积在非欧几里得空间如传感器网络拓扑、社交关系图上定义。工程价值在哪举个例子一个分布式振动监测系统有32个加速度传感器布在桥梁不同位置它们不构成规则阵列而是按物理连接关系形成一张图。你想检测局部结构损伤传统方法是每个传感器单独做FFT相关再人工比对。而自适应图卷积可以把32个传感器读数作为图信号学习一个图滤波器$H(G)$自动聚焦于“损伤易发区域”的拓扑邻域。这本质上是把“卷积核$h[n]$”扩展为“图滤波器矩阵$H$”把“滑动窗口”替换为“图傅里叶变换
返回列表