ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

MATLAB源数目估计:AIC、MDL、MEVARC算法对比与实战避坑

MATLAB源数目估计:AIC、MDL、MEVARC算法对比与实战避坑

简介:这份资源面向信号处理、无线通信与阵列信号处理方向的学习者和研究者,聚焦复杂噪声环境下的源信号数目估计问题。压缩包内提供AIC、IAIC、MDL、IMDL与MEVARC五种经典信息准则的MATLAB实现,可用于对比不同算法在模型复杂度与数据拟合度之间的权衡效果,并通过改变信噪比评估各算法在不同噪声条件下的估计准确率。资源共8个文件,以m脚本为主要类型,另含1个asv自动备份文件,整体约5KB,体积轻量便于快速部署与二次修改。目前已有183人学习下载。读者可借助完整代码复现源数目估计流程,绘制性能曲线,直观比较五种准则的优劣,并在此基础上调整参数、替换数据集,为科研实验与教学演示提供可运行的参考方案。

1. 从一次阵列调试翻车说起:这套源数目估计程序到底能干什么

去年帮某实验室调一套均匀线阵的采集系统,八通道数据采回来做空间谱估计,MUSIC 谱峰死活对不上——后来才发现是信源数填错了。信源数多填一个,噪声子空间被压缩,谱峰分裂;少填一个,弱信号直接被当成噪声扔掉。这个“填几”的问题,就是源信号数目估计,也是这套source-number-estimation.rar要解决的核心。

压缩包里是一组 MATLAB 实现的信息准则类估计算法:AIC、IAIC、MDL、IMDL、MEVARC,外加一个compound_matrix.m负责构造阵列协方差矩阵。它适合做阵列信号处理、盲源分离、通信侦察方向的从业者和研究生——你手上有一堆通道数据,需要先判断“到底有几个源”,再往下做 DOA 或分离。整套代码是脚本级的,改改参数就能跑,不需要额外工具箱,拿来当算法对比基线很省事。

2. 信息准则怎么选源数:AIC、MDL 与 MEVARC 的判据差异

2.1 从协方差矩阵特征值说起

源数目估计的物理基础很直接:M 元阵列的协方差矩阵 R 有 M 个特征值,其中大特征值对应信号子空间,小特征值对应噪声子空间。理论上噪声特征值全都相等,等于噪声功率。但实际数据里噪声特征值不会完全相等,所以需要一个“判据”来决定从第几个特征值开始算噪声。

信息准则类方法的通用形式是:

准则值(k) = 拟合优度项(k) + 惩罚项(k)

k 从 0 遍历到 M-1,取准则值最小(或最大,取决于定义)的那个 k 作为估计的源数。拟合优度项衡量“假设有 k 个源时模型对数据的解释程度”,惩罚项衡量“模型复杂度”。两者的权衡方式不同,就分化出了 AIC、MDL 等不同准则。

2.2 五种准则的公式与倾向性

AIC 的判据是:

AIC(k) = -2·N·ln( (∏_{i=k+1}^{M} λ_i)^{1/(M-k)} / (1/(M-k))·∑_{i=k+1}^{M} λ_i ) + 2·k·(2M-k)

其中 N 是快拍数,λ_i 是特征值。第一项是似然函数,第二项是惩罚项。AIC 的惩罚偏轻,倾向于高估源数——这是它的老毛病,小样本时尤其明显。

MDL 把惩罚项换成0.5·k·(2M-k)·ln(N),多了个 ln(N) 因子。N 越大惩罚越重,所以 MDL 是一致估计器,大样本下不会高估,但小样本或低信噪比时容易低估。

IAIC 和 IMDL 是改进版。IAIC 在惩罚项里引入了样本数的修正因子,缓解小样本高估;IMDL 则调整了惩罚系数的形式,让它在中等信噪比区间更稳。具体实现看source_num_est_IAIC.m和source_num_est_IMDL.m,核心差异就在惩罚项那几行。

MEVARC 走的是另一条路——基于期望均方误差的自动相关性判据。它不直接用特征值分解后的似然比,而是构造一个预测误差指标,在最小化预测误差的同时惩罚模型复杂度。source_num_est_MEVRC.m里能看到它和前面几种在循环结构上的明显区别:它多了一层对预测误差的累积计算。

