Derived/Expression Tag, just driven by one tag?

Hey all,
Recently been needing to do some math calcs in our SCADA.

One calc is to compare a current value, to it’s previous to get the change in Inflow volume.

An expression I wrote for the tag is:

if({[.]Old Data/oldData1}=0,
{[.]Old Data/oldData1},
{[~]PTM PLC/INFLOW_COUNTER}-{[.]Old Data/oldData1})

The oldData=0 so equal to old value, is a request from client’s engineers, so we have to have that.

I then used a tag event script to write my previous value to the old Data tag.

if initialChange == True:
     return
system.tag.writeBlocking(["[.]Old Data/oldData1"],[previousValue.value])`

When I simulate it, the expression is triggered when my previous value is written by the script and bounces around and breaks.
This happens even when I used a derived tag, replacing INFLOW_COUNTER with {source}.

How can I this tag driven by a single tag change other than using tag groups, we’ve got a lot of these calcs and I don’t want a tag group for each. I want it event based if possible

What do you mean it breaks? Is there an error message, or it grinds to a halt, or what?

I would consider using a single script to do everything. You technically could skip the old value tag, but it’s nice to have a visual.

if not initialChange:
	tagListOut = ["[.]Old Data/oldData1", "[.]path/to/volumeTag"]
	
	if previousValue.value == 0:
		volume = currentValue.value
	else:
		volume = currentValue.value - previousValue.value
	
	system.tag.writeBlocking(tagListOut, [previousValue.value, volume])

You might find the state local variable of my objectScript expression function useful for this case. From my Simulation Aids module.

When I say break, I’m meaning that it would switch so fast that it would on occassion write a null value to our OldData tag and stop the loop as the expression tag errored.

I’ll try using the scripting, we had originally put this entire set of calculations into gateway timer script, but had some performance issues as it wouldn’t execute as we expected. I’ll try using a similiar script though with some changes.

Main issue is this the first of several calcs and a lot of these reference other calcs

Okay, so decided to go half way and attempt some scripts. I eventually found that using the

tag("[.]Old Data/oldData1")

Will trigger the expression to run again, but if I use

runScript("system.tag.read('[.]Old Data/oldData1').value")

Won’t cause an event on the expression. I rewrote my expression to:

if(runScript("system.tag.read('Calculated/Old Data/oldData1').value")=0,
runScript("system.tag.read('Calculated/Old Data/oldData1').value"),
{[~]PTM PLC/INFLOW_COUNTER}-(runScript("system.tag.read('Calculated/Old Data/oldData1').value")))

This triggers only on a change of my Inflow Counter and I can then use my event change script to write to the old data tag.

Bit annoying that this is the only way to cleanly do it using expression tags only. I can’t be the only one calculating changes in a similar way. I would have thought the point of the derived tag was to have one driving reference and then an expression to calculate with, I have to wonder what is the use of the derived tag over a normal expression other than some kind of scaling.

objectScript("(args[0]-state.get('old', args[0])) if args[0] else 0\nstate['old'] = args[0]",
  {[~]PTM PLC/INFLOW_COUNTER})

No need for an oldData1 tag at all.

If the incoming tag is zero, the result is zero. On tag startup you also get zero for one cycle.

I agree it’s not needed in this case, some of the other calculations aren’t as simple as using previous value into the oldData, some other calcs will use a small sum so will calculate an “old Data”. This just happened to be the calc I was working on first.

I’ve kept it simply as it’s part of the client request and also keeps all of the tags similar to each other. It may also be used for setting the value to 0 for diagnostics etc.