FAILURE MAP
← Case archive

FA-91506 / Digital signal filters / Open access

Windowed sinc uses an N-periodic window · case 01

Window end points are not zero-tapered symmetrically; the filter is slightly asymmetric.

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

ROOT CAUSE

Both raised-cosine windows use 2 pi n / N instead of the symmetric 2 pi n / (N - 1).

VERIFIED REPAIR

Use N - 1 in the window phase for symmetric designs.

Unsuccessful approach: The attempted repair fixes the Hann window but leaves the Hamming window periodic.

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 * 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)
        else:
            w = 0.54 - 0.46 * math.cos(2 * math.pi * n / N)
        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=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['regression: N=4 fc=1/4 hann', [4, '1/4', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['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=4 fc=3/5 hann', [4, '3/5', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]], [['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=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['control: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['control: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['control: N=4 fc=3/5 rect', [4, '3/5', 'rect'], [0.056471, 0.443529, 0.443529, 0.056471]], ['control: N=4 fc=1 rect', [4, '1', 'rect'], [-0.25, 0.75, 0.75, -0.25]]]]
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=2 fc=1/2 hamming[0.07407407, 0.92592593][0.5, 0.5]Failed
regression: N=2 fc=1/4 hamming[0.07407407, 0.92592593][0.5, 0.5]Failed
regression: N=2 fc=3/5 hamming[0.07407407, 0.92592593][0.5, 0.5]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 / 2ba80b605404d25d77935dda1edee5679757bc7804e8d17abcaf572af438cdab

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) / (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)
        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=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['regression: N=4 fc=1/4 hann', [4, '1/4', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['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=4 fc=3/5 hann', [4, '3/5', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]], [['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=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['control: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['control: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['control: N=4 fc=3/5 rect', [4, '3/5', 'rect'], [0.056471, 0.443529, 0.443529, 0.056471]], ['control: N=4 fc=1 rect', [4, '1', 'rect'], [-0.25, 0.75, 0.75, -0.25]]]]
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=2 fc=1/2 hamming[0.07407407, 0.92592593][0.5, 0.5]Failed
regression: N=2 fc=1/4 hamming[0.07407407, 0.92592593][0.5, 0.5]Failed
regression: N=2 fc=3/5 hamming[0.07407407, 0.92592593][0.5, 0.5]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 / b1023edf0a41aa52b6e8ddb84b356091bf483ad8a5829a92d409c05d670111e1

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=2 fc=1/2 hamming', [2, '1/2', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=1/4 hamming', [2, '1/4', 'hamming'], [0.5, 0.5]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=2 fc=1 hamming', [2, '1', 'hamming'], [0.5, 0.5]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['regression: N=2 fc=3/5 hamming', [2, '3/5', 'hamming'], [0.5, 0.5]], ['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=4 fc=1/4 hamming', [4, '1/4', 'hamming'], [0.03857901, 0.46142099, 0.46142099, 0.03857901]], ['regression: N=4 fc=1/4 hann', [4, '1/4', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1/2 hamming', [4, '1/2', 'hamming'], [0.0167364, 0.4832636, 0.4832636, 0.0167364]], ['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=4 fc=3/5 hann', [4, '3/5', 'hann'], [0.0, 0.5, 0.5, 0.0]], ['regression: N=4 fc=1 hamming', [4, '1', 'hamming'], [-0.01793722, 0.51793722, 0.51793722, -0.01793722]], ['regression: N=4 fc=3/5 hamming', [4, '3/5', 'hamming'], [0.00652778, 0.49347222, 0.49347222, 0.00652778]], ['control: N=2 fc=1/2 rect', [2, '1/2', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1/4 rect', [2, '1/4', 'rect'], [0.5, 0.5]], ['control: N=2 fc=3/5 rect', [2, '3/5', 'rect'], [0.5, 0.5]], ['control: N=2 fc=1 rect', [2, '1', 'rect'], [0.5, 0.5]]], [['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=5 fc=1/4 hamming', [5, '1/4', 'hamming'], [0.02455383, 0.23438946, 0.4821134, 0.23438946, 0.02455383]], ['control: N=4 fc=1/2 rect', [4, '1/2', 'rect'], [0.125, 0.375, 0.375, 0.125]], ['control: N=4 fc=1/4 rect', [4, '1/4', 'rect'], [0.22295145, 0.27704855, 0.27704855, 0.22295145]], ['control: N=4 fc=3/5 rect', [4, '3/5', 'rect'], [0.056471, 0.443529, 0.443529, 0.056471]], ['control: N=4 fc=1 rect', [4, '1', 'rect'], [-0.25, 0.75, 0.75, -0.25]]]]
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=2 fc=1/2 hamming[0.5, 0.5][0.5, 0.5]Passed
regression: N=2 fc=1/4 hamming[0.5, 0.5][0.5, 0.5]Passed
regression: N=2 fc=3/5 hamming[0.5, 0.5][0.5, 0.5]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 / 431a3b94ee4b9126200c0008bce402d65348683900d0b9b477f64c7bf77edc3b

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.765861+00:00.

Case digest / d2d27f6dcd9883b95b7aa9c4c76156c3129d15f8f9f7bedb1b913377493377e8