# AVE and STD — Average and Spread

Source: https://rungs.dev/docs/ladder-logic/instructions/ave-std

> AVE and STD in rungs.dev work out the average and the standard deviation of a run of array elements. Use them to smooth a noisy reading or to tell steady from unstable.

Adds up a run of array elements and stores their average in a tag.

Works out how spread out a run of array elements is and stores the result in a REAL tag.

## What they are for [#what-they-are-for]

A single sensor reading jumps around. `AVE` over the last few readings smooths it — that is a
**moving average**, the standard way to get a usable number out of a noisy signal.

`STD` answers the other question: _how much_ is it jumping around? A low standard deviation
means the readings agree with each other; a high one means something is unstable, even if the
average looks fine. Watching `STD` is how you spot a bearing starting to fail before the
average temperature moves at all.

Both read a run of an array and keep their state in a
[`CONTROL`](https://rungs.dev/docs/ladder-logic/instructions/array-instructions#control-tag-members) tag.

## Operands [#operands]

| Name        | Type                                                       | Notes                                            |
| ----------- | ---------------------------------------------------------- | ------------------------------------------------ |
| `array`     | `DINT`, `INT`, `SINT`, `REAL`                              | Where the run starts — `Samples` or `Samples[2]` |
| `dimension` | the number `0`                                             | Which dimension to vary                          |
| `dest`      | `DINT`, `INT`, `SINT`, `REAL` (`AVE`), `REAL` only (`STD`) | Where the answer goes                            |
| `control`   | `CONTROL`                                                  | The instruction's state                          |
| `length`    | number                                                     | How many elements to read                        |
| `position`  | number                                                     | Not used by these two. Leave it `0`              |

`STD`'s destination must be a `REAL`: a standard deviation is almost never a whole number, and
storing one in a `DINT` would throw the answer away.

`dimension` is always `0` — Studio arrays have
[one dimension](https://rungs.dev/docs/tags/arrays#restrictions), so there is no other one to vary.

> **INFO**
>
> **Position is not an input here**
>
> Unlike the FIFO instructions, these two always start at the first element of the run. Writing
> `.POS` from your logic changes nothing about what they read; `.LEN` does.

## How It Works [#how-it-works]

Both are **one-shots**: they run on the scan the rung goes true and not again, even if the data
changes while the rung stays true. To recompute, let the rung go false and true again.

| Event                          | What happens                                                   |
| ------------------------------ | -------------------------------------------------------------- |
| Rung goes true                 | Reads `.LEN` elements, stores the answer, sets `.EN` and `.DN` |
| Rung stays true                | Nothing                                                        |
| Rung false                     | `.EN`, `.DN` and `.POS` go to `0`                              |
| The run reaches past the array | `.ER` turns on, the destination is left alone, no fault        |

Afterwards `.POS` sits on the **last** element read — `.LEN - 1`, not `.LEN`. That is different
from [`BSL`](https://rungs.dev/docs/ladder-logic/instructions/bsl-bsr), which drives `.POS` all the way to `.LEN`.

> **INFO**
>
> **.ER latches**
>
> Once `.ER` is on, a false rung leaves the whole control alone — `.EN` and `.POS` included — and
> so does start-up. Clear it with [`RES`](https://rungs.dev/docs/ladder-logic/instructions/res), or fix `.LEN` and clear `.ER` from your logic.

## STD measures the sample spread [#std-measures-the-sample-spread]

`STD` divides by **N − 1**, not by N. That is the _sample_ standard deviation: the right one
when your elements are a sample of a larger stream of readings, which they always are here.

For `[2, 4, 4, 4, 5, 5, 7, 9]` it gives `2.13809`. The population formula would give `2.0` — if
you check the answer against a calculator, make sure you picked the sample setting.

A length of `1` has no spread to measure and stores a `NaN`. That is not an error; guard it
with a length of 2 or more if you care.

## Example — Smooth a Noisy Reading [#example--smooth-a-noisy-reading]

Take the average of the last eight samples each time the buffer fills.

```ladder
XIC(BufferFull)AVE(Samples,0,SmoothValue,AvgCtl,?,?);XIC(BufferFull)STD(Samples,0,Spread,SdCtl,?,?)

AvgCtl.LEN = 8
AvgCtl.POS = 0
SdCtl.LEN = 8
SdCtl.POS = 0
```

Each instruction has its own control tag. Sharing one between them would make them disagree
about what has run.

## Structured Text [#structured-text]

Neither has a Structured Text form. In a Structured Text routine, write the sum in a `FOR` loop.

## Common Mistakes [#common-mistakes]

- Expecting a held-true rung to keep recomputing as new data arrives. It is a one-shot.
- Storing a standard deviation in a `DINT`. It needs a `REAL`.
- Reading `.POS` as "how many it did". It is the **index** of the last element — one less.
- Comparing `STD` against a population standard deviation and calling it wrong.

## Related [#related]

- [Array instructions overview](https://rungs.dev/docs/ladder-logic/instructions/array-instructions)
- [SRT](https://rungs.dev/docs/ladder-logic/instructions/srt) — sort the same run instead
- [FFL and FFU](https://rungs.dev/docs/ladder-logic/instructions/ffl-ffu) — filling the buffer these read