2.3 选型建议:什么场景用哪个

准则倾向性适用场景主要风险
AIC易高估大快拍、高 SNR小样本时源数偏多
IAIC略高估小快拍修正因子需调
MDL易低估大快拍、低 SNR弱源被吞
IMDL较均衡中等 SNR参数敏感
MEVARC较均衡非高斯噪声计算量略大

实操里我一般先跑 MDL 和 AIC 各一遍,如果两者一致,基本可以信;如果不一致,再看 IMDL 和 MEVARC 往哪边靠。num_est_main.m就是干这个的——它把五种准则的结果画在同一张图上,横轴是 SNR,纵轴是估计正确率,一眼就能看出哪种准则在你当前数据条件下更靠谱。

3. 跑通主脚本:从 compound_matrix 到 num_est_main 的完整链路

3.1 数据准备与 compound_matrix.m 的作用

compound_matrix.m负责从原始通道数据构造协方差矩阵。常见做法是用快拍数据做时间平均:

function R = compound_matrix(X, N) % X: M x N 的接收数据矩阵,M 为阵元数,N 为快拍数 % R: M x M 的协方差矩阵 M = size(X, 1); R = (X * X') / N; % 时间平均估计协方差 end

逻辑说明:X * X'是各通道数据的自相关和外相关,除以 N 做归一化。参数 N 是快拍数,直接影响协方差矩阵的估计质量——N 太小,R 本身就不准,后面什么准则都白搭。我一般要求 N 至少是阵元数的 5 到 10 倍。

如果你的数据是实信号,X'用转置即可;如果是复信号(I/Q 数据),X'是共轭转置。这一点在compound_matrix.m里通常用'实现,MATLAB 默认对复数取共轭转置,所以不用改。

3.2 主脚本 num_est_main.m 的运行流程

num_est_main.m是入口脚本,典型结构如下:

% num_est_main.m 主流程 clear; clc; M = 8; % 阵元数 N = 200; % 快拍数 SNR_list = -5:2:20; % SNR 扫描范围 K_true = 3; % 真实源数 for snr_idx = 1:length(SNR_list) SNR = SNR_list(snr_idx); % 生成仿真数据(或加载实测数据) X = generate_data(M, N, K_true, SNR); R = compound_matrix(X, N); % 五种准则分别估计 k_aic = source_num_est_AIC(R, N); k_iaic = source_num_est_IAIC(R, N); k_mdl = source_num_est_MDL(R, N); k_imdl = source_num_est_IMDL(R, N); k_mevarc= source_num_est_MEVRC(R, N); % 记录结果... end % 绘图对比

逻辑说明:外层循环扫 SNR,内层对每个 SNR 点分别调用五种准则。每个source_num_est_*.m的输入都是协方差矩阵 R 和快拍数 N,输出是估计的源数 k。注意source_num_est_MEVRC.m的文件名和函数名可能不完全一致,MATLAB 以文件名为准调用,函数名不一致会报错——这是拿到别人代码后第一个要检查的地方。

参数说明:M是阵元数,必须和你的实际阵列一致;N是快拍数,影响协方差估计精度和 MDL 的惩罚强度;SNR_list是扫描范围,一般从 -5 dB 扫到 20 dB 就能看出算法分化;K_true是仿真时的真实源数,实测数据里没有这个值,只用于验证。

3.3 结果可视化与正确率统计

num_est_main.asv是自动保存的备份文件,内容和num_est_main.m基本一致,不用管它。真正要改的是num_est_main.m里的绘图部分。常见做法是:

% 统计正确率 acc_aic(snr_idx) = mean(k_aic_hist == K_true); % ... 其余四种同理 % 绘图 figure; plot(SNR_list, acc_aic, '-o', SNR_list, acc_mdl, '-s', ... SNR_list, acc_imdl, '-^', SNR_list, acc_mevarc, '-d'); xlabel('SNR (dB)'); ylabel('估计正确率'); legend('AIC','MDL','IMDL','MEVARC'); grid on;

逻辑说明:k_aic_hist是多次蒙特卡洛实验的估计结果向量,mean(k_aic_hist == K_true)算出正确率。一般每个 SNR 点跑 200 到 500 次蒙特卡洛,曲线才平滑。参数上,蒙特卡洛次数越多越稳,但耗时线性增长——调试阶段跑 50 次看趋势,出图再跑 500 次。

4. 避坑与排查:跑这套代码最容易翻车的五个地方

4.1 现象:所有准则都估计成 0 或 M

原因:协方差矩阵构造错误。最常见的是compound_matrix.m里用了X * X.'而不是X * X',对复信号来说少了共轭,R 不是 Hermitian 矩阵,特征值分解结果全乱。

解决:确认数据是实信号还是复信号。复信号必须用'(共轭转置),实信号两者等价。检查方法:ishermitian(R)返回 1 才算对。

4.2 现象:MDL 在小快拍下总是低估

原因:MDL 的惩罚项含ln(N),N 小时惩罚不够重,但拟合优度项本身在小样本下估计不准,导致准则曲线最小值位置偏移。

解决:小快拍场景换用 IMDL 或 IAIC。如果必须用 MDL,把快拍数提到阵元数的 10 倍以上再试。另一个办法是对协方差矩阵做对角加载(R = R + eps * eye(M)),改善小样本下的特征值分布。

4.3 现象:MEVARC 报错“未定义函数”

原因:文件名是source_num_est_MEVRC.m,但函数定义行可能写的是function k = source_num_est_MEVARC(R, N)。MATLAB 调用时以文件名为准,函数名不一致会报未定义。

解决:打开source_num_est_MEVRC.m,把函数定义行的名字改成和文件名一致,或者把文件名改成和函数名一致。这是拿到非自己写的代码后第一件要检查的事。

4.4 现象:SNR 扫描曲线在低 SNR 段全部掉到 0

原因:仿真数据生成时噪声功率计算错误,实际 SNR 比设定值低很多。常见错误是把信号功率和噪声功率的比值算反了,或者噪声用randn生成后没乘噪声标准差。

解决:在generate_data里加一行验证——10*log10(mean(abs(signal).^2)/mean(abs(noise).^2)),打印出来看是否等于设定的 SNR。不等就检查功率计算。

4.5 现象:五种准则结果完全一样

原因:协方差矩阵是单位阵或秩 1 矩阵,所有特征值相等或只有一个非零,准则曲线没有区分度。

解决:检查数据生成部分是否真的产生了 K_true 个独立源。如果源信号之间高度相关(相关系数接近 1),协方差矩阵会降秩,源数估计失效。常见做法是让源信号之间保持低相关,或者用去相关预处理。

5. 进阶技巧:用特征值分布预判准则可靠性

跑完主脚本拿到结果之后,我一般还会多做一步——画特征值分布图。这一步能提前告诉你哪种准则在当前数据下更可信,省得盲目对比。

% 特征值分布预判 [V, D] = eig(R); lambda = sort(diag(D), 'descend'); figure; semilogy(lambda, 'o-'); xlabel('特征值序号'); ylabel('特征值大小'); title('协方差矩阵特征值分布');

逻辑说明:eig(R)做特征值分解,sort降序排列。如果大特征值和小特征值之间有明显的“断崖”,说明信号子空间和噪声子空间分得开,所有准则都容易估对。如果特征值缓慢衰减、没有明显拐点,说明源数估计本身就很困难,这时候准则之间的差异反而更有参考价值——哪种准则在拐点附近更稳定,就优先用它。

参数上,semilogy用对数纵轴,因为噪声特征值通常比信号特征值小几个数量级,线性坐标下看不清。如果断崖出现在第 3 和第 4 个特征值之间,那源数大概率是 3。

还有一个实操习惯:把num_est_main.m里的蒙特卡洛循环改成并行(parfor),500 次实验从几分钟压到几十秒。但注意parfor里不能直接写文件或绘图,统计结果要存成数组在循环外画。

从那以后我每次拿到新的阵列数据,都强制先跑一遍特征值分布,再决定用哪几种准则对比——这个习惯帮我省了不少在错误准则上浪费的时间。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

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