0

I am working on a Model Predictive Control for a chiller - storage tank system. I'm a thermal engineering master student and this topic is new to me, so the things I'm asking may not be for this forum, but I'm running out of ideas.

I'm developing the code in Matlab and solving the non-linear optimization problem using CasADi. The solver I'm using is Ipopt.

For the time being my actuation variables are the mass flow rate through the chiller and the temperature of the water at the chiller's outlet. With those two variables and the return temperature I calculate the chiller's cooling capacity. The equations of the models are non-linear.

The mass flow rate through the chiller has a lower and an upper limit for safety reasons: m_chiller_min <= m_chiller <= m_chiller_max.

One of the problems I've encountered is that while I need to respect that, I also need to be able to set the variable to zero if there's no need to produce chilled water.

I have a similar problem with the chiller's capacity/partial load ratio, because it has a lower limit but also needs to be zero if needed.

I have tried declaring a binary (chiller_on) optimization variable and using it to make m_chiller = 0 if needed:

0 <= chiller on <= 1;
m_chiller = m_chiller*chiller_on;
m_chiller_min*chiller_on <= m_chiller <= m_chiller_max;

While it converges with some difficulty, the solution is dependant on the initial guess value I give to the chiller_on value. If I give a 1 to the binary, even if the better solution is to turn off the chiller it will not do it. I have also tried this with CasADi's bonmin solver, declaring the binary as discrete, but I have the same problem.

The MPC runs well without limiting the chiller's minimum mass flow rate and partial load ratio.

I don't know if I'm doing it right, but as I said I've hit a wall. I need to find a way, preferably without any binary variables, to limit the lower value but still be able to shut it off.

Edit: I have tried this for a prediction horizon of 1, and it works:

m_chiller_max = Chiller(1).lim.m_max;
m_chiller_min = Chiller(1).lim.m_min;
con( 0 <= chiller_on <= 1 );
con( 0 <= m_chiller <= m_chiller_max*chiller_on );
con( m_chiller_min*chiller_on <= m_chiller );

I have had to use the solver bonmin for this, and declare the binary variable as discrete. I would prefer a solution without binary variables, to be able to use Ipopt.

Martin B
  • 1
  • 1
  • I don’t have experience with this, but I would try optimizing twice: once with `m_chiller` limited as you require, and once with it set to 0. Then pick the solution that produces the best result. – Cris Luengo May 31 '23 at 13:14
  • Thank you for your answer, I had not thought of that. I will give it a try, although it may be too time consuming hehe. Also, the variable m_chiller may need to alternate its value many times in the prediction horizon (setting the chiller on and off), and I don't see clearly how to do that with the solution you proposed. – Martin B May 31 '23 at 13:29

1 Answers1

0

Your formulation m_chiller_min*chiller_on <= m_chiller <= m_chiller_max; is not quite right.

A variable x that can be zero or between L and U is called a semi-continuous variable. Many MIP solvers have built-in support for this. Otherwise, you can use a binary variable and write:

  δ⋅L ≤ x ≤ δ⋅U
  δ ∈ {0,1}
  x ∈ [0,U]
Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39
  • Thank you. Do you recommend any MINLP solvers that can handle semi-continuous variables? – Martin B Jun 02 '23 at 12:08
  • I am not recommending any solver because I don't know the model and how it behaves. But semi-continuous variables are directly supported by solvers like dicopt, sbb and scip. Of course, using binary variables is a good and simple alternative. – Erwin Kalvelagen Jun 02 '23 at 13:15