1
votes

I am trying to solve what I believe should be a simple steady-state component staging problem using Modelica, but I am struggling to come to a solution.

I have prepared an example case with two parallel pumps which must deliver a target total flow rate to a system (vTotal). One pump is a variable frequency pump and delivers a flow rate (v1) proportional to the command frequency (fPump1), which can vary between 0 and fMax. The other pump is a fixed speed pump, and outputs a fixed flow rate (v2IfRunning) whenever it is running, and zero flow when it is not running.

The goal is to solve for the number of pumps that are running and for the variable speed pump frequency. The variable speed pump is always running and the fixed speed pump is only used when the variable speed pump would need to run at a frequency greater than fMax. My example code is below:

model TwoPumpCode
  // Pump 1
  Modelica.SIunits.Frequency fPump1 "pump 1 frequency";
  Modelica.SIunits.Frequency fMax = 50 "maximum frequency";
  Modelica.SIunits.VolumeFlowRate v1;

  // Pump 2
  // Boolean runPump2(start=false) "true if pump 2 should run";
  Modelica.SIunits.VolumeFlowRate v2IfRunning = 30;
  Modelica.SIunits.VolumeFlowRate v2 
    "actual flow through pump 2";

  Integer nPumpsRunning(start = 1) "number of pumps running";

  // Total flow
  Modelica.SIunits.VolumeFlowRate vTotal = 70;

equation 
  // Calculate the flow through pump 1 as a function of frequency
  v1 = fPump1;

  // Calculate the flow through pump 2 based upon running state
  if fPump1 > fMax then
    nPumpsRunning = 2;
    v2 = v2IfRunning;
  else
    nPumpsRunning = 1;
    v2 = 0;
  end if;

  // Calculate the total flow
  vTotal = v1 + v2;

end TwoPumpCode;

Again, this is a steady-state model. I have tried using if, when, reinit, Boolean variables for pumpRunning state, Integer variables for number of pumps running, etc. and I am still unable to get the steady-state solution to resolve.

Any suggestions would be greatly appreciated.

Thanks, Justin

2
You could separate the control logic from your pump model, as it is done e.g. in the MSL models. Then you have a pump model that has an on/off switch, and a controller. In the controller, use hysteresis to avoid chattering.matth
Thanks for the feedback matth. The remainder of the system is purely steady-state so I would prefer to avoid the dynamics of the controller if possible. Can you recommend a particular example from MSL that I can review?Justin Kauffman
Controllers like Modelica.Blocks.Logical.OnOffController do not add dynamics, as there is no storage/integration etc, it uses an if condition just like your code. Maybe I should not call it a controller, better call it a logical block!? You might find usage example on github: git.io/v9IGPmatth

2 Answers

1
votes

I now understand it better. The issue is that we need to separate variables.

model TwoPumpCode
  Modelica.SIunits.VolumeFlowRate vTotal = 70-40*time;
  model TwoPumpSimple
  // Pump 1
  Modelica.SIunits.Frequency fPump1 "pump 1 frequency";
  Modelica.SIunits.Frequency fMax = 50 "maximum frequency";
  Modelica.SIunits.VolumeFlowRate v1;

  // Pump 2
  // Boolean runPump2(start=false) "true if pump 2 should run";
  Modelica.SIunits.VolumeFlowRate v2IfRunning = 30;
  Modelica.SIunits.VolumeFlowRate v2 
    "actual flow through pump 2";

  Integer nPumpsRunning(start = 1) "number of pumps running";
    // Total flow
  input Modelica.SIunits.VolumeFlowRate vTotal;
  input Boolean activeSecond;
  equation
     // Calculate the flow through pump 1 as a function of frequency
  v1 = fPump1;

  // Calculate the flow through pump 2 based upon running state
  if activeSecond  then
    nPumpsRunning = 2;
    v2 = v2IfRunning;
  else
    nPumpsRunning = 1;
    v2 = 0;
  end if;

  // Calculate the total flow
  vTotal = v1 + v2;
  end TwoPumpSimple;
  //TwoPumpSimple first(vTotal=vTotal,activeSecond=first.fPump1>first.fMax);
  TwoPumpSimple first(vTotal=vTotal,activeSecond=false);
  TwoPumpSimple second(vTotal=vTotal,activeSecond=first.fPump1>first.fMax);
end TwoPumpCode;

The out-commented line is the same as the first solution, and changed it to a discrete problem - but that problem sometimes lack a solution.

The new variant does the following: 1 How high frequency is needed without the 2nd pump?

2 Should we activate 2nd pump?

3 Compute new frequency - based on that.

Adding some hysteresis in the decision would have a similar effect.

1
votes

Based upon the feedback from matth, I was able to use the pre() operator based upon an example from Modelica.Blocks.Logical.OnOffController. The functional code is shown below for reference.

model TwoPumpCode_matth
  // Pump 1
  Modelica.SIunits.Frequency fPump1 "pump 1 frequency";
  Modelica.SIunits.Frequency fMax = 50 "maximum frequency";
  Modelica.SIunits.VolumeFlowRate v1;

  // Pump 2
  parameter Boolean runPump2InitialValue = false;
  Boolean runPump2(start=runPump2InitialValue) "true if pump 2 should run";
  Modelica.SIunits.VolumeFlowRate v2IfRunning = 30;
  Modelica.SIunits.VolumeFlowRate v2 "actual flow through pump 2";

  // Total flow
  Modelica.SIunits.VolumeFlowRate vTotal = 70;

initial equation 
  pre(runPump2) = runPump2InitialValue;

equation 
  // Calculate the flow through pump 1 as a function of frequency
  v1 = fPump1;

  // Calculate the flow through pump 2 based upon running state
  runPump2 = pre(runPump2) or (fPump1 > fMax);
  if runPump2 then
    v2 = v2IfRunning;

  else
    v2 = 0;

  end if;

  // Calculate the total flow
  vTotal = v1 + v2;

end TwoPumpCode_matth;