1 of 1 people found this helpful
I have moved your post to All Things PI because it lacked having code to justify being in PI Developers Club.
Do you not have a continuous measurement of tank percent full (or tank percent empty)? Is the only related measurement you receive truly a UOM from the Mass class? I find that odd because short of a tank percent fill, I normally would expect a Volume to know how much liquid is in the tank. It's Mass (or weight) would require knowing more about the density of the liquid.
To calculate a percent level based on Volume requires knowing meta data about the tank. Is the tank shape a cylinder, bullet, or sphere? Is the tank orientation vertical or horizontal? What is the height or length of the tank? What is the diameter or radius? Each answer would require a different set of calculations, some easier than others. Typically for most plants, these calculations would be done at the DCS reading the Volume. Then the PI interface would read that calculated value from the DCS just as if it were an instrument reading.
Are you trying to skimp and save on tag counts, which makes the a possible solution either very difficult or horribly slow, or do you have freedom to create tags as outputs from Asset Analytics? I don't think you need event frames.
You have 2 valves: input and output. It sounds like logically that one is the negative of the other. That is Input is open, Output is closed, and vice versa. As long as both cannot be open or both cannot be closed at the same time, you can treat them in a binary manner. You don't need a new tag for this, you would just look at either the Input valve being open or closed to decide if the tank is filling or discharging. Alternatively, you could look at the Output valve instead.
Using one of the valve's to decide the tank's Filling/Discharging state, I would suggest trying to calculate a DAILY value for both 'Daily Filling Mass' and 'Daily Discharge Mass'. This requires 2 new PI tags to be used as outputs from an Analysis. Then for a MONTHLY calculation, you would need yet another 2 new output tags ('Monthly Filling Mass' and 'Monthly Discharge Mass'). The monthly calculations will be much faster since they will be grabbing at most 31 daily values each. This also gives you the benefit of being able to see a partial monthly calculation quickly, or perhaps only recalculating for a specific day if the need arises.
If you are an EA customer with virtually unlimited tags, you could create a new tag to hold the binary tank state (filling vs discharging). This could be a Boolean, an integer 1 or 0, but I would recommend it be a digital state. I would have 3 states (0 = None, 1 = Discharging, 2 = Filling). The None state would be used in case the Input/Output valve has a bad value. You should try to set up the Analysis to update this state tag only on a change in state, which means NoOutput() is your friend.
Again, you don't need event frames for this.
Hello again Konstantin,
I have still been pondering your problem. You originally posted this in .NET Framework, so I am going to offer a way that I would do this with .NET code.
- I would create a Console based application using AF SDK. I would have it be configurable through the App.Config. There should be no UI prompts.
- I would schedule this Console app to run periodically at the same time every day with Windows Task Scheduler.
- I would choose to run it at 3:15 AM so as to cautiously avoid any conflict of any DST transitions between 1:00-3:00 AM.
- I would use a time range between "y" and "t". Note that if the day covered a DST transition that some days may be 23 hours and others 25.
- I would use RecordedValues calls on the Input Valve (or Output Valve since it is the opposite) and Tank Mass. These calls should use an Interpolated boundary to get values at Yesterday Midnight and Today Midnight. This is a twist because you don't just want to check for state changes, but rather state changes for a given day (in LocalTime).
- I would then iterate over the Input Valve to see if its had a state change (Filling, Discharging, BadVal). I would keep track of the first value that begins a new state.
- When a state change is detected, this would be the last value of the previous state. I would then calculate the difference between the first and last values for that state, and save to the appropriate output tag (Daily Filling Mass or Daily Discharging Mass).
- I would program an acceptable tolerance when comparing values rather than checking for pure equality. This will help remove noise from the signal. Using psuedo-code, Math.Abs(EndingMass - StartingMass) <= Tolerance would be equivalent to 0.
- I would use Yesterday at midnight as the output timestamp because you are calculating the Daily Filling/Discharge for Yesterday.
To then calculate Monthly Filling Mass or Monthly Discharge Mass, a periodic analysis could be run 30 minutes after the daily Console app is scheduled. This too would have to be scheduled to run daily, so the trick would be to detect if Day('*') = 1, where '*' is the trigger time. I would call the expression variable IsBOM and this would be a Boolean. If it is Not IsBOM, then NoOutput() is used. If IsBOM is True, I would then sum up the respective daily values and output to their monthly counterparts.
Is Very difficult for me. I want to get smart decision in PI AF. For example
DELTA_LEVEL= if 'VALVE_IN_OPEN' then TagVal('LEVEL','*')-Tagval('LEVEL',TimeStamp(PrevVal('VALVE_IN_OPEN','*'))) else NoOutput()
And next calculation is
Total LEVEL= if '*' = Bom('*') then "0.0" else tagtot('DELTA_LEVEL',bom('*'),'*')