I have a question regarding the choice of prediction horizon.
In my understanding a bigger prediction horizon should stabilize the control of the system in MPC.
However when I choose the prediction horizon (N Ts) for my example below to high the results of a setpoint tracking simulation deteriorate with growing prediction horizon.
I attached the results of the simulation for prediction horizons of 60, 90 and 100 seconds to demonstrate my problem. I figured out then that if I raise the number of iterations according to the length of the predicition horizon (N Ts) the results get equivalent for all horizon length
user.opt.Nhor = N*Ts; % Number of steps for the system integration
user.opt.MaxGradIter = N*Ts; % Maximum number of gradient iterations
user.opt.MaxMultIter = N*Ts; % Maximum number of augmented Lagrangian iterations
user.opt.ConvergenceCheck = 'on';
When I choose a prediction horizon higher than exactly 112 my simulation terminates becaue of NaN values although my problemfct.c does not define divisions by zero even for unphysical values of states and controls.
Does somebody know how those NaN values could be explained?
Also if I use grampc_estim_penmin_Cmex for a horizon bigger than 112 it gives the error:
PenaltyMin: Invalid value for option.
Error using grampc_estim_penmin_Cmex
Invalid setting of option or parameter
I am clearly missing something here. Any hint is appreciated.
Best regards
startMPC.m
function[vec,grampc,figNr]=startMPC(figNr,compile,varargin)%%Checkinputargumentsifnargin<1||isempty(figNr)figNr=1;endifnargin<2||isempty(compile)compile=0;end%%Parameters%pathtogrampcrootgrampc_root_path='../GRAMPC_v2.1/';addpath([grampc_root_path'matlab/mfiles']);%nameofproblemfunctionprobfct='probfct_tank.c';%plotpredictedtrajectoriesPLOT_PRED=1;%plotsolutiontrajectoriesPLOT_TRAJ=1;%plotoptimizationstatisticsPLOT_STAT=1;%updateplotsafterNstepsPLOT_STEPS=10;%pauseaftereachplotPLOT_PAUSE=0;%problem-specificplotPLOT=0;%Optionsforthereferencesimulationodeopt=[];%odeset('RelTol',1e-6,'AbsTol',1e-8);%%Compilation%compiletoolboxifcompile>1||~exist([grampc_root_path'matlab/bin'],'dir')grampc_make_toolbox(grampc_root_path,varargin{:});end%compileproblemifcompile>0||~exist('+CmexFiles','dir')grampc_make_probfct(grampc_root_path,probfct,varargin{:});end%%Initialization%initGRAMPCandprintoptionsandparameters[grampc,Tsim]=initData;CmexFiles.grampc_printopt_Cmex(grampc);CmexFiles.grampc_printparam_Cmex(grampc);%initsolutionstructurevec=grampc_init_struct_sol(grampc,Tsim);%initplotsandstorefigurehandlesifPLOT_PREDphpP=grampc_init_plot_pred(grampc,figNr);figNr=figNr+1;endifPLOT_TRAJphpT=grampc_init_plot_sim(vec,figNr);figNr=figNr+1;endifPLOT_STATphpS=grampc_init_plot_stat(vec,grampc,figNr);figNr=figNr+1;end%%MPCloopi=1;while1%setcurrenttimeandcurrentstategrampc=CmexFiles.grampc_setparam_Cmex(grampc,'t0',vec.t(i));grampc=CmexFiles.grampc_setparam_Cmex(grampc,'x0',vec.x(:,i));%%Führungsgrößensprungifi>200grampc=CmexFiles.grampc_setparam_Cmex(grampc,'xdes',[150,130,125,5000,5000,5000]);end%runMPCandsaveresults[grampc,vec.CPUtime(i)]=CmexFiles.grampc_run_Cmex(grampc);vec=grampc_update_struct_sol(grampc,vec,i);%printsolverstatusprinted=CmexFiles.grampc_printstatus_Cmex(grampc.sol.status,'Error');ifprintedfprintf('at simulation time %f.\n --------\n',vec.t(i));end%checkforendofsimulationifi+1>length(vec.t)break;end%simulatesystem[~,xtemp]=ode45(@CmexFiles.grampc_ffct_Cmex,vec.t(i)+[0double(grampc.param.dt)],vec.x(:,i),odeopt,vec.u(:,i),vec.p(:,i),grampc.userparam);vec.x(:,i+1)=xtemp(end,:);%evaluatetime-dependentconstraints%toobtainh(x,u,p)insteadofmax(0,h(x,u,p))vec.constr(:,i)=CmexFiles.grampc_ghfct_Cmex(vec.t(i),vec.x(:,i),vec.u(:,i),vec.p(:,i),grampc.userparam);%updateiterationcounteri=i+1;%plotdataifmod(i,PLOT_STEPS)==0||i==length(vec.t)ifPLOT_PREDgrampc_update_plot_pred(grampc,phpP);endifPLOT_TRAJgrampc_update_plot_sim(vec,phpT);endifPLOT_STATgrampc_update_plot_stat(vec,grampc,phpS);enddrawnowifPLOT_PAUSEpause;endendendend
#include"probfct.h"#define NPSYS 7 // size(p), s.u.#define NPCOST 9 // size(p), s.u.#define NPCONSTR 18#define NPOFFSET 18/* square macro */#define POW2(a) ((a)*(a))#define SIGNAP(x) tanh(10000*x)#define ABSAP(x) sqrt(pow(x,2)+1e-10)#define TANH(x) tanh(x)#define SQRT(x) ((x) > 0 ? sqrt(x): 1e-16)#define ALMOSTZERO(x) ((x) != 0 ? (x): 1e-16)/** OCP dimensions: states (Nx), controls (Nu), parameters (Np), equalities (Ng), inequalities (Nh), terminal equalities (NgT), terminal inequalities (NhT) **/voidocp_dim(typeInt*Nx,typeInt*Nu,typeInt*Np,typeInt*Ng,typeInt*Nh,typeInt*NgT,typeInt*NhT,typeUSERPARAM*userparam){*Nx=6;// h1=x[0] h2=x[1] h3=x[2] p1=x[3] p2=x[4] v12=x[5]*Nu=3;// delta_p1=u[0] delta_p2=u[1] delta_v12=u[2]*Np=0;//*Nh=18;//*Ng=0;*NgT=0;*NhT=0;}/** System function f(t,x,u,p,userparam) ------------------------------------ **/voidffct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){// typeRNum ist double// ctypeRNum ist constant doublectypeRNum*pSys=(typeRNum*)userparam;ctypeRNumf3=2;// C arrays werden ab 0 indiziert --> p(1) = pSys[0]...; p(7) = pSys[6]; p(6) = pSys[5]out[0]=pSys[0]*x[3]-x[5]*pSys[2]*SIGNAP(x[0]-x[1])*SQRT(f3*pSys[6]*ABSAP(x[0]-x[1]));out[1]=x[5]*pSys[2]*SIGNAP(x[0]-x[1])*SQRT(f3*pSys[6]*ABSAP(x[0]-x[1]))-pSys[3]*SIGNAP(x[1]-x[2])*SQRT(f3*pSys[6]*ABSAP(x[1]-x[2]));out[2]=pSys[3]*SIGNAP(x[1]-x[2])*SQRT(f3*pSys[6]*ABSAP(x[1]-x[2]))+pSys[1]*x[4]-pSys[4]*(ctypeRNum)(4.8)*SQRT(f3*pSys[6]*x[2]);out[3]=u[0];out[4]=u[1];out[5]=u[2];}/** Jacobian df/dx multiplied by vector vec, i.e. (df/dx)^T*vec or vec^T*(df/dx) **/voiddfdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(typeRNum*)userparam;ctypeRNumf1=1e4;ctypeRNumf2=1e-10;ctypeRNumf3=2;out[0]=vec[0]*((SQRT(f3))*f1*pSys[2]*x[5]*((POW2(TANH(f1*(x[0]-x[1]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))-((SQRT(f3))*pSys[2]*pSys[6]*x[5]*TANH(f1*(x[0]-x[1]))*(f3*x[0]-f3*x[1]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[0]-x[1]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))))-vec[1]*((SQRT(f3))*f1*pSys[2]*x[5]*((POW2(TANH(f1*(x[0]-x[1]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))-((SQRT(f3))*pSys[2]*pSys[6]*x[5]*TANH(f1*(x[0]-x[1]))*(f3*x[0]-f3*x[1]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[0]-x[1]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))));out[1]=vec[1]*((SQRT(f3))*f1*pSys[3]*((POW2(TANH(f1*(x[1]-x[2]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))+(SQRT(f3))*f1*pSys[2]*x[5]*((POW2(TANH(f1*(x[0]-x[1]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))-((SQRT(f3))*pSys[3]*pSys[6]*TANH(f1*(x[1]-x[2]))*(f3*x[1]-f3*x[2]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[1]-x[2]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2]))))))))))-((SQRT(f3))*pSys[2]*pSys[6]*x[5]*TANH(f1*(x[0]-x[1]))*(f3*x[0]-f3*x[1]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[0]-x[1]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))))-vec[0]*((SQRT(f3))*f1*pSys[2]*x[5]*((POW2(TANH(f1*(x[0]-x[1]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))-((SQRT(f3))*pSys[2]*pSys[6]*x[5]*TANH(f1*(x[0]-x[1]))*(f3*x[0]-f3*x[1]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[0]-x[1]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))))-vec[2]*((SQRT(f3))*f1*pSys[3]*((POW2(TANH(f1*(x[1]-x[2]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))-((SQRT(f3))*pSys[3]*pSys[6]*TANH(f1*(x[1]-x[2]))*(f3*x[1]-f3*x[2]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[1]-x[2]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))));out[2]=-vec[1]*((SQRT(f3))*f1*pSys[3]*((POW2(TANH(f1*(x[1]-x[2]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))-((SQRT(f3))*pSys[3]*pSys[6]*TANH(f1*(x[1]-x[2]))*(f3*x[1]-f3*x[2]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[1]-x[2]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))))-vec[2]*((12*(SQRT(f3))*pSys[4]*pSys[6])/ALMOSTZERO(5*(SQRT((x[2]*pSys[6]))))-(SQRT(f3))*f1*pSys[3]*((POW2(TANH(f1*(x[1]-x[2]))))-1)*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))+((SQRT(f3))*pSys[3]*pSys[6]*TANH(f1*(x[1]-x[2]))*(f3*x[1]-f3*x[2]))/ALMOSTZERO(4*(SQRT((f2+(POW2((x[1]-x[2]))))))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[1]-x[2])))))))))));out[3]=pSys[0]*vec[0];out[4]=pSys[1]*vec[2];out[5]=(SQRT(f3))*pSys[2]*vec[1]*TANH(f1*(x[0]-x[1]))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))))-(SQRT(f3))*pSys[2]*vec[0]*TANH(f1*(x[0]-x[1]))*(SQRT((pSys[6]*(SQRT((f2+(POW2((x[0]-x[1])))))))));}/** Jacobian df/du multiplied by vector vec, i.e. (df/du)^T*vec or vec^T*(df/du) **/voiddfdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;out[0]=vec[3];out[1]=vec[4];out[2]=vec[5];}/** Jacobian df/dp multiplied by vector vec, i.e. (df/dp)^T*vec or vec^T*(df/dp) **/voiddfdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Integral cost l(t,x(t),u(t),p,xdes,udes,userparam) -------------------------------------------------- **/voidlfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;// Verschieben der Adresse in Zeiger p = userparam um NPSYS (=size(p)) nach vorn, um pCost zu erreichen wie in initData.m definiertout[0]=pCost[0]*POW2(x[0]-xdes[0])/(typeRNum)84100+pCost[1]*POW2(x[1]-xdes[1])/(typeRNum)84100+pCost[2]*POW2(x[2]-xdes[2])/(typeRNum)84100+pCost[6]*POW2(u[0]-udes[0])/(typeRNum)98+pCost[7]*POW2(u[1]-udes[1])/(typeRNum)98+pCost[8]*POW2(u[2]-udes[2])/(typeRNum)98;}/** Gradient dl/dx **/voiddldx(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;out[0]=2*pCost[0]*(x[0]-xdes[0])/(typeRNum)84100;out[1]=2*pCost[1]*(x[1]-xdes[1])/(typeRNum)84100;out[2]=2*pCost[2]*(x[2]-xdes[2])/(typeRNum)84100;out[3]=0;out[4]=0;out[5]=0;}/** Gradient dl/du **/voiddldu(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;out[0]=2*pCost[6]*(u[0]-udes[0])/(typeRNum)98;out[1]=2*pCost[7]*(u[1]-udes[1])/(typeRNum)98;out[2]=2*pCost[8]*(u[2]-udes[2])/(typeRNum)98;}/** Gradient dl/dp **/voiddldp(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){}/** Terminal cost V(T,x(T),p,xdes,userparam) ---------------------------------------- **/voidVfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;out[0]=pCost[3]*POW2(x[0]-xdes[0])/(typeRNum)84100+pCost[4]*POW2(x[1]-xdes[1])/(typeRNum)84100+pCost[5]*POW2(x[2]-xdes[2])/(typeRNum)84100;}/** Gradient dV/dx **/voiddVdx(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;out[0]=2*pCost[3]*(x[0]-xdes[0])/(typeRNum)84100;out[1]=2*pCost[4]*(x[1]-xdes[1])/(typeRNum)84100;out[2]=2*pCost[5]*(x[2]-xdes[2])/(typeRNum)84100;out[3]=0;out[4]=0;out[5]=0;}/** Gradient dV/dp **/voiddVdp(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){}/** Gradient dV/dT **/voiddVdT(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){}/** Equality constraints g(t,x(t),u(t),p,uperparam) = 0 --------------------------------------------------- **/voidgfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dg/dx multiplied by vector vec, i.e. (dg/dx)^T*vec or vec^T*(dg/dx) **/voiddgdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dg/du multiplied by vector vec, i.e. (dg/du)^T*vec or vec^T*(dg/du) **/voiddgdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dg/dp multiplied by vector vec, i.e. (dg/dp)^T*vec or vec^T*(dg/dp) **/voiddgdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Inequality constraints h(t,x(t),u(t),p,uperparam) <= 0 ------------------------------------------------------ **/voidhfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pConstr=pSys+NPSYS+NPCOST;ctypeRNum*pOffset=pSys+NPSYS+NPCOST+NPCONSTR;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;out[0]=((x[0]-pOffset[0])-pConstr[0])/pScale[0];out[1]=((x[1]-pOffset[1])-pConstr[1])/pScale[1];out[2]=((x[2]-pOffset[2])-pConstr[2])/pScale[2];out[3]=((x[3]-pOffset[3])-pConstr[3])/pScale[3];out[4]=((x[4]-pOffset[4])-pConstr[4])/pScale[4];out[5]=((x[5]-pOffset[5])-pConstr[5])/pScale[5];out[6]=(-(x[0]-pOffset[6])+pConstr[6])/pScale[6];out[7]=(-(x[1]-pOffset[7])+pConstr[7])/pScale[7];out[8]=(-(x[2]-pOffset[8])+pConstr[8])/pScale[8];out[9]=(-(x[3]-pOffset[9])+pConstr[9])/pScale[9];out[10]=(-(x[4]-pOffset[10])+pConstr[10])/pScale[10];out[11]=(-(x[5]-pOffset[11])+pConstr[11])/pScale[11];// Inequality for deltaout[12]=((u[0])-pConstr[12])/pScale[12];out[13]=((u[1])-pConstr[13])/pScale[13];out[14]=((u[2])-pConstr[14])/pScale[14];out[15]=(-(u[0])+pConstr[15])/pScale[15];out[16]=(-(u[1])+pConstr[16])/pScale[16];out[17]=(-(u[2])+pConstr[17])/pScale[17];}/** Jacobian dh/dx multiplied by vector vec, i.e. (dh/dx)^T*vec or vec^T*(dg/dx) **/voiddhdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;//[dhdx] = [nh x nx] = [12 x 6], tag_onenote:jacobi_dhdxout[0]=vec[0]/pScale[0]-vec[6]/pScale[6];out[1]=vec[1]/pScale[1]-vec[7]/pScale[7];out[2]=vec[2]/pScale[2]-vec[8]/pScale[8];out[3]=vec[3]/pScale[3]-vec[9]/pScale[9];out[4]=vec[4]/pScale[4]-vec[10]/pScale[10];out[5]=vec[5]/pScale[5]-vec[11]/pScale[11];}/** Jacobian dh/du multiplied by vector vec, i.e. (dh/du)^T*vec or vec^T*(dg/du) **/voiddhdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;out[0]=vec[12]/pScale[12]-vec[15]/pScale[15];out[1]=vec[13]/pScale[13]-vec[16]/pScale[16];out[2]=vec[14]/pScale[14]-vec[17]/pScale[17];}/** Jacobian dh/dp multiplied by vector vec, i.e. (dh/dp)^T*vec or vec^T*(dg/dp) **/voiddhdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Terminal equality constraints gT(T,x(T),p,uperparam) = 0 -------------------------------------------------------- **/voidgTfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dgT/dx multiplied by vector vec, i.e. (dgT/dx)^T*vec or vec^T*(dgT/dx) **/voiddgTdx_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}voidtdgdu_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dgT/dp multiplied by vector vec, i.e. (dgT/dp)^T*vec or vec^T*(dgT/dp) **/voiddgTdp_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dgT/dT multiplied by vector vec, i.e. (dgT/dT)^T*vec or vec^T*(dgT/dT) **/voiddgTdT_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Terminal inequality constraints hT(T,x(T),p,uperparam) <= 0 ----------------------------------------------------------- **/voidhTfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dhT/dx multiplied by vector vec, i.e. (dhT/dx)^T*vec or vec^T*(dhT/dx) **/voiddhTdx_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dhT/dp multiplied by vector vec, i.e. (dhT/dp)^T*vec or vec^T*(dhT/dp) **/voiddhTdp_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dhT/dT multiplied by vector vec, i.e. (dhT/dT)^T*vec or vec^T*(dhT/dT) **/voiddhTdT_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Additional functions required for semi-implicit systems M*dx/dt(t) = f(t0+t,x(t),u(t),p) using the solver RODAS ------------------------------------------------------- **//** Jacobian df/dx in vector form (column-wise) **/voiddfdx(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian df/dx in vector form (column-wise) **/voiddfdxtrans(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian df/dt **/voiddfdt(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian d(dH/dx)/dt **/voiddHdxdt(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*vec,ctypeRNum*p,typeUSERPARAM*userparam){}/** Mass matrix in vector form (column-wise, either banded or full matrix) **/voidMfct(typeRNum*out,typeUSERPARAM*userparam){}/** Transposed mass matrix in vector form (column-wise, either banded or full matrix) **/voidMtrans(typeRNum*out,typeUSERPARAM*userparam){}
I downloaded your code and ran your example, but was not able to reproduce your results. For me the results looked good regardless of the prediction horizon (60, 90, 100). Are you using single or double precision floating points? Furthermore a lot less iterations were sufficient for me, i.e. 5/5 did perfectly fine.
Regarding your NaNs, in your defines you compare a floating point variable with zero. Here it would be better to make a comparison to a small epsilon. In addition, the macro SQRT() is already defined in "grampc_init.h", which could lead to problems.
I believe the error with the estimation of the penalty parameter is related to the NaNs you are seeing, since then the estimation result will also be NaN, which is not in the valid parameter range (0, inf).
Regards,
Felix
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
thanks for your answer. I expressed myself unclearly, the simulation also runs fine for me with 60, 90 and 100. But for a horizon bigger than 112, e.g. 120 (N=240 in initData.m) the simulation terminates, see the attached zip.
I am using double precision with
grampc_init.h
#define USE_typeRNum USE_DOUBLE /* USE_FLOAT */
I am using those defines as an approximation for discontinous functions like SIGN and ABS that are part of my problems ODEs. ALMOSTZERO I added to be sure not to do division by zero and the altered SQRT to avoid taking the root of a negative number.
I can reproduce your results/problem and I believe they are caused by numerical problems because of your system dynamic. To find out where exactly things go wrong you can attach Visual Studio to Matlab and debug your code.
One possible remedy could be to approximate the right hand side of your system around the critical points (e.g. x[0]-x[1] close to zero) with a polynomial, instead of approximating the sigmoid-function. By choosing the appropriate order you can ensure that your gradient is continuous.
Regards,
Felix
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
thanks again for your advice.
I tried to debug with Visual Studio, building with startMPC([], 2, debug), attaching VS debugger to the process and then setting a break point in probfct_tank.c.
Unfortunately if I execute now with startMPC(1, 0) the breakpoint is not hit. Is probfct_tank.c not evaluated during simulation?
I validated that the debugging works for other (non GRAMPC) functions following these instructions: https://de.mathworks.com/help/matlab/matlab_external/debugging-on-microsoft-windows-platforms.html
Is my workflow correct?
Appoximating the RHS around the critical points by polynomials you mean for example a taylor expansion around h1-h2 = 0 to use just when h1-h2 is close to zero and to use the "normal" dynamics when h1-h2 <<0 (h1-h2>>0) with the correct signs.
How would I implement something like this in the probfct.c?
Is a normal if-statement sufficient?
Best regrads
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I encountered your problem with debugging too. You have to attach the VS debugger before the compiled mex-File is executed. The easiest way to achieve this is to start with "startMPC([],2,'debug')" and have a break point in Matlab in line 47 after the compilation.
A normal if-statement is sufficient, if you use it in the function for the RHS (i.e. out[0] = f_1(h1-h2)) and the corresponding gradients(i.e. the functions ffct, dfdx_vec, dfdu_vec, dfdp_vec). You can define a small epsilon, so that if |h1-h2| < epsilon the polynomial approximation f_p(h1-h2) is used. For the left and right border you have several equations to ensure that the transition from your function to the approximation is continuous (as well as for the corresponding partial derivatives), i.e. f_1(-epsilon) = f_p(-epsilon), f_1(+epsilon) = f_p(+epsilon) and the corresponding partial derivatives. With those equations you can now determine the coefficients of the polynomial.
Regards,
Felix
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
great hint now I am able to debug with VS. I noticed that the first occurence of NaN-values is within the vec[i] variables when I change the xdes values for the setpoint change I am simulating. They are growing very fast and then become infinity or nan.
In which function are those values determined?
I took your advice and approximated the function around the critical points with a polynomial. However the problem with the NaN-values remains.
But I noticed that over the predicition the state values become negative (in violation with the constraints). Obviously my equations are not fit for negative values of the states.
So I introduced a direct constraint for the state values in probfct.c's ffct:
if (x[0] < 1e-16) // Höhe im ersten Tank Null, damit kann Höhe im ersten Tank nur noch zunehmen nicht abnehmen
{
x[0] = 5e-17;
if (out[0] < 1e-16)
{
out[0] = 1e-16;
}
}
so if x[0] is almost zero or smaller than zero it is set to a constant almost zero as well as the change of x[0] (out[0]) which can only be positive then. This represents the physical reality of my system where the state x[0] can't be smaller than 0.
However I am not sure how to set the dfdx_vec function accordingly.
If x goes to zero wouldn't dfdx go to infinity?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
do you mean the vec values in the function “dfdx_vec”? In this case, they are the adjoint states and calculated in gampc_run.c in the function “evaluate_adjsys” (line 637).
Like Andreas wrote in the discussion “Constraints handling in Grampc”, the states in intermediate iterations can violate the constraints. Based on a gut feeling (based on you saying the predicted states become negative) I set user.opt.LineSearchMax = 1e-2, and then your simulation runs even with a prediction horizon of 150 s (Nhor = 300). If you set PLOT_STEPS = 1, PLOT_PAUSE = 1 in your startMPC and user.opt.MaxGradIter = 1 and user.opt.MaxMultIter = 1, you can see what happens without the change to the step size. The first step is too large and your tank heights become negative, which then leads to the NaNs in successive iterations.
Regards,
Felix
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Felix,
setting LineSearchMax lower works great.
However it should be possible to account for the fact that negative values can occur in the problem formulation directly, no?
If I limit the states to positive values in ffct and dfdx before the actual equations with:
if (x[0] < 1e-16)
{
x[0] = 5e-17;
}
The states don't become negative anymore in the prediction plot however I see that they are still negative in grampc.rws.x after running the problem and the nan issue remains.
I attached a current version of my problem. Could you have a look at it?
I am not aware were the negative values in grampc.rws.x come from.
it should definitely be possible, but you are not supposed to change the value of the state x from within the probfct.c. This is why all arguments besides out and userparam are constant...
What you have to do, is to change the values in out[0], if x[0] is close or equal to zero. I believe your state x[3] is some kind of in/outflow for you first state, i.e. if x[0] == 0, then x[3] < 0 is not possible and the respective part in out[0] = ... should be removed?
I see that it is problematic altering x[i] like this.
x[3] is indeed an inflow through a pump therefore it can only be positive so I would have to alter the condition to
and combine those conditions in their variations (e.g. x[3] < 0.0 && x[0] < 0.0).
I summarized this into defining some floats for the states and setting them zero for negative values.
And added the condition that x[4], x[5], x[6] can never be negative.
If you do it like this, your system dynamic will not be continuous. This might lead to numerical problems in the integration of your adjoint states. You didn’t write so explicitly, but I assume you also added this change to every function in your probfct-file?
In addition, your predicted states 4-6 can very well be negative, since
out[3] = U0;
out[4] = U1;
out[5] = U2;
Like I wrote earlier, after changing the option LineSearchMax, I didn’t have any problems running your example (no NaNs appearing), did this not work well enough for you?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just to close this thread. There was a mistake in my macro definition:
#define SIGNAP(x) tanh(10000*x)
// --> SIGNAP(x+y) = tanh(10000*x+ y
which caused the numerical issues.
I experimented with limiting the states with sigmoid functions to avoid the non-continuity that you mentioned which of course was computationally expensive. In the end I limited the functions with the if clauses as described before and of course also adding a restriction on the change of U0 as shown below.
Now I do not have problems with negative values anymore and the results for the experiment are good.
Thanks for your help!
problfct.c
// Formulierung mit der Approximation durch tanh und harte Begrenzungen#include"probfct.h"#define NPSYS 7 // size(p), s.u.#define NPCOST 9 // size(p), s.u.#define NPCONSTR 18#define NPOFFSET 18#define NPSCALE 18#define NPTS 1#define cAP 1e-5/* square macro */#define POW2(a) ((a)*(a))#define SQRT(x) ((x) > 1e-15 ? sqrt(x): 1e-16)#define POW2(a) ((a)*(a))#define POW3(a) ((a)*(a)*(a))#define POW4(a) ((a)*(a)*(a)*(a))#define POW5(a) ((a)*(a)*(a)*(a)*(a))#define POW7(a) ((a)*(a)*(a)*(a)*(a)*(a)*(a))#define ex32(x) POW3(SQRT(x))#define ex12(x) ((x) > 1e-15 ? sqrt(x): 1e-15)#define ex42(x) POW4(SQRT(x))#define ex52(x) POW5(SQRT(x))#define ex72(x) POW7(SQRT(x))/** OCP dimensions: states (Nx), controls (Nu), parameters (Np), equalities (Ng), inequalities (Nh), terminal equalities (NgT), terminal inequalities (NhT) **/voidocp_dim(typeInt*Nx,typeInt*Nu,typeInt*Np,typeInt*Ng,typeInt*Nh,typeInt*NgT,typeInt*NhT,typeUSERPARAM*userparam){*Nx=6;// h1=X0 h2=X1 h3=X2 p1=X3 p2=X4 v12=X5*Nu=3;// delta_p1=U0 delta_p2=U1 delta_v12=U2*Np=0;//*Nh=18;//*Ng=0;*NgT=0;*NhT=0;}/** System function f(t,x,u,p,userparam) ------------------------------------ **/voidffct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){// typeRNum ist double// ctypeRNum ist constant doublectypeRNum*pSys=(typeRNum*)userparam;ctypeRNumf3=2;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;ctypeRNum*dev=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE+NPTS;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal,U2new,delta_h1,delta_h2,delta_h3,delta_h1_func,delta_h2_func,delta_h3_func,test1,test2,test3,test4;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];if(x[0]<1e-16){X0=5e-17;}elseif(x[0]>300){X0=300;}if(x[1]<1e-16){X1=5e-17;}elseif(x[1]>300){X1=300;}if(x[2]<1e-16){X2=5e-17;}elseif(x[2]>300){X2=300;}if(x[3]<1e-16){X3=5e-17;}elseif(x[3]>9.9){X3=9.9;}if(x[4]<1e-16){X4=5e-17;}elseif(x[4]>9.9){X4=9.9;}if(x[5]<1e-16){X5=5e-17;}elseif(x[5]>9.9){X5=9.9;}if(U0*Ts[0]+x[3]>9.9){U0=-5e-17;}elseif(U0*Ts[0]+x[3]<0){U0=5e-17;}if(U1*Ts[0]+x[4]>9.9){U1=-5e-17;}elseif(U1*Ts[0]+x[4]<0){U1=5e-17;}if(U2*Ts[0]+x[5]>9.9){U2=-5e-17;}elseif(U2*Ts[0]+x[5]<0){U2=5e-17;}delta_h1=X3*pSys[0]-((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))+dev[0];delta_h2=((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))+dev[1];delta_h3=X4*pSys[1]-(24*(ex12(2))*pSys[4]*(ex12((X2*pSys[6]))))/5+((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))+dev[2];if(delta_h1*Ts[0]+x[0]>300){delta_h1=-5e-17;}elseif(delta_h1*Ts[0]+x[0]<0){delta_h1=5e-17;}if(delta_h2*Ts[0]+x[1]>300){delta_h2=-5e-17;}elseif(delta_h2*Ts[0]+x[1]<0){delta_h2=5e-17;}if(delta_h3*Ts[0]+x[2]>300){delta_h3=-5e-17;}elseif(delta_h3*Ts[0]+x[2]<0){delta_h3=5e-17;}out[0]=delta_h1;out[1]=delta_h2;out[2]=delta_h3;out[3]=U0;out[4]=U1;out[5]=U2;}/** Jacobian df/dx multiplied by vector vec, i.e. (df/dx)^T*vec or vec^T*(df/dx) **/voiddfdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(typeRNum*)userparam;ctypeRNumf1=1e4;ctypeRNumf2=1e-10;ctypeRNumf3=2;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal,U2new;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];if(x[0]<1e-16){X0=5e-17;}elseif(x[0]>300){X0=300;}if(x[1]<1e-16){X1=5e-17;}elseif(x[1]>300){X1=300;}if(x[2]<1e-16){X2=5e-17;}elseif(x[2]>300){X2=300;}if(x[3]<1e-16){X3=5e-17;}elseif(x[3]>9.9){X3=9.9;}if(x[4]<1e-16){X4=5e-17;}elseif(x[4]>9.9){X4=9.9;}if(x[5]<1e-16){X5=5e-17;}elseif(x[5]>9.9){X5=9.9;}if(U0*Ts[0]+x[3]>9.9){U0=-5e-17;}elseif(U0*Ts[0]+x[3]<0){U0=5e-17;}if(U1*Ts[0]+x[4]>9.9){U1=-5e-17;}elseif(U1*Ts[0]+x[4]<0){U1=5e-17;}if(U2*Ts[0]+x[5]>9.9){U2=-5e-17;}elseif(U2*Ts[0]+x[5]<0){U2=5e-17;}out[0]=vec[1]*(((ex12(2))*pSys[2]*X5*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))*(2*X0-2*X1))/(2*(ex32((cAP+(POW2((X0-X1)))))))+((ex12(2))*pSys[2]*pSys[6]*X5*(X0-X1)*(2*X0-2*X1))/(4*(cAP+(POW2((X0-X1))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))))-vec[0]*(((ex12(2))*pSys[2]*X5*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))*(2*X0-2*X1))/(2*(ex32((cAP+(POW2((X0-X1)))))))+((ex12(2))*pSys[2]*pSys[6]*X5*(X0-X1)*(2*X0-2*X1))/(4*(cAP+(POW2((X0-X1))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))));out[1]=vec[2]*(((ex12(2))*pSys[3]*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))-((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))*(2*X1-2*X2))/(2*(ex32((cAP+(POW2((X1-X2)))))))+((ex12(2))*pSys[3]*pSys[6]*(X1-X2)*(2*X1-2*X2))/(4*(cAP+(POW2((X1-X2))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))))-vec[1]*(((ex12(2))*pSys[3]*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))+((ex12(2))*pSys[2]*X5*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))*(2*X1-2*X2))/(2*(ex32((cAP+(POW2((X1-X2)))))))+((ex12(2))*pSys[3]*pSys[6]*(X1-X2)*(2*X1-2*X2))/(4*(cAP+(POW2((X1-X2))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))-((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))*(2*X0-2*X1))/(2*(ex32((cAP+(POW2((X0-X1)))))))+((ex12(2))*pSys[2]*pSys[6]*X5*(X0-X1)*(2*X0-2*X1))/(4*(cAP+(POW2((X0-X1))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))))+vec[0]*(((ex12(2))*pSys[2]*X5*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[2]*X5*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))*(2*X0-2*X1))/(2*(ex32((cAP+(POW2((X0-X1)))))))+((ex12(2))*pSys[2]*pSys[6]*X5*(X0-X1)*(2*X0-2*X1))/(4*(cAP+(POW2((X0-X1))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1)))))))))));out[2]=vec[1]*(((ex12(2))*pSys[3]*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))-((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))*(2*X1-2*X2))/(2*(ex32((cAP+(POW2((X1-X2)))))))+((ex12(2))*pSys[3]*pSys[6]*(X1-X2)*(2*X1-2*X2))/(4*(cAP+(POW2((X1-X2))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))))-vec[2]*((12*(ex12(2))*pSys[4]*pSys[6])/(5*(ex12((X2*pSys[6]))))+((ex12(2))*pSys[3]*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2))))))))))/(ex12((cAP+(POW2((X1-X2))))))-((ex12(2))*pSys[3]*(X1-X2)*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))*(2*X1-2*X2))/(2*(ex32((cAP+(POW2((X1-X2)))))))+((ex12(2))*pSys[3]*pSys[6]*(X1-X2)*(2*X1-2*X2))/(4*(cAP+(POW2((X1-X2))))*(ex12((pSys[6]*(ex12((cAP+(POW2((X1-X2)))))))))));out[3]=pSys[0]*vec[0];out[4]=pSys[1]*vec[2];out[5]=((ex12(2))*pSys[2]*vec[1]*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))))-((ex12(2))*pSys[2]*vec[0]*(X0-X1)*(ex12((pSys[6]*(ex12((cAP+(POW2((X0-X1))))))))))/(ex12((cAP+(POW2((X0-X1))))));}/** Jacobian df/du multiplied by vector vec, i.e. (df/du)^T*vec or vec^T*(df/du) **/voiddfdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal,U2new;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];out[0]=vec[3];out[1]=vec[4];out[2]=vec[5];}/** Jacobian df/dp multiplied by vector vec, i.e. (df/dp)^T*vec or vec^T*(df/dp) **/voiddfdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*vec,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Integral cost l(t,x(t),u(t),p,xdes,udes,userparam) -------------------------------------------------- **/voidlfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;// Verschieben der Adresse in Zeiger p = userparam um NPSYS (=size(p)) nach vorn, um pCost zu erreichen wie in initData.m definiertctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];out[0]=pCost[0]*POW2(X0-xdes[0])//(typeRNum)84100+pCost[1]*POW2(X1-xdes[1])//(typeRNum)84100+pCost[2]*POW2(X2-xdes[2])//(typeRNum)84100+pCost[6]*POW2(U0-udes[0])//(typeRNum)98+pCost[7]*POW2(U1-udes[1])//(typeRNum)98+pCost[8]*POW2(U2-udes[2]);//(typeRNum)98;}/** Gradient dl/dx **/voiddldx(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];out[0]=2*pCost[0]*(X0-xdes[0]);//(typeRNum)84100;out[1]=2*pCost[1]*(X1-xdes[1]);//(typeRNum)84100;out[2]=2*pCost[2]*(X2-xdes[2]);//(typeRNum)84100;out[3]=0;out[4]=0;out[5]=0;}/** Gradient dl/du **/voiddldu(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];out[0]=2*pCost[6]*(U0-udes[0]);//(typeRNum)98;out[1]=2*pCost[7]*(U1-udes[1]);//(typeRNum)98;out[2]=2*pCost[8]*(U2-udes[2]);//(typeRNum)98;}/** Gradient dl/dp **/voiddldp(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*xdes,ctypeRNum*udes,typeUSERPARAM*userparam){}/** Terminal cost V(T,x(T),p,xdes,userparam) ---------------------------------------- **/voidVfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;doubleX0,X1,X2,X3,X4,X5;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];out[0]=pCost[3]*POW2(X0-xdes[0])//(typeRNum)84100+pCost[4]*POW2(X1-xdes[1])//(typeRNum)84100+pCost[5]*POW2(X2-xdes[2]);//(typeRNum)84100;}/** Gradient dV/dx **/voiddVdx(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pCost=pSys+NPSYS;doubleX0,X1,X2,X3,X4,X5;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];out[0]=2*pCost[3]*(X0-xdes[0]);//(typeRNum)84100;out[1]=2*pCost[4]*(X1-xdes[1]);//(typeRNum)84100;out[2]=2*pCost[5]*(X2-xdes[2]);//(typeRNum)84100;out[3]=0;out[4]=0;out[5]=0;}/** Gradient dV/dp **/voiddVdp(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){}/** Gradient dV/dT **/voiddVdT(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*xdes,typeUSERPARAM*userparam){}/** Equality constrainTs[0] g(t,x(t),u(t),p,uperparam) = 0 --------------------------------------------------- **/voidgfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dg/dx multiplied by vector vec, i.e. (dg/dx)^T*vec or vec^T*(dg/dx) **/voiddgdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dg/du multiplied by vector vec, i.e. (dg/du)^T*vec or vec^T*(dg/du) **/voiddgdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dg/dp multiplied by vector vec, i.e. (dg/dp)^T*vec or vec^T*(dg/dp) **/voiddgdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Inequality constraints h(t,x(t),u(t),p,uperparam) <= 0 ------------------------------------------------------ **/voidhfct(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pConstr=pSys+NPSYS+NPCOST;ctypeRNum*pOffset=pSys+NPSYS+NPCOST+NPCONSTR;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;ctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;doubleX0,X1,X2,X3,X4,X5,U0,U1,U2,U2cal;X0=x[0];X1=x[1];X2=x[2];X3=x[3];X4=x[4];X5=x[5];U0=u[0];U1=u[1];U2=u[2];out[0]=((X0-pOffset[0])-pConstr[0])/pScale[0];out[1]=((X1-pOffset[1])-pConstr[1])/pScale[1];out[2]=((X2-pOffset[2])-pConstr[2])/pScale[2];out[3]=((X3-pOffset[3])-pConstr[3])/pScale[3];out[4]=((X4-pOffset[4])-pConstr[4])/pScale[4];out[5]=((X5-pOffset[5])-pConstr[5])/pScale[5];out[6]=(-(X0-pOffset[6])+pConstr[6])/pScale[6];out[7]=(-(X1-pOffset[7])+pConstr[7])/pScale[7];out[8]=(-(X2-pOffset[8])+pConstr[8])/pScale[8];out[9]=(-(X3-pOffset[9])+pConstr[9])/pScale[9];out[10]=(-(X4-pOffset[10])+pConstr[10])/pScale[10];out[11]=(-(X5-pOffset[11])+pConstr[11])/pScale[11];// Inequality for deltaout[12]=((U0)-pConstr[12])/pScale[12];out[13]=((U1)-pConstr[13])/pScale[13];out[14]=((U2)-pConstr[14])/pScale[14];out[15]=(-(U0)+pConstr[15])/pScale[15];out[16]=(-(U1)+pConstr[16])/pScale[16];out[17]=(-(U2)+pConstr[17])/pScale[17];}/** Jacobian dh/dx multiplied by vector vec, i.e. (dh/dx)^T*vec or vec^T*(dg/dx) **/voiddhdx_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;//[dhdx] = [nh x nx] = [12 x 6], tag_onenote:jacobi_dhdxctypeRNum*Ts=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET+NPSCALE;out[0]=vec[0]/pScale[0]-vec[6]/pScale[6];out[1]=vec[1]/pScale[1]-vec[7]/pScale[7];out[2]=vec[2]/pScale[2]-vec[8]/pScale[8];out[3]=vec[3]/pScale[3]-vec[9]/pScale[9];out[4]=vec[4]/pScale[4]-vec[10]/pScale[10];out[5]=vec[5]/pScale[5]-vec[11]/pScale[11];}/** Jacobian dh/du multiplied by vector vec, i.e. (dh/du)^T*vec or vec^T*(dg/du) **/voiddhdu_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){ctypeRNum*pSys=(ctypeRNum*)userparam;ctypeRNum*pScale=pSys+NPSYS+NPCOST+NPCONSTR+NPOFFSET;out[0]=vec[12]/pScale[12]-vec[15]/pScale[15];out[1]=vec[13]/pScale[13]-vec[16]/pScale[16];out[2]=vec[14]/pScale[14]-vec[17]/pScale[17];}/** Jacobian dh/dp multiplied by vector vec, i.e. (dh/dp)^T*vec or vec^T*(dg/dp) **/voiddhdp_vec(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Terminal equality constraints gT(T,x(T),p,uperparam) = 0 -------------------------------------------------------- **/voidgTfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dgT/dx multiplied by vector vec, i.e. (dgT/dx)^T*vec or vec^T*(dgT/dx) **/voiddgTdx_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}voidtdgdu_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dgT/dp multiplied by vector vec, i.e. (dgT/dp)^T*vec or vec^T*(dgT/dp) **/voiddgTdp_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dgT/dT multiplied by vector vec, i.e. (dgT/dT)^T*vec or vec^T*(dgT/dT) **/voiddgTdT_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Terminal inequality constraints hT(T,x(T),p,uperparam) <= 0 ----------------------------------------------------------- **/voidhTfct(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian dhT/dx multiplied by vector vec, i.e. (dhT/dx)^T*vec or vec^T*(dhT/dx) **/voiddhTdx_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dhT/dp multiplied by vector vec, i.e. (dhT/dp)^T*vec or vec^T*(dhT/dp) **/voiddhTdp_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Jacobian dhT/dT multiplied by vector vec, i.e. (dhT/dT)^T*vec or vec^T*(dhT/dT) **/voiddhTdT_vec(typeRNum*out,ctypeRNumT,ctypeRNum*x,ctypeRNum*p,ctypeRNum*vec,typeUSERPARAM*userparam){}/** Additional functions required for semi-implicit systems M*dx/dt(t) = f(t0+t,x(t),u(t),p) using the solver RODAS ------------------------------------------------------- **//** Jacobian df/dx in vector form (column-wise) **/voiddfdx(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian df/dx in vector form (column-wise) **/voiddfdxtrans(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian df/dt **/voiddfdt(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*p,typeUSERPARAM*userparam){}/** Jacobian d(dH/dx)/dt **/voiddHdxdt(typeRNum*out,ctypeRNumt,ctypeRNum*x,ctypeRNum*u,ctypeRNum*vec,ctypeRNum*p,typeUSERPARAM*userparam){}/** Mass matrix in vector form (column-wise, either banded or full matrix) **/voidMfct(typeRNum*out,typeUSERPARAM*userparam){}/** Transposed mass matrix in vector form (column-wise, either banded or full matrix) **/voidMtrans(typeRNum*out,typeUSERPARAM*userparam){}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi all,
I have a question regarding the choice of prediction horizon.
In my understanding a bigger prediction horizon should stabilize the control of the system in MPC.
However when I choose the prediction horizon (N Ts) for my example below to high the results of a setpoint tracking simulation deteriorate with growing prediction horizon.
I attached the results of the simulation for prediction horizons of 60, 90 and 100 seconds to demonstrate my problem. I figured out then that if I raise the number of iterations according to the length of the predicition horizon (N Ts) the results get equivalent for all horizon length
When I choose a prediction horizon higher than exactly 112 my simulation terminates becaue of NaN values although my problemfct.c does not define divisions by zero even for unphysical values of states and controls.
Does somebody know how those NaN values could be explained?
Also if I use grampc_estim_penmin_Cmex for a horizon bigger than 112 it gives the error:
PenaltyMin: Invalid value for option.
Error using grampc_estim_penmin_Cmex
Invalid setting of option or parameter
I am clearly missing something here. Any hint is appreciated.
Best regards
startMPC.m
initData.m
probfct.c
Last edit: hcl734 2019-03-19
Hi,
I downloaded your code and ran your example, but was not able to reproduce your results. For me the results looked good regardless of the prediction horizon (60, 90, 100). Are you using single or double precision floating points? Furthermore a lot less iterations were sufficient for me, i.e. 5/5 did perfectly fine.
Regarding your NaNs, in your defines you compare a floating point variable with zero. Here it would be better to make a comparison to a small epsilon. In addition, the macro SQRT() is already defined in "grampc_init.h", which could lead to problems.
I believe the error with the estimation of the penalty parameter is related to the NaNs you are seeing, since then the estimation result will also be NaN, which is not in the valid parameter range (0, inf).
Regards,
Felix
Hi Felix,
thanks for your answer. I expressed myself unclearly, the simulation also runs fine for me with 60, 90 and 100. But for a horizon bigger than 112, e.g. 120 (N=240 in initData.m) the simulation terminates, see the attached zip.
I am using double precision with
grampc_init.h
I am using those defines as an approximation for discontinous functions like SIGN and ABS that are part of my problems ODEs. ALMOSTZERO I added to be sure not to do division by zero and the altered SQRT to avoid taking the root of a negative number.
Is there a better way to approximate those in GRAMPC?
Best regards
Last edit: hcl734 2019-03-20
Hi,
I can reproduce your results/problem and I believe they are caused by numerical problems because of your system dynamic. To find out where exactly things go wrong you can attach Visual Studio to Matlab and debug your code.
One possible remedy could be to approximate the right hand side of your system around the critical points (e.g. x[0]-x[1] close to zero) with a polynomial, instead of approximating the sigmoid-function. By choosing the appropriate order you can ensure that your gradient is continuous.
Regards,
Felix
Hi Felix,
thanks again for your advice.
I tried to debug with Visual Studio, building with startMPC([], 2, debug), attaching VS debugger to the process and then setting a break point in probfct_tank.c.
Unfortunately if I execute now with startMPC(1, 0) the breakpoint is not hit. Is probfct_tank.c not evaluated during simulation?
I validated that the debugging works for other (non GRAMPC) functions following these instructions:
https://de.mathworks.com/help/matlab/matlab_external/debugging-on-microsoft-windows-platforms.html
Is my workflow correct?
Appoximating the RHS around the critical points by polynomials you mean for example a taylor expansion around h1-h2 = 0 to use just when h1-h2 is close to zero and to use the "normal" dynamics when h1-h2 <<0 (h1-h2>>0) with the correct signs.
How would I implement something like this in the probfct.c?
Is a normal if-statement sufficient?
Best regrads
Hi,
I encountered your problem with debugging too. You have to attach the VS debugger before the compiled mex-File is executed. The easiest way to achieve this is to start with "startMPC([],2,'debug')" and have a break point in Matlab in line 47 after the compilation.
A normal if-statement is sufficient, if you use it in the function for the RHS (i.e. out[0] = f_1(h1-h2)) and the corresponding gradients(i.e. the functions ffct, dfdx_vec, dfdu_vec, dfdp_vec). You can define a small epsilon, so that if |h1-h2| < epsilon the polynomial approximation f_p(h1-h2) is used. For the left and right border you have several equations to ensure that the transition from your function to the approximation is continuous (as well as for the corresponding partial derivatives), i.e. f_1(-epsilon) = f_p(-epsilon), f_1(+epsilon) = f_p(+epsilon) and the corresponding partial derivatives. With those equations you can now determine the coefficients of the polynomial.
Regards,
Felix
Hi Felix,
great hint now I am able to debug with VS. I noticed that the first occurence of NaN-values is within the vec[i] variables when I change the xdes values for the setpoint change I am simulating. They are growing very fast and then become infinity or nan.
In which function are those values determined?
I took your advice and approximated the function around the critical points with a polynomial. However the problem with the NaN-values remains.
But I noticed that over the predicition the state values become negative (in violation with the constraints). Obviously my equations are not fit for negative values of the states.
So I introduced a direct constraint for the state values in probfct.c's ffct:
so if x[0] is almost zero or smaller than zero it is set to a constant almost zero as well as the change of x[0] (out[0]) which can only be positive then. This represents the physical reality of my system where the state x[0] can't be smaller than 0.
However I am not sure how to set the dfdx_vec function accordingly.
If x goes to zero wouldn't dfdx go to infinity?
Hi,
do you mean the vec values in the function “dfdx_vec”? In this case, they are the adjoint states and calculated in gampc_run.c in the function “evaluate_adjsys” (line 637).
Like Andreas wrote in the discussion “Constraints handling in Grampc”, the states in intermediate iterations can violate the constraints. Based on a gut feeling (based on you saying the predicted states become negative) I set user.opt.LineSearchMax = 1e-2, and then your simulation runs even with a prediction horizon of 150 s (Nhor = 300). If you set PLOT_STEPS = 1, PLOT_PAUSE = 1 in your startMPC and user.opt.MaxGradIter = 1 and user.opt.MaxMultIter = 1, you can see what happens without the change to the step size. The first step is too large and your tank heights become negative, which then leads to the NaNs in successive iterations.
Regards,
Felix
Hi Felix,
setting LineSearchMax lower works great.
However it should be possible to account for the fact that negative values can occur in the problem formulation directly, no?
If I limit the states to positive values in ffct and dfdx before the actual equations with:
The states don't become negative anymore in the prediction plot however I see that they are still negative in grampc.rws.x after running the problem and the nan issue remains.
I attached a current version of my problem. Could you have a look at it?
I am not aware were the negative values in grampc.rws.x come from.
Best regards
Last edit: hcl734 2019-03-27
Hi,
it should definitely be possible, but you are not supposed to change the value of the state x from within the probfct.c. This is why all arguments besides out and userparam are constant...
What you have to do, is to change the values in out[0], if x[0] is close or equal to zero. I believe your state x[3] is some kind of in/outflow for you first state, i.e. if x[0] == 0, then x[3] < 0 is not possible and the respective part in out[0] = ... should be removed?
(The same is true for x[4] and out[2])
Regards,
Felix
Last edit: Felix Mesmer 2019-03-27
Hi Felix,
I see that it is problematic altering x[i] like this.
x[3] is indeed an inflow through a pump therefore it can only be positive so I would have to alter the condition to
and similarly I have to alter then to not allow negative heights in the tanks (x[0], x[1], x[2])
and combine those conditions in their variations (e.g. x[3] < 0.0 && x[0] < 0.0).
I summarized this into defining some floats for the states and setting them zero for negative values.
And added the condition that x[4], x[5], x[6] can never be negative.
And indeed now the solution in grampc.rws.x is always positive.
But I still get the NaN error.
What am I doing wrong here?
If you do it like this, your system dynamic will not be continuous. This might lead to numerical problems in the integration of your adjoint states. You didn’t write so explicitly, but I assume you also added this change to every function in your probfct-file?
In addition, your predicted states 4-6 can very well be negative, since
Like I wrote earlier, after changing the option LineSearchMax, I didn’t have any problems running your example (no NaNs appearing), did this not work well enough for you?
Just to close this thread. There was a mistake in my macro definition:
which caused the numerical issues.
I experimented with limiting the states with sigmoid functions to avoid the non-continuity that you mentioned which of course was computationally expensive. In the end I limited the functions with the if clauses as described before and of course also adding a restriction on the change of U0 as shown below.
Now I do not have problems with negative values anymore and the results for the experiment are good.
Thanks for your help!
problfct.c