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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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