Optimisation for 3-element Windkessel Model Not Working - Using Least Squares Method and fminsearch. Advice? Should I use other optimisation algorithms?
2 views (last 30 days)
Show older comments
So I am trying to optimise the parameters (R1, R2, C) for the 3-element windkessel model for the aorta. I am supplying it with tabular data for the Pressure and Flow (Q), but neither of the models are doing anything, and not giving any errors either. Kindly advise.
My code is as follows:
clear all
close all
clc
%% Inputs
R1 = 4.4e+6;
R2 = 1.05e+8;
C = 1.31e-8;
% L = 6.799e+5;
TimeStep = 0.001;
Beta = TimeStep / (C*R2);
%Initial conditions for WK-3 parameters
IC = [C, R1, R2];
%% Importing flow and pressure data
RefPQWK = readtable('Ref_P_Q_WK_No-Osc_1-Cycle.csv');
t=RefPQWK.t;
Q=RefPQWK.Q;
P=RefPQWK.P;
P0=RefPQWK.P(1);
Q0=RefPQWK.Q(1);
dt = TimeStep;
t_0 = 0:dt:t(end);
Q = smooth(interp1(t, Q, t_0), 50);
P = smooth(interp1(t, P, t_0), 50);
%Initial conditions
IC_Q = Q(1);
IC_P = P(1);
dP = diff(P)./dt;
dP(end+1) = dP(end);
dQ = diff(Q)./dt;
dQ(end+1) = dQ(end);
%dqdt = derivative(Q,t_0);
%% Curve fitting using the method of least squares
LB = [1e-10 1 1]; UB = [1 1e10 1e10]; % Lower and Upper bounds
options = optimoptions('lsqcurvefit', 'Algorithm', 'levenberg-marquardt', 'StepTolerance', 1e-100,'FunctionTolerance', 1e-10,'Display','iter');
%options = optimoptions('lsqcurvefit', 'Algorithm', 'levenberg-marquardt', 'MaxFunctionEvaluations', 1e100, 'MaxIterations', 1e4, 'StepTolerance',1e-300, 'Display','iter');
%options =optimoptions('lsqcurvefit','MaxFunctionEvaluations', 1e100, 'MaxIterations', 1e100,'Display','iter');
f = @(x, t_0)fun_lsq(x, t_0, dt, P, Q, dQ, IC_P);
%ydata=zeros(1, height(P))';
sol = lsqcurvefit(f, IC, t_0, P, LB, UB, options);
C_optim = sol(1); Rp_optim = sol(2); Rd_optim = sol(3);
%% Curve fitting using the fminsearch
% options = optimset('Display','iter','PlotFcns',@optimplotfval);
%
% f = @(x)fun_fmin(x, t_0, dt, P, Q, dQ, IC_P);
% sol = fminsearch(f,IC);
%% Solving and Plotting ODE for P
tspan = [t_0(1):dt:t_0(end)]; %Time interval of the integration
funP = @(t,y_P) P_odefcn(t, y_P, C, R1, R2, t_0, Q, dQ);
[t,y_P] = ode78(funP, tspan, IC_P);
funP_opt = @(t,y_P_opt) P_odefcn(t, y_P_opt, C, R1, R2, t_0, Q, dQ);
[t,y_P_opt] = ode78(funP, tspan, IC_P);
% y_Q = smooth(interp1(t, y_Q, t_0), 50);
y_P = smooth(interp1(t, y_P, t_0), 50);
y_P_opt = smooth(interp1(t, y_P, t_0), 50);
figure(1), plot(t_0, P), hold on, plot(t_0, y_P); hold on, plot(t_0, y_P_opt);
xlabel('Time'); ylabel('P')
legend('Actual', 'Stergiopoulos', 'Optimised')
%% Function for lsq optimisation
function f = fun_lsq(x, time, dt, P_in, Q_out, dQ_out, IC_p)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
tspan = [0:dt:time(end)]; %Time interval of the integration
%Solving the ODEs
fun2 = @(t,y) P_odefcn(t, y, C, R1, R2, time, Q_out, dQ_out);
[t,y] = ode78(fun2, tspan, IC_p);
P = y(:,1);
%Q=interp1(t, Q, time);
f = P-P_in;
end
%% Function for fminsearch optimisation
function f = fun_fmin(x, time, dt, P_in, Q_out, dQ_out, IC_p)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
tspan = [0:dt:time(end)]; %Time interval of the integration
%Solving the ODEs
fun2 = @(t,y) P_odefcn(t, y, C, R1, R2, time, Q_out, dQ_out);
[t,y] = ode78(fun2, tspan, IC_p);
P = y(:,1);
%Q=interp1(t, Q, time);
f = sqrt(sum((P-P_in).^2));
end
%% Function for ODE
function dPdt = P_odefcn(t, y, C, Rp, Rd, time, Q_in, dQ_in)
dPdt = zeros(1,1); %Initializing the output vector
%Determine the closest point to the current time
[d, closestIndex]=min(abs(time-t));
Q = Q_in(closestIndex);
dQ = dQ_in(closestIndex);
dPdt(1) =(Q/C)*(1+Rp/Rd) + Rp*dQ - y(1)/(C*Rd);
end
Both results look like this:
I do get the following for the LSQ method though:
6 Comments
Torsten
on 24 Mar 2024
If you use "lsqcurvefit", you must return
f = P;
not
f = P-P_in;
Don't you have a separate equation for Q so that you wouldn't need to differentiate your measurement data ?
[d, closestIndex]=min(abs(time-t));
Q = Q_in(closestIndex);
dQ = dQ_in(closestIndex);
Accepted Answer
Torsten
on 24 Mar 2024
Moved: Torsten
on 24 Mar 2024
I'd try to continue with the code below.
It seems that a variation of your initial parameters does not cause a change in P such that the initial values for C, R1 and R2 are returned by the solver.
Unfortunately, I do not have an equation for Q, since it is the output of a simulation, I can try to formulate one though - would that make a difference?
The difference is that the inputs to the differential equation for P would become smooth which is usually necessary for the integrators to succeed.
%% Inputs
R1 = 4.4e+6;
R2 = 1.05e+8;
C = 1.31e-8;
%Initial conditions for WK-3 parameters
IC = [C, R1, R2];
%% Importing flow and pressure data
RefPQWK = readtable('Ref_P_Q_WK_No-Osc_1-Cycle.csv');
t=RefPQWK.t;
Q=RefPQWK.Q;
P=RefPQWK.P;
P0=RefPQWK.P(1);
Q0=RefPQWK.Q(1);
%Initial conditions
IC_P = P(1);
%% Curve fitting using the method of least squares
LB = [1e-10 1 1]; UB = [1 1e10 1e10]; % Lower and Upper bounds
options = optimoptions('lsqcurvefit', 'Algorithm', 'levenberg-marquardt', 'MaxFunEvals',10000,'MaxIter',10000,'Display','iter');
f = @(x, t)fun_lsq(x, t, P, Q, IC_P);
sol = lsqcurvefit(f, IC, t, P, LB, UB, options);
C_optim = sol(1)
Rp_optim = sol(2)
Rd_optim = sol(3)
%% Solving and Plotting ODE for P
[t,Psim] = integration(C_optim,Rp_optim,Rd_optim,t,Q,IC_P);
hold on
plot(t,P)
plot(t,Psim)
hold off
%% Function for lsq optimisation
function f = fun_lsq(x, time, P_in, Q_out, IC_p)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
[t,y] = integration(C,R1,R2,time,Q_out,IC_p);
P = y(:,1);
f = P;
end
function [t,y] = integration(C,R1,R2,time,Q_out,IC_p)
fun2 = @(t,y) P_odefcn(t, y, C, R1, R2, time, Q_out);
[t,y] = ode45(fun2, time, IC_p);
end
%% Function for ODE
function dPdt = P_odefcn(t, y, C, Rp, Rd, time, Q_in)
dPdt = zeros(1,1); %Initializing the output vector
%Determine the closest point to the current time
%[d, closestIndex]=min(abs(time-t));
Q = interp1(time,Q_in,t);
for i = 1:numel(time)
if time(i+1) >= t
dQ = (Q_in(i+1)-Q_in(i))/(time(i+1)-time(i));
break
end
end
%dQ = dQ_in(closestIndex);
dPdt(1) =(Q/C)*(1+Rp/Rd) + Rp*dQ - y(1)/(C*Rd);
end
8 Comments
Torsten
on 25 Mar 2024
In my opinion, setting p_out = 0 is simply wrong because measurements and model have different asymptotic behavior (measurements tend to P(1), model tends to 0).
In your objective function for fminsearch, you should replace
f = sqrt(sum((P-P_in).^2))
by
f = sum((P-P_in).^2);
The sqrt makes your objective function non-differentiable at 0.
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!