Michael Lloyd

CLX Rate of Change AOI?

21 posts in this topic

Is there a prebuilt Rate of Change routine in CLX? If there is I can't find it, so: I've been trying to figure out the timing routine for a rate of change AOI and I'm stumped. I would like for everything to be contained in the AOI. I would use structured text language. I originally thought that I would just use a timer and call the routine every X seconds. Interval would be Preset / 10.0 but that would mean using an external timer. It's not a horrible solution but way back in my S7300/400 days I wrote a routine that calculated elapsed time between calls based on the system clock for use in a PID loop reset and derivative calculation. I was trying to write my own PID loop. Why? Because... :) This isn't that exacting of a calculation requirement so I was hoping for something simple. The calc is for tank rate of change and direction. Since tanks vary in capacity and inflow / outflow the time interval needs to be adjustable. No longer than a minute. No less than 5s or so. It looks like I can use a TONR in a structured text routine but I didn't have much luck when I tried to code one. Maybe I should have put the timer in the local group? Ideally the AOI would be drag and drop into a function block routine and I could map the IO via STX.

Share this post


Link to post
Share on other sites
http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/ It is critical that the sample intervals be constant. Timers are not very good for this. Interrupts are much better.

Share this post


Link to post
Share on other sites
Why an external timer ? I would just put the Rate-of-Change AOI instructions in a Periodic Task - Set its Priority high (low priority number) for ultimate repeatability. That takes care of your "timebase", so the math from there should be easy.

Share this post


Link to post
Share on other sites
I'm finally getting around to building this thing and I was wondering if the Periodic Task would be accurate enough. I Googled it and it pointed me here :) Next step is wrapping my head around how to put the new value into Y2 and the previous value into Y1 (Y2-Y1)/(X2-X1) where X2-X1 = t which in this case would be the periodic task time base. Since I'm dealing with tanks and pipeline pressure I'm going to use 5s. So can I assume that the Periodic task will run only once per 5 seconds if that's what I set the time to?

Share this post


Link to post
Share on other sites
Absolutely yes !! That is what a Periodic Task was made for, it is triggered by the processor's internal clock to mS resolution, and there is no other way it can be triggered to execute. Just be thoughtful (I nearly said "careful", but I don't think a few microseconds each way will hurt a 5-second task), about Task Priorities. The task you need to have the most accurate timebase, should have the highest priority. A Periodic or Event Task will always interrupt the scan of the Continuous (Cyclic) task, by design it has the lowest priority, and a task with a higher priority will interrupt tasks with lower priorities. Tasks with equal priority levels are "time-sliced" at the system level, giving them {pseudo} equal priorities.

Share this post


Link to post
Share on other sites
Perfect. I'm downloading it to a remote machine now (not in service. I use it for a test bed and when I'm done I export the routine, delete it, download the original program back to it). As usual my "perfection" wasn't so I had to edit the routine. The nice thing about the test bed is that it has live but passive data that I can use for the test. Even link to a graphic if I want to (I don't)

Share this post


Link to post
Share on other sites
Well it works... but I'm watching the level (in barrels) of a 50,000 barrel tank full of oil and they "slosh" based on inflow vs outflow. The the Periodic Task is set to 60000ms and there is a bit of a wobble in the result even at that. I also put in some up/down/neutral bits so I can graphically show which direction it's going. I added deadband so the direction function is somewhat useful. It measure ROC in Units/second, Units/minute, and Units/Hr. The direction If/Then uses the minutes variable. I wish that I had built one for each of the units. Oh well... it's not like it's super critical... the deadband is pretty small in the instance that I am currently using it. It won't be as small if the tank is smaller or if I use it on pressure. Edited by Michael Lloyd

Share this post


Link to post
Share on other sites
Michael, I'm a little late to the party, but I've done this in the past with some good success. Here's a couple ideas that you might try. 1. Yes periodic task is a must. I generally set mine to 1 second. I then have a setting of how many scans have to go by before I take a sample. This way my period is adjustable. 2. I generally have some adjustment for averaging. For example I might grab 60 samples and calc the average. Next time around I can use that average for 5 of my samples or 10, ect and mix them in with my real time samples when I calculate the rate. This way I can smooth out my rate display.

Share this post


Link to post
Share on other sites
Good stuff. I'm going to pull the AOI off of the prior post since it needs some work. I'll put it back when I finish (whatever finish means :o) ) Edited by Michael Lloyd

