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


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


X1 = X[0,:].reshape(K,1)
theta = np.linspace(0,np.pi,314)

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)
Pmusic[0,:] = np.real(10*np.log10(Pmusic[0,:]))


  • $\begingroup$ 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. $\endgroup$ Aug 31, 2023 at 23:38
  • $\begingroup$ And: asking for code is explicitly off topic here, so I removed that aspect from your question. $\endgroup$ Aug 31, 2023 at 23:39
  • $\begingroup$ I have linear antenna array. The number of antenna is a variable that I can play around with. Minimum is 4. $\endgroup$
    – Avishek
    Sep 1, 2023 at 13:16

1 Answer 1


Just treat each subcarrier as independent receiver (they are! That's the idea behind OFDM!), and do the usual MUSIC DoA with the phase CSI estimates for the different receive antennas; no magic involved.

  • $\begingroup$ I have edited the question with the code. Somehow using just a single sub carrier, I am not getting correct result. At this point there is a single multipath in the simulation. I am not exactly sure what issue is there $\endgroup$
    – Avishek
    Sep 6, 2023 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.