最近也在上阵列信号处理的课程,目前学习的主要内容包括阵列的信号模型、方向图、空时等效、Capon波束形成器、MMSE波束形成器、LCMV波束形成器、GSC波束形成器、传统测向法(比相法、CBF/Bartlett估计器)、MUSIC算法、ESPRIT算法以及空间平滑法。下面主要介绍DOA估计算法,主要内容有:MUSIC算法及改进、MUSIC及Capon法的比较、LS-ESPRIT以及TLS-ESPRIT。本文将介绍前两部分。
时域频谱表示信号在各个频率上的能量分布;空间谱表示信号在空间各个方向上的能量分布。所以如果能够得到信号的空间谱,就能够得到信号的波达方向 (Direction of arrival, DOA) 所以空间谱估计也被称为DOA估计。
瑞利限: 一般的,在一定阵列长度下可达到的最小分辨率称为瑞利限,超过瑞利限的方法被称为 超分辨方法。
以上两种方法属于早期经典的超分辨方法,今天大多数子空间法都是在这两种方法基础上改进的。
算法假设:
1.均匀线阵且阵元间距不大于处理最高频率信号波长的二分之一
2.处理器噪声为加性高斯分布,不同阵元间距噪声均为平稳随机过程,独立同分布,各阵元噪声方差相同
3.信号为零均值平稳随机过程且与噪声独立
4.阵元数大于信源数,信号源为窄带信号且入射信源之间弱相关或者不相关。
##窄带:信号通过天线阵列的时间远远小于信号带宽的倒数
MUSIC算法步骤
1.设置信源、阵列模型、接收信号
2.计算接收信号的协方差矩阵
3.协方差矩阵特征分解,得到特征值
4.特征值由大到小排序,求对应的信号子空间和噪声子空间
5.利用计算MUSIC谱,即噪声功率谱平方和的倒数
6.搜索MUSIC谱的峰值,找到最大的K个谱峰,对应的K个DOA估计的角度
P m u s i c = 1 ∑ i = P + 1 N ∣ v i H a ( θ ) ∣ 2 {P_{music}} = \frac{1}{{{{\sum\limits_{i = P + 1}^N {\left| {v_i^Ha(\theta )} \right|} ^2}}}} Pmusic=i=P+1∑N∣∣viHa(θ)∣∣21,其中N为阵元数,P为信号子空间数, v i {v_i} vi为特征向量。
下面通过仿真来对比一下MUSIC与Capon的区别,参考的文章中给出了不同信噪比下以及不同角度间隔下两种方法的估计误差。
1. 信噪比
设置阵元数为10,阵元间隔为半波长,信源数为3(-10度,0度,20度),快拍数为1024,下图为估计得到的信号谱,左侧信噪比设置为-8dB,右侧信噪比设置为10dB。


