# Find peak values

**URL:** <https://forum.inductiveautomation.com/t/find-peak-values/106794>\
**Category:** Ignition\
**Created:** [May 28, 2025, 9:36pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794 "2025-05-28T21:36:44Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kin\_H](https://avatars.discourse-cdn.com/v4/letter/k/22d042/32.png) [@Kin\_H](https://forum.inductiveautomation.com/u/Kin_H)\
**Post date:** [May 28, 2025, 9:36pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/1 "2025-05-28T21:36:44Z")

</div>

I like to find the peak value of each cycle/hill from a tag in historian within a time range in script, only if the peak is above 7000 lbs (ignore the small hills). Is there a faster way than looking at each point in the dataset, such as using a combination of querytaghistory and scripting. Just looking for ideas not entire code. Each cycle/hill is a batch. I need to add all the peak values to come up with the weight of raw materials. Thanks!

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/3/633ca2c69a4208e67f17ae6eeca41ea168cbfda5.png)

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [May 28, 2025, 10:06pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/2 "2025-05-28T22:06:10Z")

</div>

You could simplify the problem by creating an expression tag to monitor the weight. An expression like this:

```python
if(
	{[~]Weight} > 7000,
	{[~]Weight},
	0
)

```

might do the trick. Then log that rather than, or as well as, the actual weight.

You still have some work to do though!

---

<div class="post-metadata">

**Author:** ![ASF](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@ASF](https://forum.inductiveautomation.com/u/ASF)\
**Post date:** [May 28, 2025, 10:34pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/3 "2025-05-28T22:34:03Z")

</div>

You'll need to not only determine the minimum peak value, but also the maximum "reset" value. That is, once your weight exceeds 7000lb, you capture the next peak, but then how do you determine when that peak has completed and the next one begins? Generally you would say something like "when the weight drops back below _x_". For the sake of the example, let's say the "reset" value is 250lb.

One approach might be to have an expression tag that references the live weight, with an expression that looks something like

```python
if(myValue = 0 && liveWeight < 7000, 0,
if(liveWeight >= 7000 && liveWeight > myValue, liveWeight,
if(liveWeight < 250, 0,
myValue)))

```

Line by line, this basically says:

1. If we're at zero and the live weight is less than 7000lb, remain at zero, otherwise continue
2. If the actual weight is greater than 7000lb, and greater than the current value of this tag, then update this tag to reflect the higher weight. If not, continue
3. If the live weight is less than 250lb, set my value back to zero
4. If none of the above are true, hold current value

So what should happen if I've got that right is that the tag will stay at zero until the weight exceeds 7000lb, then track the weight as high as it goes, then reset back to zero when the weight falls below 250lb

Then, add a change script to that tag. Every time it changes, if it changes from a non-zero value to a zero value, write the previous value of the tag to another memory tag called BatchWeight. So, each time your weight falls below 250lb, and your expression tag resets to zero, it will set BatchWeight to the highest greater-than-7000lb weight previously reached.

Finally, configure tag history on BatchWeight, with it set to log on change only, and just pull the entire tag history from that tag. It'll get you each batch weight and an almost-correct timestamp for that batch (i.e. not the time that the batch was completed, but the time when the batch was removed from the scale).

You'll have to consider what will happen if you get two batches in a row with the exact same weight. Depending on the resolution of your measurement this may or may not be an issue. If it is, you could do something like reset the BatchWeight tag to -1 between each batch, and when you run your tag history query, only retrieve positive values.

Of course I'd much rather do this in the PLC and just push the final batch weights to Ignition, but if you don't have that option something like this should work. Plenty of ways to deconstruct this feline!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 28, 2025, 10:59pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/4 "2025-05-28T22:59:27Z")

</div>

