波达方向估计(DOA)-Python代码实现MUSIC/ESPRIT

https://mp.weixin.qq.com/s/erv-2CvAJpPn585WERpx-w

import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as LA
import scipy.signal as ss


# Functions
def array_response_vector(array, theta):
    N = array.shape
    v = np.exp(1j * 2 * np.pi * array * np.sin(theta))
    return v / np.sqrt(N)


def music(CovMat, L, N, array, Angles):
    # CovMat is the signal covariance matrix, L is the number of sources, N is the number of antennas
    # array holds the positions of antenna elements
    # Angles are the grid of directions in the azimuth angular domain
    _, V = LA.eig(CovMat)
    Qn = V[:, L:N]
    numAngles = Angles.size
    pspectrum = np.zeros(numAngles)
    for i in range(numAngles):
        av = array_response_vector(array, Angles[i])
        pspectrum[i] = 1 / LA.norm((Qn.conj().transpose() @ av))
    psindB = np.log10(10 * pspectrum / pspectrum.min())
    DoAsMUSIC, _ = ss.find_peaks(psindB, height=1.35, distance=1.5)
    return DoAsMUSIC, pspectrum


def esprit(CovMat, L, N):
    # CovMat is the signal covariance matrix, L is the number of sources, N is the number of antennas
    _, U = LA.eig(CovMat)
    S = U[:, 0:L]
    Phi = LA.pinv(S[0:N - 1]) @ S[
                                1:N]  # the original array is divided into two subarrays [0,1,...,N-2] and [1,2,...,N-1]
    eigs, _ = LA.eig(Phi)
    DoAsESPRIT = np.arcsin(np.angle(eigs) / np.pi)
    return DoAsESPRIT


# =============================================================

np.random.seed(6)

lamda = 1  # wavelength
kappa = np.pi / lamda  # wave number
L = 5  # number of sources
N = 32  # number of ULA elements
snr = 10  # signal to noise ratio

array = np.linspace(0, (N - 1) / 2, N)

plt.figure()
plt.subplot(221)
plt.plot(array, np.zeros(N), '^')
plt.title('Uniform Linear Array')
plt.legend(['Antenna'])

Thetas = np.pi * (np.random.rand(L) - 1 / 2)  # random source directions
Alphas = np.random.randn(L) + np.random.randn(L) * 1j  # random source powers
Alphas = np.sqrt(1 / 2) * Alphas
# print(Thetas)
# print(Alphas)

h = np.zeros(N)
for i in range(L):
    h = h + Alphas[i] * array_response_vector(array, Thetas[i])

Angles = np.linspace(-np.pi / 2, np.pi / 2, 360)
numAngles = Angles.size

hv = np.zeros(numAngles)
for j in range(numAngles):
    av = array_response_vector(array, Angles[j])
    hv[j] = np.abs(np.inner(h, av.conj()))

powers = np.zeros(L)
for j in range(L):
    av = array_response_vector(array, Thetas[j])
    powers[j] = np.abs(np.inner(h, av.conj()))

plt.subplot(222)
plt.plot(Angles, hv)
plt.plot(Thetas, powers, '*')
plt.title('Correlation')
plt.legend(['Correlation power', 'Actual DoAs'])
numrealization = 100
H = np.zeros((N, numrealization)) + 1j * np.zeros((N, numrealization))

for iter in range(numrealization):
    htmp = np.zeros(N)
    for i in range(L):
        pha = np.exp(1j * 2 * np.pi * np.random.rand(1))
        htmp = htmp + pha * Alphas[i] * array_response_vector(array, Thetas[i])
    H[:, iter] = htmp + np.sqrt(0.5 / snr) * (np.random.randn(N) + np.random.randn(N) * 1j)
CovMat = H @ H.conj().transpose()

# MUSIC algorithm
DoAsMUSIC, psindB = music(CovMat, L, N, array, Angles)

plt.subplot(223)
plt.plot(Angles, psindB)
plt.plot(Angles[DoAsMUSIC], psindB[DoAsMUSIC], 'x')
plt.title('MUSIC')
plt.legend(['pseudo spectrum', 'Estimated DoAs'])

# ESPRIT algorithm
DoAsESPRIT = esprit(CovMat, L, N)
plt.subplot(224)
plt.plot(Thetas, np.zeros(L), '*')
plt.plot(DoAsESPRIT, np.zeros(L), 'x')
plt.title('ESPRIT')
plt.legend(['Actual DoAs', 'Estimated DoAs'])

print('Actual DoAs:', np.sort(Thetas), '\n')
print('MUSIC DoAs:', np.sort(Angles[DoAsMUSIC]), '\n')
print('ESPRIT DoAs:', np.sort(DoAsESPRIT), '\n')

plt.show()
posted @ 2024-01-18 20:20  碧水云天4  阅读(101)  评论(0编辑  收藏  举报