Expression tag is slow sometimes

Hi,

sometimes expression tags are not fast enough to keep with updating variables. Below I have examples of good and bad case:

GOOD


BAD

How the whole procedure looks? We collect data to a string tag, which is an expression tag. It is event driven, so every time one of the variables changes, the whole expression tag updates. After that, writerequest signal tells us, to send the data to the database. As you can see, the writerequest signal arrives with some data, so the question is, isn't it too fast and that could be causing the error? On the other hand, 99% of case, expression tags updates in time.

Ideas that come to my mind right now:

  1. Delay the script that sends data to DB. After we receive writerequest, we can wait some time, so the expression tag will have time to update?
  2. Change the expression tag execution from event driven to fixed rate?
  3. Ask the PLC programmer, if he can send writerequest a little bit late? The problem is, he is from another company they are very restrictive when it comes to signal processing times and will probably not agree to such a solution.
  4. Change the polling rate of collected data to 500 ms and the writerequest to 1000 ms? But will it speed up the expression tag?

Thanks in advance for any ideas!

Consider using a gateway tag event script to monitor the writerequest tag, then use system.opc.readValues() to read of the rest of your values. This will avoid the race condition you're seeing.

I would also try using the store and forward system to write to the database, if you're not already. Your tag change events should run super quick.

Yes, but how it will affect the expression tag execution? Because we are sending result of expression tag to database.

Same here, we are sending result of expression tag, which is calculated in Ignition, so how will store and forward improve it?

Try doing it all in the script, including the write to the db.

1 Like

This! Don't mix expression tags with scripts. If you must have a script, replace the operation of the expression with code in the script.

That sounds quite logical. I have this expression for example:

What is the most simple way to rewrite this in script?

Something like this:

tagPaths = ["[.]SerialNumber","[.]xOK","[.]xNOKProcess","[.]xNOKProduct","[.]Height","[.]HeightMin","[.]HeightMax"]

values = [val.value for val in  system.tag.readBlocking(tagPaths)]
finalStr = ""
xSum = 0

for i,val in enumerate(values):
	if i == 0:
		finalString = val + "|"
	elif i < 4:
		xSum += int(val)
	elif i == 4:
		finalString += str(xSum) + "|" + val.replace(".",",") "|"
	else:
		finalString += val.replace(".",",") + "|"

system.tag.writeAsync(["[.]pathToWrite"],[finalString])

Maybe not the cleanest way to do it, kind of has a magic number feel to it. The index numbers in the loop are dependent on how you build the tag paths list, there are issues, but this should show you the basics that you would need to accomplish what the expression is doing. You could build the string in a single concatenation operation if desired. I also assumed that all of your tag values are strings since you were doing the integer conversion. If they are not all strings then the conversions may be un-needed.

Note that if you use a gateway tag event script (recommended) then the relative tag paths wont work and you will need to use the full path.

As there is already a race condition, I'd suggest to replace the tag paths with their OPC paths and use system.opc.readValues().

My take on the post processing is a bit different, and may have to change, since the OP hasn't stated the data types.

values = ['123135848413',
		  True,
		  False,
		  False,
		  '10.123',
		  '9.000',
		  '12.000',
		 ]


for i, value in enumerate(values):
	if 1 <= i <= 3:
		values[i] = int(value)
	elif 4 <= i <= 6:
		values[i] = value.replace('.',',')

stringOut = '{}|{}{}{}|{}|{}|{}'.format(*values)
print stringOut

Output:

123135848413|100|10,123|9,000|12,000
2 Likes

Maybe I misread, but I thought you might have been running INSERT queries from a tag change script, in which case running them via the S+F system would be quicker, I believe

Hi,

I've started moving the code from expression tags to scripts. Do you have any idea, how to delay the start of the script for 50 ms? The writeRequest tag comes to Ignition in the same moment as one of the data tags and we need to delay the script, so all data is packed. I've tried using timer from threading library, but the script doesn't launch.

system.util.invokeLater ?

Short answer, don't. If this is needed then you need to look at the system design.

See good advice here:

2 Likes

Okay, so we will look to the system design.

Is it better to use Gateway Tag Change script or Tag Value Change script?

Better to use Gateway Tag Change. Tag events have a limited thread pool and queue limit.

4 Likes

A different kind of question, but what happens, when you poll OPC too fast? Are you losing data? And why?

No, you just don't get the pace you request. If you use a native IA driver, the driver diagnostics will show what pace you are really getting. When there's no free time in the scan, then writes can be delayed significantly more than normal.

When using an external OPC server, you would have to look at its own diagnostics to determine your overload level, if any.

1 Like