ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ARMA与MA模型谱估计的MATLAB实现:从修正协方差法到Durbin两步法

ARMA与MA模型谱估计的MATLAB实现:从修正协方差法到Durbin两步法 简介ARMA与MA谱估计算法的MATLAB实现源码是面向雷达专业与信号处理专业学生的入门级代码包主要用于构建LFM信号模型并依次完成ARMA估计和MA估计两项核心任务。整个资源压缩包内一共只有2个m脚本文件整体压缩后大小仅2KB代码体量非常轻量但胜在编写规范、注释清晰适合在MATLAB中直接运行和学习能够帮助读者快速抓住时域信号谱估计的编程主线。目前该资源已有789人学习浏览属于较受欢迎的入门级谱估计例程尤其适合初学者结合教材理解理论并动手在MATLAB环境中验证算法效果。借助这套源码读者可以掌握LFM信号模型的构建方法清晰对比ARMA与MA两类估计算法在实现思路上的差异同时借助详细注释理解算法关键步骤和参数设置从而为后续开展现代谱估计的深入研究奠定基础。1. 谱估计绕不开ARMA与MA模型但大多数工程现场只缺一套能跑的MATLAB源码接手过振动信号、脑电、水声或雷达回波的人大概都有同感FFT给出频谱只需要一行可一旦数据短、信噪比低或者峰值需要精确到几个频率分辨率以内周期图的方差和旁瓣会让人反复怀疑传感器坏了。这时候把数据当作随机过程的观测值用ARMA、MA这类参数化模型去做谱估计往往比直接加窗做FFT更稳。ARMA模型同时包含极点和零点能用较少的参数描述尖峰加陷波的谱形MA模型全零点结构则适合功率谱比较平坦、只有陷波的应用。本文给的是可以直接复制的MATLAB源码算法落点放在修正协方差法和Durbin两步法上再补上定阶和矩阵求逆的坑。2. 用修正协方差法把ARMA谱估计落到MATLAB参数怎么定、源码怎么读2.1 修正协方差法为什么适合ARMA谱估计ARMA(p,q)谱估计的直接思路是先用某种方法估计AR参数再估计MA参数。工程上更常用的替代做法是用一个足够高阶的AR(p)模型去逼近ARMA谱。因为ARMA谱可以写成AR(∞)的收敛级数只要阶数选得够高全极点谱就能把ARMA谱中的尖峰和陷波一并表达。这个思路最扎实的落地算法是修正协方差法它在信号处理工具箱里有现成函数但函数内部的关键参数不可见真要改造成流式处理或固定点运算还是得有一份自己能改的源码。修正协方差法与前向预测法和后向预测法的差别在于它把前向预测误差平方和与后向预测误差平方和同时拿来最小化因此数据两端的信息都进了估计特别适合短记录、低频成分明显的数据。对一段长度为N的信号使用p阶AR模型前向误差为e_f(n)x(n)Σ_{k1}^{p}a(k)x(n-k)后向误差为e_b(n)x(n-p)Σ_{k1}^{p}a*(k)x(n-pk)。优化目标变成min Σ|e_f(n)|²Σ|e_b(n)|²。当噪声是白噪声且模型阶数正确时这个准则等价于最大似然估计。2.1.1 从全极点谱逼近看ARMA的谱形优势全极点谱数值上比ARMA的零极点谱稳定。零点信息通常表现为频谱凹陷改用高阶AR逼近时凹陷会由若干极点间的干涉近似出来代价是阶数要更高谱线更细碎。所以ARM谱估计的实际操作里定阶比选算法更直接影响结果p太小峰会被抹平成圆包p太大谱线分裂成假峰。这段源码里把定阶参数留给调用方就是方便在不同信噪比下做对比。2.2 armcov_spec.m 源码实现与逐段说明function [a, Pxx, f] armcov_spec(x, p, nfft, fs) % 修正协方差法ARMA谱估计 % 输入: x 列向量信号, p AR阶数, nfft 频率点数, fs 采样率 % 输出: a AR系数(首项为1), Pxx 功率谱密度, f 频率轴 x x(:); N length(x); if nargin 4, fs 1; end x x - mean(x); % 去均值直流分量会污染自相关 % 前向观测矩阵A1第k列为x(n-k)方程A1*a -x(p1:N) A1 zeros(N-p, p); for k 1:p A1(:, k) x(p-k1 : N-k); end b1 -x(p1 : N); % 后向观测矩阵A2第k列为x(nk)方程A2*a -x(1:N-p) A2 zeros(N-p, p); for k 1:p A2(:, k) x(k1 : N-pk); end b2 -x(1 : N-p); A [A1; A2]; b [b1; b2]; a (A*A 1e-6*eye(p)) \ (A*b); % 加对角扰动防奇异 a [1; a]; % 残差方差即白噪声驱动方差 resid [A1*a(2:end)b1; A2*a(2:end)b2]; sigma2 mean(abs(resid).^2); % 频率响应H(w)1/(1sum a_k e^{-jwk}) w 2*pi*(0:nfft-1)/nfft; H ones(nfft,1); for k 1:p H H a(k1) * exp(-1j*w(:)*k); end Pxx sigma2 ./ abs(H).^2; f w/(2*pi)*fs; end这段代码把修正协方差法拆成了最小二乘问题求解。前向矩阵A1的第k列从x(p-k1)取到x(N-k)对应“用x(n-1)到x(n-p)预测x(n)”的所有时刻后向矩阵A2的第k列取x(k1)到x(N-pk)对应逆向预测。合并成A后用正规方程求最小二乘解其中1e-6*eye(p)是关键保护项避免N接近p时自相关阵奇异。参数说明p是AR模型阶数不是ARMA的总阶数。想表达ARMA(4,2)这样的峰加陷波常见做法是把p取到8到12之间靠高阶逼近。nfft只影响谱线插值密度不改变分辨率取256或512对工程判断已经足够。fs用于把归一化频率换算成物理频率如果只关心谱形fs保持默认1即可。% 调用示例 fs 1000; t (0:999)/fs; x sin(2*pi*80*t) 0.5*sin(2*pi*180*t) 0.1*randn(size(t)); [a, Pxx, f] armcov_spec(x, 10, 512, fs); plot(f, 10*log10(Pxx));调用示例展示了最短用法10阶AR模型512点频率插值。如果谱峰位置对不上预期频率先检查p是否过低再检查去均值是否生效不要一上来就动nfft。2.3 参数对照表与nfft、采样率的关系参数常见取值对结果的影响注意事项p4~20过小峰变宽过大会谱线分裂随N增大可适当加大但不要超过N/3nfft256/512/1024只影响曲线平滑度不提高真实频率分辨率fs实际采样率只改变f轴标注Pxx数值不随fs归一化会差分位N越长越好方差小条件数好短数据时优先提高p而不是N这里有个容易被忽略的点改变fs只影响输出f轴不会改变Pxx的量纲。要得到单位Hz内功率密度需要对Pxx除以fs后再画图。对于谱峰频率的工程判断用默认fs1看相对位置就好。3. MA谱估计源码先用Durbin两步法再看Blackman-Tukey基线3.1 MA(q)的谱估计本质上在估计自相关而不是在估计相位MA(q)模型表达式为x(n)σw(n)Σ_{k1}^{q}b(k)w(n-k)它的自相关函数在滞后大于q时严格为零功率谱是P(f)σ²|1Σ_{k1}^{q}b(k)e^{-j2πfk}|²。从表达式能看出来MA谱完全不携带相位信息任何相位谱都是白噪声驱动的产物。这意味着估计MA谱的第一任务是自相关函数的准确估计而不是精确求b(k)。第二任务才是从自相关反解b(k)得到更紧凑的模型描述。3.1.1 两种MA谱估计路径怎么选工程上有两条路一条是用Blackman-Tukey法估计自相关并加窗再FFT也就是直接按MA(q)的定义实现另一条是Durbin两步法先拟合一个高阶AR模型再用AR参数反推MA系数。前者实现简单但窗函数会压低峰值后者参数空间更小、谱峰更尖锐代价是阶数选择多了一个自由度。信号里的峰明确、需要准确峰值频率时我个人会优先用Durbin两步法只是要一块平滑的底噪谱黑曼-图基法更快。3.2 ma_durbin.m先用长AR参数反解MA系数的MATLAB函数function [b, Pma, f] ma_durbin(x, q, p_ar, nfft) % Durbin两步法MA谱估计 % 输入: x 列向量信号, q MA阶数, p_ar 中间AR阶数, nfft 频率点数 % 输出: b MA系数(首项为1), Pma 功率谱, f 频率轴 x x(:); N length(x); x x - mean(x); % 第一步Yule-Walker估计p_ar阶AR参数 r xcorr(x, p_ar, biased); r r(p_ar1 : end); % r(0)到r(p_ar) R toeplitz(r(1:p_ar)); % 自相关矩阵 alpha R \ (-r(2:p_ar1)); % AR系数注意符号 % 第二步MA(q)展开成AR(∞)用alpha截断解b % 对kqalpha_k b1*alpha_{k-1} ... bq*alpha_{k-q} 0 J zeros(p_ar-q, q); for k q1:p_ar for i 1:q J(k-q, i) alpha(k-i); end end b J \ (-alpha(q1:end)); % 最小二乘解 b [1; b]; % 谱计算并归一化保证总功率等于序列方差 w 2*pi*(0:nfft-1)/nfft; B ones(nfft,1); for k 1:q B B b(k1) * exp(-1j*w(:)*k); end Pma abs(B).^2; Pma Pma / mean(Pma) * var(x); % 功率对齐 f w/(2*pi); endDurbin方法的核心直觉是一个可逆的MA(q)过程也可以表示成无穷阶AR过程。第一步用Yule-Walker估出的alpha就是该无穷阶AR过程的截断第二步利用MA的AR展开系数满足线性递推的性质把alpha代入递推方程解得MA系数。代码里的J矩阵每一行对应一个kq的递推方程未知量是b(1)到b(q)这就是“反解”二字的来处。最后一步功率归一化值得说清楚。谱形状由多项式模长决定绝对功率靠白噪声方差σ²抬升而σ²从Yule-Walker估计出来会有偏差。直接把Pma的平均值对齐到var(x)保证积分功率和信号实际方差一致。这个处理在特征提取场景下很管用比纠结于σ²的估计偏差来得实用。% Blackman-Tukey基线版本两行核心语句 r xcorr(x-mean(x), q, biased); Pbt abs(fft(r(q1:end), nfft));基线版本里r(q1:end)是r(0)到r(q)正好截断MA(q)的有效自相关区间。想加窗就把r乘上hamming(2*q1)代价是3dB带宽增加约20%。对比这两份代码同一段数据下Durbin谱的峰会更细BT谱更平滑。3.3 参数对照表q、p_ar怎么定以及频谱归一化逻辑参数常见取值影响说明q2~8q太小吻合不了陷波太大会进入噪声细节对应真实自相关非零的最大滞后p_ar3q~6q越大反解的b越稳定超过N/2时方程会病态nfft256~1024只影响频率插值不算分辨率指标p_ar与q的比例是Durbin方法的成败关键。p_ar取3倍q时递推方程数量已经够多超过6倍q后J矩阵接近病态b的波动反而变大。短数据上我一般固定p_ar4*q然后只扫q避免两个自由度同时调整导致调参无法归因。4. 定阶准则、矩阵条件数与工具箱选型漏一个都会让源码失去意义4.1 AIC与BIC定阶的MATLAB循环写法function [p_aic, p_bic] choose_ar_order(x, pmax) % 用AIC/BIC自动选择ARM谱估计的AR阶数 N length(x); x x(:) - mean(x); aic zeros(pmax,1); bic zeros(pmax,1); for p 1:pmax [~, e] arcov(x, p); % e是残差方差估计 aic(p) N*log(e) 2*p; bic(p) N*log(e) p*log(N); end [~, p_aic] min(aic); [~, p_bic] min(bic); endarcov是信号处理工具箱里的协方差法函数返回残差方差e和反射系数。AIC惩罚项2p对阶数宽容适合谱峰较多的数据BIC惩罚项p*log(N)更严厉适合信噪比高、模型确实低阶的场景。两个准则给出的阶数差3以上时要警惕数据里有非平稳成分或强线谱。4.2 cond(R)对谱估计结果的量化影响自相关矩阵Rtoeplitz(r)的条件数直接决定Yule-Walker方程解的可信度。N256、p16时cond(R)通常在1e4到1e6之间信号含两个间隔很近的线谱时条件数可以到1e8以上。这时候alpha的数值会把谱峰位置推到正确值附近但峰宽和峰高会抖。4.2.1 加正则化还是换函数三个对比结论第一用修正协方差法源码时加1e-6对角扰动就够不需要上岭回归。第二用工具箱函数时armcov与pmcov在同样阶数下结果几乎一致pmcov对相位做了共轭对齐适合复数信号。第三Levinson递推解Yule-Walker比直接左除快但复数信号需要把递推改成复反射系数版本bug率显著提高。能直接用矩阵左除就别手动实现递推这是把时间花在信号上的聪明选择。4.3 自写源码与matlab优化工具箱内置函数的取舍函数所属工具箱适用场景注意点arcov信号处理AR系数快速定阶返回e是方差不是平方和pmcov信号处理复数信号ARMA谱估计不能输出模型系数时选armcovarma系统辨识时域模型参数估计不直接给谱要自己算频率响应自写armcov_spec无依赖学习、改造、嵌入性能比pmcov慢约30%armcov_spec里我刻意不调用任何工具箱专属函数这样在Octave以及深度学习的MATLAB代码生成流程里都能直接编译。做深度学习matlab特征提取时这种不依赖工具箱的源码反而是优势代码生成器不会因为工具箱函数而报错。代价是速度略慢但对N小于1e4的场景无感。matlab优化工具箱里的lsqnonlin也可以拟合ARMA系数那是另一条路把a和b拼成参数向量做非线性最小二乘效果好但慢而且初值给不好就陷入局部极小日常排错时不推荐。5. 用仿真信号验证这四个源码函数并顺手把内存占用压下来5.1 双正弦加噪声信号的端到端验证fs 1000; N 2048; t (0:N-1)/fs; x sin(2*pi*123*t) 0.4*sin(2*pi*290*t) 0.1*randn(size(t)); [a, P1, f] armcov_spec(x, 14, 1024, fs); [b, P2, ~] ma_durbin(x, 4, 16, 1024); [~, i1] max(P1); [~, i2] max(P2); fprintf(ARMA峰: %.2f Hz, MA峰: %.2f Hz\n, f(i1), f(i2));两个峰分别在123Hz和290Hz信噪比不低时armcov_spec的谱峰位置误差应小于1Hzma_durbin的谱峰偏宽误差会到2Hz左右。若误差明显偏大优先怀疑p太低而不是nfft不够。验证时看两个指标峰值频率误差和峰底宽度。5.2 数据长度N大于5000时的内存优化与嵌入式风格写法armcov_spec里最占内存的是A矩阵尺寸为2*(N-p)×p。N5000、p20时矩阵就有近20万个元素内存尚可N5e5时矩阵内存会破GB级。此时不要直接堆矩阵先对数据做分段估计再平均谱或者沿时间轴抽取间隔样本。另一个嵌入式内核源码级别的做法是把A1和A2按块写入用完一块就求一次A*A的累加项不保留整个A。也就是说用a_new (ΣA_iA_i)(ΣA_ib_i)的累加方式内存从O(Np)降到O(p²)代价是代码多一个for循环。嵌入式风格写法里用单精度取代双精度可以再降一半内存但条件数超过1e6时单精度解会出现可测量的谱峰偏移取舍时要掂量。实测小批量数据用armcov_spec大数据换累加块的版本是我在长时间连续采集场景下的标准动作。p、q两个阶数的自动定阶已经写进choose_ar_order把这几个函数存成独立m文件后续项目直接复用即可。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进