Skip to content

Commit a2b02a9

Browse files
authored
MUSIC-DOA-Estimation
1 parent 5a810d2 commit a2b02a9

File tree

4 files changed

+539
-0
lines changed

4 files changed

+539
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from cmath import e, pi, sin, cos
4+
5+
N = 5
6+
M = 10
7+
p = 100
8+
fc = 1e6
9+
fs = 1e7
10+
11+
# Generating Source Signal : Nxp
12+
13+
s = np.zeros((N, p), dtype=complex)
14+
for t in np.arange(start=1, stop=p + 1):
15+
t_val = t / fs
16+
amp = np.random.multivariate_normal(mean=np.zeros(N), cov=1 * np.diag(np.ones(N)))
17+
s[:, t - 1] = np.exp(1j * 2 * pi * fc * t_val) * amp
18+
print("Source Signal s : ", s.shape)
19+
20+
np.save('source_signal_data.npy', s)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from cmath import e, pi, sin, cos
4+
5+
N = 5
6+
M = 10
7+
p = 100
8+
fc = 1e6
9+
fs = 1e7
10+
11+
# source data
12+
s = np.load('source_signal_data.npy')
13+
print("Source Signal s : ", s.shape)
14+
15+
# storing DOAs in radians
16+
doa = np.array([20, 50, 85, 110, 145]) * pi / 180
17+
print("Original Directions of Arrival (degrees): \n", doa * 180 / pi)
18+
19+
c = 3e8
20+
d = 150
21+
22+
23+
# Steering Vector as a function of theta
24+
def a(theta):
25+
a1 = np.exp(-1j * 2 * pi * fc * d * (np.cos(theta) / c) * np.arange(M))
26+
return a1.reshape((M, 1))
27+
28+
29+
A = np.zeros((M, N), dtype=complex)
30+
for i in range(N):
31+
A[:, i] = a(doa[i])[:, 0]
32+
print("Steering Matrix A: ", A.shape)
33+
34+
# Generating Recieved Signal
35+
noise = np.random.multivariate_normal(mean=np.zeros(M), cov=np.diag(np.ones(M)), size=p).T
36+
X = (A @ s + noise)
37+
print("Recieved Signal X: ", X.shape)
38+
39+
np.save('recieved_signal_data.npy', X)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from cmath import e, pi, sin, cos
4+
5+
N = 5
6+
M = 10
7+
p = 100
8+
fc = 1e6
9+
fs = 1e7
10+
c = 3e8
11+
d = 150
12+
13+
14+
# Steering Vector as a function of theta
15+
def a(theta):
16+
a1 = np.exp(-1j * 2 * pi * fc * d * (np.cos(theta) / c) * np.arange(M))
17+
return a1.reshape((M, 1))
18+
19+
20+
# recieved signal data
21+
X = np.load('recieved_signal_data.npy')
22+
print("Recieved Signal X: ", X.shape)
23+
24+
# empirical covariance matrix of X
25+
S = X @ X.conj().T / p
26+
print("Empirical Covariance Matrix S : ", S.shape)
27+
28+
# finding eigen values and eigen vectors
29+
eigvals, eigvecs = np.linalg.eig(S)
30+
# eigen values are real as S is Hermitian matrix
31+
eigvals = eigvals.real
32+
33+
# sorting eig vals and eig vecs in decreasing order of eig vals
34+
idx = eigvals.argsort()[::-1]
35+
eigvals = eigvals[idx]
36+
eigvecs = eigvecs[:, idx]
37+
38+
# Plotting Eigen Values
39+
fig, ax = plt.subplots(figsize=(10, 4))
40+
ax.scatter(np.arange(N), eigvals[:N], label="N EigVals from Source")
41+
ax.scatter(np.arange(N, M), eigvals[N:], label="M-N EigVals from Noise")
42+
plt.title('Visualize Source and Noise Eigenvalues')
43+
plt.legend()
44+
45+
# separating source and noise eigvectors
46+
Us, Un = eigvecs[:, :N], eigvecs[:, N:]
47+
print("Source Eigen Values : Us: ", Us.shape)
48+
print("Noise Eigen Values : Un: ", Un.shape)
49+
50+
# plotting original DOAs for comparison with peaks
51+
fig, ax = plt.subplots(figsize=(10, 4))
52+
doa = np.array([20, 50, 85, 110, 145])
53+
print("Original Directions of Arrival (degrees): \n", doa)
54+
for k in range(len(doa)):
55+
plt.axvline(x=doa[k], color='red', linestyle='--')
56+
57+
58+
def P(theta):
59+
return (1 / (a(theta).conj().T @ Un @ Un.conj().T @ a(theta)))[0, 0]
60+
61+
62+
# searching for all possible theta
63+
theta_vals = np.arange(0, 181, 1)
64+
P_vals = np.array([P(val * pi / 180.0) for val in theta_vals]).real
65+
66+
# Plotting P_vals vs theta to find peaks
67+
plt.plot(np.abs(theta_vals), P_vals)
68+
plt.xticks(np.arange(0, 181, 10))
69+
plt.xlabel('theta')
70+
plt.title('Dotted Lines = Actual DOA Peaks = Estimated DOA')
71+
72+
plt.legend()
73+
plt.grid()
74+
plt.show()

0 commit comments

Comments
 (0)