线性滤波器

WPILib支持的第一种(也是最常用的)过滤器是线性过滤器,或者更具体地说,线性定常(LTI)过滤器。

An LTI filter is, put simply, a weighted moving average - the value of the output stream at any given time is a localized, weighted average of the inputs near that time. The difference between different types of LTI filters is thus reducible to the difference in the choice of the weighting function (also known as a “window function” or an “impulse response”) used. The mathematical term for this operation is convolution.

有两种广义的脉冲响应:无限脉冲响应(IIR)和有限脉冲响应(FIR)。

无限脉冲响应具有无限的“支持”——也就是说,它们在一个无穷大的区域上是非零的。广义上来说,这意味着它们也有无限的“内存”——一旦一个值出现在输入流中,它将永远影响所有后续输出。从严格的信号处理角度来看,这通常是不希望看到的,但是具有无限脉冲响应的滤波器往往非常容易计算,因为它们可以用简单的递归关系来表示。

有限冲激响应具有有限的“支持”-也就是说,它们在有界区域上不为零。 “典型” FIR滤波器是一个固定的移动平均值-也就是说,只需将输出设置为等于过去n个输入的平均值即可。 FIR滤波器往往比IIR滤波器具有更理想的属性,但计算成本更高。

Linear filters are supported in WPILib through the LinearFilter class (Java, C++, , Python).

创建一个LinearFilter

备注

c++``LinearFilter``类被模板化为用于输入的数据类型。

备注

因为过滤器有“内存”,所以每个输入流都需要它自己的过滤器对象。不要尝试对多个输入流使用相同的过滤器对象。

虽然可以直接实例化“ LinearFilter”类以构建自定义过滤器,但使用提供的工厂模式之一要方便得多(并且更常见),而不是:

单极IIR

A graph with two peaks with the input closely following the target signal.

The singlePoleIIR() factory method creates a single-pole infinite impulse response filter which performs exponential smoothing. This is the “go-to,” “first-try” low-pass filter in most applications; it is computationally trivial and works in most cases.

// Creates a new Single-Pole IIR filter
// Time constant is 0.1 seconds
// Period is 0.02 seconds - this is the standard FRC main loop period
LinearFilter filter = LinearFilter.singlePoleIIR(0.1, 0.02);
// Creates a new Single-Pole IIR filter
// Time constant is 0.1 seconds
// Period is 0.02 seconds - this is the standard FRC main loop period
frc::LinearFilter<double> filter = frc::LinearFilter<double>::SinglePoleIIR(0.1_s, 0.02_s);
from wpimath.filter import LinearFilter

# Creates a new Single-Pole IIR filter
# Time constant is 0.1 seconds
# Period is 0.02 seconds - this is the standard FRC main loop period
filter = LinearFilter.singlePoleIIR(0.1, 0.02)

参数“时间常数”决定了滤波器的脉冲响应的“特征时间尺度”。滤波器将抵消在明显短于此的时间范围内发生的任何信号动态。相关地,它也是引入的相位滞后:ref:`phase lag <docs/software/advanced-controls/filters/introduction:Phase Lag>`的近似时间尺度 。该时间标度的倒数乘以2,即为滤波器的“截止频率”。

参数“ period”是过滤器的calculate()方法将被调用的时间段。对于绝大多数实施方式,这将是0.02秒的标准主机器人循环周期。

移动平均值

A graph with two peaks with the input closely following the target signal.

``movingAverage’’工厂模式创建一个简单的平面移动平均滤波器。这是最简单的低通FIR滤波器,在许多与单极IIR滤波器相同的环境中很有用。它的计算成本较高,但通常表现得更好。

// Creates a new flat moving average filter
// Average will be taken over the last 5 samples
LinearFilter filter = LinearFilter.movingAverage(5);
// Creates a new flat moving average filter
// Average will be taken over the last 5 samples
frc::LinearFilter<double> filter = frc::LinearFilter<double>::MovingAverage(5);
from wpimath.filter import LinearFilter

# Creates a new flat moving average filter
# Average will be taken over the last 5 samples
filter = LinearFilter.movingAverage(5)

“抽头”参数是将包含在固定移动平均值中的样本数。这与上面的“时间常数”类似-有效时间常数是抽头数乘以调用calculate()的时间段。

高通

A graph with two peaks except the highpass only shows the rate of change centered around 0.

highPass工厂模式创建一个简单的一阶无限冲激响应高通滤波器。这是“ singlePoleIIR” _的“对手”。

// Creates a new high-pass IIR filter
// Time constant is 0.1 seconds
// Period is 0.02 seconds - this is the standard FRC main loop period
LinearFilter filter = LinearFilter.highPass(0.1, 0.02);
// Creates a new high-pass IIR filter
// Time constant is 0.1 seconds
// Period is 0.02 seconds - this is the standard FRC main loop period
frc::LinearFilter<double> filter = frc::LinearFilter<double>::HighPass(0.1_s, 0.02_s);
from wpimath.filter import LinearFilter

# Creates a new high-pass IIR filter
# Time constant is 0.1 seconds
# Period is 0.02 seconds - this is the standard FRC main loop period
filter = LinearFilter.highPass(0.1, 0.02)

“时间常数”参数确定了滤波器的脉冲响应的“特征时间尺度”; 滤波器将消除在时间尺度上明显长于此的任何信号动态。相关地,它也是引入的相位超前 phase lead. 的近似时间表。该时间刻度的倒数乘以2 ,即为滤波器的“截止频率”

参数“ period”是过滤器的calculate()方法将被调用的时间段。对于绝大多数实施方式,这将是0.02秒的标准主机器人循环周期。

使用LinearFilter

备注

为了使创建的过滤器服从指定的时标参数,必须在指定时间段定期调用其calculate()函数*。如果由于某种原因,必须在calculate()调用中发生重大失误,则应在进一步使用之前调用过滤器的reset()方法。

创建过滤器后,使用起来很容易-只需使用最新输入调用calculate()方法即可获取过滤后的输出:

// Calculates the next value of the output
filter.calculate(input);
// Calculates the next value of the output
filter.Calculate(input);
# Calculates the next value of the output
filter.calculate(input)