Python bộ lọc thông dải hẹp

Gần đây, khi tôi đang xử lý tín hiệu tần số rất cao là 12. 5 Khz, tôi. e. 12500 mẫu mỗi giây hoặc một mẫu cứ sau 80 micro giây. Điều thú vị hơn là tôi phải lấy nhiều điểm dữ liệu khác nhau trong tập dữ liệu này

Đây là cách dữ liệu của tôi trong một chu kỳ trông như thế nào

Python bộ lọc thông dải hẹp
Hình 1. Đáp ứng biên độ bộ lọc dải tần

Tần số trung tâm trỏ đến tần số có độ suy giảm lớn nhất, độ “nhúng” trong đáp ứng cường độ của bộ lọc

Băng thông xác định độ rộng của “điểm nhúng” hoặc “thung lũng” xung quanh tần số trung tâm

Để bộ lọc dải tần cho âm thanh có dải tần rộng như nhau ở mọi tần số trung tâm, chúng ta thường sử dụng thông số Q hay còn gọi là quality factor hoặc Q-factor. Nó được định nghĩa là

Q=fcBW,(1)Q = \frac{f_c}{BW}, \quad (1)Q=BWfc,(1)

trong đó BWBWBW là băng thông tính bằng Hz . fcf_cfc is the center frequency in Hz.

Bộ lọc “hằng số-Q” cho phép dải hẹp hơn ở tần số thấp (nơi thính giác của con người nhạy cảm hơn với tần số) và cho dải rộng hơn ở tần số cao (nơi thính giác của con người ít nhạy cảm hơn với tần số)

Lưu ý rằng chúng tôi không thể kiểm soát lượng suy giảm trong bộ lọc dải tần. Điều đó chỉ có thể thực hiện được trong bộ lọc (dải) đỉnh, đây không phải là chủ đề của bài viết này

Bộ lọc thông dải là gì?

Bộ lọc thông dải là bộ lọc làm suy giảm tất cả các tần số ngoài một phạm vi được chỉ định

Phạm vi này được xác định theo tần số trung tâm và băng thông, cả hai đều được biểu thị bằng Hz

Python bộ lọc thông dải hẹp
Hình 2. Đáp ứng biên độ của bộ lọc thông dải

Như trong trường hợp bộ lọc chặn dải, chúng ta có thể chỉ định băng thông bằng tham số Q (hệ số chất lượng, hệ số Q). Bộ lọc Constant-Q giữ nguyên “độ rộng cảm nhận” của dải tần số truyền qua. Mối quan hệ giữa tần số trung tâm, băng thông và Q được đưa ra bởi phương trình 1

Tóm tắt lại. Bộ lọc Allpass bậc hai

Khối xây dựng chính của bộ lọc thông dải và chặn dải là bộ lọc thông toàn bậc hai

Bộ lọc allpass là bộ lọc không làm suy giảm bất kỳ tần số nào nhưng nó tạo ra sự dịch pha phụ thuộc vào tần số

Hãy tóm tắt lại một số thông tin về bộ lọc này

Chức năng chuyển

Hàm truyền của bộ lọc allpass bậc hai là

