1+ # =================================================================================================================================== #
2+ # ----------------------------------------------------------- DESCRIPTION ----------------------------------------------------------- #
3+ # This script contains the functions for analyzing Angle of Arrival (AoA) measurements from RFID systems, using the classical #
4+ # antenna-array method "MUSIC Algorithm". #
5+ # =================================================================================================================================== #
6+
7+
8+ # =================================================================================================================================== #
9+ # --------------------------------------------------------- EXTERNAL IMPORTS -------------------------------------------------------- #
10+ import numpy as np # Mathematical functions. #
11+ # =================================================================================================================================== #
12+
13+
14+ # =================================================================================================================================== #
15+ # ---------------------------------------------------------- MUSIC FUNCTION --------------------------------------------------------- #
16+ def music_algorithm (phasor1 , phasor2 , L , wavelength , aoa_scan ):
17+ """
18+ Implement the MUSIC (MUltiple SIgnal Classification) algorithm for RFID AoA estimation.
19+
20+ Parameters:
21+ phasor1 [np.ndarray] : Complex phasors from antenna 1
22+ phasor2 [np.ndarray] : Complex phasors from antenna 2
23+ L [float] : Antenna separation distance (in meters)
24+ wavelength [float] : Signal wavelength (in meters)
25+ aoa_scan [np.ndarray] : Array of angles to scan (in degrees)
26+
27+ Returns:
28+ - tuple : (theta_music, P_music)
29+ - theta_music : Estimated angle using MUSIC algorithm
30+ - P_music : MUSIC spectrum
31+ """
32+ # STEP 1: Form spatial covariance matrix
33+ # Reshape phasors to column vectors and combine
34+ x1 = phasor1 .reshape (- 1 , 1 )
35+ x2 = phasor2 .reshape (- 1 , 1 )
36+ X = np .hstack ((x1 , x2 )) # Combine signals from both antennas
37+ # Calculate spatial covariance matrix
38+ R = X .conj ().T @ X / X .shape [0 ]
39+ # STEP 2: Eigendecomposition
40+ eigenvalues , eigenvectors = np .linalg .eig (R )
41+ # Sort eigenvectors by eigenvalues in descending order
42+ idx = np .argsort (eigenvalues )[::- 1 ]
43+ eigenvectors = eigenvectors [:, idx ]
44+ # STEP 3: Noise subspace (assuming 1 signal, so 1 eigenvector for signal)
45+ # Take all eigenvectors except the first one
46+ En = eigenvectors [:, 1 :]
47+ # STEP 4: MUSIC spectrum calculation
48+ k = 2 * np .pi / wavelength
49+ P_music = np .zeros (len (aoa_scan ))
50+ for i in range (len (aoa_scan )):
51+ # Array steering vector
52+ a = np .array ([1 , np .exp (- 1j * k * L * np .sin (np .deg2rad (aoa_scan [i ])))])
53+ a = a .reshape (- 1 , 1 )
54+ # MUSIC pseudospectrum - FIX: Extract scalar value using .item()
55+ denominator = a .conj ().T @ (En @ En .conj ().T ) @ a
56+ P_music [i ] = 1 / np .abs (denominator .item ()) # Use .item() to extract scalar value
57+ # STEP 5: Normalize spectrum
58+ P_music = P_music / np .max (P_music ) if np .max (P_music ) > 0 else P_music
59+ # STEP 6: Find peak
60+ theta_music = aoa_scan [np .argmax (P_music )]
61+
62+ return theta_music , P_music
0 commit comments