3

I have a Matlab script to compute the DFT of a signal and plot it:

(data can be found here)

clc; clear; close all;

fid = fopen('s.txt');
txt = textscan(fid,'%f'); 

s = cell2mat(txt);

nFFT = 100;
fs = 24000;
deltaF = fs/nFFT;
FFFT = [0:nFFT/2-1]*deltaF;
win = hann(length(s));

sw = s.*win;
FFT = fft(sw, nFFT)/length(s);
FFT = [FFT(1); 2*FFT(2:nFFT/2)];
absFFT = 20*log10(abs(FFT));

plot(FFFT, absFFT)
grid on

I am trying to translate it to Python and can't get the same result.

import numpy as np
from matplotlib import pyplot as plt

x = np.genfromtxt("s.txt", delimiter='  ')

nfft = 100
fs = 24000
deltaF = fs/nfft;
ffft = [n * deltaF for n in range(nfft/2-1)]
ffft = np.array(ffft)
window = np.hanning(len(x))

xw = np.multiply(x, window)
fft = np.fft.fft(xw, nfft)/len(x)
fft = fft[0]+ [2*fft[1:nfft/2]]
fftabs = 20*np.log10(np.absolute(fft))

plt.figure()
plt.plot(ffft, np.transpose(fftabs))
plt.grid()

The plots I get (Matlab on the left, Python on the right):

enter image description here

What am I doing wrong?

5
  • Maybe not your main problem, but your window function should be the same size as the FFT, i.e. nfft, not len(x) (applies to both MATLAB and Python code). Commented Jun 21, 2017 at 13:51
  • @Paul R Interesting, where can I find more information about that ? Commented Jun 21, 2017 at 14:18
  • There are quite a few questions and answers right here on StackOverflow which cover window functions and FFTs. The bottom line though is that you apply a window function to the input data of an FFT in order to reduce spectral leakage. The size of this window function therefore needs to match the size of the FFT. Commented Jun 21, 2017 at 14:22
  • 1
    unlikely to be the issue, but be aware that matlab's [0:49] is not the same as python's range(49). In python you're off by one. (i.e. range(49) is equivalent to [0:48]) Commented Jun 21, 2017 at 14:28
  • There are at least two points i found incorrect in your python code. For instance the line ffft = [n * deltaF for n in range(nfft/2-1)]. 1) you need to use integer division nfft//2; 2) By range(nfft//2-1) you have missed 1. The correct shall be range(nfft//2). Commented Jul 30, 2024 at 11:59

3 Answers 3

3

Both codes are different in one case you concatenate two lists

FFT = [FFT(1); 2*FFT(2:nFFT/2)];

in the matlab code

in the other you add the first value of fft with the rest of the vector

fft = fft[0]+ [2*fft[1:nfft/2]]

'+' do not concatenate here because you have numpy array

In python, it should be:

fft = fft[0:nfft/2]
fft[1:nfft/2] =  2*fft[1:nfft/2]
Sign up to request clarification or add additional context in comments.

Comments

0

I am not a Mathlab user so I am not sure but there are few things I'd ask to see if I can help you.

You called np.array after array has been made (ffft). That probably will not change the nature of array as well as you hoped, perhaps it would be better to try to define it inside np.array(n * deltaF for n in range(nfft/2-1)) I am not sure of formatting but you get the idea. The other thing is that the range doesn't seem right to me. You want it to have a value of 49?

Another one is the fft = fft[0]+ [2*fft[1:nfft/2]] compared to FFT = [FFT(1); 2*FFT(2:nFFT/2)]; I am not sure if the comparsion is accurate or not. It just seemed to be a different type of definition to me?

Also, when I do these type of calculations, I 'print' out the intermediate steps so I can compare the numbers to see where it breaks.

Hope this helps.

1 Comment

Thanks. I changed the definition of ffft that way : ffft = np.array(n * deltaF for n in range(nfft/2-1)). Not sure either about the second portion of code you mention. I found a solution and will post it below. And I don't reaaly care about the number of points I get. I'll probably do some tests with different values.
0

I found out that using np.fft.rfft instead of np.fft.fft and modifying the code as following does the job :

import numpy as np
from matplotlib import pyplot as pl

x = np.genfromtxt("../Matlab/s.txt", delimiter='  ')

nfft = 100
fs = 24000
deltaF = fs/nfft;
ffft = np.array([n * deltaF for n in range(nfft/2+1)])
window = np.hanning(len(x))

xw = np.multiply(x, window)
fft = np.fft.rfft(xw, nfft)/len(x)
fftabs = 20*np.log10(np.absolute(fft))

pl.figure()
pl.plot(np.transpose(ffft), fftabs)
pl.grid()

The resulting plot : right result with Python

I can see that the first and the last points, as well as the amplitudes are not the same. It isn't a problem for me (I am more interested in the general shape), but if someone can explain, I'd be happy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.