Share this post


Link to post
Share on other sites
Could someone take a look at this? You can't see the parameters so if you need a value for clarity let me know Y1 and Y2 are typically going to be in the 10,0000 to 40,000 range for tanks Since the periodic task is 1000ms now t :=1.0 which makes cs := cst/t unnecessary. I'm going to leave it in case I want to adjust the periodic task timing. c:=60.0 All of the Moving Average stuff is on local tags so I can't watch to see that they are working... I hate that... but it's the cleanest way to implement them. If I make them In/Out tags I have to use external arrays for the variables and I don't want to do that. // Begin Rate of Change Calculation If t > 0.0 THEN Y1 := Y2; // Move current value into previous register Y2 := PV; // Move process value into current register cst := (Y2-Y1)/t; // Calculate Rate of Change Per Unit Time in Seconds cs := cst/t; // Calculate Rate of Change Per Second mAvg.In := cs*c; hAvg.In := mAvg.Out*c; MAVE(mAvg, ms); MAVE(hAvg, hs); cm := mAvg.Out; // Calculate Rate of Change Per Minute ch := hAvg.Out; // Calculate Rate of Change Per Hour End_IF; // Direction Bit Routine for Seconds IF (cs-db) > 0.0 AND css THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (cs+db) < 0.0 AND css THEN // Check for Down d:=1; ELSE d:=0; END_IF; // Direction Bit Routine for Minutes IF (cm-db) > 0.0 AND cms THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (cm+db) < 0.0 AND cms THEN // Check for Down d:=1; ELSE d:=0; END_IF; // Direction Bit Routine for Minutes IF (ch-db) > 0.0 AND chs THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (ch+db) < 0.0 AND chs THEN // Check for Down d:=1; ELSE d:=0; END_IF; // If Neither Up or Down Check IF NOT u AND NOT d THEN // If Not Up or Down Then Neutral n:= 1; ELSE n:=0; END_IF; Edited by Michael Lloyd

Share this post


Link to post
Share on other sites
When I watch an AOI in ladder, there;'s a drop-down upper-right which allows me to "Instantiate" the display for each "call" to the AOI. Doesn't the same thing apply to STL?

Share this post


Link to post
Share on other sites
Also you can read the task period. At the top of the AOI GSV(Task, THIS, Rate, TaskRate); // TaskRate is a DINT tag - in microSeconds If you change the task period, the code can automatically pick this up. Edited by daba

Share this post


Link to post
Share on other sites
Thanks for taking the time to look it over. I have it running on (4) tanks and I'll add it to 5 or 6 more in the morning. So I've attached it to this post I found it. It's in the AOI itself. Open the tags. There is a drop down box that lets you view the local tags of the function block. I used the AOI in an FB. I may try it in STL later. It's written in STL and used as a Function Block. Rc.zip Edited by Michael Lloyd
1 person likes this

Share this post


Link to post
Share on other sites
But the ELSE statements can turn a bit off that was turned on earlier.... IF condition1 THEN u:=1 ELSE u:=0 IF condition2 THEN u:=1 ELSE u:=0 IF condition3 THEN u:=1 ELSE u:=0 What happens to u if ONLY Condition1 is TRUE ? I would.... u:=0 IF condition1 THEN u:=1 IF condition2 THEN u:=1 IF condition3 THEN u:=1 Edited by daba

Share this post


Link to post
Share on other sites
I too would suggest using the average to get your "pushing in/Pulling out" rate fairly certain.You cold make the average poll the time rate a bit differently too. I know the in rate can be pretty much the same as my out rate and it would help if one could know for sure. Of course that's still faster than hand-lining the tank too...

Share this post


Link to post
Share on other sites
That's what I wanted to happen. The level can only be in one of three states. Rising, Falling, or Not Rising or Falling. Each bit corresponds to the visibility of a different graphic so I don't want one to be on when the other is. A friend of mine would call this a kludgey solution :o) to a simple problem

Share this post


Link to post
Share on other sites
I used a MAVE (Moving Average) on the value second value to get a minute average and then used the result of the minute average to in a MAVE for an hourly average. It seems to work pretty well. I let all three variables be outputs so if the AOI were to be used in something that moves a lot faster than a tank level it would still have some value.

Share this post


Link to post
Share on other sites
Ah! Very good!. I'll add this to the AOI. Thanks a bunch. One more thing to not have to enter

