FAILURE MAP
← Case archive

FA-91501 / Digital signal filters / Open access

Windowed sinc ignores the cutoff in the sinc argument · case 01

All cutoffs yield the same (full-band) impulse shape.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The sinc is evaluated at t instead of fc t.

VERIFIED REPAIR

Use sin(pi fc t)/(pi fc t).

Unsuccessful approach: The attempted repair halves the argument (fc t / 2), confusing Nyquist-relative and sample-rate-relative cutoffs.

Case contract

Input [N, fc, window]; fc is the cutoff as a fraction of Nyquist in (0, 1], window hamming (0.54 - 0.46 cos(2 pi n/(N-1))), hann (0.5 - 0.5 cos(...)) or rect (N = 1 uses 1). Taps h[n] = fc sinc(fc (n - (N-1)/2)) w[n], normalized to unit DC gain and rounded to 8 decimals; "bad-spec" for invalid input (Hann needs N != 2).

Why this case matters

Windowed-sinc design is the default FIR recipe; centre or normalization slips yield non-linear-phase or wrong-gain filters.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    N, fc_s, win = x
    fc = float(Fraction(fc_s))
    if N < 1 or not 0 < fc <= 1:
        return 'bad-spec'
    c = (N - 1) / 2
    taps = []
    for n in range(N):
        t = n - c
        s = 1.0 if t == 0 else math.sin(math.pi * t) / (math.pi * t)
        if N == 1 or win == 'rect':
            w = 1.0
        elif win == 'hann':
            w = 0.5 - 0.5 * math.cos(2 * math.pi * n / (N - 1))
        else:
            w = 0.54 - 0.46 * math.cos(2 * math.pi * n / (N - 1))
        taps.append(fc * s * w)
    tot = sum(taps)
    return [round(v / tot, 8) + 0.0 for v in taps]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/2 hamming', [1, '1/2', 'hamming'], [1.0]], ['control: N=1 fc=1/2 hann', [1, '1/2', 'hann'], [1.0]], ['control: N=1 fc=1/2 rect', [1, '1/2', 'rect'], [1.0]], ['control: N=1 fc=1/4 hamming', [1, '1/4', 'hamming'], [1.0]]], [['regression: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/4 hann', [1, '1/4', 'hann'], [1.0]], ['control: N=1 fc=1/4 rect', [1, '1/4', 'rect'], [1.0]], ['control: N=1 fc=3/5 hamming', [1, '3/5', 'hamming'], [1.0]], ['control: N=1 fc=3/5 hann', [1, '3/5', 'hann'], [1.0]]], [['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['regression: N=5 fc=1/2 hann', [5, '1/2', 'hann'], [0.0, 0.19449226, 0.61101547, 0.19449226, 0.0]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=1 fc=3/5 rect', [1, '3/5', 'rect'], [1.0]], ['control: N=1 fc=1 hamming', [1, '1', 'hamming'], [1.0]], ['control: N=1 fc=1 hann', [1, '1', 'hann'], [1.0]], ['control: N=1 fc=1 rect', [1, '1', 'rect'], [1.0]]], [['regression: N=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['regression: N=5 fc=1/4 hann', [5, '1/4', 'hann'], [0.0, 0.23688591, 0.52622818, 0.23688591, 0.0]], ['repair check: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['control: N=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]]], [['regression: N=5 fc=3/5 hamming', [5, '3/5', 'hamming'], [-0.00820621, 0.17925211, 0.65790821, 0.17925211, -0.00820621]], ['regression: N=5 fc=3/5 hann', [5, '3/5', 'hann'], [0.0, 0.16767497, 0.66465005, 0.16767497, 0.0]], ['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['control: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: N=4 fc=1/2 hamming[-0.01793722, 0.51793722, 0.51793722, -0.01793722][0.0167364, 0.4832636, 0.4832636, 0.0167364]Failed
regression: N=4 fc=1/2 rect[-0.25, 0.75, 0.75, -0.25][0.125, 0.375, 0.375, 0.125]Failed
regression: N=4 fc=1/4 hamming[-0.01793722, 0.51793722, 0.51793722, -0.01793722][0.03857901, 0.46142099, 0.46142099, 0.03857901]Failed
control: N=1 fc=1/2 hamming[1.0][1.0]Passed
control: N=1 fc=1/2 hann[1.0][1.0]Passed
control: N=1 fc=1/2 rect[1.0][1.0]Passed
control: N=1 fc=1/4 hamming[1.0][1.0]Passed

SHA-256 / 8af77cc6c98428fc077a968cebdb6e1efa0f6761e2ccfc67576f14a169c4e82e

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    N, fc_s, win = x
    fc = float(Fraction(fc_s))
    if N < 1 or not 0 < fc <= 1:
        return 'bad-spec'
    c = (N - 1) / 2
    taps = []
    for n in range(N):
        t = n - c
        s = 1.0 if t == 0 else math.sin(math.pi * fc * t / 2) / (math.pi * fc * t / 2)
        if N == 1 or win == 'rect':
            w = 1.0
        elif win == 'hann':
            w = 0.5 - 0.5 * math.cos(2 * math.pi * n / (N - 1))
        else:
            w = 0.54 - 0.46 * math.cos(2 * math.pi * n / (N - 1))
        taps.append(fc * s * w)
    tot = sum(taps)
    return [round(v / tot, 8) + 0.0 for v in taps]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/2 hamming', [1, '1/2', 'hamming'], [1.0]], ['control: N=1 fc=1/2 hann', [1, '1/2', 'hann'], [1.0]], ['control: N=1 fc=1/2 rect', [1, '1/2', 'rect'], [1.0]], ['control: N=1 fc=1/4 hamming', [1, '1/4', 'hamming'], [1.0]]], [['regression: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/4 hann', [1, '1/4', 'hann'], [1.0]], ['control: N=1 fc=1/4 rect', [1, '1/4', 'rect'], [1.0]], ['control: N=1 fc=3/5 hamming', [1, '3/5', 'hamming'], [1.0]], ['control: N=1 fc=3/5 hann', [1, '3/5', 'hann'], [1.0]]], [['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['regression: N=5 fc=1/2 hann', [5, '1/2', 'hann'], [0.0, 0.19449226, 0.61101547, 0.19449226, 0.0]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=1 fc=3/5 rect', [1, '3/5', 'rect'], [1.0]], ['control: N=1 fc=1 hamming', [1, '1', 'hamming'], [1.0]], ['control: N=1 fc=1 hann', [1, '1', 'hann'], [1.0]], ['control: N=1 fc=1 rect', [1, '1', 'rect'], [1.0]]], [['regression: N=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['regression: N=5 fc=1/4 hann', [5, '1/4', 'hann'], [0.0, 0.23688591, 0.52622818, 0.23688591, 0.0]], ['repair check: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['control: N=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]]], [['regression: N=5 fc=3/5 hamming', [5, '3/5', 'hamming'], [-0.00820621, 0.17925211, 0.65790821, 0.17925211, -0.00820621]], ['regression: N=5 fc=3/5 hann', [5, '3/5', 'hann'], [0.0, 0.16767497, 0.66465005, 0.16767497, 0.0]], ['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['control: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: N=4 fc=1/2 hamming[0.03857901, 0.46142099, 0.46142099, 0.03857901][0.0167364, 0.4832636, 0.4832636, 0.0167364]Failed
regression: N=4 fc=1/2 rect[0.22295145, 0.27704855, 0.27704855, 0.22295145][0.125, 0.375, 0.375, 0.125]Failed
regression: N=4 fc=1/4 hamming[0.04488511, 0.45511489, 0.45511489, 0.04488511][0.03857901, 0.46142099, 0.46142099, 0.03857901]Failed
control: N=1 fc=1/2 hamming[1.0][1.0]Passed
control: N=1 fc=1/2 hann[1.0][1.0]Passed
control: N=1 fc=1/2 rect[1.0][1.0]Passed
control: N=1 fc=1/4 hamming[1.0][1.0]Passed

SHA-256 / a7217c75ad1f752a078ff8159f434107a7259ad768f4b91b80addd7fda6bfee9

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    N, fc_s, win = x
    fc = float(Fraction(fc_s))
    if N < 1 or not 0 < fc <= 1:
        return 'bad-spec'
    c = (N - 1) / 2
    taps = []
    for n in range(N):
        t = n - c
        s = 1.0 if t == 0 else math.sin(math.pi * fc * t) / (math.pi * fc * t)
        if N == 1 or win == 'rect':
            w = 1.0
        elif win == 'hann':
            w = 0.5 - 0.5 * math.cos(2 * math.pi * n / (N - 1))
        else:
            w = 0.54 - 0.46 * math.cos(2 * math.pi * n / (N - 1))
        taps.append(fc * s * w)
    tot = sum(taps)
    return [round(v / tot, 8) + 0.0 for v in taps]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/2 hamming', [1, '1/2', 'hamming'], [1.0]], ['control: N=1 fc=1/2 hann', [1, '1/2', 'hann'], [1.0]], ['control: N=1 fc=1/2 rect', [1, '1/2', 'rect'], [1.0]], ['control: N=1 fc=1/4 hamming', [1, '1/4', 'hamming'], [1.0]]], [['regression: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['regression: N=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['control: N=1 fc=1/4 hann', [1, '1/4', 'hann'], [1.0]], ['control: N=1 fc=1/4 rect', [1, '1/4', 'rect'], [1.0]], ['control: N=1 fc=3/5 hamming', [1, '3/5', 'hamming'], [1.0]], ['control: N=1 fc=3/5 hann', [1, '3/5', 'hann'], [1.0]]], [['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['regression: N=5 fc=1/2 hann', [5, '1/2', 'hann'], [0.0, 0.19449226, 0.61101547, 0.19449226, 0.0]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=1 fc=3/5 rect', [1, '3/5', 'rect'], [1.0]], ['control: N=1 fc=1 hamming', [1, '1', 'hamming'], [1.0]], ['control: N=1 fc=1 hann', [1, '1', 'hann'], [1.0]], ['control: N=1 fc=1 rect', [1, '1', 'rect'], [1.0]]], [['regression: N=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['regression: N=5 fc=1/4 hann', [5, '1/4', 'hann'], [0.0, 0.23688591, 0.52622818, 0.23688591, 0.0]], ['repair check: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['control: N=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]]], [['regression: N=5 fc=3/5 hamming', [5, '3/5', 'hamming'], [-0.00820621, 0.17925211, 0.65790821, 0.17925211, -0.00820621]], ['regression: N=5 fc=3/5 hann', [5, '3/5', 'hann'], [0.0, 0.16767497, 0.66465005, 0.16767497, 0.0]], ['regression: N=5 fc=1/2 hamming', [5, '1/2', 'hamming'], [0.0, 0.20371237, 0.59257526, 0.20371237, 0.0]], ['control: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: N=4 fc=1/2 hamming[0.0167364, 0.4832636, 0.4832636, 0.0167364][0.0167364, 0.4832636, 0.4832636, 0.0167364]Passed
regression: N=4 fc=1/2 rect[0.125, 0.375, 0.375, 0.125][0.125, 0.375, 0.375, 0.125]Passed
regression: N=4 fc=1/4 hamming[0.03857901, 0.46142099, 0.46142099, 0.03857901][0.03857901, 0.46142099, 0.46142099, 0.03857901]Passed
control: N=1 fc=1/2 hamming[1.0][1.0]Passed
control: N=1 fc=1/2 hann[1.0][1.0]Passed
control: N=1 fc=1/2 rect[1.0][1.0]Passed
control: N=1 fc=1/4 hamming[1.0][1.0]Passed

SHA-256 / 8b745303584f8b9e2d164dc3c0f6fe41010b13ebfc0b0702e1b4ef8bcf5c541f

Verification & scope

A deterministic bounded teaching model with a stipulated toy contract; exact rational arithmetic or fixed-decimal rounding keeps outputs strict JSON. It is not a production DSP library and claims no standards conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:51:36.698016+00:00.

Case digest / cde44a84d96b5280a128e8a9f057535214f5aae5a39961f59e3623bfd4fa094c