How to fit damped oscillation curves
Afficher commentaires plus anciens
Hey folks,
I'm currently trying to get some oscillation characteristics (first/second/third max/min, logarithmic decrement, damping ratio) out of some data I've measured.
My attempts haven't led to useful results yet, most probably due to the non-sinusoidality, noise and/or parasitic sub-peaks of the graphs.
Is there a good way to handle this in matlab? I'm quite a newbie on this.
I would appreciate any help on this topic! Thank you very much in advance!
Réponses (4)
Star Strider
le 21 Juil 2015
I’m not certain how closely you want to fit it. One option for fitting a sine curve is Curve fitting to a sinusoidal function.
In the context of my Answer there, the ‘fit’ function and fminsearch call for your data become:
fit = @(b,x) b(1).*exp(b(2).*x).*(sin(2*pi*x./b(3) + 2*pi/b(4))) + b(5); % Function to fit
s = fminsearch(fcn, [yr; decay; per; -1; ym]) % Minimise Least-Squares
with the addition of ‘decay’, the exponential decay constant. An appropriate initial estimate for it is -1. My function is a ‘smoothed’ sinusoidal function, so the fit will be approximate.
I would do a fft of your data to see what other frequency components are in it. You could then create a regression function that would approximate it more closely.
18 commentaires
MrBlub
le 21 Juil 2015
Star Strider
le 21 Juil 2015
I don’t have the Robust Control Toolbox, so I wasn’t aware I was shadowing a function. Rename the ‘decay’ variable to something else, perhaps simply ‘DK’, or some variable or function that is not already in your code or toolboxes. Or simply replace it in the initial estimates vector with -1. MATLAB doesn’t care, so long as it has an (appropriate) initial estimate for every parameter you want it to estimate.
Since you’re also naming your data the same as in my earlier code, no other changes should be necessary.
I would check the last value estimated in the ‘zx’ (‘zero-crossings’) assignment, to be sure it corresponds to an actual zero-crossing and is not a spurious ‘end-effect’ value. I can’t tell from your plotted data. If it is a spurious value, simply insert:
zx = zx(1:end-1);
just after the initial ‘zx’ assignment. The rest of the code ideally will work without problems. (I don’t have your data, so I can’t experiment with it.)
MrBlub
le 21 Juil 2015
Star Strider
le 21 Juil 2015
The data I wrote that for were row vectors, so the ‘zx’ function did not calculate the zero-crossings correctly. I didn’t have your data originally, so I couldn’t write the code specifically for it.
This works:
fidi = fopen('MrBlub test.txt','rt');
D = textscan(fidi, '%f%f', 'Delimiter','\t');
x = D{1};
y = D{2};
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zx = x(yz .* circshift(yz,[1 0]) <= 0); % Find zero-crossings
per = 2*mean(diff(zx)); % Estimate period
ym = mean(y); % Estimate offset
fit = @(b,x) b(1).*exp(b(2).*x).*(sin(2*pi*x./b(3) + 2*pi/b(4))) + b(5); % Function to fit
fcn = @(b) sum((fit(b,x) - y).^2); % Least-Squares cost function
s = fminsearch(fcn, [yr; -1; per; -1; ym]) % Minimise Least-Squares
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'b', xp,fit(s,xp), 'r')
grid
The fft reveals two principal frequencies, at 0.08 and 0.27 Hz with amplitudes of 0.36 and 0.07 respectively. You could write a ‘fit’ anonymous function to include both, but I doubt including the second would significantly improve the fit.
The best objective function would be a model of the process that created your data. The parameters would then have direct physical significance.
MrBlub
le 22 Juil 2015
Star Strider
le 22 Juil 2015
The ‘envelope’ function are the parts of my anonymous function with the first two parameters:
env_fcn = @(b,x) b(1).*exp(b(2).*x);
so the exponential (or logarithmic) decrement is ‘b(2)’.
My ‘fit’ function is the solution of the differential equation of a second-order system. Combinations of the appropriate parameters should provide all the values mentioned in the Wikipedia article on Damping ratio.
I did an fft on your data that revealed one primary peak and one small secondary peak. The fit you got with my code is likely as good as you can get if you are modeling a single second-order system to your data.
MrBlub
le 23 Juil 2015
Star Strider
le 23 Juil 2015
It is necessary to fit all the data to the function in order to get the correct parameter estimates. My code does everything you want. In its parameter estimates, s(s2)=-0.084 is the exponential decay, corresponding to a log decrement of 1.088.
This slightly revised code (adding explicitly the log decrement calculation and plotting the envelope) depicts everything:
fidi = fopen('MrBlub test.txt','rt');
D = textscan(fidi, '%f%f', 'Delimiter','\t');
x = D{1};
y = D{2};
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zx = x(yz .* circshift(yz,[1 0]) <= 0); % Find zero-crossings
per = 2*mean(diff(zx)); % Estimate period
ym = mean(y); % Estimate offset
fit = @(b,x) b(1).*exp(b(2).*x).*(sin(2*pi*x./b(3) + 2*pi/b(4))) + b(5); % Function to fit
fcn = @(b) sum((fit(b,x) - y).^2); % Least-Squares cost function
s = fminsearch(fcn, [yr; -1; per; -1; ym]) % Minimise Least-Squares
envlp = @(b,x) b(1) .* exp(b(2) .* x) + b(5);
logdec = sprintf('Log decrement = %.3f', exp(-s(2)));
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'b', xp,fit(s,xp), 'r')
hold on
plot(x, envlp(s,x), 'g', 'LineWidth',1)
hold off
grid
legend('Data', 'Fitted Function', 'Envelope', 'Location','NE')
text(11, 1.1, logdec)
MrBlub
le 23 Juil 2015
Star Strider
le 23 Juil 2015
I guess I’m not understanding what you’re doing. I am modeling your data as a linear time-invariant function. That is going to be difficult to model, unless you already know the time-varying features of the system you are measuring. Since I don’t know what the system is, that is likely not something I can help you with.
You can improve the fit somewhat by adding an additional exponentially decreasing sine curve, but that is about the limit of the ability of any parameter estimation technique. There actually seems to be an initial impulse with a rapid exponential decrease all its own to account for the first peak. Since I have no idea what system you’re modeling, I’ll stop guessing at a solution.
Insert these lines in the appropriate parts of the code to see the result of adding the second function:
fit = @(b,x) b(1).*exp(b(2).*x).*(sin(2*pi*x./b(3) + 2*pi/b(4))) + b(5) + b(6).*exp(b(7).*x).*(sin(2*pi*x./b(8) + 2*pi/b(9))); % Function to fit
S0 = [yr; -1; per; -1; ym; 1; -1; per*11; 1];
s = fminsearch(fcn, S0) % Minimise Least-Squares
envlp = @(b,x) b(1) .* exp(b(2) .* x) + b(5) + b(6).*exp(b(7).*x);
logdec = sprintf('Log decrement = %.3f', exp(-(s(2)+s(7))));
Add an additional exponentially-decreasing ‘spike’ if you want to experiment with it:
fit = @(b,x) b(1).*exp(b(2).*x).*(sin(2*pi*x./b(3) + 2*pi/b(4))) + b(5) + b(6).*exp(b(7).*x).*(sin(2*pi*x./b(8) + 2*pi/b(9))) + b(10).*exp(b(11).*x); % Function to fit
S0 = [yr; -1; per; -1; ym; 1; -1; per*11; 10; 15; -2];
envlp = @(b,x) b(1) .* exp(b(2) .* x) + b(5) + b(6).*exp(b(7).*x) + b(10).*exp(b(11).*x);
logdec = sprintf('Log decrement = %.3f', exp(-(s(2)+s(7)+s(11))));
Nothing else in the code changes. Except for the anomaly of the initial peak, it’s actually a good fit (adding the ‘spike’ and using the last set of parameters).