关于谱峰强度的解释:
MUSIC谱峰只反映阵列流形矢量与噪声子空间的正交性,与信噪比无关;
Capon谱峰是真正的输出功率,与信噪比有关。
2.角度间隔/分辨率
设置阵元数为10,阵元间隔为半波长,信源数为3(-0.5度,0度,0.5度),快拍数为1024,信噪比设置为10dB,下图为估计得到的信号谱,为方便观察进行了归一化。
可以看到这种情况下,MUSIC的分辨率是优于Capon法的。
上述仿真分析感觉也不是特别严谨,至于两种方法谁好谁坏,在处理具体问题的时候都试一下哪个好就用哪个吧😄😄
下面给出仿真代码
clear all;
close all
clc;
source_number=3;%信元数
sensor_number=10;%阵元数
N_x=1024; %信号长度
snapshot_number=N_x;%快拍数
w=[pi/4 pi/6 pi/3].';%信号频率 三个非相干元
l=sum(2*pi*3e8./w)/3;%信号波长
d=0.5*l;%阵元间距
snr=10;%信噪比
source_doa=[-0.5 0 0.5];%两个信号的入射角度
A=[exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(1)*pi/180)/l);exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(2)*pi/180)/l);exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(3)*pi/180)/l)].';%阵列流型
s=sqrt(10.^(snr/10))*exp(1j*w*[0:N_x-1]);%仿真信号
x=awgn(A*s,snr);
R=x*x'/snapshot_number;
inv_R=inv(R);
[V,D]=eig(R);
Un=V(:,1:sensor_number-source_number);%信源已知,直接划分
Gn=Un*Un';
searching_doa=-90:0.1:90;%线阵的搜索范围为-90~90度
for i=1:length(searching_doa)
a_theta=exp(-1j*(0:sensor_number-1)'*2*pi*d*sin(pi*searching_doa(i)/180)/l);
Pmusic(i)=a_theta'*a_theta./abs((a_theta)'*Gn*a_theta);
Pcapon(i)=1./abs((a_theta)'*inv_R*a_theta);
end
plot(searching_doa,10*log10(Pmusic/max(Pmusic)),'k-',searching_doa,10*log10(Pcapon/max(Pcapon)),'b--');
xlabel('DOAs/degree');
xlim([-5 5])
ylabel('Normalized Spectrum/dB');
legend('Music Spectrum','Capon Spectrum');
title('Comparation of MUSIC and Capon for DOA Estimation');
grid on;
从代码上看还是很简单的,可以通过修改线阵搜索的步进值实现分辨率一定程度上地提高。
1. 信源数未知——>一维噪声子空间法(加权子空间法的特例)
2. 色噪声——>基于高阶统计量的阵列处理
3. 快拍数有限——>求根MUSIC
4. 信噪比低——>加权MUSIC
5. 相干源
...
相干源下的MUSIC算法
对于相干源,采取的措施是将信号取共轭重排之后计算自相关后与原信号自相关相加,再进行MUSIC算法。
仿真参数与上文一致,只是信号频率变为[pi/4, pi/6, pi/4],入射角度为[-10, 0, 10],结果如下图所示

从上图可以看到,MUSIC算无法估计出正负10度的两个相干信号,而相干的MUSIC算法实现了精确的估计。
下面给出仿真代码
clc
clear all
close all
source_number=3;%信元数
sensor_number=10;%阵元数
N_x=1024; %信号长度
snapshot_number=N_x;%快拍数
w=[pi/4 pi/6 pi/4].';%信号频率 三个非相干元
l=sum(2*pi*3e8./w)/3;%信号波长
d=0.5*l;%阵元间距
snr=10;%信噪比
source_doa=[-10 0 10];%两个信号的入射角度
A=[exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(1)*pi/180)/l);exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(2)*pi/180)/l);exp(-1j*(0:sensor_number-1)*d*2*pi*sin(source_doa(3)*pi/180)/l)].';%阵列流型
s=sqrt(10.^(snr/10))*exp(1j*w*[0:N_x-1]);%仿真信号
x=awgn(A*s,snr);
% x=A*s+(1/sqrt(2))*(randn(sensor_number,N_x)+1j*randn(sensor_number,N_x));%加了高斯白噪声后的阵列接收信号
R=x*x'/snapshot_number;
B=eye(sensor_number);
J=fliplr(B);
Y=J*conj(x);
R1=Y*Y'/snapshot_number;
R2=R1+R;
%相干music
[V,D]=eig(R2);
[lamda,index]=sort((diag(D)));
UU=V(:,index(1:source_number)); %噪声子空间
Gn_music=UU*UU';
%music
[V_m,D_m]=eig(R);
[lamda_m,index_m]=sort((diag(D_m)));
Un=V_m(:,index(1:source_number));
Gn_mmusic=Un*Un';
searching_doa=-90:0.1:90;%线阵的搜索范围为-90~90度
for i=1:length(searching_doa)
a_theta=exp(-1j*(0:sensor_number-1)'*2*pi*d*sin(pi*searching_doa(i)/180)/l);
Pmusic(i)=a_theta'*a_theta./abs((a_theta)'*Gn_music*a_theta);
Pmmusic(i)=a_theta'*a_theta./abs((a_theta)'*Gn_mmusic*a_theta);
end
plot(searching_doa,10*log10(Pmusic/max(Pmusic)),'k-',searching_doa,10*log10(Pmmusic/max(Pmmusic)),'b--');
xlabel('DOAs/degree');
% xlim([-5 5])
ylabel('Normalized Spectrum/dB');
legend('相干Music','Music');
title('Comparation of MUSIC and Capon for DOA Estimation');
grid on;
#-----------------------------------------------------------------------------总结---------------------------------------------------------------------------------#
本文主要进行了较为基础的MUSIC算法的实现以及与Capon方法的对比,涉及到的相关代码均已给出,供大家参考。
#-------------------------------------------------------------------------下一步计划----------------------------------------------------------------------------#
#--------------------------------------------------------------------------参考文献------------------------------------------------------------------------------#
《现代数字信号处理》——王展,李双勋等
《最优阵列处理技术》——Harry L. Van Trees…
《The Difference Between Capon and MUSIC Algorithms》 Huiping Huang
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in
我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby-vips的github页面上的链接,我们将不胜感激!如果有ruby-
我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d
给定两个大小相等的数组,如何找到不考虑位置的匹配元素的数量?例如:[0,0,5]和[0,5,5]将返回2的匹配项,因为有一个0和一个5共同;[1,0,0,3]和[0,0,1,4]将返回3的匹配项,因为0有两场,1有一场;[1,2,2,3]和[1,2,3,4]将返回3的匹配项。我尝试了很多想法,但它们都变得相当粗糙和令人费解。我猜想有一些不错的Ruby习惯用法,或者可能是一个正则表达式,可以很好地回答这个解决方案。 最佳答案 您可以使用count完成它:a.count{|e|index=b.index(e)andb.delete_at
我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。