RSLogix5000. How to write Expression to find Greater Than other values

Join Date
Jul 2021
Location
perth
Posts
185
Hi all. I am looking for an expression, or possibly even an instruction, that evaluates if a value of say tagA is greater than tagB, and tagC, and tagD... and tagZ.

A brute force method is to create a wrung and insert 16 GRT instructions in it, then repeat the same rung 16 more times in order to achieve the comparison that i am looking for.

(Which is to find the tag with the highest number inside a given minute of time. So for example, for 10 minutes, there are 10 minutes of time. And for every minute, i want to find the tag with the highest value, only for that specific minute.)

The next method i thought about is to use CPT which then requires an expression. I do not know how to write the expression i would need for this.

Any ideas?

Thank you
 
Do you want to know the maximum value in a series of value?

Or do you want to know if TagA is the max value, and/or if TagB is the max value, etc.?

What happens if two tags have the same max value?

Because we can find the max value, tag MXVAL, in a one-rung loop, or perhaps in a CPT if Tags A-Z are elements in an array, and then the single instructions [EQU TagA MXVAL], [EQU TagB MXVAL], ... [EQU TagZ MXVAL] will identify which tags have the maximum value.
 
Do you want to know the maximum value in a series of value?

Or do you want to know if TagA is the max value, and/or if TagB is the max value, etc.?

What happens if two tags have the same max value?

Because we can find the max value, tag MXVAL, in a one-rung loop, or perhaps in a CPT if Tags A-Z are elements in an array, and then the single instructions [EQU TagA MXVAL], [EQU TagB MXVAL], ... [EQU TagZ MXVAL] will identify which tags have the maximum value.
What happens if 2 values are the same? Have not reached that problem yet. Will cross that bridge when i get there.
 
Do you want to know the maximum value in a series of value?

Or do you want to know if TagA is the max value, and/or if TagB is the max value, etc.?

What happens if two tags have the same max value?

Because we can find the max value, tag MXVAL, in a one-rung loop, or perhaps in a CPT if Tags A-Z are elements in an array, and then the single instructions [EQU TagA MXVAL], [EQU TagB MXVAL], ... [EQU TagZ MXVAL] will identify which tags have the maximum value.
Hi Bitboy. Thank you for your reply.

What i am comparing are values in a counter. I do not think i can use 'counter...ACC' inside an array. If i can, please advise how to as this would be useful.

I can describe what i am up to in the program.

I am measuring wind direction. There are 16 directions of wind i am measuring; N, NNE, NE... NNW.

Each measurement has a counter to indicate how often a particular direction of wind was blowing inside a minute.

So for example, inside a given minute, the wind might have been recorded as blowing N 52 times, NNE 2 times, and NNW 6 times.

Or Counter N.ACC = 52
Counter NNE.ACC = 2
Counter NNW.ACC = 6

In this example, N was the dominant direction.

What is the best way to compare the three counters such that the PLC knows which counter produced the highest count.

The value of the count is not important (So high value of 52 is not relevant). Only WHICH counter produced the highest value is significant. (Counter N was the highest value)
 
Move the values to an array and use SRT to sort the values
Thank you Paully. I am trying to get my head around your suggestion.

If i have say 3 counters, and each counter produced different values:

Counter 1: 1
Counter 2: 100
Counter 3: 2

I MOV these values into an array, then sort, from lowest value to highest value. This i am ok with so far.

Once they are sorted:

1, 2, 100

The PLC knows 100 is the highest number. I personally know that the number 100 is from Counter 2. But how does the PLC know that Counter 2 counted the highest number?

Please elaborate.
 
Sort the indices.

Start with an array of Counter objects, counters, so N(orth) count is counters[0].ACC, NNE count is counters[1].ACC, ..., S(outh) count is counters[8].ACC, ..., NNW count is counters[15].ACC.

Put the indices into an array of indices, indices.

Then sort the indices, but the compare is not (indices[indexA] < indices[indexB]?), but (counters[iindexA].ACC < counters.[indices[iindexB]].ACC?), where iindexA is indices[indexA] and iindexB is indices[indexB], because counters[indices[indexA]].ACC is not acceptable syntax because of the multiple levels of brackets.

