I have an acoustic setup. A sender, emitting a clean sine signal. The receiver is far away. In the time domain, the sine is hardly visible because the noise is nearly as big as the signal. In the frequency domain, the noise is distributed across all frequencies.
I need to extract the amplitude at the target frequency, I do not care about the phase.
Currently, I calculate the length of my fft-window to contain exactly N periods of my target frequency (
n_bins=N * samplerate / frequency) to avoid a loss in magnitude due to spectral leakage.
To remove the noise at this frequency, I do the same with a measurement w/o signal to estimate the noise background and subtract it.
My question now is, should I still use a window-function like blackman? From my understanding, I could now have leakage from noise in adjacent bins into my signal?
I have tried using a window-function in a python-example for this, with simulated data. Here, when using a window, the amplitude at my target frequency was actually higher than expected, while the results without the window were closer to reality.
EDIT: Python source code:
import numpy as np import matplotlib.pyplot as plt from scipy.signal import blackman as w_function target_freq = 12000 samplerate = 1000000. window = True # generate data x = np.array(range(0,17166)) / samplerate y = 290*np.sin(2*np.pi*target_freq*x) # signal y += 150*np.sin(2*np.pi*(target_freq - 451)*x) # noise near the signal y += 232*np.sin(2*np.pi*200185*x) # noise far away # find closest multiple reduced_len = len(y) while not float(reduced_len * target_freq / samplerate).is_integer(): reduced_len -= 1 def calc_fft(window): # prepare window if window: wndw = w_function(len(y)) else: wndw = np.array( * len(y)) wndw_correction = float(len(y)) / float(np.sum(wndw)) # amplitude correction factor for window # calculate fft, apply corrections for correct amplitude representation rft = np.abs(np.fft.fft(y * wndw, reduced_len, norm=None)) rft *= 2 * wndw_correction / float(len(rft)) # calculate corresponding frequencies, show only positive frequencies fft_freq = np.fft.fftfreq(len(rft), 1 / samplerate) rft = rft[np.argsort(fft_freq)] fft_freq = fft_freq[np.argsort(fft_freq)] low_ind = (np.abs(fft_freq-0)).argmin() fft_freq = fft_freq[low_ind:] rft = rft[low_ind:] return fft_freq, rft fft_freq, rft_window = calc_fft(True) fft_freq, rft_no_window = calc_fft(False) plt.plot(fft_freq, rft_window, label="window") plt.plot(fft_freq, rft_no_window, "-.", label="no window") plt.legend() plt.show()