> ## Documentation Index
> Fetch the complete documentation index at: https://axiom.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://axiom.co/docs/feedback

```json
{
  "path": "/apl/scalar-functions/time-series/series-iir",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# series_iir

> This page explains how to use the series_iir function in APL.

The `series_iir` function applies an Infinite Impulse Response (IIR) filter to a numeric dynamic array (series). This filter processes the input series using coefficients for both the numerator (feedforward) and denominator (feedback) components, creating a filtered output series that incorporates both current and past values.

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.

## For users of other query languages

If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL.

<AccordionGroup>
  <Accordion title="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.

    <CodeGroup>
      ```sql Splunk example theme={null}
      ... | streamstats window=5 avg(value) as smoothed_value
      ... (limited to basic moving averages)
      ```

      ```kusto APL equivalent theme={null}
      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]))
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="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.

    <CodeGroup>
      ```sql SQL example theme={null}
      -- Complex recursive CTE required for IIR filtering
      WITH RECURSIVE filtered AS (...)
      SELECT * FROM filtered;
      ```

      ```kusto APL equivalent theme={null}
      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]))
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Usage

### Syntax

```kusto theme={null}
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

<Tabs>
  <Tab title="Log analysis">
    In log analysis, you can use `series_iir` to smooth noisy request duration measurements, making trends and patterns more visible.

    **Query**

    ```kusto theme={null}
    ['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](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20summarize%20durations%20%3D%20make_list\(req_duration_ms\)%20by%20id%20%7C%20extend%20smoothed%20%3D%20series_iir\(durations%2C%20dynamic\(%5B0.2%2C%200.6%2C%200.2%5D\)%2C%20dynamic\(%5B1.0%5D\)\)%20%7C%20take%205%22%7D)

    **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.
  </Tab>

  <Tab title="OpenTelemetry traces">
    In OpenTelemetry traces, you can use `series_iir` to filter span duration data, removing high-frequency noise to better identify sustained performance trends.

    **Query**

    ```kusto theme={null}
    ['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](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'otel-demo-traces'%5D%20%7C%20extend%20duration_ms%20%3D%20duration%20%2F%201ms%20%7C%20summarize%20durations%20%3D%20make_list\(duration_ms\)%20by%20%5B'service.name'%5D%20%7C%20extend%20filtered%20%3D%20series_iir\(durations%2C%20dynamic\(%5B0.1%2C%200.8%2C%200.1%5D\)%2C%20dynamic\(%5B1.0%2C%20-0.3%5D\)\)%20%7C%20take%205%22%7D)

    **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.
  </Tab>

  <Tab title="Security logs">
    In security logs, you can use `series_iir` to filter request rate data, separating sustained traffic changes from brief anomalies.

    **Query**

    ```kusto theme={null}
    ['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](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20summarize%20request_counts%20%3D%20make_list\(req_duration_ms\)%20by%20status%20%7C%20extend%20filtered%20%3D%20series_iir\(request_counts%2C%20dynamic\(%5B0.15%2C%200.7%2C%200.15%5D\)%2C%20dynamic\(%5B1.0%2C%20-0.4%5D\)\)%20%7C%20take%205%22%7D)

    **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.
  </Tab>
</Tabs>

## List of related functions

* [series\_sum](/apl/scalar-functions/time-series/series-sum): Returns the sum of series elements. Use for simple aggregation instead of filtering.
* [series\_stats](/apl/scalar-functions/time-series/series-stats): Returns statistical measures. Use for statistical analysis instead of signal processing.
* [series\_abs](/apl/scalar-functions/time-series/series-abs): Returns absolute values. Often used after IIR filtering to analyze magnitude.
* [make\_series](/apl/tabular-operators/make-series): Creates time-series from tabular data. Often used before applying `series_iir` for signal processing.
