Overview

series_iir

You can use series_iir when you need to apply digital signal processing techniques to time-series data. This is particularly useful for smoothing noisy data, removing high-frequency components, implementing custom filters, or applying frequency-selective transformations to time-series measurements.

Usage#

Syntax#

series_iir(array, numerator, denominator)

Parameters#

Parameter Type Description
array dynamic A dynamic array of numeric values (input series).
numerator dynamic A dynamic array of numerator (feedforward) coefficients.
denominator dynamic A dynamic array of denominator (feedback) coefficients.

Returns#

A dynamic array containing the filtered output series after applying the IIR filter defined by the numerator and denominator coefficients.

Use case examples#

In log analysis, you can use series_iir to smooth noisy request duration measurements, making trends and patterns more visible.

Query

['sample-http-logs']
| summarize durations = make_list(req_duration_ms) by id
| extend smoothed = series_iir(durations, dynamic([0.2, 0.6, 0.2]), dynamic([1.0]))
| take 5

Run in Playground

Output

id durations smoothed
u123 [50, 120, 45, 200, 60] [50, 91, 62, 128, 88]
u456 [30, 35, 80, 40, 45] [30, 33, 54, 46, 45]

This query applies an IIR filter to smooth request duration measurements, reducing noise while preserving the underlying trend.

In OpenTelemetry traces, you can use series_iir to filter span duration data, removing high-frequency noise to better identify sustained performance trends.

Query

['otel-demo-traces']
| extend duration_ms = duration / 1ms
| summarize durations = make_list(duration_ms) by ['service.name']
| extend filtered = series_iir(durations, dynamic([0.1, 0.8, 0.1]), dynamic([1.0, -0.3]))
| take 5

Run in Playground

Output

service.name durations filtered
frontend [100, 150, 95, 200, 120] [100, 130, 108, 152, 133]
checkout [200, 250, 180, 300, 220] [200, 230, 202, 248, 232]

This query applies an IIR filter with feedback to span durations, smoothing out transient spikes while maintaining sensitivity to sustained changes.

In security logs, you can use series_iir to filter request rate data, separating sustained traffic changes from brief anomalies.

Query

['sample-http-logs']
| summarize request_counts = make_list(req_duration_ms) by status
| extend filtered = series_iir(request_counts, dynamic([0.15, 0.7, 0.15]), dynamic([1.0, -0.4]))
| take 5

Run in Playground

Output

status request_counts filtered
200 [100, 105, 300, 110, 95] [100, 103, 180, 142, 120]
401 [10, 12, 50, 15, 11] [10, 11, 27, 20, 16]

This query uses IIR filtering to smooth security event patterns, helping distinguish between brief anomalies and sustained attack patterns.

  • series_sum: Returns the sum of series elements. Use for simple aggregation instead of filtering.
  • series_stats: Returns statistical measures. Use for statistical analysis instead of signal processing.
  • series_abs: Returns absolute values. Often used after IIR filtering to analyze magnitude.
  • make_series: Creates time-series from tabular data. Often used before applying series_iir for signal processing.

Other query languages#

Splunk SPL users

In Splunk SPL, signal processing typically requires external tools or complex manual calculations with streamstats. In APL, series_iir provides built-in digital filtering capabilities for array data.

Splunk example

... | streamstats window=5 avg(value) as smoothed_value
... (limited to basic moving averages)

APL equivalent

datatable(values: dynamic)
[
  dynamic([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
]
| extend filtered = series_iir(values, dynamic([0.25, 0.5, 0.25]), dynamic([1.0, -0.5]))
ANSI SQL users

In SQL, implementing IIR filters requires complex recursive queries or user-defined functions. In APL, series_iir provides this functionality as a built-in operation on array data.

SQL example

-- Complex recursive CTE required for IIR filtering
WITH RECURSIVE filtered AS (...)
SELECT * FROM filtered;

APL equivalent

datatable(values: dynamic)
[
  dynamic([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
]
| extend filtered = series_iir(values, dynamic([0.25, 0.5, 0.25]), dynamic([1.0, -0.5]))

Updated

Was this page helpful?