Two Water Tanks

Physical system

The two-tanks systems consists of two tanks which are connected by two valves. Liquid inflow Q1 to the first tank is governed by a pump and there are two interconnections between the tanks:
  1. Through Valve 1, which is always fully open. The liquid flows through this valve if h1 > hv.
  2. Through Valve 2, which can be either fully open (V2=1), or fully closed (V2=0).
In addition, there is a permanent leak from tank 2. The system has two manipulated variables:
  1. Liquid inflow Q1 which can change continuously.
  2. Position of Valve 2 which can be either fully open (V2=1), or fully closed (V2=0). No other positions are allowed.
The system is subject to constraints on liquid inflow and heights of liquid levels in both tanks. The two-tanks system shows clear characteristics of hybrid systems. First, the dynamics changes depending on current operating conditions (e.g. there is a direct flow from tank 1 to tank 2 through Valve 1 if level in the first tank is above certain level), and secondly, some system inputs are in fact on-off switches, such as Valve 2.

Control objectives

The aim is to design a controller which is able to stabilize liquid level in the second tank at the given reference point h2 = 0.2 m. The controller can manipulate liquid inflow Q1 continuously in range of 0 <= Q1 <= 1 and position of Valve 2, which can only take boolean values 0 or 1. The controller must cope with different constraints and have good regulation performance.

Modelling in HYSDEL

SYSTEM twotanks {
  INTERFACE {
    STATE {
      REAL h1 [0, 0.62];  /* level in 1st tank */
      REAL h2 [0, 0.62];   /* level in 2nd tank */
    }
    INPUT {
      REAL q1 [0, 1];     /* liquid inflow */ 
      BOOL V2;            /* position of Valve 2 */
    }
    OUTPUT {
      REAL y;             /* output = h2 */
    }
    PARAMETER {
      REAL dT = 10;       /* sampling time */
      REAL hv = 0.3;      /* height of Valve 1 */
      REAL s = 10e-6;     /* scross-section of valves */
      REAL hmax = 0.62;   /* maximum height of liquid */
      REAL g = 9.81; 
      REAL F = 0.0143/dT; /* area of each tank */
      REAL q_in = 0.1e-3; /* maximum liquid inflow */
      REAL k1 = s*sqrt(2*g/(hmax-hv)); 
      REAL k2 = s*sqrt(2*g/hmax); 
    }
  }
  IMPLEMENTATION {
    AUX {
      /* auxiliary variables */
      REAL z1_1, z2_1, z3_1, z4_1;
      REAL z1_2, z2_2, z3_2, z4_2;
      BOOL above;
    }
    AD {
      above = h1 >= hv;    /* d1 will be true iff h1 >= hv */
    }
    DA {
    z1_1 = { 
      /* h1>=hv and V2 open */
      IF (above & V2) THEN 
        (1-k1/F)*h1 - k2/F*h2 + hv/F*k1 
      ELSE 
        0 
      };
      
      z1_2 = {
        /* h1>=hv and V2 open */
        IF (above & V2) THEN
          (k1+k2)/F*h1 +  (1-k2/F)*h2 - hv/F*k1
        ELSE
          0
      };
      
      z2_1 = {
        /* h1 <=hv and V2 open */
        IF (~above & V2) THEN
          (1-k2/F)*h1 
        ELSE
          0
      };
      
      z2_2 = {
        /* h1 < hv and V2 open */
        IF (~above & V2) THEN
          k2/F*h1 + (1-k2/F)*h2
        ELSE
          0
      };
      
      z3_1 = {
        /* h1>=hv and V2 closed */
        IF (above & ~V2) THEN
          (1-k1/F)*h1 + k1/F*hv
        ELSE
          0
      };
      
      z3_2 = {
        /* h1>=hv and V2 closed */
        IF (above & ~V2) THEN
          k1/F*h1 + (1-k2/F)*h2 - k1/F*hv
        ELSE
          0
      };
      
      z4_1 = {
        /* h1<=hv and V2 closed */
        IF (~above & ~V2) THEN
          h1
        ELSE
          0
      };
      
      z4_2 = {
        /* h1<=hv and V2 closed */
        IF (~above & ~V2) THEN
          1-k2/F
        ELSE
          0
      };
    }
    CONTINUOUS {
      /* state update equations */
    
      /* h1(k+1) = ... */
      h1 = z1_1 + z2_1 + z3_1 + z4_1 + q_in/F*q1;
    
      /* h2(k+1) = ... */
      h2 = z1_2 + z2_2 + z3_2 + z4_2;
    }
    OUTPUT {
      /* output is just h2 */
      y = h2;
    }
    MUST {
      /* level in tank 2 must be below level in tank 1 */
      h2 <= h1;
    }
  }
} 

Controller design in MPT

In order to design a model-based controller with MPT, we first need to define model of the dynamical system. We can do that by importing the HYSDEL model and converting it into an equivalent Piecewise-Affine (PWA) model:
>> Ts = 10;                               % sampling time
>> model = mpt_sys('twotanks.hys', Ts);
The command mpt_sys will read description of the system stored in file twotanks.hys and convert it into an PWA model. Second step is to define system constraints:
>> ymax = 0.62;          % maximum  height of liquid in 2nd tank
>> ymin = 0;            % minimum height of liquid in 2nd tank
>> qmax = 1;            % maximum inflow (manipulated variable Q1)
>> qmin = 0;            % minimum inflow (manipulated variable Q1)
>> v2max = 1;           % maximum value for Valve 2
>> v2min = 0;           % minimum value for Valve 2

>> model.ymax = ymax;
>> model.ymin = ymin;
>> model.umax = [qmax; v2max];
>> model.umin = [qmin; v2min];
Now we can define the optimization problem. Our objective is to obtain a controller which stabilizes liquid level in the second tank at h2_ref = 0.2. Our controller will predict system behavior 3 sampling times into the future, choosing such control actions which minimize the difference between the predicted output and our given reference:
>> problem.N = 3;             % prediction horizon
>> problem.yref = 0.2;        % reference value for outputs
>> problem.norm = 1;          % cost function based on 1-norms
>> problem.Qy = 100;          % cost which penalizes (y-yref)
>> problem.Q = zeros(2);      % zero cost on states
>> problem.R = 1e-3*eye(2);   % cost which penalizes usage of inputs
Once the model and the problem are given, the controller can be obtained by
>> controller = mpt_control(model, problem);

Results and simulations

For the parameters specified above, the controller consists of 136 regions which can be plotted using
>> plot(controller)
The controller can now be either used for simulations, or exported to C-code for embeding into the real application. To simulate the closed-loop system from a given starting conditions, one would use
>> x0 = [0.5; 0];     % initial conditions h1=0.5m, h2=0
>> Nsim = 60;         % number of simulation steps
>> simplot(controller, x0, Nsim)
Of course you can choose any initial conditions which the controller covers. The function simplot also allows you to choose such initial points on mouse-click if the initial state x0 is not provided:
>> simplot(controller);
The controller can be further simplified to reduced number of regions. The command to do such a simplification is as follows:
>> simple_controller = mpt_simplify(controller);
The simplification is based on merging regions which have the same control law, which guarantees that the simplified controller will maintain fullfilment of the same control objectives as the original controller does. The simplified controller consists of 50 regions and is depicted on the figure below.