Open T-Buesing opened 3 years ago
After trying out different ways of defining system properties to store the opti object, I can get stepImpl
to access a constructed Opti solver via nested structs. Problem is, it still loses the names of variables/parameters defined during initialization.
If we take the racecar example, it is possible to initialize in setupImpl
and within stepImpl
call
opti=obj.optstruct.opti1
sol=opti.solve
then sol does indeed contain the calculated solution, but commands like sol.value(speed)
or sol.value(T)
result in
Unrecognized function or variable 'speed'.
Unrecognized function or variable 'T'.
Inspecting the solution with sol.value_variables
shows them as expressions.
val =
(1.90463==opti39_x_3)
But it's not accessible through sol.value(opti39_x_3)
So far I've only managed to extract the numeric value from sol.value_variables{i,j}
by converting the expression containing it into a string and then using str2num on a slice of it.
The same declaration loss applies to parameters, they only appear in opti.value_parameters
as expression, e.g.
ans =
(123==opti40_p_1)
They can't be addressed with opti.set_value(opti40_p_1 , 234)
before running opti.solve
, so setting parameters to new values for a step doesn't seem possible.
Setting new parameters per step was talked about in https://github.com/casadi/casadi/issues/2439 but there is no mention about how the OP employed Opti inside Simulink
- In the matlab system script, declare a property in "properties (Access=private)", for example, "casadi_solver"
- In setupImpl, create opti by writing "opti = casadi.Opti()"
- Again in setupImpl, define solver used by opti, for example, "opti.solver('ipopt', opti_options, ipopt_options)"
- Again in setupImpl, assign the opti to casadi_solver, "obj.casadi_solver = opti"
- Then in stepImpl, you can invoke the solver by writing "obj.casadi_solver.solve()"
- You can even set initial value by "obj.casadi_solver.set_initial(your_problems_optimization_variables, your_guess);
I have a question for you Zheng-JIA ! I did exactly same process you mentioned above. However, once I set value of parameter my Simulink cannot find parameter that I already set in setupImpl.
For example, the parameter 'X0' is defined in setupImpl. Next, I invoke the solver in stepImpl as mentioned, and I set the value of X0 in stepImpl. But the error comes up "X0 is not a recognizable function or variable" (This may not be an exact translation because I'm not using English version. Sorry for that). Here's the brief code below. Can you help me please?
function setupImpl(obj,~,~)
import casadi.*
....
opti = casadi.Opti();
....
X0 = opti.parameter(n_x, 1);
....
opti.minimize(cost);
p_opts = struct('expand',true);
s_opts = struct('max_iter',100);
opti.solver('ipopt',p_opts, s_opts)
obj.casadi_solver = opti;
end
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1)
....
obj.casadi_solver.set_value(X0, x_pre(:,1));
....
sol = obj.casadi_solver.solve();
....
end
- In the matlab system script, declare a property in "properties (Access=private)", for example, "casadi_solver"
- In setupImpl, create opti by writing "opti = casadi.Opti()"
- Again in setupImpl, define solver used by opti, for example, "opti.solver('ipopt', opti_options, ipopt_options)"
- Again in setupImpl, assign the opti to casadi_solver, "obj.casadi_solver = opti"
- Then in stepImpl, you can invoke the solver by writing "obj.casadi_solver.solve()"
- You can even set initial value by "obj.casadi_solver.set_initial(your_problems_optimization_variables, your_guess);
I have a question for you Zheng-JIA ! I did exactly same process you mentioned above. However, once I set value of parameter my Simulink cannot find parameter that I already set in setupImpl.
For example, the parameter 'X0' is defined in setupImpl. Next, I invoke the solver in stepImpl as mentioned, and I set the value of X0 in stepImpl. But the error comes up "X0 is not a recognizable function or variable" (This may not be an exact translation because I'm not using English version. Sorry for that). Here's the brief code below. Can you help me please?
function setupImpl(obj,~,~) import casadi.* .... opti = casadi.Opti(); .... X0 = opti.parameter(n_x, 1); .... opti.minimize(cost); p_opts = struct('expand',true); s_opts = struct('max_iter',100); opti.solver('ipopt',p_opts, s_opts) obj.casadi_solver = opti; end
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1) .... obj.casadi_solver.set_value(X0, x_pre(:,1)); .... sol = obj.casadi_solver.solve(); .... end
Hi, First of all, obj refers to the object of your MATLAB system object. Similar to any object oriented programming, you need to set variable to its properties so the object's function/method knows there exist such variable in the object. In you problem, X0 is locally declared in setupImpl. You need to
properties (Access = private)
casadi_solver
X0
end
function setupImpl(obj,~,~)
import casadi.*
....
opti = casadi.Opti();
....
obj.X0 = opti.parameter(n_x, 1); % save the parameter varaible to object's properties
....
opti.minimize(cost);
p_opts = struct('expand',true);
s_opts = struct('max_iter',100);
opti.solver('ipopt',p_opts, s_opts)
obj.casadi_solver = opti;
end
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1)
....
obj.casadi_solver.set_value(obj.X0, x_pre(:,1)); % use obj.X0 that is the parameter saved in object's properties
....
sol = obj.casadi_solver.solve();
....
end
Try it out and see if it works. Zheng
- In the matlab system script, declare a property in "properties (Access=private)", for example, "casadi_solver"
- In setupImpl, create opti by writing "opti = casadi.Opti()"
- Again in setupImpl, define solver used by opti, for example, "opti.solver('ipopt', opti_options, ipopt_options)"
- Again in setupImpl, assign the opti to casadi_solver, "obj.casadi_solver = opti"
- Then in stepImpl, you can invoke the solver by writing "obj.casadi_solver.solve()"
- You can even set initial value by "obj.casadi_solver.set_initial(your_problems_optimization_variables, your_guess);
I have a question for you Zheng-JIA ! I did exactly same process you mentioned above. However, once I set value of parameter my Simulink cannot find parameter that I already set in setupImpl. For example, the parameter 'X0' is defined in setupImpl. Next, I invoke the solver in stepImpl as mentioned, and I set the value of X0 in stepImpl. But the error comes up "X0 is not a recognizable function or variable" (This may not be an exact translation because I'm not using English version. Sorry for that). Here's the brief code below. Can you help me please?
function setupImpl(obj,~,~) import casadi.* .... opti = casadi.Opti(); .... X0 = opti.parameter(n_x, 1); .... opti.minimize(cost); p_opts = struct('expand',true); s_opts = struct('max_iter',100); opti.solver('ipopt',p_opts, s_opts) obj.casadi_solver = opti; end
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1) .... obj.casadi_solver.set_value(X0, x_pre(:,1)); .... sol = obj.casadi_solver.solve(); .... end
Hi, First of all, obj refers to the object of your MATLAB system object. Similar to any object oriented programming, you need to set variable to its properties so the object's function/method knows there exist such variable in the object. In you problem, X0 is locally declared in setupImpl. You need to
- declare obj.X0 in the properties(Access = private)
properties (Access = private) casadi_solver X0 end
- write obj.X0 = opti.parameter(n_x, 1); in setupImpl
function setupImpl(obj,~,~) import casadi.* .... opti = casadi.Opti(); .... obj.X0 = opti.parameter(n_x, 1); % save the parameter varaible to object's properties .... opti.minimize(cost); p_opts = struct('expand',true); s_opts = struct('max_iter',100); opti.solver('ipopt',p_opts, s_opts) obj.casadi_solver = opti; end
- write obj.casadi_solver.set_value(obj.X0, x_pre(:,1)); in setpImpl
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1) .... obj.casadi_solver.set_value(obj.X0, x_pre(:,1)); % use obj.X0 that is the parameter saved in object's properties .... sol = obj.casadi_solver.solve(); .... end
Try it out and see if it works. Zheng
Thank you, Zheng It works! And I've figured out that not only parameters but also variables must be declared in the properties(Access = private). Appreciate it!
- In the matlab system script, declare a property in "properties (Access=private)", for example, "casadi_solver"
- In setupImpl, create opti by writing "opti = casadi.Opti()"
- Again in setupImpl, define solver used by opti, for example, "opti.solver('ipopt', opti_options, ipopt_options)"
- Again in setupImpl, assign the opti to casadi_solver, "obj.casadi_solver = opti"
- Then in stepImpl, you can invoke the solver by writing "obj.casadi_solver.solve()"
- You can even set initial value by "obj.casadi_solver.set_initial(your_problems_optimization_variables, your_guess);
I have a question for you Zheng-JIA ! I did exactly same process you mentioned above. However, once I set value of parameter my Simulink cannot find parameter that I already set in setupImpl. For example, the parameter 'X0' is defined in setupImpl. Next, I invoke the solver in stepImpl as mentioned, and I set the value of X0 in stepImpl. But the error comes up "X0 is not a recognizable function or variable" (This may not be an exact translation because I'm not using English version. Sorry for that). Here's the brief code below. Can you help me please?
function setupImpl(obj,~,~) import casadi.* .... opti = casadi.Opti(); .... X0 = opti.parameter(n_x, 1); .... opti.minimize(cost); p_opts = struct('expand',true); s_opts = struct('max_iter',100); opti.solver('ipopt',p_opts, s_opts) obj.casadi_solver = opti; end
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1) .... obj.casadi_solver.set_value(X0, x_pre(:,1)); .... sol = obj.casadi_solver.solve(); .... end
Hi, First of all, obj refers to the object of your MATLAB system object. Similar to any object oriented programming, you need to set variable to its properties so the object's function/method knows there exist such variable in the object. In you problem, X0 is locally declared in setupImpl. You need to
- declare obj.X0 in the properties(Access = private)
properties (Access = private) casadi_solver X0 end
- write obj.X0 = opti.parameter(n_x, 1); in setupImpl
function setupImpl(obj,~,~) import casadi.* .... opti = casadi.Opti(); .... obj.X0 = opti.parameter(n_x, 1); % save the parameter varaible to object's properties .... opti.minimize(cost); p_opts = struct('expand',true); s_opts = struct('max_iter',100); opti.solver('ipopt',p_opts, s_opts) obj.casadi_solver = opti; end
- write obj.casadi_solver.set_value(obj.X0, x_pre(:,1)); in setpImpl
function [x_pred, u_pred, lat_caltime, MPC_fail] = stepImpl(obj, x_pre, u_pre, x_ref, curv1, curv2, VX1) .... obj.casadi_solver.set_value(obj.X0, x_pre(:,1)); % use obj.X0 that is the parameter saved in object's properties .... sol = obj.casadi_solver.solve(); .... end
Try it out and see if it works. Zheng
Thank you, Zheng It works! And I've figured out that not only parameters but also variables must be declared in the properties(Access = private). Appreciate it!
Great! I also observed that stepImpl will be called more than once in simulink. Currently I have no clue to force this function to be called only once at every simulation step. If you later know how to do this, let me know.
Hi,
I've been trying to set up an NLMPC within Matlab Simulink by using the interpreted Matlab Systems method outlined in https://web.casadi.org/blog/mpc-simulink/ just with the Optistack syntax. Because my problem features multiple phases, free end time and changing model parameters, keeping as much readability for setting up the solver(s) would be nice. I'd like to reduce my problem definition once each phase has finished. So my idea was to initialize multiple Opti solvers with successively reduced phase count and then call the currently appropriate solver within a state machine.
Initial
setupImpl
works fine, and the system object becomes a complete Opti object that can be solved by calling it.But once it transitions into
stepImpl
the system object becomes empty and unusable.I've tried different inputs in the properties section, but the results are the same. Is Opti not meant for use within Simulink, or am I missing a certain setting in either the block parameters or the definitions of the system?
Best regards!