diff --git a/src/ezmsg/sigproc/butterworthfilter.py b/src/ezmsg/sigproc/butterworthfilter.py index 942f5dc..c3bcb67 100644 --- a/src/ezmsg/sigproc/butterworthfilter.py +++ b/src/ezmsg/sigproc/butterworthfilter.py @@ -97,8 +97,13 @@ def butter_design_fun( """ coefs = None - if order > 0: - btype, cutoffs = ButterworthFilterSettings(order=order, cuton=cuton, cutoff=cutoff).filter_specs() + # order > 0 with neither corner set is a valid "no filter" request: + # filter_specs() returns None, which we treat as passthrough (coefs stays + # None -> the transformer returns the input unchanged) rather than crashing + # on an unpack of None. + specs = ButterworthFilterSettings(order=order, cuton=cuton, cutoff=cutoff).filter_specs() + if order > 0 and specs is not None: + btype, cutoffs = specs coefs = scipy.signal.butter( order, Wn=cutoffs, diff --git a/tests/unit/test_butter.py b/tests/unit/test_butter.py index e8f0db6..44fe257 100644 --- a/tests/unit/test_butter.py +++ b/tests/unit/test_butter.py @@ -288,6 +288,26 @@ def test_butterworth_empty_order0_passthrough(): check_empty_result(result) +def test_butterworth_order_no_corners_passthrough(): + """order > 0 with neither cuton nor cutoff is a valid "no filter" request. + + Regression test: this used to crash in butter_design_fun on an unpack of + None from filter_specs(); now it designs no filter and passes data through. + """ + from ezmsg.sigproc.butterworthfilter import ( + ButterworthFilterSettings, + ButterworthFilterTransformer, + butter_design_fun, + ) + + assert butter_design_fun(fs=1000.0, order=4) is None + + proc = ButterworthFilterTransformer(ButterworthFilterSettings(order=4, axis="time")) + msg = make_msg() + result = proc(msg) + assert np.array_equal(result.data, msg.data) + + def test_butterworth_empty_first(): from ezmsg.sigproc.butterworthfilter import ButterworthFilterSettings, ButterworthFilterTransformer