def test_clamp(self): input_signal = torch.ones(1, 44100 * 1, dtype=self.dtype, device=self.device) b_coeffs = torch.tensor([1, 0], dtype=self.dtype, device=self.device) a_coeffs = torch.tensor([1, -0.95], dtype=self.dtype, device=self.device) output_signal = F.lfilter(input_signal, a_coeffs, b_coeffs, clamp=True) assert output_signal.max() <= 1 output_signal = F.lfilter(input_signal, a_coeffs, b_coeffs, clamp=False) assert output_signal.max() > 1
def test_lfilter(self): signal_length = 2048 torch.manual_seed(2434) x = torch.randn(self.batch_size, signal_length) a = torch.rand(self.batch_size, 3) b = torch.rand(self.batch_size, 3) batchwise_output = F.lfilter(x, a, b, batching=True) itemwise_output = torch.stack( [F.lfilter(x[i], a[i], b[i]) for i in range(self.batch_size)]) self.assertEqual(batchwise_output, itemwise_output)
def func(tensor): # Design an IIR lowpass filter using scipy.signal filter design # https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.iirdesign.html#scipy.signal.iirdesign # # Example # >>> from scipy.signal import iirdesign # >>> b, a = iirdesign(0.2, 0.3, 1, 60) b_coeffs = torch.tensor( [ 0.00299893, -0.0051152, 0.00841964, -0.00747802, 0.00841964, -0.0051152, 0.00299893, ], device=tensor.device, dtype=tensor.dtype, ) a_coeffs = torch.tensor( [ 1.0, -4.8155751, 10.2217618, -12.14481273, 8.49018171, -3.3066882, 0.56088705, ], device=tensor.device, dtype=tensor.dtype, ) return F.lfilter(tensor, a_coeffs, b_coeffs)
def test_perf_biquad_filtering(self): fn_sine = os.path.join(self.test_dirpath, "assets", "whitenoise.wav") b0 = 0.4 b1 = 0.2 b2 = 0.9 a0 = 0.7 a1 = 0.2 a2 = 0.6 # SoX method E = torchaudio.sox_effects.SoxEffectsChain() E.set_input_file(fn_sine) _timing_sox = time.time() E.append_effect_to_chain("biquad", [b0, b1, b2, a0, a1, a2]) waveform_sox_out, sr = E.sox_build_flow_effects() _timing_sox_run_time = time.time() - _timing_sox _timing_lfilter_filtering = time.time() waveform, sample_rate = torchaudio.load(fn_sine, normalization=True) waveform_lfilter_out = F.lfilter( waveform, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2]) ) _timing_lfilter_run_time = time.time() - _timing_lfilter_filtering assert torch.allclose(waveform_sox_out, waveform_lfilter_out, atol=1e-4) _test_torchscript_functional( F.lfilter, waveform, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2]) )
def test_perf_biquad_filtering(self): fn_sine = common_utils.get_asset_path('whitenoise.wav') b0 = 0.4 b1 = 0.2 b2 = 0.9 a0 = 0.7 a1 = 0.2 a2 = 0.6 # SoX method E = torchaudio.sox_effects.SoxEffectsChain() E.set_input_file(fn_sine) E.append_effect_to_chain("biquad", [b0, b1, b2, a0, a1, a2]) waveform_sox_out, _ = E.sox_build_flow_effects() waveform, _ = torchaudio.load(fn_sine, normalization=True) waveform_lfilter_out = F.lfilter(waveform, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2])) torch.testing.assert_allclose(waveform_lfilter_out, waveform_sox_out, atol=1e-4, rtol=1e-5)
def _shallow_ar_inference(out, stream_sizes, analysis_filts): from torchaudio.functional import lfilter out_streams = split_streams(out, stream_sizes) # back to conv1d friendly (B, C, T) format out_streams = map(lambda x: x.transpose(1, 2), out_streams) out_syn = [] for sidx, os in enumerate(out_streams): out_stream_syn = torch.zeros_like(os) a = analysis_filts[sidx].get_filt_coefs() # apply IIR filter for each dimiesion for idx in range(os.shape[1]): # NOTE: scipy.signal.lfilter accespts b, a in order, # but torchaudio expect the oppsite; a, b in order ai = a[idx].view(-1).flip(0) bi = torch.zeros_like(ai) bi[0] = 1 out_stream_syn[:, idx, :] = lfilter(os[:, idx, :], ai, bi, clamp=False) out_syn += [out_stream_syn] out_syn = torch.cat(out_syn, 1) return out_syn.transpose(1, 2)
def test_shape(self, shape): torch.random.manual_seed(42) waveform = torch.rand(*shape, dtype=self.dtype, device=self.device) b_coeffs = torch.tensor([0, 0, 0, 1], dtype=self.dtype, device=self.device) a_coeffs = torch.tensor([1, 0, 0, 0], dtype=self.dtype, device=self.device) output_waveform = F.lfilter(waveform, a_coeffs, b_coeffs) assert shape == waveform.size() == output_waveform.size()
def func(tensor): a = torch.tensor([0.7, 0.2, 0.6], device=tensor.device, dtype=tensor.dtype) b = torch.tensor([0.4, 0.2, 0.9], device=tensor.device, dtype=tensor.dtype) return F.lfilter(tensor, a, b)
def test_perf_biquad_filtering(self): b0 = 0.4 b1 = 0.2 b2 = 0.9 a0 = 0.7 a1 = 0.2 a2 = 0.6 data, path = self.get_whitenoise() result = F.lfilter(data, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2])) self.assert_sox_effect(result, path, ['biquad', b0, b1, b2, a0, a1, a2])
def forward( self, x: "torch.Tensor", y: Optional["torch.Tensor"] = None ) -> Tuple["torch.Tensor", Optional["torch.Tensor"]]: """ Apply filter to a single sample `x`. :param x: A single audio sample. :param y: Label of the sample `x`. This function does not affect them in any way. :return: Similar sample. """ import torch # lgtm [py/repeated-import] from torchaudio.functional import lfilter if int(torch.__version__.split(".")[1]) > 5: x_preprocess = lfilter( b_coeffs=torch.tensor(self.numerator_coef, device=self._device), a_coeffs=torch.tensor(self.denominator_coef, device=self._device), waveform=x, clamp=False, ) else: x_preprocess = lfilter( b_coeffs=torch.tensor(self.numerator_coef, device=self._device), a_coeffs=torch.tensor(self.denominator_coef, device=self._device), waveform=x, ) if self.clip_values is not None: x_preprocess = x_preprocess.clamp(min=self.clip_values[0], max=self.clip_values[1]) return x_preprocess, y
def _test_lfilter_basic(self, dtype, device): """ Create a very basic signal, Then make a simple 4th order delay The output should be same as the input but shifted """ torch.random.manual_seed(42) waveform = torch.rand(2, 44100 * 1, dtype=dtype, device=device) b_coeffs = torch.tensor([0, 0, 0, 1], dtype=dtype, device=device) a_coeffs = torch.tensor([1, 0, 0, 0], dtype=dtype, device=device) output_waveform = F.lfilter(waveform, a_coeffs, b_coeffs) assert torch.allclose(waveform[:, 0:-3], output_waveform[:, 3:], atol=1e-5)
def test_simple(self): """ Create a very basic signal, Then make a simple 4th order delay The output should be same as the input but shifted """ torch.random.manual_seed(42) waveform = torch.rand(2, 44100 * 1, dtype=self.dtype, device=self.device) b_coeffs = torch.tensor([0, 0, 0, 1], dtype=self.dtype, device=self.device) a_coeffs = torch.tensor([1, 0, 0, 0], dtype=self.dtype, device=self.device) output_waveform = F.lfilter(waveform, a_coeffs, b_coeffs) self.assertEqual(output_waveform[:, 3:], waveform[:, 0:-3], atol=1e-5, rtol=1e-5)
def test_lfilter_shape(self, input_shape, coeff_shape, target_shape): torch.random.manual_seed(42) waveform = torch.rand(*input_shape, dtype=self.dtype, device=self.device) b_coeffs = torch.rand(*coeff_shape, dtype=self.dtype, device=self.device) a_coeffs = torch.rand(*coeff_shape, dtype=self.dtype, device=self.device) output_waveform = F.lfilter(waveform, a_coeffs, b_coeffs) assert input_shape == waveform.size() assert target_shape == output_waveform.size()
def test_lfilter_9th_order_filter_stability(self): """ Validate the precision of lfilter against reference scipy implementation when using high order filter. The reference implementation use cascaded second-order filters so is more numerically accurate. """ # create an impulse signal x = torch.zeros(1024, dtype=self.dtype, device=self.device) x[0] = 1 # get target impulse response sos = signal.butter(9, 850, 'hp', fs=22050, output='sos') y = torch.from_numpy(signal.sosfilt(sos, x.cpu().numpy())).to(self.dtype).to(self.device) # get lfilter coefficients b, a = signal.butter(9, 850, 'hp', fs=22050, output='ba') b, a = torch.from_numpy(b).to(self.dtype).to(self.device), torch.from_numpy( a).to(self.dtype).to(self.device) # predict impulse response yhat = F.lfilter(x, a, b, False) self.assertEqual(yhat, y, atol=1e-4, rtol=1e-5)
def _test_lfilter(self, waveform, device): """ Design an IIR lowpass filter using scipy.signal filter design https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.iirdesign.html#scipy.signal.iirdesign Example >>> from scipy.signal import iirdesign >>> b, a = iirdesign(0.2, 0.3, 1, 60) """ b_coeffs = torch.tensor( [ 0.00299893, -0.0051152, 0.00841964, -0.00747802, 0.00841964, -0.0051152, 0.00299893, ], device=device, ) a_coeffs = torch.tensor( [ 1.0, -4.8155751, 10.2217618, -12.14481273, 8.49018171, -3.3066882, 0.56088705, ], device=device, ) output_waveform = F.lfilter(waveform, a_coeffs, b_coeffs) assert len(output_waveform.size()) == 2 assert output_waveform.size(0) == waveform.size(0) assert output_waveform.size(1) == waveform.size(1) _test_torchscript_functional(F.lfilter, waveform, a_coeffs, b_coeffs)
def test_perf_biquad_filtering(self): b0 = 0.4 b1 = 0.2 b2 = 0.9 a0 = 0.7 a1 = 0.2 a2 = 0.6 # SoX method E = torchaudio.sox_effects.SoxEffectsChain() E.set_input_file(self.noise_filepath) E.append_effect_to_chain("biquad", [b0, b1, b2, a0, a1, a2]) waveform_sox_out, _ = E.sox_build_flow_effects() waveform_lfilter_out = F.lfilter(self.noise_waveform, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2])) self.assertEqual(waveform_lfilter_out, waveform_sox_out, atol=1e-4, rtol=1e-5)