Use when you must compute the coefficients of a digital Butterworth IIR lowpass or highpass frequency-selective filter from a cutoff frequency, sample rate, and order: prewarp the analog cutoff, map the normalized Butterworth poles through the bilinear transform, build the b and a coefficients with unity DC or Nyquist gain, evaluate the magnitude response in dB at any frequency, and apply the filter to a sampled signal with the direct-form difference equation. Produces the coefficient vectors...
Scanned 9/27/2026
Install to Claude Code
npx -y skills add ashfordeOU/aero-agent-skills --skill digital-filter-design --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Digital Filter Design?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ashfordeou-digital-filter-design)More formats (shields.io, HTML) on the badges page.
---
name: digital-filter-design
description: "Use when you must compute the coefficients of a digital Butterworth IIR lowpass or highpass frequency-selective filter from a cutoff frequency, sample rate, and order: prewarp the analog cutoff, map the normalized Butterworth poles through the bilinear transform, build the b and a coefficients with unity DC or Nyquist gain, evaluate the magnitude response in dB at any frequency, and apply the filter to a sampled signal with the direct-form difference equation. Produces the coefficient vectors, the 3 dB point check at the cutoff, passband and attenuation band gains, the filtered signal, and a design verdict from the Schur-Jury stability table. Trigger: digital filter design, Butterworth, bilinear transform, IIR lowpass, highpass filter, cutoff frequency, prewarping, filter coefficients, 3 dB point."
license: Apache-2.0
compliance: STANDARDS-REF
standards:
- id: naca-tr-824
reference-only: true
gated: false
domain: cross-cutting
pack: cross-cutting
compatibility: "agentskills.io SKILL.md; any SKILL.md host (Claude Code, Hermes, OpenClaw)"
metadata:
domain: cross-cutting
subdomain: numerics
tags: [digital-filter-design, butterworth-filter, bilinear-transform, iir-lowpass, highpass-filter, cutoff-frequency, filter-coefficients]
version: 0.1.0
author: Aero Agent Skills
---
# Digital Filter Design (cross-cutting/numerics/digital-filter-design)
Use when the task is designing a digital Butterworth IIR lowpass or
highpass frequency-selective filter from a cutoff frequency, a sample
rate, and an order, then applying it to a sampled signal: prewarping
the analog cutoff for the bilinear transform, placing the normalized
Butterworth poles, mapping them into the z-plane, building the b and a
coefficient vectors with unity DC (lowpass) or Nyquist (highpass) gain,
evaluating the magnitude response in dB, and filtering with the
direct-form difference equation. All coefficients are computed, none
are lookup values. This leaf designs frequency-selective filters only:
state estimation belongs to the gnc-autonomy estimation-filtering pack
(Kalman, alpha-beta, complementary, particle observers), raw flight-test
trace smoothing belongs to flight-test data reduction, and frequency
content analysis belongs to cross-cutting/numerics/fast-fourier-transform.
It pairs with fast-fourier-transform for spectral analysis of the
filtered output and with finite-difference-derivatives for
differentiating noisy signals after the filter has removed the
out-of-band content.
## Domain quick reference
- Prewarped analog cutoff: Omega_a = 2*fs*tan(pi*fc/fs), the frequency
at which the analog prototype has its 3 dB point so that the digital
filter reaches -3.0103 dB exactly at the requested cutoff fc. Units
are SI: Hz for frequencies, samples per second for fs.
- Normalized Butterworth lowpass poles on the unit circle, left half
plane: s_k = exp(j*pi*(2k + n - 1)/(2n)) for k = 1..n. Every pole has
a negative real part; complex conjugate pairs give real
coefficients. For n = 2 the poles are -0.7071068 +/- 0.7071068j.
- Bilinear pole map: z = (2*fs + s)/(2*fs - s). Poles strictly in the
left half plane map strictly inside the unit circle, which preserves
stability; the imaginary axis maps onto the unit circle.
- Lowpass transfer function: H(z) = K*(1 + z^-1)^n / A(z), numerator
coefficients b_k = K*C(n,k) from the binomial expansion, with
K = sum(a)/2^n so the DC gain at z = 1 is exactly 1.
- Highpass construction: mirror each scaled analog lowpass pole through
p = Omega_a^2/s (the reciprocal stays in the left half plane), map to
z, and use b_k = K*C(n,k)*(-1)^k with K = sum(a[k]*(-1)^k)/2^n so the
Nyquist gain at z = -1 is exactly 1.
- Magnitude response in dB: 20*log10(|H(e^jw)|) with
e^-jw = exp(-j*2*pi*f/fs) and H evaluated by Horner on z^-1. The 3 dB
point: -3.0103 dB = 20*log10(1/sqrt(2)) at the cutoff.
- Direct-form difference equation: y[n] = b[0]*x[n] + sum_{k>=1}
(b[k]*x[n-k] - a[k]*y[n-k]) with a[0] normalized to 1 and zero
initial conditions (past samples treated as zero).
- Stability check: the Schur-Jury table on the denominator for orders
1..4 (all roots strictly inside the unit circle); above order 4 the
check returns not-checked.
## Workflow
1. Fix the operating point: sample rate fs, cutoff fc, filter order n,
and type (lowpass or highpass).
2. Prewarp the cutoff with prewarp(cutoff_hz, fs) to get the analog
Omega_a used by the bilinear design.
3. Get the prototype poles with butterworth_poles(order) (normalized,
unit circle, left half plane) and confirm the layout.
4. Design the filter with design_lowpass(fs, cutoff_hz, order) or
design_highpass(fs, cutoff_hz, order); both return (b, a) with
len(b) == len(a) == order + 1 and a[0] == 1. The prewarping
guarantee puts the -3.0103 dB point exactly at the cutoff.
5. Probe the design at any in-band or stop-band frequency with
freq_response_db(b, a, freq_hz, fs); magnitudes are in dB.
6. Apply the filter to the sampled signal x with
apply_filter(b, a, x) (direct form, zero initial condition, output
length equals input length).
7. Verify the design with filter_design_checks(b, a, fs, cutoff_hz,
ftype): cutoff gain within 0.02 dB of -3.0103 dB, reference gain at
DC (1 Hz probe, lowpass) or near Nyquist (fs/2 - 1 Hz probe,
highpass), Schur-Jury stability for orders 1..4, and the verdict
string.
8. For spectral analysis of the filtered output, hand the signal to
cross-cutting/numerics/fast-fourier-transform.
## Worked example
fs = 1000 Hz, lowpass, fc = 100 Hz, order 2.
- prewarp(100, 1000) = 2000*tan(0.1*pi) = 649.8393.
- butterworth_poles(2) = -0.7071068 +/- 0.7071068j.
- design_lowpass(1000, 100, 2): a = [1.0, -1.14298, 0.41280],
b = [0.067455, 0.134911, 0.067455]; a[0] == 1 and the denominator
comes from the mapped conjugate pole pair.
- freq_response_db at the cutoff: -3.0103 dB (within 0.02 dB).
- freq_response_db at 10 Hz: -0.0004 dB (passband, within 0.02 dB of
0 dB).
- freq_response_db at 400 Hz: -39.06 dB (below -30 dB).
- apply_filter to x = [5.0]*400: the last 50 output samples equal 5.0
to within 0.001 (DC gain 1 after the transient decays).
- filter_design_checks: passband_ok True, stable True (Schur-Jury),
verdict PASS.
Highpass order 2 at fc = 100 Hz on the same channel:
- design_highpass(1000, 100, 2): a = [1.0, -1.14298, 0.41280] (the
mirrored poles coincide with the lowpass pole set for even order),
b = [0.638946, -1.277891, 0.638946], signs alternating.
- freq_response_db at 400 Hz: -0.0005 dB (within 0.05 dB of 0 dB).
- Reference gain at fs/2 - 1 = 499 Hz: 0.0000 dB (within 0.05 dB).
- Attenuation floor: a second order Butterworth highpass attenuates by
12.72 dB at fc/2 = 50 Hz and reaches below -15 dB by fc/4 = 25 Hz
(-24.65 dB); the -15 dB contract bound is asserted at 25 Hz.
## Pitfalls
- Skipping the frequency prewarp: the design maps the analog prototype
through the bilinear transform at prewarp(100, 1000) = 649.8393, and
the cutoff gain of -3.0103 dB only holds when fc is prewarped before
the mapping.
- Asserting spec bounds the standard method cannot meet: an order-2
Butterworth highpass attenuates only 12.72 dB at fc/2 (a 12 dB per
octave rolloff from the -3.01 dB point), so the -15 dB contract bound
is asserted at 25 Hz where it genuinely holds, not at 50 Hz.
- Designing outside the supported orders: the design functions accept
order 1..8 (butterworth_poles 1..10), probe frequencies must lie in
(0, fs/2), and fs <= 0, cutoff <= 0, cutoff >= fs/2, empty or
non-finite samples, and unknown ftype all raise ValueError.
- Reading the stability verdict above order 4 as a guarantee: stability
is verified as stable True only for orders 1..4 and returns None above
order 4, while a fabricated denominator with a root at z = 1.1
reports stable False with a FAIL verdict.
- Reading the DC response from the transient: a constant input of 5.0
settles to 5.0 within 0.001 only after the transient decays (the last
50 samples of the worked record), not from the leading samples.
- Expecting highpass coefficients to look like lowpass ones: the
even-order highpass shares the lowpass denominator (a = [1.0,
-1.14298, 0.41280]) while the numerator signs alternate (b =
[0.638946, -1.277891, 0.638946]).
## Verification
- Confirm prewarp(100, 1000) returns 649.8393925 (spec anchor 649.8393
within 1e-3).
- Confirm the lowpass cutoff gain is -3.0103 +/- 0.02 dB at fc and the
order-1 lowpass hits the same anchor with DC gain 1.
- Confirm the analytic magnitude identity: the module value at any
frequency equals 10*log10(1/(1 + r^(2n))) dB with r the ratio of the
prewarped tangents, lowpass and highpass.
- Confirm steady state: a constant input of 5.0 settles to 5.0 within
0.001 (DC gain exactly 1), and apply_filter with b = [1], a = [1] is
the identity.
- Confirm stability verdicts: stable True for designed orders 1..4,
stable None above order 4, and a fabricated denominator with a root
at z = 1.1 reports stable False and a FAIL verdict.
- Confirm every non-physical input raises ValueError: fs <= 0,
cutoff <= 0, cutoff >= fs/2, order outside 1..8 for the design
functions (1..10 for butterworth_poles), probe frequencies outside
(0, fs/2), empty or non-finite sample lists, and unknown ftype.
- Recorded assumption: the spec worked example asked for "below -15 dB
at 50 Hz" on the order-2 highpass with fc = 100 Hz; the standard
Butterworth magnitude gives -12.72 dB at fc/2 (a 12 dB per octave
rolloff measured from the -3.01 dB point reaches -15 dB only one
third of an octave below cutoff), so the module implements the
standard method and the contract asserts the -15 dB floor at 25 Hz
where the bound genuinely holds. All other spec anchors match the
module output exactly.
- Run the contract test offline: python3
scripts/test_digital_filter_design.py (32 tests, deterministic).
## Related leaves
- cross-cutting/numerics/fast-fourier-transform: spectral analysis of
the filtered signal, the frequency-domain partner of this leaf.
- cross-cutting/numerics/finite-difference-derivatives: differentiating
the filtered (denoised) signal with controlled step-size error.
- cross-cutting/numerics/numerical-integration: quadrature of smooth
signals, complementary to filtering when the goal is an integral
rather than a cleaned time series.
## Behavior contract (gate 3)
Run the deterministic contract test (stdlib unittest, offline):
python3 scripts/test_digital_filter_design.py
The test covers the prewarp anchor (649.8393), pole placement for
orders 1, 2, and 3 with symmetry checks, coefficient shapes
(len b == len a == order + 1, a[0] == 1), the lowpass 3 dB cutoff
gain, the passband gain at 10 Hz, the attenuation band at 400 Hz, the
DC steady state of a constant input, the identity round trip, the
impulse response sanity, the order-1 anchor, highpass cutoff and
reference gains near Nyquist, the alternating highpass numerator,
the -15 dB attenuation floor at fc/4 with the closed-form magnitude
match at fc/2, the 2 Hz cutoff on a 50 Hz channel scenario, the
Schur-Jury stability verdicts for orders 2, 4, and 6 (not-checked),
the unstable-denominator FAIL verdict, and ValueError rejection of
non-physical inputs. Runs in well under a second.
## Compliance
- Standards referenced, not reproduced: NACA TR-824 anchors the
numerics-pack public-domain reference set; Butterworth prototype
design and the bilinear transform are classical digital-filter
methodology (Hamming and Oppenheim and Schafer style summaries),
paraphrase-only per standards-map.yaml.
- compliance: STANDARDS-REF, gated: false.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!