Piece-wise non-linear fitting with fminsearch - issue with quadratic function

2 Ansichten (letzte 30 Tage)
Hello everybody.
I have a series of experimental data (tabella_raw.txt, column #4) for which I want to find the best interpolation function. If you have a look at the experimental data named 'qse' you can see that the best option is a piece-wise interpolation: three functions, in particular, the first part quadratic (from 0 to 1 h), as well as the second (from 1 to 2), and the third is hyperbolic (from 2 to end). The function must be continuous. I tried to find at first some suitable expressions for the three parts and then, by adopting fminsearch that minimizes the error between the two curves, and I got some kind of interpolation curve (the red one). In blue you can see the experimental data.
However, there is something wrong or better to say, something I don't like. At 1 and 2 (yellow dots) I want to have the maximum and the minimum values of the function. Is there any possibile way to set up some paramters contraints to obtain something like the second picture?
I attach the matlab code, as well.
For any doubts, please write me.
Thanks in advance.
Maja
  10 Kommentare
Mathieu NOE
Mathieu NOE am 15 Jan. 2024
tada !
now the full monty with fminsearch at the rescue
see answer section

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Mathieu NOE
Mathieu NOE am 15 Jan. 2024
as announced above in the teaser , please find now the full code with fminsearch for the fine tuning
I tooked a while to make it work as I wanted but I am happy to have achieved this (in parallel to my official work today :))
clc
clear all
close all
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% INTERPOLAZIONE CURVE DINAMICO %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
data=readmatrix('tabella_raw.txt');
tsi=data(:,1); tse=data(:,2); qsi=data(:,3); qse=data(:,4);
ti=data(:,5); to=data(:,6);
%__________________________________________________________________________
% INTERPOLAZIONE CURVE
%__________________________________________________________________________
% usare la scala x ogni ora per fitting corretto
n = 500;
ind = (1:n);
x=(ind/60)';
dT = 10; % delta T impulso (10°)
qse = qse(ind);
%% flusso termico esterno qse
%% step1 : best expo fit of first segment to compute exactly t1 with best accuracy
[m1,i1] = max(qse); % initial guess (i1) where is t1 , but this is not yet accurate enough
[k, yInf, y0, ~] = fitExponential(x(1:i1), qse(1:i1));
yFit = yInf + (y0-yInf) * exp(-k*(x-x(1)));
% refined t1 / x1 value (important for the step2 good performance
ind = find(yFit>qse);
ind = ind(ind>i1);
ind = ind(1);
x1 = x(ind); % or t1 if you prefer
%% step2 : do the general equation fit
% sigmoid a parameter (fixed paramter)
a_sig = -1000; % a large negative value so the sigmoid is like a steped window (sharp transition); -1000 is fine
% compute some vlaues we need to supply as IC for fminsearch
[m1,i1] = max(qse);
s1 = mysigmoid(x,x1,a_sig);
[m2,i2] = min(qse);
x2 = x(i2); % or t2 if you prefer
s2 = mysigmoid(x,x2,a_sig);
% curve fit using fminsearch
smooth_factor = 0.1; % 1 is too large , 0.1 is good
b1 = -2; % exponant term
b2 = -2; % exponant term
b3 = -1; % exponant term
b4 = -1; % exponant term
f = @(a,b,c,d,e,f,g,h,l,m,x) a*(1-exp(b*x)).*s1 + (c - d*(1-exp(e*(abs(x-x1)).^m))).*(1-s1).*s2 + (f*exp(g*(x-x2) + b4*(abs(x-x2)).^l)).*(1-s2);
obj_fun = @(p) norm(f(p(1),p(2),p(3),p(4),p(5),p(6),p(7),p(8),p(9),p(10),x)-qse) + smooth_factor*sum(abs(gradient(f(p(1),p(2),p(3),p(4),p(5),p(6),p(7),p(8),p(9),p(10),x))));
IC = [m1 b1 m1 (m1-m2) b2 m2 b3 b4 0.25 0.75];
sol = fminsearch(obj_fun, IC);
a_sol = sol(1);
b_sol = sol(2);
c_sol = sol(3);
d_sol = sol(4);
e_sol = sol(5);
f_sol = sol(6);
g_sol = sol(7);
h_sol = sol(8);
l_sol = sol(9);
m_sol = sol(10);
yfit = f(a_sol,b_sol,c_sol,d_sol,e_sol,f_sol,g_sol,h_sol,l_sol,m_sol, x);
plot(x,qse)
hold on
plot(x,yfit)
hold off
legend('data','fminsearch fit');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [k, yInf, y0, yFit] = fitExponential(x, y)
% FITEXPONENTIAL fits a time series to a single exponential curve.
% [k, yInf, y0] = fitExponential(x, y)
%
% The fitted curve reads: yFit = yInf + (y0-yInf) * exp(-k*(x-x0)).
% Here yInf is the fitted steady state value, y0 is the fitted initial
% value, and k is the fitted rate constant for the decay. Least mean square
% fit is used in the estimation of the parameters.
%
% Outputs:
% * k: Relaxation rate
% * yInf: Final steady state
% * y0: Initial state
% * yFit: Fitted time series
%
% Last modified on 06/26/2012
% by Jing Chen
% improve accuracy by subtracting large baseline
yBase = y(1);
y = y - y(1);
fh_objective = @(param) norm(param(2)+(param(3)-param(2))*exp(-param(1)*(x-x(1))) - y, 2);
initGuess(1) = -(y(2)-y(1))/(x(2)-x(1))/(y(1)-y(end));
initGuess(2) = y(end);
initGuess(3) = y(1);
param = fminsearch(fh_objective,initGuess);
k = param(1);
yInf = param(2) + yBase;
y0 = param(3) + yBase;
yFit = yInf + (y0-yInf) * exp(-k*(x-x(1)));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y = mysigmoid(x,c,a)
% sigmoid evaluates a simple sigmoid function along x:
%
% ______1________
% y = -a(x-c)
% 1 + e^
%
%% Syntax
%
% y = sigmoid(x)
% y = sigmoid(x,c)
% y = sigmoid(x,c,a)
%
y = 1./(1 + exp(-a.*(x-c)));
end

Weitere Antworten (0)

Produkte


Version

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by