code: def test_reporting_fir(phase, fir_window, btype):
      """Test FIR filter reporting."""
      l_freq = 1.0 if btype == "bandpass" else None
      fs = 1000.0
      with catch_logging() as log:
          x = create_filter(
              None,
              fs,
              l_freq,
              40,
              method="fir",
              phase=phase,
              fir_window=fir_window,
              verbose=True,
          )
      n_taps = len(x)
      log = log.getvalue()
      keys = [
          "FIR",
          btype,
          fir_window.capitalize(),
          "Filter length: %d samples" % (n_taps,),
          "passband ripple",
          "stopband attenuation",
      ]
      if phase == "minimum":
          keys += [" causal "]
      else:
          keys += [" non-causal ", " dB cutoff frequency: 45.00 Hz"]
          if btype == "bandpass":
              keys += [" dB cutoff frequency: 0.50 Hz"]
      for key in keys:
          assert key in log
      if phase == "zero":
          assert "-6 dB cutoff" in log
      elif phase == "zero-double":
          assert "-12 dB cutoff" in log
      else:
          # XXX Eventually we should figure out where the resulting point is,
          # since the minimum-phase process will change it. For now we don't
          # report it.
          assert phase == "minimum"
      # Verify some of the filter properties
      if phase == "zero-double":
          x = np.convolve(x, x)  # effectively what happens
      w, h = freqz(x, worN=10000)
      w *= fs / (2 * np.pi)
      h = np.abs(h)
      # passband
      passes = [np.argmin(np.abs(w - f)) for f in (1, 20, 40)]
      # stopband
      stops = [np.argmin(np.abs(w - 50.0))]
      # transition
      mids = [np.argmin(np.abs(w - 45.0))]
      # put these where they belong based on filter type
      assert w[0] == 0.0
      idx_0 = 0
      idx_0p5 = np.argmin(np.abs(w - 0.5))
      if btype == "bandpass":
          stops += [idx_0]
          mids += [idx_0p5]
      else:
          passes += [idx_0, idx_0p5]
      assert_allclose(h[passes], 1.0, atol=0.01)
      attenuation = -20 if phase == "minimum" else -50
      assert_allclose(h[stops], 0.0, atol=10 ** (attenuation / 20.0))
      if phase != "minimum":  # haven't worked out the math for this yet
          expected = 0.25 if phase == "zero-double" else 0.5
          assert_allclose(h[mids], expected, atol=0.01)
  
imports: import numpy
  import pytest
  from numpy.fft import fft, fftfreq
  from numpy.testing import assert_allclose, assert_almost_equal, assert_array_almost_equal, assert_array_equal, assert_array_less
  from scipy.signal import butter, freqz, sosfreqz
  from scipy.signal import resample
  from mne import Epochs, create_info
  from mne._fiff.pick import _DATA_CH_TYPES_SPLIT
  from mne.filter import _length_factors, _overlap_add_filter, _resample_stim_channels, _smart_pad, construct_iir_filter, create_filter, design_mne_c_filter, detrend, estimate_ringing_samples, filter_data, notch_filter, resample
  from mne.io import RawArray, read_raw_fif
  from mne.utils import catch_logging, requires_mne, run_subprocess, sum_squared
label_desc: Use image node_id 20 for calling a global function with example usage: test_reporting_fir(phase, fir_window, btype) without return types