# Amplitude of frequency bin in FFT doesn't match time-domain amplitude

I have a sinusoidal current that I am sampling at about 357k SPS. The current signal is about 3A pk-pk @ 750hz (top figure). I am wondering why when I take the fft using numpy/scipy's fft function, the amplitude of the fundamental frequency doesn't match.

I have a sample size of 8000 so I divided the fft by 8000 and multiplied by 2 to get the results below.

Current and fft calculation:

# current sense
df['current'] = (df['Viout'] - 2.5)/20/0.003
df['current_ft'] = np.fft.fft(df['current']) / 8000 * 2


Plot:

plt.subplot(211)
plt.title('current')
plt.xlabel('time [s]')
plt.ylabel('current [A]')
plt.plot(df.t_1, df.current)

plt.subplot(212)
plt.title('current fft')
plt.xlabel('frequency [Hz]')
plt.ylabel('|F(f)| / 8000 * 2')
plt.plot(df.freqz, np.abs(df.current_ft), 'o')
plt.xlim(-ax, ax)

plt.tight_layout()
plt.show()


• this looks like you've found the exact right scaling to preserve energy in time and single-sided frequency domain. Where's your problem with this? – Marcus Müller Jul 24 '18 at 0:27
• @MarcusMüller the issue is I expect the peak in the frequency domain to be the same amplitude as in the time domain. I expect 3 however am getting a peak of around 1.7. I assumed my scaling was correct as well since I've gotten the correct amplitudes with other frequencies I have measured. Unfortunately, this shows otherwise! – khuynh Jul 24 '18 at 5:54

You seem to know how to handle the DFT/FFT scaling so that its output matches the sampled signal's power/amplitude levels.

Yet there is a discrepancy between your expectation and the obsevred DFT result? There are a few reasons. Your assumptions on the sampling rate or the signal frequency could be wrong. Indeed as it seems from your figures, the signal is not a pure sine wave. In that case the amplitude looses its crisp definition and spectral leakage and main lobe width smearing becomes an issue. For details please search the site for spectral estimation, spectral display etc...

For your convenience, I have produced an ideal case to your description with MATLAB / OCTAVE code. I'm getting exactly what is expected. So this suggests me that your signal is not a pure sine wave. It's either modulated, or your sampling rate and frequency information is not consistent.

clc; clear all; close all;

T = 0.0225;     % observaton interval in seconds
f0 = 750;      % sine frequency in Hz.
Fs = 357E3;     % sampling frequency in Hz.

t = 0:1/Fs:T;   % analog time

N = length(t);  % number of samples taken...

A = 1.5;        % amplitiude of the sine
x = A*sin(2*pi*f0*t);   % sampled analog signal...

figure,plot(t,x);
title('Analog current waveform');

M = N;          % DFT length (mostly equal to sample size)
X = (2/N)*fft(x,M);

f = linspace(-Fs/2,Fs/2,M); % analog frequenc range in Hz.
figure,stem( f , abs(fftshift(X)));
axis([-1500 1500 -0.1 2]);
title('FFT magnitude of the obtained samples');


The resulting figures are as follows:

• Ah thank you. I got the same results as you after I generated an ideal sine wave in python too. Since my measured sinusoid isn't exactly pure, are there any methods to compensate for the spectral leakage and retrieve an accurate amplitude? – khuynh Jul 24 '18 at 6:02
• @khuynh when multiple unknown sine waves are present in a signal, you cannot exactly compansate for the leakage etc. Hence you cannot find the exact individual amplitudes. There is a resolution limit to every spectral estimation technique. Some error is unavoidable. – Fat32 Jul 24 '18 at 18:33
• @Fat32 I've combined two sine waves one having amplitude and frequency of 1000 and 390Hz and the second with 2000and 440Hz respectively. I've used a sampling rate of 1000Hz but I can't retrieve the correct amplitude. The most I could get is an amplitude of 1400 at 440Hz and 700 at 390Hz approximately. Is there a certain threshold after which leakage can't be avoided or am I doing something wrong? – Furqan Hashim Nov 17 '18 at 22:18