Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
An exponential moving average reduces sensor noise by combining each new reading with the previous smoothed value. It produces a result for every accepted reading.
For example, readings of 30, 35, and 35 produce smoothed values of 30, 32.5, and 33.75 when each calculation gives equal weight to the new reading and the previous result. Each sensor is smoothed separately. All examples are synthetic.
Prerequisites
Start with an existing Azure IoT Operations deployment and MQTT broker access. Follow Create a data flow graph to configure a data flow profile and MQTT endpoint.
Complete the Azure Samples deployment instructions for registry setup and single-instance deployment, then use the standalone sample setup. The examples use namespace azure-iot-operations.
The default data flow profile must already exist with one instance. The examples reuse the existing factory-mqtt MQTT endpoint and factory-artifacts registry endpoint for ghcr.io; they don't create profiles or endpoints.
The Azure CLI installed on your development machine. Check Available Azure CLI extensions for the minimum required version to use the azure-iot-ops extension. Use
az --versionto check your version andaz upgradeto update if necessary. For more information, see Install the Azure CLI.The Azure IoT Operations extension for the Azure CLI. Use the following command to add the extension or update it to the latest version:
az extension add --upgrade --name azure-iot-ops
The Azure CLI examples in this article use environment variables so that you can set each value once and then copy and paste the commands as-is. If you're using the Azure IoT Operations Codespaces environment from the quickstart, these variables are already set for you and you can skip this step. Otherwise, set the following environment variables in your shell before you run the commands.
The following scripts set the most commonly used environment variables:
| Environment variable | Description |
|---|---|
SUBSCRIPTION_ID |
The ID of the subscription that contains your Azure IoT Operations instance. |
RESOURCE_GROUP |
The name of the resource group that contains your Azure IoT Operations instance. |
AIO_INSTANCE_NAME |
The name of your Azure IoT Operations instance. To list your instances, run az iot ops list -o table. |
CLUSTER_NAME |
The name of the Azure Arc-enabled Kubernetes cluster that hosts your instance. |
LOCATION |
The Azure region to use for new resources, for example eastus. |
SUBSCRIPTION_ID=<subscription-id>
RESOURCE_GROUP=<resource-group-name>
AIO_INSTANCE_NAME=<instance-name>
CLUSTER_NAME=<cluster-name>
LOCATION=<region>
You only need to set the variables that this article uses. This article might use additional environment variables for resource names that you choose. The article explains how to set them where they're introduced.
Deploy the complete graph
This sample uses a custom artifact from ghcr.io. The operations experience supports custom artifacts from Azure Container Registry (ACR), not GHCR. Use the Azure CLI or Bicep tab to deploy this example unchanged.
To use the operations experience, first copy the graph and its referenced WASM modules to ACR and configure a registry endpoint. Then follow Deploy custom WASM transforms for the supported UI workflow. The graph configuration in the Azure CLI tab shows the required topics and settings.
The source subscribes to factory/smoothing-readings; the destination is factory/smoothed. Authorize sensor publishers for the readings topic.
The example blends half of each new reading with half of the previous smoothed output (alpha: 0.5). The first reading initializes the output directly. Each later accepted reading uses:
new smoothed output = 0.5 * new reading + 0.5 * previous smoothed output
The blend uses the previous smoothed output. A larger weight follows changes faster; a smaller weight retains more of the previous result. Supported weights are greater than 0 and at most 1.
Check the blend
Publish each line separately on factory/smoothing-readings:
{"kind":"reading","assetId":"sensor-1","messageId":"r0","sequence":0,"value":30}
{"kind":"reading","assetId":"sensor-1","messageId":"r1","sequence":1,"value":35}
{"kind":"reading","assetId":"sensor-1","messageId":"r2","sequence":2,"value":35}
| Reading | Calculation | smoothedValue |
|---|---|---|
30 |
Initialize directly | 30 |
35 |
0.5 * 35 + 0.5 * 30 |
32.5 |
35 |
0.5 * 35 + 0.5 * 32.5 |
33.75 |
The second reading produces this output when it arrives 0.1 seconds into the example timeline:
{"kind":"smoothed","assetId":"sensor-1","messageId":"r1","sequence":1,"value":35,"smoothedValue":32.5,"emittedAtMs":100}
Each output retains the raw value and other input metadata, including optional sampledAt. The processor adds smoothedValue and computes emittedAtMs automatically. The example time is relative to the timeline's start; live outputs use processing-clock epoch milliseconds. Results aren't rounded.
Advanced: reading frequency and restart
The weight applies to each accepted reading. More frequent readings make the output follow a change faster in elapsed time. This graph needs no clock publisher.
Keep messageId unique per asset, including across restarts, and sequence strictly increasing. Retry a message only with its original ID, sequence, and unchanged content.
A restart clears previous outputs and retry tracking. The next reading initializes directly, which can create a sudden change in the output. If continuity matters, coordinate replay from saved readings and make sure consumers don't process replayed outputs twice. Use separate assets or deployments for different measurements and units.