0

Im trying on DFT and FFT in Python with numpy and pyplot.

My Sample Vector is

x = np.array([1,2,4,3]

The DFT coefficients for that vector are

K = [10+0j, -3+1j, 0+0j, -3-1j]

so basically we have 10, -3+i, 0 and -3-1i as DFT coefficients.

My problem now is to get a combination of sin and cos to fit all 4 points.

Let's assume we have a sample Rate of 1hz.

This is my code :

from matplotlib import pyplot as plt
import numpy as np

x = np.array([1,2,4,3])

fft = np.fft.fft(x)

space = np.linspace(0,4,50)
values = np.array([1,2,3,4])

cos0 = fft[0].real * np.cos(0 * space)

cos1 = fft[1].real * np.cos(1/4 * np.pi * space)
sin1 = fft[1].imag * np.sin(1/4 * np.pi * space)

res = cos0 + cos1 + sin1

plt.scatter(values, x, label="original")
plt.plot(space, cos0, label="cos0")
plt.plot(space, cos1, label="cos1")
plt.plot(space, sin1, label="sin1")
plt.plot(space, res, label="combined")

plt.legend()

As result i get the plot:

img
(source: heeser-it.de)

Why isnt the final curve hitting any point?

I would appreciate your help. Thanks!

EDIT:

N = 1000
dataPoints = np.linspace(0, np.pi, N)
function = np.sin(dataPoints)
fft = np.fft.fft(function)

F = np.zeros((N,))
for i in range(0, N):
    F[i] = (2 * np.pi * i) / N
F_sin = np.zeros((N,N))
F_cos = np.zeros((N,N))

res = 0
for i in range(0, N):
    F_sin[i] = fft[i].imag / 500 * np.sin(dataPoints * F[i])
    F_cos[i] = fft[i].real / 500* np.cos(dataPoints * F[i])
    res = res + F_sin[i] + F_cos[i] 
plt.plot(dataPoints, function)
plt.plot(dataPoints, res)

my plot looks like:

img
(source: heeser-it.de)

where do i fail?

Community
  • 1
  • 1
YHc44
  • 1
  • 1
  • I beleive your question is more maths related than programming – Mixone Aug 12 '18 at 09:39
  • I have posted my python code in my original post. Maybe an idea? – YHc44 Aug 12 '18 at 09:52
  • Sorry I have little expertise on the laths part :/ I think it would be better if you moed the question the maths stack exchange – Mixone Aug 12 '18 at 10:12
  • 1
    Possible duplicate of [How do I obtain the frequencies of each value in an FFT?](https://stackoverflow.com/questions/4364823/how-do-i-obtain-the-frequencies-of-each-value-in-an-fft) – Spektre Aug 12 '18 at 10:13
  • No, i know how to get the frequencies. But when i want to plot it i dont get a good result – YHc44 Aug 12 '18 at 10:22
  • I do not see any phase in your `sin,cos` ... (like `atan2(im,re)`) for each Nyquist frequency ... – Spektre Aug 12 '18 at 10:31
  • so when f = 1/2 * sample_f i need to add phase? – YHc44 Aug 12 '18 at 11:57
  • @YHc44 what you got is amplitude and phase for each Nyquist sinwave ... so you need to summ all the waves together + the DC offset (first coeff) ... each sinwave is in form `amplitude*sin(2*PI*t*f + phase0)` where `t` is time, `f` is corresponding Nyquist frequency and `phase0=atan2(im,re)` and `amplitude=sqrt(re*re + im*im)`... – Spektre Aug 12 '18 at 12:40
  • Sorry for my questions.. but i dont understand it 100%.. My frequencies at 8 samples with 1HZ sampling rate are: [0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1].. right? Which frequencies are nyquist frequencies? or do i need to take these values as f in your formula? – YHc44 Aug 12 '18 at 13:01
  • @YHc44 all of them are ... use `0.125` for the second DFT output , `0.25` for the third etc ... You should add 7 sinwaves + DC offset together to get your plot ...btw add `@nick` to your comment so user `nick` is notified by the site – Spektre Aug 12 '18 at 14:00

2 Answers2

0

Your testing vector x looks bit like a sawtooth because it rises linearly and then starts to decrease but with that few datapoints it's hard to tell what signal it is. This has an infinite FFT series, which means it has lot of higher harmonic frequency components in it. So to describe it with DTF coefficients and get close to original points, you would have to use

  1. higher sample rate, to get information about higher frequencies (you should learn about nyquist theorem)
  2. more data points (samples), so you can extract more precise information about frequencies in your signal) This means you have to have more items in your array 'x'.

Also you could try to fit some simpler signal. What about you try to fit a sine signal for start? Generate 1000 data points of low frequency sine (1Hz or one cycle per 1000 samples) and then run DTF on it to check if your code works.

nio
  • 5,141
  • 2
  • 24
  • 35
  • What confuses me is that when i enter my 4 samples on https://planetcalc.com/7543/ it calculates a curve, that fits all points. – YHc44 Aug 12 '18 at 10:28
  • I edited my code below and tested for a sin with Frequency of 1HZ. Please check out. I dont know, maybe i have understanding problems? – YHc44 Aug 12 '18 at 11:06
0

There are a few mistakes:

  • The xs you assigned to the original values are off by one
  • The frequency you assigned to fft[1] is incorrect
  • The coefficients are incorrectly scaled

This one works:

from matplotlib import pyplot as plt
import numpy as np

x = np.array([1,2,4,3])

fft = np.fft.fft(x)

space = np.linspace(0,4,50)
values = np.array([0,1,2,3])

cos0 = fft[0].real * np.cos(0 * space)/4

cos1 = fft[1].real * np.cos(1/2 * np.pi * space)/2
sin1 = -fft[1].imag * np.sin(1/2 * np.pi * space)/2

res = cos0 + cos1 + sin1

plt.scatter(values, x, label="original")
plt.plot(space, cos0, label="cos0")
plt.plot(space, cos1, label="cos1")
plt.plot(space, sin1, label="sin1")
plt.plot(space, res, label="combined")

plt.legend()
plt.show()
Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87
  • Thank you. Why are you scaling cos0 with 1/4 and cos1 / sin1 with 1/2? – YHc44 Aug 12 '18 at 14:25
  • it's really 4 for everything: -fft[1].imag/2 is actually (fft[3]-fft[1]).imag / 4. The coefficients are not really for sines and cosines, they're for complex exponentials. fft[1] and fft[3] have sine and cosine components for the same frequency that add together. – Matt Timmermans Aug 12 '18 at 15:32