声源定位系统设计(二)——MUSIC算法以及Python代码实现
声源定位系统设计(二)——MUSIC算法以及Python代码实现目录声源定位系统设计(二)——MUSIC算法以及Python代码实现一、前言二、MUSIC算法三、MVDR代码实现四、MUSIC算法代码实现一、前言上篇博客中已经详细介绍了声源定位的一些概念以及MVDR波束形成法的原理,在本篇博客中,我将介绍另一种更为精准的波束形成算法:MUSIC算法以及这两种算法的Python代码实现。二、MUSI
声源定位系统设计(二)——MUSIC算法以及Python代码实现
上一篇:声源定位系统设计(一)——MVDR波束形成算法讲述了声源定位系统的一些基本概念以及MVDR算法的原理。
一、前言
上篇博客中已经详细介绍了声源定位的一些概念以及MVDR波束形成法的原理,在本篇博客中,我将介绍另一种更为精准的波束形成算法:MUSIC算法以及这两种算法的Python代码实现。
二、MUSIC算法
MUSIC(Multiple Signal Classification)算法的方法类似于MVDR算法,只是在最后计算的时候有些许不同。该算法建立在一下假设基础上:
①、噪声为高斯分布,每个麦克风之间的噪声分布为随机过程,之间相互独立,空间平稳,即每个麦克风噪声方差相等。
②、要求空间信号为高斯平稳随机过程,且与单元麦噪声互不相干,相互独立。
③、目标声源数目小于阵列元数目。
④、阵元间隔不大于来波信号中频率最高波长的1/2。
MUSIC算法是空间谱估计技术的代表之一,它利用特征结构分析。其基本原理是将协方差矩阵进行特征值分解。它通常把空间信号分为两种,一种是信号特征向量对应的信号空间,另一种是噪声向量对应的噪声空间,利用噪声空间和信号空间的正交性原理,构造空间谱函数进行搜索,从而预估出DOA信息。
按照上一篇博客的做法,阵列数据的协方差矩阵为:
R
=
E
[
X
(
t
)
X
H
(
t
)
]
=
A
R
S
A
+
R
N
R=E[X(t)X^H(t)]=AR_SA+R_N
R=E[X(t)XH(t)]=ARSA+RN
其中,
R
S
R_S
RS和
R
N
R_N
RN分别为信源的协方差矩阵和噪源的协方差矩阵。
通过对阵列协方差矩阵进行特征值分解,将特征值进行升序排列,其中有D个较大的特征值,对应于声源信号,而有M-D个较小的特征值,对应于噪声信号。
设
λ
i
\lambda_i
λi为第i个特征值,
v
i
v_i
vi为其对应的特征向量,则:
R
v
i
=
λ
i
v
i
Rv_i=\lambda_i v_i
Rvi=λivi
设
λ
i
=
σ
2
\lambda_i=\sigma^2
λi=σ2是R的最小特征值,则:
R
v
i
=
σ
2
v
i
,
i
=
D
+
1
,
D
+
2
,
.
.
.
,
M
Rv_i=\sigma^2v_i,i=D+1,D+2,...,M
Rvi=σ2vi,i=D+1,D+2,...,M
将
R
=
A
R
S
A
H
+
σ
2
I
R=AR_SA^H+\sigma^2I
R=ARSAH+σ2I代入上式得:
σ
2
v
i
=
(
A
R
S
A
H
+
σ
2
I
)
v
i
\sigma^2v_i=(AR_SA^H+\sigma^2I)v_i
σ2vi=(ARSAH+σ2I)vi
化简可得:
A
R
S
A
H
v
i
=
0
AR_SA^Hv_i=0
ARSAHvi=0
由于
A
H
A
A^HA
AHA是满秩矩阵,
(
A
H
A
)
−
1
(A^HA)^{-1}
(AHA)−1存在,而
R
S
−
1
R_S^{-1}
RS−1也存在,则上式同乘以
R
S
−
1
(
A
H
A
)
−
1
A
H
R_S^{-1}(A^HA)^{-1}A^H
RS−1(AHA)−1AH后变成:
R
S
−
1
(
A
H
A
)
−
1
A
H
A
R
S
A
H
v
i
=
0
R_S^{-1}(A^HA)^{-1}A^HAR_SA^Hv_i=0
RS−1(AHA)−1AHARSAHvi=0
于是有
A
H
v
i
=
0
,
i
=
D
+
1
,
D
+
2
,
.
.
.
,
M
A^Hv_i=0,i=D+1,D+2,...,M
AHvi=0,i=D+1,D+2,...,M
故可以用噪声向量来求信号源的角度。先构造噪声矩阵
E
n
E_n
En
E
n
=
[
v
D
+
1
,
v
D
+
2
,
.
.
.
v
M
]
E_n=[v_{D+1},v_{D+2},...v_M]
En=[vD+1,vD+2,...vM]
最后定义空间谱
P
(
θ
)
P(\theta)
P(θ)
P
(
θ
)
=
1
a
H
(
θ
)
E
n
E
n
H
a
(
θ
)
P(\theta)=\frac{1}{a^H(\theta)E_nE_n^Ha(\theta)}
P(θ)=aH(θ)EnEnHa(θ)1
其中a为上一篇博客中的方向导向向量,通过遍历
θ
\theta
θ,即可得到一个空间的功率谱,寻找其最值即可寻得DOA方向角。二维的估计也想同,增加一个遍历的维度即可。
三、MVDR算法代码实现
直接上代码了:
我这里用了一个16阵元的麦克风阵列信号采集板。设计两层圆阵。
nmicro = 16
layers = 2
micros_every_layer = nmicro//layers
R = [0.082, 0.103]
theta_micro = np.zeros(nmicro)#所有麦克风阵元的角度
for layer in range(layers):
theta_micro[micros_every_layer*layer:micros_every_layer*(layer+1)] = \
2*np.pi/micros_every_layer*(np.arange(micros_every_layer)+0.5*layer)
#所有麦克风阵元的坐标
pos = np.concatenate((np.stack([R[0] * np.cos(theta_micro[:8]), R[0] * np.sin(theta_micro[:8]), np.zeros(8)],axis = 1), \
np.stack([R[1] * np.cos(theta_micro[8:]), R[1] * np.sin(theta_micro[8:]), np.zeros(8)],axis = 1)), axis=0)
#PyAudio的信号采集参数
CHUNK = 1600
FORMAT = pyaudio.paInt16
CHANNELS = 18
RATE = 16000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
#最后求得的声源位置
xr = 0
yr = 0
#遍历的x和y,假设z为固定深度1m
X_STEP = 20
Y_STEP = 20
x = np.linspace(-0.4, 0.4, X_STEP)
y = np.linspace(-0.4, 0.4, Y_STEP)
z = 1
def beamforming():
global xr, yr, x, y
while True:
data = stream.read(1600)
data = np.frombuffer(data, dtype=np.short)
data = data.reshape(1600,18)[:,:16].T
p = np.zeros((x.shape[0], y.shape[0]))#声强谱矩阵
#傅里叶变换,在频域进行检测
data_n = np.fft.fft(data)/data.shape[1]# [16,1600]
data_n = data_n[:, :data.shape[1]//2]
data_n[:, 1:] *= 2
#宽带处理,对于50个不同的频率都进行计算
#r存储每个频率下对应信号的R矩阵
r = np.zeros((50, nmicro, nmicro), dtype=np.complex)
for fi in range(1,51):
rr = np.dot(data_n[:, fi*10-10:fi*10+10], data_n[:, fi*10-10:fi*10+10].T.conjugate())/nmicro
r[fi-1,...] = np.linalg.inv(rr)
#MVDR搜索过程
for i in range(x.shape[0]):
for j in range(y.shape[0]):
dm = np.sqrt(x[i]**2+y[j]**2+z**2)
delta_dn = pos[:,0]*x[i]/dm + pos[:,1]*y[j]/dm
for fi in range(1,51):
a = np.exp(-1j*2*np.pi*fi*100*delta_dn/340)
p[i,j] = p[i,j] + 1/np.abs(np.dot(np.dot(a.conjugate(), r[fi-1]), a))
xr = np.argmax(p)//Y_STEP
yr = np.argmax(p)%Y_STEP
print(x[xr],y[yr])
#转为强度0-1
p /= np.max(p)
绘制声强图
x1, y1 = np.meshgrid(x,y)
ax = plt.axes(projection='3d')
ax.plot_surface(x1,y1,np.abs(p.T))
plt.pause(0.01)
if __name__='__main__':
while True:
beamforming()
四、MUSIC算法代码实现
阵列与MVDR相同
nmicro=16
layers = 2
micros_every_layer = nmicro//layers
R = [0.082, 0.103]
theta_micro = np.zeros(nmicro)#所有麦克风阵元的角度
for layer in range(layers):
theta_micro[micros_every_layer*layer:micros_every_layer*(layer+1)] = \
2*np.pi/micros_every_layer*(np.arange(micros_every_layer)+0.5*layer)
#所有麦克风阵元的坐标
pos = np.concatenate((np.stack([R[0] * np.cos(theta_micro[:8]), R[0] * np.sin(theta_micro[:8]), np.zeros(8)],axis = 1), \
np.stack([R[1] * np.cos(theta_micro[8:]), R[1] * np.sin(theta_micro[8:]), np.zeros(8)],axis = 1)), axis=0)
#PyAudio的信号采集参数
CHUNK = 1600
FORMAT = pyaudio.paInt16
CHANNELS = 18
RATE = 16000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
#最后求得的声源位置
xr = 0
yr = 0
#遍历的x和y,假设z为固定深度1m
X_STEP = 20
Y_STEP = 20
x = np.linspace(-0.4, 0.4, X_STEP)
y = np.linspace(-0.4, 0.4, Y_STEP)
z = 1
def beamforming():
global xr, yr, ifplot, x, y
while True:
data = stream.read(1600)
data = np.frombuffer(data, dtype=np.short)
data = data.reshape(1600,18)[:,:16].T
data_n = np.fft.fft(data)/data.shape[1]# [16,1600]
data_n = data_n[:, :data_n.shape[1]//2]
data_n[:, 1:] *= 2
r = np.zeros((50, nmicro, nmicro-1), dtype=np.complex)
for fi in range(1,51):
rr = np.dot(data_n[:, fi*10-10:fi*10+10], data_n[:, fi*10-10:fi*10+10].T.conjugate())/nmicro
feavec,_,_ = np.linalg.svd(rr)
r[fi-1,...] = feavec[:, 1:]
p = np.zeros((x.shape[0], y.shape[0]))
for i in range(x.shape[0]):
for j in range(y.shape[0]):
dm = np.sqrt(x[i]**2+y[j]**2+z**2)
delta_dn = pos[:,0]*x[i]/dm + pos[:,1]*y[j]/dm
for fi in range(1,51):
a = np.exp(-1j*2*np.pi*fi*100*delta_dn/340)
p[i,j] = p[i,j] + 1/np.abs(np.dot(np.dot(np.dot(a.conjugate(), r[fi-1]), r[fi-1].T.conjugate()), a))
#n = np.argmin(np
xr = np.argmax(p)//Y_STEP
yr = np.argmax(p)%Y_STEP
print(x[xr],y[yr])
p /= np.max(p)
x1, y1 = np.meshgrid(x,y)
ax = plt.axes(projection='3d')
ax.plot_surface(x1,y1,np.abs(p.T))
plt.pause(0.01)
上一篇:声源定位系统设计(一)——MVDR波束形成算法讲述了声源定位系统的一些基本概念以及MVDR算法的原理。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)