> [@ASF](#):
>
> 1. If none of the above are true, hold current value

Expression tags cannot safely reference their own value. Don't do this.

---

<div class="post-metadata">

**Author:** ![ASF](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@ASF](https://forum.inductiveautomation.com/u/ASF)\
**Post date:** [May 28, 2025, 11:36pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/5 "2025-05-28T23:36:56Z")

</div>

Thanks for the tip! Maybe you could just put a change script on the live weight tag then, and do effectively the same thing there?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 28, 2025, 11:53pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/6 "2025-05-28T23:53:06Z")

</div>

If you really need state like that, I recommend using the `state` dictionary that my `objectScript()` function offers.

---

<div class="post-metadata">

**Author:** ![Kin\_H](https://avatars.discourse-cdn.com/v4/letter/k/22d042/32.png) [@Kin\_H](https://forum.inductiveautomation.com/u/Kin_H)\
**Post date:** [May 29, 2025, 2:32am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/7 "2025-05-29T02:32:31Z")

</div>

Thanks! I think I understand your logic and Phil's suggestion and will try them out. We tried that in the PLC but the outcome wasn't consistent, resulting raw materials less than the final product sometimes. I am hoping I don't have to use expression tag but rather use the mixer weight tag that has months of data already. If that's not possible or working, I will resort to expression and memory tags.

Just to clarity, the raw material is dumping into the blender for mixing. When the weight reaches maximum (peak) that's the weight of that batch, when it decreases, that's when the gate valve and pump are running to move the product to filling. The little hills are washing.

---

<div class="post-metadata">

**Author:** ![Leor\_Fishman](https://avatars.discourse-cdn.com/v4/letter/l/e19adc/32.png) [@Leor\_Fishman](https://forum.inductiveautomation.com/u/Leor_Fishman)\
**Post date:** [May 29, 2025, 2:39am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/8 "2025-05-29T02:39:42Z")

</div>

split the list up every time you drop below 7k, pick the max from each sublist?

---

<div class="post-metadata">

**Author:** ![Kin\_H](https://avatars.discourse-cdn.com/v4/letter/k/22d042/32.png) [@Kin\_H](https://forum.inductiveautomation.com/u/Kin_H)\
**Post date:** [May 29, 2025, 3:05am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/9 "2025-05-29T03:05:17Z")

</div>

The weight scale fluctuates, could be bouncing around 7k.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [May 29, 2025, 3:31am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/10 "2025-05-29T03:31:00Z")

</div>

> [@pturmel](#):
>
> , I recommend using the `state` dictionary

Say what?

---

<div class="post-metadata">

**Author:** ![Leor\_Fishman](https://avatars.discourse-cdn.com/v4/letter/l/e19adc/32.png) [@Leor\_Fishman](https://forum.inductiveautomation.com/u/Leor_Fishman)\
**Post date:** [May 29, 2025, 3:28pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/11 "2025-05-29T15:28:10Z")

</div>

Then do the same for 6k/5k

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 29, 2025, 4:59pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/12 "2025-05-29T16:59:37Z")

</div>

What do you mean by "ignore" ?

In the PLC do you have a "batch start" and "batch complete" ? You could track those start and end times and find the max between start and end.

Or use a combination of tags and expression tags on the weight value change script to "detect" batch start/stop in Ignition. Something like `Batch_Running`, `Batch_Start_Min` [7000] `Batch_Stop_Max` [100] Expression tag check the weight.

Something like (pseudocode),

```python
if NOT Batch_Running and ( Batch_Weight > Batch_Start_Min )
    Batch_Running = True

if Batch_Running and ( Batch_Weigh < Batch_Start_Max )
    Batch_Running = False

```

---

<div class="post-metadata">

**Author:** ![Kin\_H](https://avatars.discourse-cdn.com/v4/letter/k/22d042/32.png) [@Kin\_H](https://forum.inductiveautomation.com/u/Kin_H)\
**Post date:** [May 29, 2025, 6:53pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/13 "2025-05-29T18:53:53Z")

</div>

Thank you! Unfortunately no batch start or end in PLC. Ignoring the small hills because they are washouts not actual raw materials.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 29, 2025, 8:16pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/14 "2025-05-29T20:16:22Z")

</div>

If you have access to the PLC program you can do this in Ignition or in the PLC. I would use the same approach either way. Either the PLC or Ignition will writhe to the `Batch_Running` tag.

Turn history on for the `Batch_Running` tag. Query it to get the last start and stop times, use those to query again and get the max between start and stop and into a `Last_Batch_Weight_Max` and also turn history on on that.

You should be able to use aggregation methods to get whatever data you need from there.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [May 30, 2025, 12:27am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/15 "2025-05-30T00:27:56Z")

</div>

A simplified flowchart with one pass through the dataset.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/f/9/f94f9ff8dfb0401230ce6c0f4fe9950a3db3fb4b.png)

[Peaks.pdf](https://forum.inductiveautomation.com/uploads/short-url/gn01CvkaI4JTJCZ66mInENCzJdk.pdf) (14.7 KB)

---

<div class="post-metadata">

**Author:** ![ASF](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@ASF](https://forum.inductiveautomation.com/u/ASF)\
**Post date:** [May 30, 2025, 3:26am UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/16 "2025-05-30T03:26:31Z")

</div>

> [@Kin\_H](#):
>
> We tried that in the PLC but the outcome wasn't consistent

...if you can't get it to happen accurately in the PLC, you won't be able to make it happen accurately with Ignition. Anything you can do with Ignition is only as good as the data you give it, and if the PLC can't track it in realtime, Ignition has no hope.

It should be as simple as this, really (not sure of your PLC, this is Allen-Bradley, but they're all generic instructions).

Feed the weight reading that you're looking at on your trends into LiveWeight, and put tag history on LastBatchWeight, and you're basically done.

 ![Screenshot 2025-05-30 at 1.24.57 pm](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/f/bfb8667394bcda6a70fbf8d5eb9ff523d7d6203d.png)

---

<div class="post-metadata">

**Author:** ![Chris\_Bingham](https://avatars.discourse-cdn.com/v4/letter/c/e5b9ba/32.png) [@Chris\_Bingham](https://forum.inductiveautomation.com/u/Chris_Bingham)\
**Post date:** [May 31, 2025, 6:46pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/17 "2025-05-31T18:46:26Z")

</div>

> [@ASF](#):
>
> as simple as this

Bonus points if you convert this rung to utilize an output coil, instead of latch/unlatch.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 31, 2025, 7:06pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/18 "2025-05-31T19:06:51Z")

</div>

> [@Chris\_Bingham](#):
>
> an output coil, instead of latch/unlatch

That changes behavior through program mode changes or power blips. Maybe for the better, but not always.

---

<div class="post-metadata">

**Author:** ![Chris\_Bingham](https://avatars.discourse-cdn.com/v4/letter/c/e5b9ba/32.png) [@Chris\_Bingham](https://forum.inductiveautomation.com/u/Chris_Bingham)\
**Post date:** [May 31, 2025, 7:53pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/19 "2025-05-31T19:53:32Z")

</div>

> [@pturmel](#):
>
> That changes behavior through program mode changes or power blips

So much needs to be discussed for this to be a consideration for this rung (output state during controller not scanning, power supply feeding PLC, whether or not that programmer who made a program mode change while a system is running should _ **ever** _ be invited back, etc.).  
Logic is almost-always more robust - and easier to maintain - when latches are replaced by coils.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 31, 2025, 8:12pm UTC](https://forum.inductiveautomation.com/t/find-peak-values/106794/20 "2025-05-31T20:12:45Z")

</div>

> [@Chris\_Bingham](#):
>
> Logic is almost-always more robust - and easier to maintain - when latches are replaced by coils.

Completely agree. But that "almost" stuck in there means _unconditional_ bonus points are not appropriate.

(I've seen enough places with poor utility reliability to not knock defensive programming.)

[Next page](https://forum.inductiveautomation.com/t/find-peak-values/106794.md?page=2)
