How can I find a rough ( as accurate as possible) Amplitude of each frequency when there is spectral leakage. Currently, I am dealing with a system that contains special leakage which seems unavoidable as I am measuring a real signal with any possible frequency. currently, I can identify the component frequencies to a decent level of accuracy even with the leakage, but I can't find the amplitude of this frequency as the energy is spread over multiple frequency bins.
Is it possible to get a rough prediction of a frequency amplitude either directly from the FFT, or afterwords using the identified frequencies?
I have been experimenting with Windowing and found this useful. https://www.youtube.com/watch?v=VxTx9QW8Zx8&ab_channel=Adash using the Hann window and using a frequency correction equation. it gives good approximations for frequency but no amplitude or phase.
A sample of the code currently used to test and generate the spectra.
import numpy as np
def gendata(FreqR,AmplR ,Ssize):
PhaseR = np.pi # phase range
FreqR = (FreqR*10) +1
AmplR = (AmplR*100)+1
PhaseR = (PhaseR*100)+1
freq_OR = []
ampl_OR= []
phase_OR =[]
for i in range(Ssize):
freq_OR. append((((FreqR-1)/Ssize)*(i+1)/10)) # currently just equaly spread but can be any value between 0-9 rad/s
ampl_OR.append(1) # unit amplitude to check for variation and error.
phase_OR.append(np.random.randint((-PhaseR),(PhaseR))/100) # random phase
return(freq_OR,ampl_OR,phase_OR)
def pltsignal(freq_OR,ampl_OR,phase_OR,t_OR):
z = 0 # original signal flat sea's
if len(freq_OR) == len(ampl_OR):
for i in range(len(freq_OR)): # for each frequency generate a regular wave.
wave_OR = ampl_OR[i] * np.cos(2*np.pi*freq_OR[i]*t_OR + phase_OR[i]) # generated wave signal using the frequncy, amplitude and phase of each wave.
z = z + wave_OR # superpostion each wave ontop of each other.
else:
print("amplutide and frequency are diffrent lengths")
return z # returns superimposed irregular wave.
FreqR = 1.5 # htz or (9 rad/s ish)
AmplR = 1 # currently unit amplitude to measure the error
Size = 12 # sample size, also used to move around frequencies
E_OR = 20 # time over wich signal is measured (max values is about 120 ish)
Fs = 6 # Sample rate in Hz
t_OR = np.arange(0,E_OR,1/Fs) # starts at 0, ends at E, steps by 1/Fs
data_OR = gendata(FreqR,AmplR,Size)
z = pltsignal(data_OR[0],data_OR[1],data_OR[2],t_OR) # original signal ( simulation of mesurment )
# anaysisng the signal using NumPy fft, then scaling and finding peaks.
Ramp = np.fft.fft(z) #real aplitudes used to find phase
Rfeq = np.fft.fftfreq(z.shape[-1]) #real frequency domain to find phase
Signal Model:
$$ x \left( t \right) = \sum_{i = 1}^{M} {a}_{i} \cos \left( 2 \pi {f}_{i} t + {\phi}_{i} \right) + n \left( t \right) $$
Where $ M, {\left\{ {a}_{i} \right\}}_{i = 1}^{M}, {\left\{ {f}_{i} \right\}}_{i = 1}^{M}, {\left\{ {\phi}_{i} \right\}}_{i = 1}^{M} $ are unknown parameters and $ n \left( t \right) $ is Additive Gaussian White Noise (AWGN).
One could assume:
- The SNR is very very high.
- The observation time is ~
120 [Sec]
. - The number of signals is 1-20.
- The frequencies are up to
2 [Hz]
. - The gap between frequencies can be as small as
0.005 [Hz]
.
cos()
andsin()
). Specifically when the observation time doesn't allow the required resolution to see them in the DFT, right? $\endgroup$