FFT fitting of a damped sinusoid

3 views (last 30 days)
Ibrahim Younis
Ibrahim Younis on 26 Apr 2022
Answered: Sudarsanan A K on 10 Oct 2023
Hello, I have the following code. For some reason I can't figure out why I can't fit my data with an FFT that has the correct period, phase, and amplitude. I can't use standard fourier series because I want to obtain the spectral graphs. I can only fit a single period without problems.
tspan=[0:0.1:30];
x0=[0.2;0.5];
[tf,xf]=ode45(@func,tspan,x0);
xout=xf(:,1);
xdot=xf(:,2);
figure
[x1,x2]=meshgrid(4:0.09:9,-3:0.09:6);
k=8;
c=2;
m=5;
U=x2;
V=-(c/m)*x2-(k/m)*x1+10;
L=sqrt(U.^2+V.^2);
quiver(x1,x2,U./L,V./L,0.7,'b');
xlabel('x(m)')
ylabel('xdot (m/s)')
title('Phase Portrait')
hold on
plot(xout,xdot,'r','linewidth',2)
xlim([4.8 8])
ylim([-2 1.5])
hold off
dt=tspan(end)/length(tspan);
T=5;
NSP= floor(T/dt);
yfit = xout(1:6*NSP);
coefs=fft((1/NSP)*yfit);
tr=0:0.01:T;
An=-imag(coefs);
Bn=real(coefs);
ynew=0;
for N=1:NSP
ynew=ynew+An(N)*sin((N-1)*2*pi/T*tr);
ynew=ynew+Bn(N)*cos((N-1)*2*pi/T*tr);
end
figure
plot(tr,ynew,"r",'linewidth',2)
title('Mass 2 Response')
xlabel('time(s)')
ylabel('amplitude(m)')
hold on
plot(tspan,xout,"bo")
hold off
% figure
% plot(abs(coefs))
% xlabel('Frequency (Hz)')
% ylabel('Magnitude')
% title('Mass 2 Magnitude Plot')
%
function xdot=func(t,x)
k=8;
c=2;
m=5;
xdot(1)=x(2);
xdot(2)=-(c/m)*x(2)-(k/m)*x(1)+10;
xdot=xdot';
end

Answers (1)

Sudarsanan A K
Sudarsanan A K on 10 Oct 2023
Hi Ibrahim,
It is my understanding that you are trying to fit your data using the Fast Fourier Transform (FFT) to obtain the spectral graphs and facing issue with plotting the reconstructed signal based on the Fourier coefficients ('An' and 'Bn').
In this regard, I have made some slight modifications to your code as follows so as to address the desired use-case:
  • Modified 'T' Calculation: I modified the calculation of 'T' to use the full time span 'tspan(end)'. This ensures that 'T' represents the correct period of the signal.
  • Removed Subset Selection for 'yfit': In your code, there is a line 'yfit = xout(1:6*NSP);' that selected a subset of the data for fitting. I removed this line to ensure that the fitted signal is generated using the entire 'xout' data.
  • Revised 'tr' Time Vector: I modified the variable 'tr' by using 'linspace' to create a linearly spaced vector that covers the full time span. This ensures that the fitted signal is plotted correctly over the entire time range.
Please find the modified code attached below.
tspan = 0:0.1:30;
x0 = [0.2; 0.5];
[tf, xf] = ode45(@func, tspan, x0);
xout = xf(:, 1);
xdot = xf(:, 2);
figure
[x1, x2] = meshgrid(4:0.09:9, -3:0.09:6);
k = 8;
c = 2;
m = 5;
U = x2;
V = -(c/m) * x2 - (k/m) * x1 + 10;
L = sqrt(U.^2 + V.^2);
quiver(x1, x2, U./L, V./L, 0.7, 'b');
xlabel('x(m)')
ylabel('xdot (m/s)')
title('Phase Portrait')
hold on
plot(xout, xdot, 'r', 'linewidth', 2)
xlim([4.8 8])
ylim([-2 1.5])
hold off
dt = tspan(end) / length(tspan);
T = tspan(end); % modified T to use the full time span tspan(end)
NSP = floor(T / dt);
coefs = fft((1 / NSP) * xout);
tr = linspace(0, T, length(tspan)); % used 'linspace' to create a linearly spaced vector that covers the full time span
An = -imag(coefs);
Bn = real(coefs);
ynew = zeros(size(tr));
for N = 1:NSP
ynew = ynew + An(N) * sin((N-1) * 2*pi/T * tr) + Bn(N) * cos((N-1) * 2*pi/T * tr);
end
figure
plot(tr, ynew, 'r', 'linewidth', 2)
title('Mass 2 Response')
xlabel('time(s)')
ylabel('amplitude(m)')
hold on
plot(tspan, xout, 'bo')
grid on
hold off
function xdot = func(~, x)
k = 8;
c = 2;
m = 5;
xdot(1) = x(2);
xdot(2) = -(c/m) * x(2) - (k/m) * x(1) + 10;
xdot = xdot';
end
I hope this helps you to resolve your issue.

Categories

Find more on Measurements and Feature Extraction in Help Center and File Exchange

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!