We cannot use the SRT instruction, but there are only 16 items to sort, so an O(N2) algorithm such as bubble sort is good enough and completes in one scan.

The original post did not need to sort, just find the index with the greatest count, so a simple loop will do the trick:

CLR index_of_max_count MOV 1 test_index
LBL loop BST GRT counters[test_index].ACC counters[index_of_max_count].ACC MOV index_of_max_count test_index
NXB
ADD test_index 1 test_index LES test_index 16 JMP loop
BND



[index_of_max_count] will be the lowest index, 0 to 15, of the element of the counters array with the greatest .ACC value.
 
Sort the indices.

Start with an array of Counter objects, counters, so N(orth) count is counters[0].ACC, NNE count is counters[1].ACC, ..., S(outh) count is counters[8].ACC, ..., NNW count is counters[15].ACC.

Put the indices into an array of indices, indices.

Then sort the indices, but the compare is not (indices[indexA] < indices[indexB]?), but (counters[iindexA].ACC < counters.[indices[iindexB]].ACC?), where iindexA is indices[indexA] and iindexB is indices[indexB], because counters[indices[indexA]].ACC is not acceptable syntax because of the multiple levels of brackets.

We cannot use the SRT instruction, but there are only 16 items to sort, so an O(N2) algorithm such as bubble sort is good enough and completes in one scan.

The original post did not need to sort, just find the index with the greatest count, so a simple loop will do the trick:

CLR index_of_max_count MOV 1 test_index
LBL loop BST GRT counters[test_index].ACC counters[index_of_max_count].ACC MOV index_of_max_count test_index
NXB
ADD test_index 1 test_index LES test_index 16 JMP loop
BND



[index_of_max_count] will be the lowest index, 0 to 15, of the element of the counters array with the greatest .ACC value.
Thank you bitboy. I do not know if i actually have the knowledge to successfully execute your instructions. But i will give it a try and respond in the next day or two with an update
 
Thank you Paully. I am trying to get my head around your suggestion.

If i have say 3 counters, and each counter produced different values:

Counter 1: 1
Counter 2: 100
Counter 3: 2

I MOV these values into an array, then sort, from lowest value to highest value. This i am ok with so far.

Once they are sorted:

1, 2, 100

The PLC knows 100 is the highest number. I personally know that the number 100 is from Counter 2. But how does the PLC know that Counter 2 counted the highest number?

Please elaborate.


One approach, even though we do not need to sort: for index = 0 to 15, use a FAL instruction encode the index into the values to be sorted without changing their sorting order, by putting the result of the expression (counters[index].ACC*16 + index) into an array, xarray[0..15], of INTs (or of DINTs, just in case to avoid overflow), then SRT xarray. One sorted, the bitwise expression (xarray[15] AND 15) will extract the value of the highest index of the counters array that has the greatest value of .ACC.

CPT ctlfal 16 0 ALL (counters[ctlfal.pos].ACC*16)+ctlfal.ipos xarray[ctl.pos] SRT 0 xarray[0] ctlsrt 16 0 AND xarray[15] 16 index_of_max_count




 
Last edited:
Thank you bitboy. I do not know if i actually have the knowledge to successfully execute your instructions. But i will give it a try and respond in the next day or two with an update


double-click on the rung number on the left, and enter the mnemonics as one line (fixing my typos is left as an exercise for the user ;)).


