PAC PID with Two Proportional Valves

I will start by saying that I’m a newb when it comes to PID’s and heating/cooling.

That said, I have an application in which I need to maintain the liquid temperature in a tank using a heat exchanger. I’ve been told the heat exchanger has two proportional output valves, one for heating and one for cooling, I assume one with hot water and the other cold, respectively.

My presumption is the system would partially open one or both valves until the temperature was at the setpoint. I wouldn’t think it’s a simple matter of opening one valve and closing the other otherwise the system would be constantly opening/closing valves.

Any thoughts on how I can do this with a PAC PID? Should I use two PID’s instead? I think I read somewhere here about using one for heating and one for cooling but I’m not sure how that would work either.

Thanks!

What temperature range does the tank need to be kept within?

Edit: Doesn’t matter - I would recommend using a separate PID for cooling and heating since they will likely require different tuning coefficients. You can then use some PAC Control code to switch between them (by changing the mode to manual, see SetPidMode). Use the velocity algorithm as the other algorithms are a pain when modifying them in your strategy. Avoid using the D term, you shouldn’t need it.

To determine the time to switch PIDs, you would look at the PID output (your valve position request) and when it reaches zero output AND your input is passed the middle of the deadband (the range between the cooling and heating setpoints) to need the other valve, you would switch PIDs.

Can we look at an example?

Let’s say the current temperature is 20 C and the setpoint is 60 C.

When it starts, since the current temperature is less than the setpoint, we enable the heating PID.
The heating valve opens continually until the temperature reaches target 60C.
The valve will then start to close and continue to close until it reaches at or near 0 (fully closed). I’m not sure where the temperature would be at this point. It could be just below 60 or well below 60 depending on how fast the liquid changes temperature.
At that point, the strategy disables heating and enables cooling which is an inverse relationship, the farther the valve is open, the lower the temperature.
The cooling valve opens continually until the temperature reaches target.
As the temperature falls, the valve continues to close until it too reaches 0.
The strategy then switches back to the heating valve.

Does this sound right? Wouldn’t the temperature get too high or low as each valve fully closes? Perhaps the valves close fairly quickly as the temperature gets further from the setpoint?

I did this sort of thing a lot at the hospitable I worked at in Australia…
It was easy to do because I always had a 2-5 deg © deadband. (Between when we had to heat and when we had to cool).
What’s your dead band options look like for the temperature in the tank?
Once we know that, we can answer more fully.

Not sure, I’ll need to ask. The setpoints I’ve been given range from 50 to 90 C, HOT!

The control loop will do all that for you once tuned.

You could setup a control loop with a 0 integral “I term”, and you could have proportional loops which could work like this:

50C HV 100% CV 0%
55C HV 50% CV 0%
60C HV 0% CV 0%
65C HV 0% CV 50%
70C HV 0% CV 100%

That is a very simple way to control it if the process tolerates being away from setpoint. With the added integral “I term” of the control loop, this offset from setpoint will be eliminated and the output would gradually change to reach the setpoint value. In this way the loop will “find” the output value that is needed to maintain the input value at the setpoint value.

That’s a good range.
Does the set point for the tank have to be user adjustable?
The answer will impact how you set up the PIDs (a little).

The setpoints are adjustable though I suspect they won’t be. Once they get their process figured out, I don’t think they’ll want to change them much.

I did ask about deadbands and was told 0.5 C. That sounds pretty tight to me.

Hmmm, 0.5 deg C might be a bit much for the mechanical setup of the tank etc, but with careful tuning, it might be doable (its very doable from an Opto / PID point of view - it’s more just a question of the valves, heat/cool exchanger setup, temperature probe location, thermal mass, tank volume etc).

So here is how I would go about it.
Set up your analog input (the temp probe) and the two analog outputs (the proportional valves).

I have set the valves up for 0 to 10vDC, but yours might be 4-20mA.
I set up the scaling for 0 to 100% as that’s pretty typical I suspect.

The temperature input is just an ICTD, you will probably have something else, but the range and input details will be much the same.

The PID configuration is also very standard (to start).

The cooling one is the same, just with a P-term of 10 and a Set point of 80.
I chose not to do anything with the output over range options.
You can set that up if you like, it will just give you options to try and protect the tank temperature if the input goes out of range.

Carefully pick some set points to get started, or don’t start the PID loops in auto and only start them once you have applied the desired set point. The reason for this that the PID set point is zero by default, which is probably not what you want. So either set it at a starting range, or add strategy code to start the PID loops after you have set up the set point values.

As for the strategy code, here is what I imagine you would start with.

By keeping a dead band around your desired set point your PID loops (once they are tuned) will never fight each other and your tank will hover around the desired set point.

When it comes to tuning, I would be doing a step function response tune of the heating and cooling.
Both will be different due to different valves and pumps etc.
Here is a guide I wrote to help with that.
https://www.opto22.com/support/resources-tools/demos/pid-reaction-curve-tuning-for-interactive-pid-alg

Hope that helps you get started.

2 Likes

Ben’s strategy code will work if the setpoints can be separated with a decent deadband (once you swap the setpoints around for each PID, as written you will have two valves at 100%) .

If they want 0.5C of range, then likely the setpoints for heating and cooling will be very close, or the same and you will need a way to switch between cooling and heating. You will also need a fairly slow loop that avoids overshoot (less gain, lower TuneI and slower to reach setpoint).

Here is some logic for PID switching - I left the two setpoints in case the user can accept a deadband, but they could be set to the same value. If a faster control response is needed which may cause overshoot, then some timers should be incorporated as well to delay the switching between cooling and heating.

//sanity check
if(tank_setpoint_upper < tank_setpoint_lower) then
  tank_setpoint_lower = tank_setpoint_upper;
endif

//Assign setpoints
SetPidSetpoint(cooling_PID, tank_setpoint_upper);
SetPidSetpoint(heating_PID, tank_setpoint_lower);

//get the midpoint of the setpoints for PID switching
tank_mid_setpoint = (tank_setpoint_upper + tank_setpoint_lower) / 2.0;

//If heating is enabled, check if we need to switch to cooling
//Using 0.1 for pid output comparision instead of 0.0 since this is an analog world
if(GetPidMode(heating_PID) == 0 and GetPidOutput(heating_PID) <= 0.1 and tank_temperature > tank_mid_setpoint) then
  //switch to cooling
  //Turn off heating (set to manual, and set output to 0%)
  SetPidMode(heating_PID, 1);
  SetPidOutput(heating_PID, 0.0);
  //Turn on cooling loop
  SetPidMode(cooling_PID, 0);
endif

//If cooling is enabled, check if we need to switch to heating
//Using 0.1 for pid output comparision instead of 0.0 since this is an analog world
if(GetPidMode(cooling_PID) == 0 and GetPidOutput(cooling_PID) <= 0.1 and tank_temperature < tank_mid_setpoint) then
  //switch to heating
  //Turn off cooling (set to manual, and set output to 0%)
  SetPidMode(cooling_PID, 1);
  SetPidOutput(cooling_PID, 0.0);
  //Turn on heating loop
  SetPidMode(heating_PID, 0);
endif

[facePalm]
Its Friday right? It must be Friday…

Yes, it’s Friday!
I personally reserve these mistakes for Mondays though.

Happens to the best of us! :smiley:
I will implement this. I won’t have the hardware for a while. I’m going to try to simulate it though. I recently found that I can’t do that with PAC Sim but I do have an actual controller I can use.

Thanks and have a good weekend!

Great, thanks for sharing!