Share this post


Link to post
Share on other sites
OK, it looks like I'm going to have to spell this out... You have 3 different "timebases", css, cms, and chs - I am assuming the AOI runs with only one of those true, because you have only 1 u (up) and 1 d (down) flag .... Your AOI looks first to see if css is true AND cs-db > 0.0 // Direction Bit Routine for Seconds IF (cs-db) > 0.0 AND css THEN // Check for Up u:=1; ELSE u:=0; END_IF; Assume that css is true AND cs-db IS > 0.0, the u flag will be turned on... Later, your AOI code looks to see if cms is true AND cm-db > 0.0 // Direction Bit Routine for Minutes IF (cm-db) > 0.0 AND cms THEN // Check for Up u:=1; ELSE u:=0; END_IF; Now assume that cms if FALSE, regardless of the value of cm-db, the ELSE part of the IF-THEN-ELSE construct is executed, which will turn u off again. Any one of the first two scenarios could turn u on, only for it to be turned off by the code that follows it. As I said, I made the assumption that only one of css, cms, or chs, is true. If that is not the case, then you will need separate u and d flags for each timebase. I would code the whole routine something like this, which is shorter, and would execute faster..... // Begin Rate of Change Calculation If t > 0.0 THEN Y1 := Y2; // Move current value into previous register Y2 := PV; // Move process value into current register cst := (Y2-Y1)/t; // Calculate Rate of Change Per Unit Time in Seconds cs := cst/t; // Calculate Rate of Change Per Second mAvg.In := cs*c; hAvg.In := mAvg.Out*c; MAVE(mAvg, ms); MAVE(hAvg, hs); cm := mAvg.Out; // Calculate Rate of Change Per Minute ch := hAvg.Out; // Calculate Rate of Change Per Hour End_IF; // get the selected value to test IF css THEN ctemp:=cs; ELSIF cms THEN ctemp:=cm; ELSIF chs THEN ctemp:=ch; END_IF; //Initialise flags u:=0; d:=0; n:=1; // Direction Bit Routine IF (ctemp-db) > 0.0 THEN // Check for Up u:=1; n:=0; END_IF; IF (ctemp+db) < 0.0 THEN // Check for Down d:=1; n:=0; END_IF;

Share this post


Link to post
Share on other sites
I see where we are not connecting. When I started this I had plans to make direction bits for time base and I literally got in such a hurry to see the time calc that I forgot to finish basically. So in looking at what I wrote (admittedly not very clean and in need of some help), since all of the IF statements are fundamentally the same If value minus deadband is greater tban zero AND the Check Seconds State Bit is true Then do the deal otherwise don't. I only turn one cXs bit on. X = H, M, or S. which means that, if I choose css only the first block runs and if neither of those are true the last block sets it's value.. I have this working in a couple of places. That said- your version is what I wanted to end up with but I got in a hurry and put up with sloppy code. If you don't mind I'll add your version to the AOI and repost the (hopefully) final version. I'm glad I got distracted by an Atmega 328P on Friday or I would've had the kludgey version installed everywhere. IF (cs-db) > 0.0 AND [color="#FF0000"]css[/color] THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (cs+db) < 0.0 AND [color="#FF0000"]css[/color] THEN // Check for Down d:=1; ELSE d:=0; END_IF; // Direction Bit Routine for Minutes IF (cm-db) > 0.0 AND [color="#0000FF"]cms[/color] THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (cm+db) < 0.0 AND [color="#0000FF"]cms[/color] THEN // Check for Down d:=1; ELSE d:=0; END_IF; // Direction Bit Routine for Hours IF (ch-db) > 0.0 AND [color="#FF8C00"]chs[/color] THEN // Check for Up u:=1; ELSE u:=0; END_IF; IF (ch+db) < 0.0 AND [color="#FF8C00"]chs[/color] THEN // Check for Down d:=1; ELSE d:=0; END_IF; // If Neither Up or Down Check IF NOT u AND NOT d THEN // If Not Up or Down Then Neutral n:= 1; ELSE n:=0; END_IF;

Share this post


Link to post
Share on other sites

I would like to add to this topic, I feel the leg work performed is good and I have created an AOI, I will post here for future reference, including my own since I almost always seem to land on this thread. I took the liberty of adding alarming to the AOI. The result is a pretty solid AOI.

Please discuss/comment/improve as needed.

ROC.L5X

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now