Reputation: 107
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
Acceleration to Position
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
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
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