I do not understand exit message given by lsqnonlin,
Show older comments
Hello everyone, I'm trying to do an estimation of parameter based on simulink electric circuit. My goal is minimize the error between simulated voltage and real one.
I wrote a code that runs different simulations in an iterative way in order to find parameter that are able to fit different measurements. I'm using lsqnonlin. I tried with fmincon, but since my object function is sum((Vsim-Vreal).^2) it seems to make more sense use lsqnonlin and change object function in (V_sim-V_real). The code runs and the cost function decreases (while remaining very high).
The optimization stop with this message: "fmincon stopped because the size of the current step is less than the value of the step size tolerance and constraints are satisfied to within the value of the constraint tolerance." but I can't understand why it refers to fmincon and why it says that about the current step since step tolerance is setted at 1e-8, and display iter shows 5.088e+01 as norm of step.
I also noticed that sometimes it stops because it evaluates a negative parameter (as resistance, and simulink automatically stop everything) also if i set boundaries and constraints in order to avoid that
I attach here the main code, avoiding all the import data and the initializations of different variables that runs with no problem .Hope someone is able to help me solving this. Thank you in advance for your time
while true
x0=x_in; %set initial guess
V_sim_tot=cell(length(data_sets)); %Initialize the vector in order to save all the V simulated
for i=1:length(data_sets) %Performing the optimization for the number of datasets I'm working with
I=[data_sets{i}.time,data_sets{i}.current]; %take into consideration current of the actual dataset. This will be input for simulink model
V_real=data_sets{i}.V_real; %Take into consideration real voltage for each datasets in order to perform optimization
assignin('base','V_0',v_in_C0(i)); %it assign the right initial voltage to C0 of the simulink model
%Define nested function
y = @(x) objectiveFunction(x, V_real);
cfun = @(x) myNonlinearConstraints(x);
% call optimization lsqnonlin
[x, exitflag, output] = lsqnonlin(y, x0,lb,ub,A , b, [], [], cfun, opts);
x0=x;
V_sim_tot{i}=V_sim; %Save final voltage for each datasets
end
iter=iter+1; %advance with iterstions
%Evaluating different conditions for stopping criteria
if ( (iter>min_iter) && (norm(x_in-x0)<=tol) ) %if the code have done enough iteration(>min_iter) and if the n
x_opt=x0;
disp('Optimal vector is not changing')
break
elseif (iter>max_iter)
x_opt=x0;
disp('Maximum iterations reached')
break
else
x_in=x0;
end
end
function [c1,c2,c3,c4,c5,c6,ceq] = myNonlinearConstraints(x)
V_sim= evalin('base','V_sim');
Vsim_max = max(V_sim);
c1 = x(1).*x(4)-120;
c2= x(2).*x(5)-1800;
c3= 120- x(2).*x(5);
c4= x(3).*x(6)-5400;
c5= 1800-x(3).*x(6);
c6= V_sim-105;
ceq = [];
end
function V_sim = mySimulation(x)
assignin('base', 'R0', x(1));
assignin('base', 'R1', x(2));
assignin('base', 'R2', x(3));
assignin('base', 'C0', x(4));
assignin('base', 'C1', x(5));
assignin('base', 'C2', x(6));
sim('RC_branch');
end
function y = objectiveFunction(x,V_real)
V_sim=mySimulation(x);
assignin('base', 'V_sim', V_sim);
y= (V_sim - V_real);
end
Accepted Answer
More Answers (1)
Should be
function [c,ceq] = myNonlinearConstraints(x)
V_sim= evalin('base','V_sim');
Vsim_max = max(V_sim);
c(1) = x(1).*x(4)-120;
c(2)= x(2).*x(5)-1800;
c(3)= 120- x(2).*x(5);
c(4)= x(3).*x(6)-5400;
c(5)= 1800-x(3).*x(6);
c(6)= Vsim_max-105;
ceq = [];
end
instead of
function [c1,c2,c3,c4,c5,c6,ceq] = myNonlinearConstraints(x)
V_sim= evalin('base','V_sim');
Vsim_max = max(V_sim);
c1 = x(1).*x(4)-120;
c2= x(2).*x(5)-1800;
c3= 120- x(2).*x(5);
c4= x(3).*x(6)-5400;
c5= 1800-x(3).*x(6);
c6= V_sim-105;
ceq = [];
end
And the actual V_sim is not available in "myNonlinearConstraints", is it ? Why didn't you stick to the embedded function solution suggested before ?
And concerning "fmincon", I don't have an explanation. Maybe you should start MATLAB anew or at least clear your workspace when rerunning your code.
18 Comments
John D'Errico
on 28 Aug 2023
When MathWorks decided to allow lsqnonlin to use general constraints beyond just bounds, they did so by making it a wrapper to then call fmincon. So the termination statement was generated by fmincon.
Irene Fodale
on 28 Aug 2023
Torsten
on 28 Aug 2023
At first when it's inside lsqnonlin, it goes to my object function, save V_sim on workspace thank to "assignin" so myconstraint can take the value from workspace.
This assumes that lsqnonlin calls objective and constraints alternately. This is not true in general.
Irene Fodale
on 28 Aug 2023
I'm not sure what you mean. How it should work?
Both functions (objective and constraint function) must work with the V_sim that is deduced from the actual x transfered to these functions. This is not guaranteed with your new code, I guess.
c(6)= V_sim-105;
Please copy my code correctly.
When MathWorks decided to allow lsqnonlin to use general constraints beyond just bounds, they did so by making it a wrapper to then call fmincon. So the termination statement was generated by fmincon.
Thank you for the info. I thought it is a real improvement :-)
Irene Fodale
on 28 Aug 2023
Irene Fodale
on 28 Aug 2023
Irene Fodale
on 28 Aug 2023
Your approach does not make sense. First of all, you will never get parameters that will be valid for all your datasets separately. Second, imagine you want to fit one parameter and for x_in = 3, you get in your loop over the datasets x = 245, x = -105, x = 2145 and x = 3.0000001. Now you accept a parameter that is nonsense for datasets 1, 2 and 3.
The usual way to handle this is:
Use all your datasets V_real{i} at once, determine the corresponding V_sim{i} and return sum_i sum_j (V_real{i}(j)-V_sim{i}(j))^2 to "fmincon" - all in only one call to the optimizer.
Irene Fodale
on 28 Aug 2023
Irene Fodale
on 28 Aug 2023
So you basically are saying to collect the data of n different data set in one vector, so V_real{i} will be the concatenation of V_real{1},V_real{2},..., V_real{n}. The optimization will run now on a "virtual dataset" that is the concatenation of n real datasets.
Yes.
If this is right, what should be the index j that you define sum_i sum_j (V_real{i}(j)-V_sim{i}(j))^2 ?
The index to sum over the elements of V_real{i} (and V_sim{i}) (j = 1:numel(V_real{i}))
But the problem remains that in "myNonlinearConstraints", you don't work with the actual "V_sim" in most cases.
And again you have c(6)= V_sim-105;
And there are no inputs to "myNonlinearConstraints"
And you don't assign sim('RC_branch') to V_sim in "mySimulation".
Irene Fodale
on 28 Aug 2023
But the problem remains that in "myNonlinearConstraints", you don't work with the actual "V_sim" in most cases.
I'm sorry but I still do not understand why you say that and how it should be solved.
The variable vector x you receive from "fmincon" in function "myNonlinearConstraints" needn't be the same vector with which you calculated V_sim in function "objectiveFunction" before. So it may happen that all inequalities or equalities that use V_sim in function "myNonlinearConstraints" get formulated with an array V_sim that does not correspond to the x that is input to this function.
The problem can be solved by either calling your Simulink simulation in both functions ("myNonlinearConstraints" and "objectiveFunction") or - in order to save calls - by using the embedded functions approach derived earlier. MATLAB engineers don't suggest this rather complicated approach if the problem could be solved as easily as you try it in your code ...
If I set V_sim=sim('RC_branch'), V_sim returns the simulation time. On simulink I have a "to workspace" that after each simulations return the vector "V_sim".
So in the assignment
V_sim_con=[V_sim_con;V_sim];
MATLAB knows of an array V_sim although it is nowhere assigned in the function ? I didn't know of this before.
function V_sim_con = mySimulation(x,data_sets)
assignin('base', 'R0', x(1));
assignin('base', 'R1', x(2));
assignin('base', 'R2', x(3));
assignin('base', 'C0', x(4));
assignin('base', 'C1', x(5));
assignin('base', 'C2', x(6));
V_sim_con=[];
for i=1:length(data_sets)
I = [data_sets{i}.time, data_sets{i}.current];
assignin('base', 'I', I);
sim('RC_branch');
V_sim_con=[V_sim_con;V_sim];
end
end
Irene Fodale
on 28 Aug 2023
Edited: Irene Fodale
on 28 Aug 2023
I don't know about your Simulink settings, but does
out=sim('RC_branch');
V_sim=out.V_sim;
really give you back an array of size V_real_con that is the simulated equivalent of your measurement data ? Don't you have to call Simulink for each data set separately to get back the equivalent of data_sets{i}.V_real ?
Since you don't use it anywhere, you can skip "out" as an output argument from "computeall":
function [f1,c,ceq] = computeall(x,V_real_con)
instead of
function [f1,c,ceq,out] = computeall(x,V_real_con)
Categories
Find more on Linear Algebra in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!