FAILURE MAP
← Case archive

FA-91641 / Digital signal filters / Open access

Linear-phase check skips the centre tap for antisymmetry · case 01

[1, 2, -1] is classified as type 3 although a nonzero centre breaks antisymmetry.

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

ROOT CAUSE

The antisymmetry test only compares mirrored pairs (range(N // 2)), never requiring the centre to be zero.

VERIFIED REPAIR

Test g[i] == -g[N-1-i] for every i, which forces the centre to 0.

Unsuccessful approach: The attempted repair additionally requires g[N//2] == 0 for every length, rejecting valid even-length type 4 filters.

Case contract

Input integer taps. Strip leading and trailing zeros ("degenerate" if all zero). The trimmed support of length N is type 1/2 if symmetric (odd/even N), type 3/4 if antisymmetric (odd/even N), otherwise not linear phase. Return {"type", "group_delay": leading zeros + (N-1)/2 as a fraction string} or both None.

Why this case matters

Linear-phase type determines which responses an FIR can realize (e.g. no highpass for type 2); misclassification picks the wrong design.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(x):
    h = list(x)
    lead = 0
    while lead < len(h) and h[lead] == 0:
        lead += 1
    if lead == len(h):
        return 'degenerate'
    end = len(h)
    while h[end - 1] == 0:
        end -= 1
    g = h[lead:end]
    N = len(g)
    sym = all(g[i] == g[N - 1 - i] for i in range(N))
    anti = all(g[i] == -g[N - 1 - i] for i in range(N // 2))
    if sym:
        typ = 1 if N % 2 else 2
    elif anti:
        typ = 3 if N % 2 else 4
    else:
        return {'type': None, 'group_delay': None}
    return {'type': typ, 'group_delay': str(lead + Fraction(N - 1, 2))}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: type IV', [1, -1], {'type': 4, 'group_delay': '1/2'}], ['control: type III zero centre', [1, 0, -1], {'type': 3, 'group_delay': '1'}], ['control: type I', [1, 2, 1], {'type': 1, 'group_delay': '1'}], ['control: type II', [1, 1], {'type': 2, 'group_delay': '1/2'}], ['control: leading zeros symmetric', [0, 0, 1, 2, 1], {'type': 1, 'group_delay': '3'}]], [['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['repair check: random linear phase 1', [0, 2, -2, 0, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: trailing zeros', [1, 2, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: interior zero symmetric', [1, 0, 1], {'type': 1, 'group_delay': '1'}], ['control: all zero', [0, 0, 0], 'degenerate'], ['control: not linear phase', [1, 2, 3], {'type': None, 'group_delay': None}]], [['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['repair check: random linear phase 10', [0, 0, 0, -1, 1, 0], {'type': 4, 'group_delay': '7/2'}], ['control: padded type II', [0, 3, 3, 0, 0], {'type': 2, 'group_delay': '3/2'}], ['control: single tap', [5], {'type': 1, 'group_delay': '0'}], ['control: padded interior zeros', [0, 2, 0, 0, 2], {'type': 2, 'group_delay': '5/2'}], ['control: random linear phase 0', [-1, -2, -1, 0, 1, 2, 1, 0], {'type': 3, 'group_delay': '3'}]], [['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 12', [-1, 1, -1, 1, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: random linear phase 3', [1, 0, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: random linear phase 5', [0, 0, -3, -3, -2, -3, -3, 0], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 7', [0, 0, 0, 0, 0], 'degenerate'], ['control: random linear phase 9', [0, 0, -1, -3, 3, -1, 3, -3, -1, 0, 0], {'type': 1, 'group_delay': '5'}]], [['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 16', [0, -3, -1, 1, 3, 0, 0], {'type': 4, 'group_delay': '5/2'}], ['control: random linear phase 13', [-3, -3, 0, 0], {'type': 2, 'group_delay': '1/2'}], ['control: random linear phase 15', [0, 0, 1, -1, -1, 1, 0, 0], {'type': 2, 'group_delay': '7/2'}], ['control: random linear phase 17', [0, -3, 1, 3, -1, 3, 1, -3], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 18', [0, 0, 3, 3, 0, 0], {'type': 2, 'group_delay': '5/2'}]]]
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: type III nonzero centre{'group_delay': '1', 'type': 3}{'group_delay': None, 'type': None}Failed
regression: random linear phase 2{'group_delay': '4', 'type': 3}{'group_delay': None, 'type': None}Failed
repair check: type IV{'group_delay': '1/2', 'type': 4}{'group_delay': '1/2', 'type': 4}Passed
control: type III zero centre{'group_delay': '1', 'type': 3}{'group_delay': '1', 'type': 3}Passed
control: type I{'group_delay': '1', 'type': 1}{'group_delay': '1', 'type': 1}Passed
control: type II{'group_delay': '1/2', 'type': 2}{'group_delay': '1/2', 'type': 2}Passed
control: leading zeros symmetric{'group_delay': '3', 'type': 1}{'group_delay': '3', 'type': 1}Passed

SHA-256 / 06733e0f0ec551e27e182f201c925776543c270a8a4ccba52a50a3ccffd951ab

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(x):
    h = list(x)
    lead = 0
    while lead < len(h) and h[lead] == 0:
        lead += 1
    if lead == len(h):
        return 'degenerate'
    end = len(h)
    while h[end - 1] == 0:
        end -= 1
    g = h[lead:end]
    N = len(g)
    sym = all(g[i] == g[N - 1 - i] for i in range(N))
    anti = all(g[i] == -g[N - 1 - i] for i in range(N // 2)) and g[N // 2] == 0
    if sym:
        typ = 1 if N % 2 else 2
    elif anti:
        typ = 3 if N % 2 else 4
    else:
        return {'type': None, 'group_delay': None}
    return {'type': typ, 'group_delay': str(lead + Fraction(N - 1, 2))}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: type IV', [1, -1], {'type': 4, 'group_delay': '1/2'}], ['control: type III zero centre', [1, 0, -1], {'type': 3, 'group_delay': '1'}], ['control: type I', [1, 2, 1], {'type': 1, 'group_delay': '1'}], ['control: type II', [1, 1], {'type': 2, 'group_delay': '1/2'}], ['control: leading zeros symmetric', [0, 0, 1, 2, 1], {'type': 1, 'group_delay': '3'}]], [['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['repair check: random linear phase 1', [0, 2, -2, 0, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: trailing zeros', [1, 2, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: interior zero symmetric', [1, 0, 1], {'type': 1, 'group_delay': '1'}], ['control: all zero', [0, 0, 0], 'degenerate'], ['control: not linear phase', [1, 2, 3], {'type': None, 'group_delay': None}]], [['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['repair check: random linear phase 10', [0, 0, 0, -1, 1, 0], {'type': 4, 'group_delay': '7/2'}], ['control: padded type II', [0, 3, 3, 0, 0], {'type': 2, 'group_delay': '3/2'}], ['control: single tap', [5], {'type': 1, 'group_delay': '0'}], ['control: padded interior zeros', [0, 2, 0, 0, 2], {'type': 2, 'group_delay': '5/2'}], ['control: random linear phase 0', [-1, -2, -1, 0, 1, 2, 1, 0], {'type': 3, 'group_delay': '3'}]], [['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 12', [-1, 1, -1, 1, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: random linear phase 3', [1, 0, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: random linear phase 5', [0, 0, -3, -3, -2, -3, -3, 0], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 7', [0, 0, 0, 0, 0], 'degenerate'], ['control: random linear phase 9', [0, 0, -1, -3, 3, -1, 3, -3, -1, 0, 0], {'type': 1, 'group_delay': '5'}]], [['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 16', [0, -3, -1, 1, 3, 0, 0], {'type': 4, 'group_delay': '5/2'}], ['control: random linear phase 13', [-3, -3, 0, 0], {'type': 2, 'group_delay': '1/2'}], ['control: random linear phase 15', [0, 0, 1, -1, -1, 1, 0, 0], {'type': 2, 'group_delay': '7/2'}], ['control: random linear phase 17', [0, -3, 1, 3, -1, 3, 1, -3], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 18', [0, 0, 3, 3, 0, 0], {'type': 2, 'group_delay': '5/2'}]]]
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: type III nonzero centre{'group_delay': None, 'type': None}{'group_delay': None, 'type': None}Passed
regression: random linear phase 2{'group_delay': None, 'type': None}{'group_delay': None, 'type': None}Passed
repair check: type IV{'group_delay': None, 'type': None}{'group_delay': '1/2', 'type': 4}Failed
control: type III zero centre{'group_delay': '1', 'type': 3}{'group_delay': '1', 'type': 3}Passed
control: type I{'group_delay': '1', 'type': 1}{'group_delay': '1', 'type': 1}Passed
control: type II{'group_delay': '1/2', 'type': 2}{'group_delay': '1/2', 'type': 2}Passed
control: leading zeros symmetric{'group_delay': '3', 'type': 1}{'group_delay': '3', 'type': 1}Passed

SHA-256 / 1cec7236905a67e9e7fb815343b068b5e9c8194317e1c4b3de455addcad4baa1

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(x):
    h = list(x)
    lead = 0
    while lead < len(h) and h[lead] == 0:
        lead += 1
    if lead == len(h):
        return 'degenerate'
    end = len(h)
    while h[end - 1] == 0:
        end -= 1
    g = h[lead:end]
    N = len(g)
    sym = all(g[i] == g[N - 1 - i] for i in range(N))
    anti = all(g[i] == -g[N - 1 - i] for i in range(N))
    if sym:
        typ = 1 if N % 2 else 2
    elif anti:
        typ = 3 if N % 2 else 4
    else:
        return {'type': None, 'group_delay': None}
    return {'type': typ, 'group_delay': str(lead + Fraction(N - 1, 2))}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: type IV', [1, -1], {'type': 4, 'group_delay': '1/2'}], ['control: type III zero centre', [1, 0, -1], {'type': 3, 'group_delay': '1'}], ['control: type I', [1, 2, 1], {'type': 1, 'group_delay': '1'}], ['control: type II', [1, 1], {'type': 2, 'group_delay': '1/2'}], ['control: leading zeros symmetric', [0, 0, 1, 2, 1], {'type': 1, 'group_delay': '3'}]], [['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['repair check: random linear phase 1', [0, 2, -2, 0, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: trailing zeros', [1, 2, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: interior zero symmetric', [1, 0, 1], {'type': 1, 'group_delay': '1'}], ['control: all zero', [0, 0, 0], 'degenerate'], ['control: not linear phase', [1, 2, 3], {'type': None, 'group_delay': None}]], [['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 6', [0, 3, 2, -3], {'type': None, 'group_delay': None}], ['repair check: random linear phase 10', [0, 0, 0, -1, 1, 0], {'type': 4, 'group_delay': '7/2'}], ['control: padded type II', [0, 3, 3, 0, 0], {'type': 2, 'group_delay': '3/2'}], ['control: single tap', [5], {'type': 1, 'group_delay': '0'}], ['control: padded interior zeros', [0, 2, 0, 0, 2], {'type': 2, 'group_delay': '5/2'}], ['control: random linear phase 0', [-1, -2, -1, 0, 1, 2, 1, 0], {'type': 3, 'group_delay': '3'}]], [['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['regression: random linear phase 4', [0, 1, -1, -1, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 12', [-1, 1, -1, 1, 0, 0], {'type': 4, 'group_delay': '3/2'}], ['control: random linear phase 3', [1, 0, 1, 0], {'type': 1, 'group_delay': '1'}], ['control: random linear phase 5', [0, 0, -3, -3, -2, -3, -3, 0], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 7', [0, 0, 0, 0, 0], 'degenerate'], ['control: random linear phase 9', [0, 0, -1, -3, 3, -1, 3, -3, -1, 0, 0], {'type': 1, 'group_delay': '5'}]], [['regression: type III nonzero centre', [1, 2, -1], {'type': None, 'group_delay': None}], ['regression: random linear phase 2', [0, 0, 2, 0, 2, 0, -2, 0, 0], {'type': None, 'group_delay': None}], ['repair check: random linear phase 16', [0, -3, -1, 1, 3, 0, 0], {'type': 4, 'group_delay': '5/2'}], ['control: random linear phase 13', [-3, -3, 0, 0], {'type': 2, 'group_delay': '1/2'}], ['control: random linear phase 15', [0, 0, 1, -1, -1, 1, 0, 0], {'type': 2, 'group_delay': '7/2'}], ['control: random linear phase 17', [0, -3, 1, 3, -1, 3, 1, -3], {'type': 1, 'group_delay': '4'}], ['control: random linear phase 18', [0, 0, 3, 3, 0, 0], {'type': 2, 'group_delay': '5/2'}]]]
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: type III nonzero centre{'group_delay': None, 'type': None}{'group_delay': None, 'type': None}Passed
regression: random linear phase 2{'group_delay': None, 'type': None}{'group_delay': None, 'type': None}Passed
repair check: type IV{'group_delay': '1/2', 'type': 4}{'group_delay': '1/2', 'type': 4}Passed
control: type III zero centre{'group_delay': '1', 'type': 3}{'group_delay': '1', 'type': 3}Passed
control: type I{'group_delay': '1', 'type': 1}{'group_delay': '1', 'type': 1}Passed
control: type II{'group_delay': '1/2', 'type': 2}{'group_delay': '1/2', 'type': 2}Passed
control: leading zeros symmetric{'group_delay': '3', 'type': 1}{'group_delay': '3', 'type': 1}Passed

SHA-256 / 300734ad7ae38facf5aebf6bca097aa1c9c3bbb1d20af99b30cfa4e98c0aa506

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

Case digest / 3ea157171e366f981d2beb6d1c190d2816a09004dd19cf872c1dbd8ddd282eba