You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PaddleSpeech/audio/tests/audiotools/core/test_lowpass.py

110 lines
3.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# MIT License, Copyright (c) 2020 Alexandre Défossez.
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Modified from julius(https://github.com/adefossez/julius/blob/main/tests/test_lowpass.py)
import math
import random
import sys
import unittest
import numpy as np
import paddle
from audio.audiotools.core import lowpass_filter
from audio.audiotools.core import LowPassFilter
from audio.audiotools.core import LowPassFilters
from audio.audiotools.core import resample_frac
def pure_tone(freq: float, sr: float=128, dur: float=4, device=None):
"""
Return a pure tone, i.e. cosine.
Args:
freq (float): frequency (in Hz)
sr (float): sample rate (in Hz)
dur (float): duration (in seconds)
"""
time = paddle.arange(int(sr * dur), dtype="float32") / sr
return paddle.cos(2 * math.pi * freq * time)
def delta(a, b, ref, fraction=0.9):
length = a.shape[-1]
compare_length = int(length * fraction)
offset = (length - compare_length) // 2
a = a[..., offset:offset + length]
b = b[..., offset:offset + length]
# 计算绝对差值均值然后除以ref的标准差乘以100
return 100 * paddle.mean(paddle.abs(a - b)) / paddle.std(ref)
TOLERANCE = 1 # Tolerance to errors as percentage of the std of the input signal
class _BaseTest(unittest.TestCase):
def assertSimilar(self, a, b, ref, msg=None, tol=TOLERANCE):
self.assertLessEqual(delta(a, b, ref), tol, msg)
class TestLowPassFilters(_BaseTest):
def setUp(self):
paddle.seed(1234)
random.seed(1234)
def test_keep_or_kill(self):
for _ in range(10):
freq = random.uniform(0.01, 0.4)
sr = 1024
tone = pure_tone(freq * sr, sr=sr, dur=10)
# For this test we accept 5% tolerance in amplitude, or -26dB in power.
tol = 5
zeros = 16
# If cutoff frequency is under freq, output should be zero
y_killed = lowpass_filter(tone, 0.9 * freq, zeros=zeros)
self.assertSimilar(
y_killed, 0 * y_killed, tone, f"freq={freq}, kill", tol=tol)
# If cutoff frequency is under freq, output should be input
y_pass = lowpass_filter(tone, 1.1 * freq, zeros=zeros)
self.assertSimilar(
y_pass, tone, tone, f"freq={freq}, pass", tol=tol)
def test_same_as_downsample(self):
for _ in range(10):
x = paddle.randn([2 * 3 * 4 * 100])
x = paddle.ones_like(x)
np.random.seed(1234)
x = paddle.to_tensor(
np.random.randn(2 * 3 * 4 * 100), dtype="float32")
rolloff = 0.945
for old_sr in [2, 3, 4]:
y_resampled = resample_frac(
x, old_sr, 1, rolloff=rolloff, zeros=16)
y_lowpass = lowpass_filter(
x, rolloff / old_sr / 2, stride=old_sr, zeros=16)
self.assertSimilar(y_resampled, y_lowpass, x,
f"old_sr={old_sr}")
def test_fft_nofft(self):
for _ in range(10):
x = paddle.randn([1024])
freq = random.uniform(0.01, 0.5)
y_fft = lowpass_filter(x, freq, fft=True)
y_ref = lowpass_filter(x, freq, fft=False)
self.assertSimilar(y_fft, y_ref, x, f"freq={freq}", tol=0.01)
def test_constant(self):
x = paddle.ones([2048])
for zeros in [4, 10]:
for freq in [0.01, 0.1]:
y_low = lowpass_filter(x, freq, zeros=zeros)
self.assertLessEqual((y_low - 1).abs().mean(), 1e-6,
(zeros, freq))
if __name__ == "__main__":
unittest.main()