Btw, if a comparison (binary operator <) could be part of a FAL expression (which it can't), then that loop can be accomplished with a single CLR/FAL instruction pair:

CLR index_of_max_count FAL ctl 16 1 ALL index_of_max_count index_of_max_count)+((counters[index_of_max_count]<counters[ctl.POS])*(ctl.POS-index_of_max_count))


 
Finally (maybe), we may be missing the obvious solution, i.e. use the scan cycle to do the looping:
Untitled.png
Presumably, on every scan:

  • the program is reading the wind direction input, and
  • converting that wind direction to the index of the corresponding compass point, and
  • putting that compass point index into an INT such as CURRENT_COMPASS_POINT
  • So whenever the rising-edge trigger of a counter occurs,
    • it will only occur to the element at index CURRENT_COMPASS_POINT of the COUNTERS[0..15] array of counter structures, and
    • since, at that trigger,
      • all other counters will maintain their current value at that trigger, and
      • counter struct COUNTERS[CURRENT_COMPASS_POINT] will be incremented,
    • the comparison between COUNTERS[CURRENT_COMPASS_POINT].ACC and COUNTERS[].ACC is the only one that needs to be made to ensure that COMPASS_POINT_OF_MAX_COUNT is the first index of the counter structure element of the COUNTERS array that reached greatest value.
  • And even when there is no rising edge of the counting trigger,
    • that logic will still be valid, and
    • that logic will not assign an incorrect value to COMPASS_POINT_OF_MAX_COUNT
 
Thank you Paully. I am trying to get my head around your suggestion.

If i have say 3 counters, and each counter produced different values:

Counter 1: 1
Counter 2: 100
Counter 3: 2

I MOV these values into an array, then sort, from lowest value to highest value. This i am ok with so far.

Once they are sorted:

1, 2, 100

The PLC knows 100 is the highest number. I personally know that the number 100 is from Counter 2. But how does the PLC know that Counter 2 counted the highest number?

Please elaborate.

drbitboy mentioned the FAL instruction, and another approach would be take the result of the value from the SRT and use the FAL to index through the counters (which must be an array of counters for this to work). If the FAL instruction finds the Counter[FAL.POS].ACC that matches the SRT value. The FAL.POS is the counter.

This is actually a good introduction to sorting algorithms and I would suggest you do some homework on them. This is something you could build an Add-On instruction for and use it in future projects. Pascal is very close to structured text and you can find examples online for sorting code in Pascal. Apply it to ST and give it a go. NOTE, most examples are going to be single dimension sorting just like the SRT, however it's not difficult to include an identifier key to the algorithm.
 
Stepping back, we could also consider what the meaning of the most-sampled wind direction over a minute of samples. What if, over the course of one minute, the wind blows for 29s out of the north at 10kt, and for 31s out of the south at 1kt. Wouldn't North be a better choice for that minute?


E.g. the directional wind barbs in the wind speed part of the plot at this link use a speed-weighted directional average for each plotted barb. It's not complex, and RSLogix 5000 does have cosine, sine, and arc tangent instructions.
 
CLR index_of_max_count FAL ctl 16 1 ALL index_of_max_count index_of_max_count+((counters[index_of_max_count]<counters[ctl.POS])*(ctl.POS-index_of_max_count))



This will also not work for another reason: FAL needs a rising edge. perhaps the once-per-minute trigger?

This might fix both problems:

XIC once_per_minute CLR compass_point_of_max_count FAL ctl 16 0 ALL compass_point_of_max_count+((ctl.POS-compass_point_of_max_count)*((counters[compass_point_of_max_count].ACC-counters[ctl.POS].ACC) AND -32768)/-32768))


but other solutions are better.
 
Last edited:

Similar Topics

I am replacing a PLC5 with a 1756-L73 and i am trying to reuse a 1771-DB Basic Module. I am leaving the PLC5 in the chassis setup as RIO adapter...
Replies
7
Views
5,118
Need good example/sample of aoi RSLogix5000 code to read&write through RS232 port on Need good example/sample of aoi RSLogix5000 code to...
Replies
0
Views
1,843
Hey All, As the title states, how do I write a MinorFault generated by an instruction, for example a negative .PRE value was entered for a timer...
Replies
12
Views
2,999
Is it possible to partially restrict the types of communications allowed through a ControlLogix communications module? Ideally I'd like something...
Replies
7
Views
3,325
Hi! So my problem is a little funky, I had Studio 5000 v 24 and 30 installed, but forgot to install RSLogix (which I cannot go without). Is there...
Replies
2
Views
136
Back
Top Bottom