HAP2(z)=−c+d(1−c)z−1+z−21+d(1−c)z−1−cz−2,(2)H_{\text{AP HAP2(z)=1+d(1c)z1cz2c+d(1c)z1+z2,(2)

ở đâu

c=tan⁡(πBW/fs)−1tan⁡(πBW/fs)+1,(3)c = \frac{\tan(\pi BW / f_s) - 1}{\tan(\ c=tan(πBW/fs)+1tan(πBW/fs)1,(3)

d=−cos⁡(2πfb/fs),(4)d = - \cos(2\pi f_\text{b} / f_s), \quad (4)d=cos(2πfb/fs),(4)

BWBWBW là băng thông tính bằng Hz, . Tần số ngắt xác định tần suất tại đó sự dịch pha là fb is the break frequency in Hz, and fsf_sfs is the sampling rate in Hz. The break frequency specifies the frequency at which the phase shift is −π-\piπ. The bandwidth specifies the width of the transition band in which the phase shift goes from 0 to −2π-2\pi2π.

Đáp ứng pha

Phản hồi pha của bộ lọc allpass bậc hai có thể nhìn thấy trong Hình 3

Python bộ lọc thông dải hẹp
Hình 3. Phản hồi pha của bộ lọc chuyển tiếp bậc hai cho các tần số ngắt quãng khác nhau fbf_\text{b}fb< . 022BW / f_s = 0. 022 and bandwidth BW/fs=0.022BW / f_s = 0.022BW/f . =0.022 .

Như bạn có thể thấy, độ lệch pha là 0 tại 0 Hz và dần dần thay đổi thành −2π-2\pi2π. The steepness of the phase response is determined by the bandwidth BWBWBW .

Bạn có thể đoán rằng tham số băng thông của bộ lọc bỏ qua bậc hai chuyển thành tham số băng thông của bộ lọc thông dải và chặn dải. Theo đó, tần số ngắt tương ứng với tần số trung tâm. Làm sao?

Nhờ hiệu ứng khử pha, nếu chúng ta thêm hai âm ở cùng tần số nhưng có độ lệch pha tương đối là π\piπ< . Việc dịch chuyển , they will cancel each other. A shift by π\piπ tương đương với phép nhân của âm với -1.

Với kiến ​​thức này, giờ đây chúng ta có thể sử dụng bộ lọc bỏ qua bậc hai cho lọc thông dải hoặc chặn dải

Bộ lọc Bandstop dựa trên Allpass

Nếu chúng ta thêm đầu ra của bộ lọc allpass bậc hai vào tín hiệu đầu vào của nó, thì ở tần số ngắt, chúng ta sẽ thu được sự hủy pha. Tại sao?

Ở tần số ngắt, độ trễ pha là −π-\piπ. Adding two tones at the break frequency with the relative phase shift of π\piπ , chúng tôi loại bỏ chúng một cách hiệu quả khỏi . Khi độ lệch pha lệch khỏi π\piπ càng xa tần số ngắt, thì hiện tượng triệt tiêu ngày càng ít .

Sơ đồ DSP

Đây là sơ đồ khối của bộ lọc bandstop

Python bộ lọc thông dải hẹp
hinh 4. Sơ đồ DSP của bộ lọc chặn dải dựa trên allpass

AP2(z)\text{AP}_2(z)AP2(z) denotes the second-order allpass filter.

Đầu ra của bộ lọc bỏ qua bậc hai được thêm vào đường dẫn trực tiếp. Chúng tôi nhân kết quả với 12\frac{1}{2}21 to stay in the [-1, 1] range (input is in [-1, 1] range, allpass’s output is in [-1, 1] range so their sum is in the [-2, 2] range; we want to scale that back down to [-1, 1], otherwise we’ll possibly clip the signal).

Phản ứng cường độ

Đây là hàm truyền cường độ của bộ lọc chặn dải từ Hình 4 với tần số trung tâm là 250 Hz và QQQ equal to 3.

Python bộ lọc thông dải hẹp
Hình 5. Chức năng truyền cường độ của bộ lọc dải tần

Ở tần số trung tâm, chúng tôi nhận được sự suy giảm lớn nhất, giảm càng xa tần số trung tâm. Chúng ta có thể thấy mức độ chọn lọc về tần suất của bộ lọc này

Kiểm soát thời gian thực

Vì bộ lọc này yêu cầu tính toán khá dễ dàng để kiểm soát tần số trung tâm và băng thông, chúng tôi có thể thay đổi các tham số của nó trong thời gian thực

Ví dụ: đây là tín hiệu nhiễu trắng được lọc bằng bộ lọc chặn dải, có tần số trung tâm thay đổi từ 100 đến 16000 Hz theo thời gian và Q bằng 3

Trình duyệt của bạn không hỗ trợ thẻ âm thanh

Để hình dung những gì đang xảy ra ở đây, hãy xem quang phổ của tệp âm thanh

Python bộ lọc thông dải hẹp
Hình 6. Spectrogram của ví dụ lọc bandstop

Trên trục x, chúng ta có thời gian, trên trục y, chúng ta có tần số theo tỷ lệ log và màu biểu thị mức biên độ của tần số tại một thời điểm cụ thể tính bằng decibel toàn thang đo (dBFS)

Như bạn có thể thấy, mức giảm di chuyển theo cấp số nhân (lưu ý thang log. ) từ tần số thấp đến cao. Do đó, chúng ta có thể nghe thấy cái gọi là "quét bộ lọc"

Thực hiện

Bạn sẽ tìm thấy một triển khai mẫu của bộ lọc bandstop trong Python ở cuối bài viết này

Bộ lọc thông dải dựa trên Allpass

Bộ lọc thông dải dựa trên allpass chỉ khác với bộ lọc bandstop ở dấu hiệu của đầu ra bộ lọc allpass. Trong trường hợp thông dải, chúng tôi đảo ngược đầu ra của thông toàn bộ theo pha để quá trình khử pha xảy ra ở tần số 0 Hz và tần số Nyquist. Do âm ở tần số ngắt bị đảo ngược hai lần nên nó cùng pha với tín hiệu đầu vào. Do đó, tổng dẫn đến việc tăng gấp đôi biên độ của âm tương ứng với tần số ngắt của allpass

Sơ đồ DSP

Trong Hình 7, có một sơ đồ khối của bộ lọc thông dải được trình bày

Python bộ lọc thông dải hẹp
Hình 7. Sơ đồ DSP của bộ lọc thông dải dựa trên allpass

AP2(z)\text{AP}_2(z)AP2(z) denotes the second-order allpass filter.

Phép nhân với 12\frac{1}{2}21 is just to preserve the [-1, 1] amplitude range of the signal.

Phản ứng cường độ

Trong Hình 8, có đáp ứng cường độ của bộ lọc thông dải với tần số trung tâm được đặt thành 250 Hz và QQQ set to 3.

Python bộ lọc thông dải hẹp
Hình 8. Chức năng truyền cường độ của bộ lọc thông dải

Như bạn có thể thấy, nó thực sự chỉ đi qua các tần số trong dải được chỉ định

Kiểm soát thời gian thực

Chính xác như bộ lọc chặn dải, bộ lọc thông dải có thể được điều khiển dễ dàng trong thời gian thực

Đây là mẫu âm thanh có nhiễu trắng được lọc thông dải, trong đó tần số trung tâm thay đổi từ 100 Hz đến 16000 Hz và Q bằng 3

Trình duyệt của bạn không hỗ trợ thẻ âm thanh

Bạn có thể quan sát ảnh hưởng của bộ lọc thông dải trên phổ của tệp âm thanh trên (Hình 9)

Python bộ lọc thông dải hẹp
Hình 9. Biểu đồ phổ của ví dụ lọc thông dải

Một lần nữa, trục y là trục log-tần số, trục x là trục thời gian và cường độ màu tương ứng với mức âm thanh tính bằng decibel toàn thang đo (dBFS)

Thực hiện

Đây là một triển khai Python mẫu của cả hai bộ lọc. bandpass và bandstop

Mã này tạo ra 5 giây tiếng ồn trắng và sau đó lọc nó bằng các bộ lọc thông dải và thông dải thay đổi theo thời gian tương ứng. Tần số trung tâm trong cả hai trường hợp thay đổi theo cấp số nhân từ 100 Hz đến 16000 Hz (mã này được sử dụng để tạo các ví dụ trước trong bài viết này)

Mã được bình luận nhiều nên bạn sẽ không gặp vấn đề gì trong việc hiểu

Liệt kê 1. Triển khai lọc thông dải và lọc dải thông dựa trên tất cả và ứng dụng quét bộ lọc

import numpy as np
import scipy.signal as sig
import soundfile as sf


def apply_fade(signal):
    """Apply a fade-in and a fade-out to the 1-dimensional signal"""
    # Use a half-cosine window
    window = sig.hann(8192)
    # Use just the half of it
    fade_length = window.shape[0] // 2
    # Fade-in
    signal[:fade_length] *= window[:fade_length]
    # Fade-out
    signal[-fade_length:] *= window[fade_length:]
    # Return the modified signal
    return signal


def second_order_allpass_filter(break_frequency, BW, fs):
    """
    Returns b, a: numerator and denominator coefficients
    of the second-order allpass filter respectively

    Refer to scipy.signal.lfilter for the explanation
    of b and a arrays.

    The coefficients come from the transfer function of
    the allpass (Equation 2 in the article).

    Parameters
    ----------
    break_frequency : number
        break frequency of the allpass in Hz
    BW : number
        bandwidth of the allpass in Hz
    fs : number
        sampling rate in hz

    Returns
    -------
    b, a : array_like
        numerator and denominator coefficients of
        the second-order allpass filter respectively
    """
    tan = np.tan(np.pi * BW / fs)
    c = (tan - 1) / (tan + 1)
    d = - np.cos(2 * np.pi * break_frequency / fs)
    
    b = [-c, d * (1 - c), 1]
    a = [1, d * (1 - c), -c]
    
    return b, a


def bandstop_bandpass_filter(input_signal, Q, center_frequency, fs, bandpass=False):
    """Filter the given input signal

    Parameters
    ----------
    input_signal : array_like
        1-dimensional audio signal
    Q : float
        the Q-factor of the filter
    center_frequency : array_like
        the center frequency of the filter in Hz
        for each sample of the input
    fs : number
        sampling rate in Hz
    bandpass : bool, optional
        perform bandpass filtering if True, 
        bandstop filtering otherwise, by default False

    Returns
    -------
    array_like
        filtered input_signal according to the parameters
    """
    # For storing the allpass output
    allpass_filtered = np.zeros_like(input_signal)
    
    # Initialize filter's buffers
    x1 = 0
    x2 = 0
    y1 = 0
    y2 = 0
    
    # Process the input signal with the allpass
    for i in range(input_signal.shape[0]):
        # Calculate the bandwidth from Q and center frequency
        BW = center_frequency[i] / Q
        
        # Get the allpass coefficients
        b, a = second_order_allpass_filter(center_frequency[i], BW, fs)
        
        x = input_signal[i]
        
        # Actual allpass filtering:
        # difference equation of the second-order allpass
        y = b[0] * x + b[1] * x1 +  b[2] * x2 - a[1] * y1 - a[2] * y2
        
        # Update the filter's buffers
        y2 = y1
        y1 = y
        x2 = x1
        x1 = x
        
        # Assign the resulting sample to the output array
        allpass_filtered[i] = y
    
    # Should we bandstop- or bandpass-filter?
    sign = -1 if bandpass else 1
    
    # Final summation and scaling (to avoid clipping)
    output = 0.5 * (input_signal + sign * allpass_filtered)

    return output


def main():
    """
    Sample application of bandpass and bandstop
    filters: filter sweep.
    """
    # Parameters
    fs = 44100
    length_seconds = 6
    length_samples = fs * length_seconds
    Q = 3

    # We have a separate center frequency for each sample
    center_frequency = np.geomspace(100, 16000, length_samples)

    # The input signal
    noise = np.random.default_rng().uniform(-1, 1, (length_samples,))
    
    # Actual filtering
    bandstop_filtered_noise = bandstop_bandpass_filter(noise, Q, center_frequency, fs)
    bandpass_filtered_noise = bandstop_bandpass_filter(noise, Q, center_frequency, fs, 
                                                                        bandpass=True)
    
    # Make the audio files not too loud
    amplitude = 0.5
    bandstop_filtered_noise *= amplitude
    bandpass_filtered_noise *= amplitude
    
    # Apply the fade-in and the fade-out to avoid clicks
    bandstop_filtered_noise = apply_fade(bandstop_filtered_noise)
    bandpass_filtered_noise = apply_fade(bandpass_filtered_noise)
    
    # Write the output audio file
    sf.write('bandstop_filtered_noise.flac', bandstop_filtered_noise, fs)
    sf.write('bandpass_filtered_noise.flac', bandpass_filtered_noise, fs)


if __name__=='__main__':
    main()

Các ứng dụng

Ngoài việc chỉ lọc, bộ lọc thông dải và chặn dải có thể được sử dụng trong nhiều ứng dụng hiệu ứng âm thanh

Quét bộ lọc

Quét bộ lọc là một hiệu ứng rất mạnh có thể tạo thêm nét mạnh mẽ cho âm thanh. Đó chính xác là hiệu ứng mà bạn đã nghe thấy trong ví dụ về bộ lọc dải chặn

“Nghe” một dải tần (Trong phần bổ sung âm thanh)

Các plugin âm thanh sử dụng thông tin từ dải tần để kiểm soát hành vi của chúng thường có chức năng “nghe” cho phép bạn nghe dải tần bạn đã chỉ định và điều chỉnh nó

Ví dụ: plugin Tonmann Deesser có nút “nghe” để có thể nghe được dải tần đang được nén. Với chức năng “nghe”, chúng ta có thể tìm thấy phạm vi âm thanh dễ nghe nhất với phụ âm “s” để nén và tránh nén tín hiệu mong muốn

Python bộ lọc thông dải hẹp
Hình 10. Plugin Tonmann Deesser có chức năng “nghe”

Ngoài ra, có thể sử dụng “lắng nghe” để chỉ tập trung vào một phần của quang phổ trong khi thực hiện các chỉnh sửa

phaser

Ví dụ, nếu chúng ta điều chỉnh tần số trung tâm của bộ lọc dải tần theo thời gian, bằng cách sử dụng bộ tạo dao động tần số thấp (LFO), chúng ta có thể dễ dàng thu được hiệu ứng phaser

Tốt hơn nữa, nếu chúng ta có một loạt các bộ lọc bandstop, hiệu ứng sẽ thực sự tuyệt vời. Hãy nghĩ mức độ Phun trào của Van Halen thật tuyệt vời

Ứng dụng thực tế của hiệu ứng phaser sẽ là chủ đề của một bài viết khác nhưng bạn đã có thể thử nghiệm với mã triển khai đính kèm

Bản tóm tắt

Trong bài viết này, chúng ta đã tìm hiểu cách triển khai các bộ lọc thông dải và chặn dải hiệu quả, có thể kiểm soát theo thời gian thực bằng cách sử dụng bộ lọc thông tất bậc hai

Bộ lọc thông dải và chặn dải là một trong những hiệu ứng cơ bản trong kho vũ khí của người lập trình âm thanh. Nếu bạn muốn biết những yếu tố nào tạo nên hộp công cụ dành cho nhà phát triển plugin âm thanh, hãy xem danh sách kiểm tra dành cho nhà phát triển plugin âm thanh miễn phí của tôi