I really have nothing more to offer after this, since I’m doing nothing more than guessing at the system you’re measuring, and doing my best to model it.
I leave you to experiment.
MrBlub
le 24 Juil 2015
Star Strider
le 24 Juil 2015
It is understandable, but it is essentially impossible to model a time-varying process from the output from it, even assuming an impulse input. Without a specific model of the physics of the process (that is beyond my knowledge of physics), there is no way to determine how the parameters vary in time.
I suggest you model the physics of the process, and estimate the parameters from that model. Modeling them as a linear time-invariant system, as I have attempted, won’t work.
I can help you with the MATLAB coding and some of the modeling and parameter estimation, but not the physics. That’s beyond the scope of MATLAB Answers in any event.
Since I can’t help you, I’ll delete this Answer in a few hours, since it’s obviously not relevant to your problem.
MrBlub
le 24 Juil 2015
Star Strider
le 24 Juil 2015
I don’t understand what you mean by ‘time-averaged log decrement’. This is the best I can do (requires the Signal Processing Toolbox):
fidi = fopen('MrBlub test.txt','rt');
D = textscan(fidi, '%f%f', 'Delimiter','\t');
x = D{1};
y = D{2};
ya = abs(y);
[pks,locs] = findpeaks(ya, 'MinPeakDistance', 200);
logdec = log(pks(1:end-1) ./ pks(2:end)); % Log Decrement
zeta = 1./(sqrt(1 + (2*pi./logdec).^2)); % Damping Ratio
for k1 = 1:length(logdec)
fprintf(1, '\n\tLog decrement between peaks %2d and %2d = %.4f, Damping ratio = %.4f\n', k1, k1+1, logdec(k1), zeta(k1))
end
figure(3)
plot(x, ya)
hold on
plot(x(locs), ya(locs), 'bp')
plot(x(locs), ya(locs), '-r')
hold off
grid
Log decrement between peaks 1 and 2 = 1.0986, Damping ratio = 0.1722
Log decrement between peaks 2 and 3 = 0.0690, Damping ratio = 0.0110
Log decrement between peaks 3 and 4 = 0.1542, Damping ratio = 0.0245
Log decrement between peaks 4 and 5 = 0.0870, Damping ratio = 0.0138
The ‘logdec’ assignment is the log-decrement between the absolute values of the adjacent peaks. The ‘zeta’ assignment is the damping ratio for each. Note that the relevant variables are between ‘pks(n)’ and ‘pks(n+1)’, so there are one fewer than the number of peaks. With a nonlinear system where the ratios of the peaks is not close to being constant, taking the time average of data calculated from them would not seem to be appropriate.
MrBlub
le 24 Juil 2015
Star Strider
le 24 Juil 2015
You will need to have some function describing ‘R(t)’ to effectively model your system.
I suggested that taking the mean of the damping might not be appropriate because of the time-varying nature of the system.
There are a few ways to configure an RLC circuit. What is your particular model?
MrBlub
le 25 Juil 2015
Star Strider
le 25 Juil 2015
Simulating RLC circuits is not the problem, but modeling a specific RLC circuit requires that we know how the components are configured. Is it series, parallel, or some combination? That has a decisive effect on its characteristics and frequency-dependent impedance.
If we can’t at least approximate R(t) with some sort of function, then any attempt at modeling its behaviour is impossible. Spark gaps are not new, and formed the basis of wireless transmitters up to about a century ago. It amazes me that there is no mathematical model of the electrical characteristics of one.
In any event, without knowing the configuration of the RLC circuit model of your system, and having a realistic model of R(t). I can go no further.
the cyclist
le 21 Juil 2015
Modifié(e) : the cyclist
le 21 Juil 2015
0 votes
If you have the Statistics and Machine Learning Toolbox, I would suggest that you look at using the nlinfit function to do a fit like this. You can define your own specific functional form, and fit to that. There are examples on that page that can help you with syntax.
John D'Errico
le 24 Juil 2015
0 votes
Is there a good way to handle a hard problem where you have no model for the process, where there is nasty, non-normal noise, random bumps, discontinuities? Hmm. not really.
Personally, I'd start by building a shape that does reflect this process. A sine wave, because it is symmetrical, does not do so, even though it is periodic. The ramp up and ramp down behaviors are clearly not the same here. So, were it for me to do (I have seen no actual data, so I cannot even play around with what you have) I would break that curve you have shown into 5 distinct segments. Essentially, I would
1. Locate where the curve crosses zero between each segment.
2. Then shift each piece on top of each other, translating them in time so they now overlap.
3. Now, create a model of this "process". I'd probably play with a principle components solution, that would allow me to model these 5 curves, and find one characteristic curve that represents the overall shape. The PCA analysis would find a basic curve shape, then scaled by a different amount for each segment.
4. I would then build a spline model from that estimated curve. My SLM toolbox would be useful to do this, since I would constrain the curve to pass through zero at each end, use periodicity constraints, etc.
5. Finally, I would now model the entire curve as a piecewise amalgamation of those segments.
I can't suggest much more than that without any actual data.
1 commentaire
Star Strider
le 24 Juil 2015
Justine Nyakundi
le 5 Juil 2017
0 votes
did you get a solution to this?
Catégories
En savoir plus sur Data Distribution Plots dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!