Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

iir_filter plugin for MADS

This is a Filter plugin for MADS.

It applies a configurable IIR filter to signals picked out of the frames it subscribes to. The signals are selected in the settings as a map of topic to a list of keypaths (JSON pointers), so that one agent can filter several signals coming from several topics. Each selected signal gets its own filter instance, so their states never mix.

The filters come from the iir1 library: Butterworth and Chebyshev (type I and II) designs, as lowpass, highpass, bandpass or bandstop. Family, response, order and frequencies are all set in the INI file.

Required MADS version: 2.4.3.

Supported platforms

Currently, the supported platforms are:

  • Linux
  • MacOS
  • Windows

Installation

Linux and MacOS:

cmake -Bbuild -DCMAKE_INSTALL_PREFIX="$(mads -p)"
cmake --build build -j4
sudo cmake --install build

Windows:

cmake -Bbuild -DCMAKE_INSTALL_PREFIX="$(mads -p)"
cmake --build build --config Release
cmake --install build --config Release

INI settings

The plugin supports the following settings in the INI file:

[iir_filter]
sub_topic = ["signals"]   # agent setting: what to subscribe to
pub_topic = "filtered"    # agent setting: must differ from sub_topic

sampling_rate = 10.0      # Hz, the rate at which frames actually arrive
family = "butterworth"    # butterworth | chebyshev1 | chebyshev2
response = "lowpass"      # lowpass | highpass | bandpass | bandstop
order = 4
cutoff = 0.5              # Hz, lowpass and highpass only
center = 1.0              # Hz, bandpass and bandstop only
width = 0.5               # Hz, bandpass and bandstop only
ripple_db = 1.0           # dB of passband ripple, chebyshev1 only
stopband_db = 40.0        # dB of stopband attenuation, chebyshev2 only
passthrough = true        # republish the whole input frame, filtered fields added
suffix = "_filt"          # appended to each output keypath

# the signals to filter: one entry per subscribed topic
[iir_filter.inputs]
signals = ["/temperature", "/pressure"]

All settings are optional except inputs, which must select at least one signal; if omitted, the default values below are used.

Key Type Default Meaning
inputs table (empty) Map of topic = ["/keypath", ...]. Mandatory. The keypaths are JSON pointers into the incoming frame; a bare field name is accepted as a shorthand for a top-level one ("temperature" means "/temperature"). A single string is accepted instead of a one-element array.
sampling_rate float 10.0 Hz. The rate at which frames arrive on the subscribed topics, i.e. the reciprocal of the upstream source's period. Every cutoff is interpreted against it, so a wrong value detunes the filter.
family string "butterworth" butterworth, chebyshev1 or chebyshev2. Case and separators are ignored, and chebyshevI / cheby1 are accepted spellings.
response string "lowpass" lowpass, highpass, bandpass or bandstop (notch is a synonym of the last one).
order int 4 1 to 16. For bandpass and bandstop this is the prototype order: the realised filter has twice as many poles.
cutoff float 1.0 Hz, for lowpass and highpass. Must lie strictly between 0 and the Nyquist frequency, sampling_rate / 2.
center float 1.0 Hz, center of the band, for bandpass and bandstop.
width float 0.5 Hz, width of the band, for bandpass and bandstop. The whole band must fall between 0 and Nyquist.
ripple_db float 1.0 dB of allowed passband ripple. chebyshev1 only.
stopband_db float 40.0 dB of stopband attenuation. chebyshev2 only.
passthrough bool false When true, the output frame is a copy of the input frame with the filtered values added to it, so that raw and filtered signals travel together. When false, only the filtered values are published.
suffix string "" Appended to the last token of each output keypath, e.g. "_filt" publishes /temperature as /temperature_filt. With the default empty suffix the filtered value takes the place of the raw one. May not contain / or ~.

Any of these can also be set on the command line, e.g. mads filter iir_filter.plugin -o cutoff=2.0 -o order=6. Note that [iir_filter.inputs] is a nested table, so it can only come from the INI file.

An invalid setting (an unknown family, a cutoff above Nyquist, an order above 16, no input signal at all) is reported by info() at startup and makes the agent stop on its first frame with a critical return.

Output frames

With passthrough = false, the published frame carries one field per filtered signal, at the same keypath it was read from plus suffix:

{ "temperature": 24.98, "pressure": 3.01, "source_topic": "signals" }

With passthrough = true the whole input frame is republished, with the filtered values added to it:

{
  "n": 121, "t": 12.35, "sample_rate": 9.91,
  "temperature": 30.25, "temperature_filt": 17.73,
  "pressure": 2.49,     "pressure_filt": 2.47,
  "source_topic": "signals"
}

In both cases:

  • source_topic is the topic the frame was received on, which is how a downstream agent tells apart the sources of a multi-topic filter.
  • The fields the upstream agent stamped (agent_id, hostname, timestamp, timecode, clock_offset_us, clock_ref, topic) are dropped from a passed-through frame, so that this agent's own host stamps it with its own identity and time base.

Topics are matched the way ZMQ subscriptions are, by prefix: a topic key of "sig" picks up frames arriving on signals.

An IIR filter starts from a zeroed delay line, so the first frames after startup carry a transient: the output climbs from 0 to the signal over roughly sampling_rate / cutoff samples.

Per frame, the plugin returns:

Situation Return Effect
Every configured signal found success the filtered frame is published
The frame came from a topic with no configured signal retry nothing is published, nothing is logged
Some of the signals of that topic are missing or not numeric warning the rest is published, with the reason attached
None of them is usable, or the frame is not a JSON object error nothing is published; the reason goes out as an agent event
The settings are invalid critical the agent stops

Non-finite values (NaN, infinities) are treated as missing and never reach the delay line, where they would stick forever.

Executable demo

The build also produces a standalone test driver from the same source file (./build/iir_filter.plugin on MacOS, ./build/iir_filter on Linux, build/iir_filter.exe on Windows). It needs neither a broker nor a network: it drives the plugin exactly as mads filter does and checks, among others, that

  • a constant passes a lowpass unchanged and is removed by a highpass;
  • a tone well above the cutoff is rejected, and a notch removes its center frequency while leaving a nearby tone alone;
  • frames from an unconfigured topic are skipped, partial frames are a warning, and malformed ones are an error;
  • passthrough and suffix produce the documented frame;
  • every invalid setting is rejected.

It prints one line per check and exits non-zero if any of them fails.

About

Infinite-Impulse Response Filter (IIR) for MADS signals

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages