模拟技术
from __future__ import annotations
# from audio_filters.iir_filter import IIRFilter
import numpy as np
import matplotlib.pyplot as plt
from typing_extensions import Protocol
from math import pi
from math import cos, sin, sqrt, tau
class IIRFilter:
def __init__(self, order: int) -> None:
order =
# a_{0} ... a_{k}
[1.0] + [0.0] * order =
# b_{0} ... b_{k}
[1.0] + [0.0] * order =
# x[n-1] ... x[n-k]
[0.0] * self.order =
# y[n-1] ... y[n-k]
[0.0] * self.order =
def set_coefficients(self, a_coeffs: list[float], b_coeffs: list[float]) -> None:
if len(a_coeffs) < self.order:
a_coeffs = [1.0] + a_coeffs
if len(a_coeffs) != self.order + 1:
raise ValueError(
a_coeffs to 有 {self.order + 1} elements for {self.order}"
filter, got {len(a_coeffs)}"
)
if len(b_coeffs) != self.order + 1:
raise ValueError(
b_coeffs to have {self.order + 1} elements for {self.order}"
filter, got {len(a_coeffs)}"
)
a_coeffs =
b_coeffs =
def process(self, sample: float) -> float:
result = 0.0
# 从索引 1 开始,最后执行索引 0
for i in range(1, self.order + 1):
result += (self.b_coeffs[i] * self.input_history[i-1]-self.a_coeffs[i]*self.output_history[i-1]
)
result = (result + self.b_coeffs[0] * sample) / self.a_coeffs[0]
] = self.input_history[:-1] :
] = self.output_history[:-1] :
sample =
result =
return result
def make_lowpass(
frequency: int, samplerate: int, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
b0 = (1 - _cos) / 2
b1 = 1 - _cos
a0 = 1 + alpha
a1 = -2 * _cos
a2 = 1 - alpha
filt = IIRFilter(2)
a1, a2], [b0, b1, b0])
return filt
def make_highpass(
frequency: int, samplerate: int, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
b0 = (1 + _cos) / 2
b1 = -1 - _cos
a0 = 1 + alpha
a1 = -2 * _cos
a2 = 1 - alpha
filt = IIRFilter(2)
a1, a2], [b0, b1, b0])
return filt
def make_bandpass(
frequency: int, samplerate: int, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
"""
创建带通滤波器
filter = make_bandpass(1000, 48000)
filter.a_coeffs + filter.b_coeffs # doctest: +NORMALIZE_WHITESPACE
-1.9828897227476208, 0.9077040443587427, 0.06526309611002579,
-0.06526309611002579]
"""
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
b0 = _sin / 2
b1 = 0
b2 = -b0
a0 = 1 + alpha
a1 = -2 * _cos
a2 = 1 - alpha
filt = IIRFilter(2)
a1, a2], [b0, b1, b2])
return filt
def make_allpass(
frequency: int, samplerate: int, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
b0 = 1 - alpha
b1 = -2 * _cos
b2 = 1 + alpha
filt = IIRFilter(2)
b1, b0], [b0, b1, b2])
return filt
def make_peak(
frequency: int, samplerate: int, gain_db: float, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
big_a = 10 ** (gain_db / 40)
b0 = 1 + alpha * big_a
b1 = -2 * _cos
b2 = 1 - alpha * big_a
a0 = 1 + alpha / big_a
a1 = -2 * _cos
a2 = 1 - alpha / big_a
filt = IIRFilter(2)
a1, a2], [b0, b1, b2])
return filt
def make_lowshelf(
frequency: int, samplerate: int, gain_db: float, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
big_a = 10 ** (gain_db / 40)
pmc = (big_a + 1) - (big_a - 1) * _cos
ppmc = (big_a + 1) + (big_a - 1) * _cos
mpc = (big_a - 1) - (big_a + 1) * _cos
pmpc = (big_a - 1) + (big_a + 1) * _cos
aa2 = 2 * sqrt(big_a) * alpha
b0 = big_a * (pmc + aa2)
b1 = 2 * big_a * mpc
b2 = big_a * (pmc - aa2)
a0 = ppmc + aa2
a1 = -2 * pmpc
a2 = ppmc - aa2
filt = IIRFilter(2)
a1, a2], [b0, b1, b2])
return filt
def make_highshelf(
frequency: int, samplerate: int, gain_db: float, q_factor: float = 1 / sqrt(2)
-> IIRFilter:
w0 = tau * frequency / samplerate
_sin = sin(w0)
_cos = cos(w0)
alpha = _sin / (2 * q_factor)
big_a = 10 ** (gain_db / 40)
pmc = (big_a + 1) - (big_a - 1) * _cos
ppmc = (big_a + 1) + (big_a - 1) * _cos
mpc = (big_a - 1) - (big_a + 1) * _cos
pmpc = (big_a - 1) + (big_a + 1) * _cos
aa2 = 2 * sqrt(big_a) * alpha
b0 = big_a * (ppmc + aa2)
b1 = -2 * big_a * pmpc
b2 = big_a * (ppmc - aa2)
a0 = pmc + aa2
a1 = 2 * mpc
a2 = pmc - aa2
filt = IIRFilter(2)
a1, a2], [b0, b1, b2])
return filt
class FilterType(Protocol):
def process(self, sample: float) -> float:
return 0.0
def get_bounds(
fft_results: np.ndarray, samplerate: int
-> tuple[int | float, int | float]:
lowest = min([-20, np.min(fft_results[1: samplerate // 2 - 1])])
highest = max([20, np.max(fft_results[1: samplerate // 2 - 1])])
return lowest, highest
def show_frequency_response(filter: FilterType, samplerate: int) -> None:
size = 512
inputs = [1] + [0] * (size - 1)
outputs = [filter.process(item) for item in inputs]
filler = [0] * (samplerate - size) # zero-padding
outputs += filler
fft_out = np.abs(np.fft.fft(outputs))
fft_db = 20 * np.log10(fft_out)
# Frequencies on log scale from 24 to nyquist frequency
samplerate / 2 - 1)
(Hz)")
plt.xscale("log")
# Display within reasonable bounds
bounds = get_bounds(fft_db, samplerate)
bounds[0]]), min([80, bounds[1]]))
(dB)")
plt.plot(fft_db)
plt.show()
def show_phase_response(filter: FilterType, samplerate: int) -> None:
size = 512
inputs = [1] + [0] * (size - 1)
outputs = [filter.process(item) for item in inputs]
filler = [0] * (samplerate - size)
outputs += filler
fft_out = np.angle(np.fft.fft(outputs))
samplerate / 2 - 1)
(Hz)")
plt.xscale("log")
* pi, 2 * pi)
shift (Radians)")
-2 * pi))
plt.show()
filt = IIRFilter(4)
48000)
全部0条评论
快来发表一下你的评论吧 !