# MUSIC algorithm on CSI data

I am trying to write a simulation code to estimate AOA's from channel state informations(CSI) using MUSIC algorithm. I am using OFDM with 64 subcarriers. Is there any material on how to estimate AOAs directly from CSIs using MUSIC?

I have linear antenna array. The number of antenna is a variable that I can play around with. Minimum is 4.


import numpy as np
import matplotlib.pyplot as plt

def get_chans_from_params(params, K, sep, lambs):
'''
given the params/4-tuples for the physical paths, compute the channel
across K antenna for given wavelengths.
Based on Equation 3 of paper
'''
d_ns, a_ns, phi_ns, psi_ns = params
N = len(d_ns)
I = len(lambs)
H = np.zeros(([I, K]),dtype=complex)

for i_wl in range(len(lambs)):
wl = lambs[i_wl]
### based on eq 3
for i_K in range(K):  ###for each antenna
t = 0
for i_N in range(N):  ###for each path
c1 = np.exp(-2j * np.pi * (i_K) * sep[i_wl] * psi_ns[i_N] / wl)
H[i_wl, i_K] += c1
return H

def get_lambsWifi(cf, bw, nfft):
c = 3e8
f = np.fft.fftfreq(nfft)
f = np.fft.fftshift(f)
f = f * bw
cf = f + cf
cf_wifi = np.concatenate((cf[6:32], cf[33:59]))
l1 = []
for f in cf_wifi:
l1.append(c / f)
return np.array(l1)

sep = 0.06  ## antenna separation, no effect when K=1
nfft = 64  ## nfft for channel
K = 4  ## num antennas
cf = 2.412e9  ## center freq
bw = 20e6  ## bandwidth over which channel is observed
l1 = get_lambsWifi(cf, bw, nfft)  ## wavelengths, lambda for subcarriers in channel
sep = l1/2

params = [ [5], [0.8], [0.001], [np.cos(np.pi/4)]]
K = 4
lambs = l1

print(l1)

X = get_chans_from_params(params,K,sep,lambs)

print(X[0,:])

X1 = X[0,:].reshape(K,1)
theta = np.linspace(0,np.pi,314)
Pmusic=np.zeros((1,len(theta)),dtype=complex)
l=l1[0]

X_h = X1.conj().T
eigenValues, eigenVectors = np.linalg.eig(X1*X_h)

idx = eigenValues.argsort()[::-1]
eigenValues = eigenValues[idx]
eigenVectors = eigenVectors[:,idx]

idx = eigenValues.argsort()[::-1]

eigenValues = eigenValues[idx]# soriting the eigenvectors and eigenvalues from greatest to least eigenvalue
eigenVectors = eigenVectors[:,idx]

signal_eigen = eigenVectors[0:1]#these vectors make up the signal subspace, by using the number of principal compoenets, 2 to split the eigenvectors
noise_eigen = eigenVectors[1:len(eigenVectors)]# noise subspace

U_N = np.transpose(noise_eigen)
# noisy_eigenvalues = eig_val[1:]
# thresholded_indices = np.where(noisy_eigenvalues > 0.5)[0]
# U_N = eig_vect[:, thresholded_indices]

for i in range(len(theta)):
psi_ns = np.cos(theta[i])
SS = np.zeros((K,1),dtype=complex);
### based on eq 3
for i_K in range(K):  ###for each antenna
SS[i_K] = np.exp(-2j * np.pi * (i_K)* sep[0]*psi_ns/l)
PP = np.dot(np.dot(np.transpose(SS),np.dot(U_N,np.transpose(U_N))),SS)
print('print',PP)
Pmusic[0,i]=(1/PP);
Pmusic[0,:] = np.real(10*np.log10(Pmusic[0,:]))

print(Pmusic)

plt.plot(theta,Pmusic[0,:])
plt.show()
$$$$
`
• How many receive antennas are you using? How are they arranged? The number of subcarriers is less important here, the antenna array geometry does make a difference. Aug 31, 2023 at 23:38
• And: asking for code is explicitly off topic here, so I removed that aspect from your question. Aug 31, 2023 at 23:39
• I have linear antenna array. The number of antenna is a variable that I can play around with. Minimum is 4. Sep 1, 2023 at 13:16