fpga实现音频预加重(pre-emphasis)滤波器

文章来源:FPGA开源工作室

1.png

1. 预加重滤波器的作用

在语音信号中,声门波激励和口鼻辐射效应共同导致语音信号的高频分量能量要比低频分量弱。预加重(Pre-emphasis)的目的就是:
1 .提升高频分量,平衡语音频谱,使得高频特征更加明显,便于后续的特征提取(如MFCC)。
2.消除发声过程中口唇辐射的影响。
3.在一定程度上抑制工频干扰。

2. 预加重滤波器的使用场景

  1. 语音识别前端处理
    作用:这是预加重最经典和最重要的应用。
    平衡频谱:语音信号在产生过程中受到声门脉冲和口唇辐射的影响,天然具有大约-6dB/倍频程的高频衰减。预加重通过+6dB/倍频程的提升来补偿这种衰减,使频谱变得平坦。
    提升高频特征:清辅音(如/s/、/f/、/th/)包含重要的高频信息但能量较弱,预加重能增强这些关键特征,提高识别准确率。
    改善信噪比:在某种程度上抑制低频噪声干扰。

  2. 语音编码
    在CELP、ACELP等线性预测编码中,预加重使信号频谱平坦化,提高线性预测的准确性。
    减少量化误差,提高编码效率。

  3. 语音增强与降噪
    提升语音高频分量,使其在背景噪声中更加突出。
    配合后续的频谱减法等算法,获得更好的降噪效果。

  4. 音频录制与重放系统
    磁带录音系统(历史经典应用):
    录制时预加重:提升高频信号,克服磁带本底噪声(主要是高频噪声)。
    播放时去加重:衰减高频,恢复原始频率响应,同时降低高频噪声。
    标准预加重时间常数:50μs(FM广播)、75μs(Audio磁带)

  5. FM调频广播
    采用预加重(美国标准75μs)来改善广播信号的抗噪声性能。
    接收机使用对应的去加重网络。

2.png

3.  预加重滤波器的原理与传递函数

预加重通常被建模为一个一阶高通滤波器。它的作用是抑制低频,通过高频。
其数字滤波器的传递函数通常定义为:

3.png

4.png

4. matlab 实现

function[y, freq_response]= pre_emphasis_analysis(x, fs, alpha, plot_results)
% 完整的预加重分析与实现
% 输入:
%   x - 输入语音信号
%   fs - 采样频率
%   alpha - 预加重系数
%   plot_results - 是否绘制结果图表
% 输出:
%   y - 预加重后的信号
%   freq_response - 滤波器频率响应

if nargin <3
        alpha =0.97;
    end
if nargin <4
        plot_results =true;
    end

    % 预加重滤波
    y = filter([1, -alpha], 1, x);

    % 计算频率响应
[h, w]= freqz([1, -alpha], 1, 1024, fs);
    freq_response = abs(h);
    frequencies = w;

    % 绘制结果
if plot_results
        plot_preemphasis_results(x, y, frequencies, freq_response, fs, alpha);
    end
end


function plot_preemphasis_results(x, y, f, h, fs, alpha)
% 绘制预加重结果
    figure('Position', [100, 100, 1200, 800]);

    % 时域信号对比
    subplot(3, 2, 1);
    t =(0:length(x)-1) / fs;
    plot(t, x, 'b', 'LineWidth', 1);
    title('原始语音信号 (时域)');
    xlabel('时间 (s)');
    ylabel('幅度');
    grid on;

    subplot(3, 2, 2);
    plot(t, y, 'r', 'LineWidth', 1);
    title('预加重后信号 (时域)');
    xlabel('时间 (s)');
    ylabel('幅度');
    grid on;

    % 频域对比
    N = length(x);
    f_axis =(0:N-1) * fs / N;

    X = abs(fft(x));
    Y = abs(fft(y));

    subplot(3, 2, 3);
    plot(f_axis(1:N/2), X(1:N/2), 'b', 'LineWidth', 1.5);
    title('原始信号频谱');
    xlabel('频率 (Hz)');
    ylabel('幅度');
    grid on;

    subplot(3, 2, 4);
    plot(f_axis(1:N/2), Y(1:N/2), 'r', 'LineWidth', 1.5);
    title('预加重后频谱');
    xlabel('频率 (Hz)');
    ylabel('幅度');
    grid on;

    % 滤波器频率响应
    subplot(3, 2, 5);
    plot(f, 20*log10(h), 'g', 'LineWidth', 2);
    title('预加重滤波器频率响应');
    xlabel('频率 (Hz)');
    ylabel('增益 (dB)');
    grid on;

    % 频谱对比(重叠)
    subplot(3, 2, 6);
    plot(f_axis(1:N/2), X(1:N/2)/max(X), 'b--', 'LineWidth', 1, 'DisplayName', '原始');
    hold on;
    plot(f_axis(1:N/2), Y(1:N/2)/max(Y), 'r-', 'LineWidth', 1.5, 'DisplayName', '预加重');
    title('频谱对比 (归一化)');
    xlabel('频率 (Hz)');
    ylabel('归一化幅度');
    legend('show');
    grid on;

    sgtitle(sprintf('语音预加重分析 (α = %.2f)', alpha));
end

5.png

5. 预加重滤波器FPGA实现

6.png

module pre_emphasis(
    input wire clk,
    input wire rst_n,
    input wire signed[15:0] data_in,
    output reg signed[15:0] data_out
);

// 预加重系数 α = 0.97,Q1.15格式
parameter ALPHA =16'd31782;// 0.97 * 2^15

// 寄存器声明
reg signed[15:0] x_delay;// 延迟寄存器
reg signed[31:0] product_reg;// 乘法结果寄存器
reg signed[15:0] input_reg;// 输入寄存器

// 流水线处理
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
        input_reg <=16'sd0;
        x_delay <=16'sd0;
        product_reg <=32'sd0;
        data_out <=16'sd0;
    end else begin
// 第一级: 输入和延迟
        input_reg <= data_in;
        x_delay <= input_reg;// 注意: 这里使用input_reg而不是data_in

// 第二级: 乘法
        product_reg <= ALPHA * x_delay;

// 第三级: 减法和输出
        data_out <= input_reg - product_reg[30:15];// Q格式调整
    end
end

endmodule