Skip to content

Filters

Overview

Filters in EVA Motors are decorators that clean and smooth control signals before they reach the motor. They remove noise, suppress spikes, and provide predictable signal conditioning. All filters share the same Go(value) interface and can be stacked with behavioral decorators.

Filter Type Best For
SlidingWindowDecor Moving average General noise reduction
MinmaxDecor Morphological Impulse noise removal
AdaptiveSmoothDecor Adaptive exponential Mixed noise with varying dynamics

SlidingWindowDecor – Moving Average

Simple moving average filter that computes the arithmetic mean of the last N values.

template <class Motor, unsigned short N>
class SlidingWindowDecor : public Motor

Parameters:

  • N: Window size (number of values to average)

Behavior:

  • Maintains running sum of last N values
  • Output = sum / N (arithmetic mean)
  • Pass-through until buffer fills
  • Constant delay of N/2 samples

Methods:

  • Go(value) – Apply moving average

Example:

// Smooth throttle with 5-sample window
using SmoothESC = evam::SlidingWindowDecor<evam::ForwardMotor<evam::PwmDriver<9>>, 5>;
SmoothESC motor;
motor.Go(500);  // Output = average of last 5 inputs

Use cases:

  • General purpose noise reduction
  • Pre-filtering for PID control
  • Data acquisition smoothing
  • Removing quantization noise

MinmaxDecor – Morphological Filter

Advanced filter that removes both positive and negative impulse noise while preserving edges.

template <class Motor, unsigned char N>
class MinmaxDecor : public Motor

Parameters:

  • N: Chunk size (total buffer = N × N elements)

Behavior:

  • Divides buffer into N chunks of N elements each
  • Finds maximum and minimum in each chunk
  • Computes minimax = min of chunk maximums (removes negative spikes)
  • Computes maximin = max of chunk minimums (removes positive spikes)
  • Output = (minimax + maximin) / 2

Methods:

  • Go(value) – Apply filter (pass-through until buffer full)
  • getMinimax() – Get current minimax value
  • getMaximin() – Get current maximin value

Example:

// Clean noisy potentiometer signal
using CleanMotor = evam::MinmaxDecor<evam::DirectionalMotor<evam::TA6586Driver<9, 10>>, 3>;
CleanMotor motor;
motor.Go(500);  // Filtered after 9 samples

Use cases:

  • Removing impulse noise from potentiometers
  • Cleaning encoder signals with glitches
  • Radar/lidar signal conditioning
  • Audio pop removal

AdaptiveSmoothDecor – Adaptive Exponential

Exponential filter that automatically adjusts its time constant based on input rate of change.

template <class Motor, unsigned short kMinTimeConstantMs = 10, unsigned short kMaxTimeConstantMs = 150>
class AdaptiveSmoothDecor : public Heartbeat, public Motor

Requirements:

Must call eva::tac() in loop() to drive the filter updates (inherits from Heartbeat with 10ms period).

Parameters:

  • kMinTimeConstantMs: Fast response (5..200ms). Default: 10ms
  • kMaxTimeConstantMs: Heavy smoothing (≥ kMinTimeConstantMs, ≤500ms). Default: 150ms

Behavior:

  • Large input change (≥200) → fast response (min time constant)
  • Small input change (≤5) → heavy smoothing (max time constant)
  • Intermediate changes → linear interpolation between min and max
  • Deadzone (±3) forces zero output near origin

Methods:

  • Go(value) – Set target value (range -1000..1000)
  • GetCurrentTimeConstant() – Get current smoothing amount

Example:

using AdaptiveMotor = evam::AdaptiveSmoothDecor<evam::DirectionalMotor<evam::TA6586Driver<9, 10>>>;
AdaptiveMotor motor;
motor.Go(800);  // Fast response to large change
motor.Go(810);  // Heavy smoothing for small change

Use cases:

  • Joystick-controlled vehicles (fast response + smooth idle)
  • Camera gimbals (smooth tracking + quick moves)
  • Robotic arms (precision positioning + rapid moves)
  • Any system requiring both responsiveness and noise rejection

Combining Filters

Filters can be stacked for enhanced noise rejection:

#include <evaTac.h>
#include <evamTA6586Driver.h>
#include <evamDirectionalMotor.h>
#include <evamSlidingWindowDecor.h>
#include <evamMinmaxDecor.h>
#include <evamAdaptiveSmoothDecor.h>

using namespace eva;
using namespace evam;

// Remove impulse noise, then smooth, then adapt to dynamics
using BaseMotor = DirectionalMotor<TA6586Driver<9, 10>>;
using SpikeFilter = MinmaxDecor<BaseMotor, 3>;        // Remove spikes
using SmoothFilter = SlidingWindowDecor<SpikeFilter, 5>; // General smoothing
using SmartMotor = AdaptiveSmoothDecor<SmoothFilter>;    // Adaptive response

SmartMotor motor;

void loop() {
    eva::tac();  // Drives AdaptiveSmoothDecor
    int raw = analogRead(A0);
    int mapped = map(raw, 0, 1023, -1000, 1000);
    motor.Go(mapped);  // Triple-filtered signal
}

Performance Considerations

Filter Memory (bytes per N) Computation Requires tac()
SlidingWindowDecor 2 × N + 4 O(1)
MinmaxDecor 2 × N + 2 × N × N O(N²)
AdaptiveSmoothDecor 6 + 4 O(1)

Recommendations:

  • Use SlidingWindowDecor for general noise (lowest overhead)
  • Use MinmaxDecor when spikes are present (N=2 or 3 usually sufficient)
  • Use AdaptiveSmoothDecor when both fast response and smooth idle are critical
  • Stack filters in order: spike removal → smoothing → adaptive behavior