FA-91521 / Digital signal filters / Open access
Frequency response reports magnitude with the power decibel factor · case 01
A gain of 2 is reported as 3.01 dB instead of 6.02 dB.
ROOT CAUSE
10 log10 is applied to an amplitude ratio.
VERIFIED REPAIR
Use 20 log10 |H| for amplitude.
Unsuccessful approach: The attempted repair uses 20 log10 |H|^2, doubling the decibel values.
Case contract
Input [b, a, freqs]; coefficients and frequencies are numbers or rational strings, frequencies are fractions of Nyquist. For w = pi f evaluate H = B(e^{jw})/A(e^{jw}) with z^-k = e^{-jwk}; return per frequency [20 log10 |H| rounded to 4, phase in degrees rounded to 3], "pole" if |A| < 1e-12, "zero" if |H| < 1e-9.
Why this case matters
Magnitude and phase plots are how filters are verified; unit or sign slips misreport cutoff and delay.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
import cmath
from fractions import Fraction
N = 1
observations = []
def solve(x):
b, a, fs = x
b = [float(Fraction(v)) for v in b]
a = [float(Fraction(v)) for v in a]
out = []
for f in fs:
w = math.pi * float(Fraction(f))
B = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(b))
A = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(a))
if abs(A) < 1e-12:
out.append('pole')
continue
H = B / A
mag = abs(H)
if mag < 1e-9:
out.append('zero')
continue
out.append([round(10 * math.log10(mag), 4) + 0.0, round(math.degrees(cmath.phase(H)), 3) + 0.0])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: first difference', [[1, -1], [1], ['0', '1/2', '1']], ['zero', [3.0103, 45.0], [6.0206, 0.0]]], ['regression: one pole', [[1], [1, '-1/2'], ['0', '1/4', '1/2']], [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: small magnitude', [[1, '-0.9999'], [1], ['0']], [[-80.0, 0.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['regression: random response 4', [[-1], [1, '1/2'], ['3/4', '1', '0']], [[2.6529, -151.325], [6.0206, -180.0], [-3.5218, 180.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 6', [[1, -1], [1, '1/3', '1/3'], ['1/8', '1', '1/2']], [[-12.1798, 91.992], [6.0206, 0.0], [5.563, 71.565]]], ['regression: random response 7', [[2, -1], [1, '1/2'], ['3/4', '1/3', '1/3']], [[11.5896, 43.314], [2.3408, 49.107], [2.3408, 49.107]]], ['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 9', [[1], [1, '1/2'], ['1', '1/4', '1']], [[6.0206, 0.0], [-2.9161, 14.639], [6.0206, 0.0]]], ['regression: random response 10', [[-1, 1], [1], ['1/3', '1', '1/3']], [[0.0, -120.0], [6.0206, -180.0], [0.0, -120.0]]], ['regression: random response 5', [[1], [1, '1/2', '1/2'], ['1/4', '1', '1/8']], [[-4.0835, 32.236], [0.0, 0.0], [-5.5545, 16.706]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]]]
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: first difference | ['zero', [1.5051, 45.0], [3.0103, 0.0]] | ['zero', [3.0103, 45.0], [6.0206, 0.0]] | Failed |
| regression: one pole | [[3.0103, 0.0], [1.3264, -28.675], [-0.4846, -26.565]] | [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]] | Failed |
| regression: deep notch | ['zero', [-12.0189, -88.2]] | ['zero', [-24.0378, -88.2]] | Failed |
| control: two-tap average at nyquist | ['zero'] | ['zero'] | Passed |
| control: pole on unit circle | ['pole'] | ['pole'] | Passed |
| control: pure delay phase | [[0.0, -45.0], [0.0, -90.0]] | [[0.0, -45.0], [0.0, -90.0]] | Passed |
| control: random response 3 | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | Passed |
SHA-256 / 6a63025981b4ddb66d66f9af62027c723f5355e3d9538869dbfff660cb0e4a32
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
import cmath
from fractions import Fraction
N = 1
observations = []
def solve(x):
b, a, fs = x
b = [float(Fraction(v)) for v in b]
a = [float(Fraction(v)) for v in a]
out = []
for f in fs:
w = math.pi * float(Fraction(f))
B = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(b))
A = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(a))
if abs(A) < 1e-12:
out.append('pole')
continue
H = B / A
mag = abs(H)
if mag < 1e-9:
out.append('zero')
continue
out.append([round(20 * math.log10(mag ** 2), 4) + 0.0, round(math.degrees(cmath.phase(H)), 3) + 0.0])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: first difference', [[1, -1], [1], ['0', '1/2', '1']], ['zero', [3.0103, 45.0], [6.0206, 0.0]]], ['regression: one pole', [[1], [1, '-1/2'], ['0', '1/4', '1/2']], [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: small magnitude', [[1, '-0.9999'], [1], ['0']], [[-80.0, 0.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['regression: random response 4', [[-1], [1, '1/2'], ['3/4', '1', '0']], [[2.6529, -151.325], [6.0206, -180.0], [-3.5218, 180.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 6', [[1, -1], [1, '1/3', '1/3'], ['1/8', '1', '1/2']], [[-12.1798, 91.992], [6.0206, 0.0], [5.563, 71.565]]], ['regression: random response 7', [[2, -1], [1, '1/2'], ['3/4', '1/3', '1/3']], [[11.5896, 43.314], [2.3408, 49.107], [2.3408, 49.107]]], ['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 9', [[1], [1, '1/2'], ['1', '1/4', '1']], [[6.0206, 0.0], [-2.9161, 14.639], [6.0206, 0.0]]], ['regression: random response 10', [[-1, 1], [1], ['1/3', '1', '1/3']], [[0.0, -120.0], [6.0206, -180.0], [0.0, -120.0]]], ['regression: random response 5', [[1], [1, '1/2', '1/2'], ['1/4', '1', '1/8']], [[-4.0835, 32.236], [0.0, 0.0], [-5.5545, 16.706]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]]]
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: first difference | ['zero', [6.0206, 45.0], [12.0412, 0.0]] | ['zero', [3.0103, 45.0], [6.0206, 0.0]] | Failed |
| regression: one pole | [[12.0412, 0.0], [5.3057, -28.675], [-1.9382, -26.565]] | [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]] | Failed |
| regression: deep notch | ['zero', [-48.0757, -88.2]] | ['zero', [-24.0378, -88.2]] | Failed |
| control: two-tap average at nyquist | ['zero'] | ['zero'] | Passed |
| control: pole on unit circle | ['pole'] | ['pole'] | Passed |
| control: pure delay phase | [[0.0, -45.0], [0.0, -90.0]] | [[0.0, -45.0], [0.0, -90.0]] | Passed |
| control: random response 3 | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | Passed |
SHA-256 / 78a9309e36cf78b9e31249803eeb61616c5947de35713464cce8f1e0428bde66
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
import cmath
from fractions import Fraction
N = 1
observations = []
def solve(x):
b, a, fs = x
b = [float(Fraction(v)) for v in b]
a = [float(Fraction(v)) for v in a]
out = []
for f in fs:
w = math.pi * float(Fraction(f))
B = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(b))
A = sum(c * cmath.exp(-1j * w * k) for k, c in enumerate(a))
if abs(A) < 1e-12:
out.append('pole')
continue
H = B / A
mag = abs(H)
if mag < 1e-9:
out.append('zero')
continue
out.append([round(20 * math.log10(mag), 4) + 0.0, round(math.degrees(cmath.phase(H)), 3) + 0.0])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: first difference', [[1, -1], [1], ['0', '1/2', '1']], ['zero', [3.0103, 45.0], [6.0206, 0.0]]], ['regression: one pole', [[1], [1, '-1/2'], ['0', '1/4', '1/2']], [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: small magnitude', [[1, '-0.9999'], [1], ['0']], [[-80.0, 0.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['regression: deep notch', [[1, 0, 1], [1], ['1/2', '0.49']], ['zero', [-24.0378, -88.2]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['regression: random response 4', [[-1], [1, '1/2'], ['3/4', '1', '0']], [[2.6529, -151.325], [6.0206, -180.0], [-3.5218, 180.0]]], ['regression: random response 0', [['-1/4', 1], [1, 0], ['1/3', '1/8', '1/8']], [[-0.9018, -73.898], [-2.2144, -29.591], [-2.2144, -29.591]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 6', [[1, -1], [1, '1/3', '1/3'], ['1/8', '1', '1/2']], [[-12.1798, 91.992], [6.0206, 0.0], [5.563, 71.565]]], ['regression: random response 7', [[2, -1], [1, '1/2'], ['3/4', '1/3', '1/3']], [[11.5896, 43.314], [2.3408, 49.107], [2.3408, 49.107]]], ['regression: random response 2', [['1/2', '-1/4', 0, 2], [1, '1/2', '1/2'], ['1/2', '1/2', '1/2']], [[10.2633, 122.471], [10.2633, 122.471], [10.2633, 122.471]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]], [['regression: random response 9', [[1], [1, '1/2'], ['1', '1/4', '1']], [[6.0206, 0.0], [-2.9161, 14.639], [6.0206, 0.0]]], ['regression: random response 10', [[-1, 1], [1], ['1/3', '1', '1/3']], [[0.0, -120.0], [6.0206, -180.0], [0.0, -120.0]]], ['regression: random response 5', [[1], [1, '1/2', '1/2'], ['1/4', '1', '1/8']], [[-4.0835, 32.236], [0.0, 0.0], [-5.5545, 16.706]]], ['control: two-tap average at nyquist', [[1, 1], [1], ['1']], ['zero']], ['control: pole on unit circle', [[1], [1, -1], ['0']], ['pole']], ['control: pure delay phase', [[0, 1], [1], ['1/4', '1/2']], [[0.0, -45.0], [0.0, -90.0]]], ['control: random response 3', [[0, 0, -1], [1], ['1/2', '1/8', '1']], [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]]]]]
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: first difference | ['zero', [3.0103, 45.0], [6.0206, 0.0]] | ['zero', [3.0103, 45.0], [6.0206, 0.0]] | Passed |
| regression: one pole | [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]] | [[6.0206, 0.0], [2.6529, -28.675], [-0.9691, -26.565]] | Passed |
| regression: deep notch | ['zero', [-24.0378, -88.2]] | ['zero', [-24.0378, -88.2]] | Passed |
| control: two-tap average at nyquist | ['zero'] | ['zero'] | Passed |
| control: pole on unit circle | ['pole'] | ['pole'] | Passed |
| control: pure delay phase | [[0.0, -45.0], [0.0, -90.0]] | [[0.0, -45.0], [0.0, -90.0]] | Passed |
| control: random response 3 | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | [[0.0, 0.0], [0.0, 135.0], [0.0, -180.0]] | Passed |
SHA-256 / 86f08a8ecf434ce787c710f602d5bf5e786bc0acea7ae79cd57215e63e7a8991
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.806482+00:00.
Case digest / ebccf44172177ddab3a3dc9f4750bdbbb96bd3e409e029108265c5a43bebed1c