You work with Johnson Control PCT or CCT, I’m pretty sure you are doing your sideloops wrong !
Ok but what is the link to Pyhon ? Well… this post is a little off-topic but I thought I could bring that here anyway. And to be honest, I found out this while working with BAC0 to test my sequences of operation. I’ll release something soon related to that but let stick to sideloops for now.
For those who don’t work with Johnson Controls FEC or FX-PC products, you could think you won’t learn anything… I’m sure it could help with other products. And by the way, it still relates to building automation !
For outsiders to JCI stuff, you must know that all PIDs, by default, will be configured to use their auto-tuning features and building a “program” for a controller is easier when you use the selection tree which wil build for you the basic sequences you will need to modify. No more blank page. Some like it, some not. But let’s put aside our feelings for now.
Sideloops
When in a sequence, you need to add a PID loop of some kind, you can use what’s called “Sideloop” using a friendly button called… yeah “Sideloop”.
This button will ask some questions and you will end with a PID loop and everything else you need (like interlocks, override detection, entries in the state table (ok for those who don’t know the product, the state table is a kind of coordinator for your different blocks. It is really close to a Finite-State-Machine algorithm). This little button is kinda sharp and creates for you everything you need is much less time than if you would create everything by hand.
Everything ?
Nope. And this is where we (yes I include myself here) make a gigantic mistake.
Remember I told you about the auto-tuning feature of JCI devices ? This feature is really interesting. It works really well in “mostly” all situations. But ! If you ever leave a PID loop active for a long period of time when it should not be active (like a heating loop when it’s cooling time), you will end over-tuning the loop… Always. It will result in PID loop acting really bad. So bad that you will get call back, you will get angry against the tool, argue about the auto-tune and try by any mean to deactivate this stupid feature that never work…
Sounds familiar ? Don’t lie.
The problem
Problem is that we missed a step. An important step. If you study how things are done in JCI applications, you will find for every PID loop, a state generation block attached. Let’s take a simple example of a Fan Coil application with Cooling and Heating.
There is a Output Control Block for the Cooling PID Loop. There is another one for the Heating PID loop.
In the state table, we can see that they are not let in control everytime. Forced in Hold for PID tuning, in Hold when an override is detected, OFF when the Fan is not running… And in T Control only when the “Occupied Zone Sequencing” state generation block tells to the state table that we are in Cooling mode or in Heating mode (depending on the loop you are looking at).
This state generation block will assure you that the PID loop will run only when it’s needed. It will never run forever with an output to 0%.
But why there is no such block for Sideloop ?
It would probably be hard to cover every use cases. But what I know is that you need one. So build it ! A simple addition that will save you time and make your app stronger.
How ?
You first need to know what your sideloop is controlling. For now, let’s say we need a heating loop for an auxiliary room. You created the sideloop and got all the common stuff.
You now need to add in the state generation column, something like a “Occupied Zone Sequencing” block. This block will need some inputs and output to work. The same room temperature than the one used by the sideloop. The setpoints used (cooling and heating). And the control status of the heating sideloop.
What do I take for control status ?
You will need a Last Value Enum block that you will add to the Output Control colum. No efforts needed here the default value of those blocks is Control Status. And you will choose the control status of the PID Loop related to your process that will get to a maximum output.
More details about control status
I’m going a little further than our case here. But let’s say that we would be cascading a PID loop calculating a setpoint. Setpoint used by a second PID loop. When the setpoint loop reaches its maximum, it is possible (and mostly sure) that the output of the second loop won’t need to get to a max position. A control status will notify the app by telling if the control is
- Overridden (typically not in control)
- Low (at 0% since a certain delay, you could turn this off)
- Timing Low (just reach 0%… counting)
- Normal (working)
- Timing High (just reach 100%… counting)
- High (at 100% since a certain delay, need backup!)
The control status is used to switch the mode of the state generation block. Here is what could be in the mind of a simple heating app :
- I’m satisfied, temperature reached setpoint
- No, now I need heating, start heating loop
- Control status of heating is normal, continue
- Control Status of heating is now High, we reached maximum. Switch state to more heat (a second stage for example)
- Second stage of heating is normal, modulating…
- Second stage control status is now Low…. I can get back to my first heating stage…
- Heating stage is now Low… I’m back to Satisfied
So what would happen in the case of cascaded PIDs if I would use the heating valve PID loop control status instead of the setpoint loop control status ?
- I’m satisfied
- No, I need heating
- Control Status of heating is normal, it modulates.
- Setpoint has reached max value
- Control Status of heating is normal, it modulates. Yeah it is a very powerful heating valve, I’m at 25% modulation
- But room temp is now OK
- I don’t care, I’m still modulating and I didn’t reached my control status “Low State”
- I really chose the wrong status right ?
- You bet ! So I keep heating.
Pretty subtile difference but really important. In our case though, no cascade. So we just link the Sideloop Control Status to the last value block… and we link the output of the Last Value block to the Occupied Zone Sequencing State Generation block. Now the block will know when the Sideloop starve or when it is no more needed.
Modifying the state table
Last step, you must create a new table in the State Table that will use the same output than the Occupied Zone Sequencing. You will create it after all the table holding the Control state for the Sideloop (typically the override check table or the passtrough).
The sideloop will then be configured to be in control only when needed (in heating mode). Will be Off in all other cases. Don’t forget to replace the old Control state in the preceding table by a star.
That’s it
You now have a robust Sideloop that won’t over-tune and stop working for no reason… in fact, reasons you didn’t know. Because now you know why it was not working correctly.
You know why you did your Sideloop wrong.