Kakemonster
Kakemonster

Reputation: 107

Different results using FFT in Matlab compared to Python

I have time series with accelerometer data which I want to integrate to velocity and position time series. This is done using FFT, but the two methods in Matlab and Python give me different results.

Matlab Code:

nsamples = length(acc(:,1));
domega = 2*pi/(dt*nsamples);      
acchat = fft(acc);

% Make frequency array:
Omega = zeros(nsamples,1);

% Create Omega:
if even(nsamples)
   nh = nsamples/2;
   Omega(1:nh+1) = domega*(0:nh);
   Omega(nh+2:nsamples) = domega*(-nh+1:-1);
else
   nh = (nsamples-1)/2;
   Omega(1:nh+1) = domega*(0:nh); 
   Omega(nh+2:nsamples) = domega*(-nh:-1);
end

% High-pass filter:
n_low=floor(2*pi*f_low/domega);
acchat(1:n_low)=0;
acchat(nsamples-n_low+1:nsamples)=0;

% Multiply by omega^2:
acchat(2:nsamples) = -acchat(2:nsamples) ./ Omega(2:nsamples).^2;

% Inverse Fourier transform:
pos = real(ifft(acchat));

% --- End of function ---

Python Code:

import numpy as np


def acc2velpos(acc, dt):

    n = len(acc)

    freq = np.fft.fftfreq(n, d=dt)
    omegas = 2 * np.pi * freq
    omegas = omegas[1:]

    # Fast Fourier Transform of Acceleration
    accfft = np.array(np.fft.fft(acc, axis=0))

    # Integrating the Fast Fourier Transform
    velfft = -accfft[1:] / (omegas * 1j)
    posfft = accfft[1:] / ((omegas * 1j) ** 2)

    velfft = np.array([0] + list(velfft))
    posfft = np.array([0] + list(posfft))

    # Inverse Fast Fourier Transform back to time domain
    vel = np.real(np.fft.ifft(velfft, axis=0))
    pos = np.real(np.fft.ifft(posfft, axis=0))

    return vel, pos

The two codes should generally give the exact same results, but when I plot a comparison this is what I get

Acceleration to Velocity

enter image description here

Acceleration to Position

enter image description here

Any idea why the Python results are not identical to Matlab results in Position? It is crucial for me to have the same results as I am using these acceleration measurements from experiments to identify the motion of a barge.

I also have a second version in Python where I try to include the filter which is in the Matlab code. This also gives different results, much like the one without a filter in Python.

def acc2vel2(acc, dt, flow):

    nsamples = len(acc)
    domega = (2*np.pi) / (dt*nsamples)
    acchat = np.fft.fft(acc)

    # Make Freq. Array
    Omega = np.zeros(nsamples)

    # Create Omega:
    if nsamples % 2 == 0:
        nh = int(nsamples/2)
        Omega[:nh] = domega * np.array(range(0, nh))
        Omega[nh:] = domega * np.array(range(-nh-1, -1))

    else:
        nh = int((nsamples - 1)/2)
        Omega[:nh] = domega * np.array(range(0, nh))
        Omega[nh:] = domega * np.array(range(-nh-2, -1))

    # High-pass filter
    n_low = int(np.floor((2*np.pi*flow)/domega))
    acchat[:n_low - 1] = 0
    acchat[nsamples - n_low:] = 0

    # Divide by omega
    acchat[1:] = -acchat[1:] / Omega[1:]

    # Inverse FFT
    vel = np.imag(np.fft.ifft(acchat))

return vel

This still gives a little bit different than the Matlab code. Suggestions?

Upvotes: 4

Views: 1859

Answers (2)

vvvvv
vvvvv

Reputation: 31569

Implementing the high-pass filter in the Python script solved the problem:

def acc2velpos(acc, dt, f_low):

    n = len(acc)

    freq = np.fft.fftfreq(n, d=dt)
    domega = (2*np.pi)/(dt*(n + 1))
    omegas = 2 * np.pi * freq
    omegas = omegas[1:]

    # Fast Fourier Transform of Acceleration
    accfft = np.array(np.fft.fft(acc, axis=0))

    # High-pass filter
    n_low = int(np.floor((2*np.pi*f_low)/domega))
    accfft[:n_low - 1] = 0
    accfft[n - n_low:] = 0

    # Integrating the Fast Fourier Transform
    velfft = -accfft[1:] / (omegas * 1j)
    posfft = accfft[1:] / ((omegas * 1j) ** 2)

    velfft = np.array([0] + list(velfft))
    posfft = np.array([0] + list(posfft))

    # Inverse Fast Fourier Transform back to time domain
    vel = np.real(np.fft.ifft(velfft, axis=0))
    pos = np.real(np.fft.ifft(posfft, axis=0))

    return vel, pos

This answer was posted as an edit to the question Different results using FFT in Matlab compared to Python by the OP Kakemonster under CC BY-SA 3.0.

Upvotes: 0

James
James

Reputation: 85

It looks like you have a high pass filter in the matlab code and not in the python code. Which makes sense given the difference between your python and matlab position results.

Your python position wave appears to oscillate up and down at a low frequency, indicating that some low frequency component in the frequency domain was not filtered out. The high pass filter in your matlab code removed the low frequency component.

Upvotes: 4

Related Questions