语音信号的FFT变换+谱减法进行降噪

记录研一数字通信课设,课设题目"语音信号的FFT变换",要求:使用matlab,不直接调用内置函数。

一、思路:

1、生成几个示例信号,观察FFT变换

2、导入音频信号进行FFT变换

3、得出了FFT变换的结果是否能对实际生活提供帮助呢?比如是否能对语音信号进行降噪处理呢?------利用谱减法进行降噪处理

4、生成时域频域对比图,并播放降噪前后音频进行对比

二、基本原理和代码

1、FFT变换------Cooley-Tukey算法

关于该算法的博客有很多,都讲的很清楚。接下来我直接附上我PPT中梳理的步骤和对应的代码。

附上我觉的讲的很清楚的一个up主的视频:

14. 快速傅里叶变换原理_哔哩哔哩_bilibili

2、谱减法

谱减法基本原理-理论篇哔哩哔哩bilibili

语音增强--谱减法介绍及MATLAB实现_减谱法-CSDN博客

三、程序流程图

四、效果演示

结果分析:

时域波形对比:绿色的波形在噪声密集的地方,比蓝色的平滑一点。

频域对比图:高频区域的噪声杂波被大幅削弱,仅保留语音的 "有效频率成分"(如低频基频、中高频谐波),频谱更加干净。

五、谱减法关键代码

Matlab 复制代码
function [cleanSignal, noiseProfile] = spectralSubtraction(noisySignal, fs, varargin)
% 改进的通用谱减法降噪 - 适用于各种音频类型
% 输入:
%   noisySignal - 含噪声信号
%   fs - 采样率
%   varargin - 可选参数: 'NoiseEstimationTime', 'Alpha', 'Beta', 'Gamma'
% 输出:
%   cleanSignal - 降噪后信号
%   noiseProfile - 噪声谱估计

    % 默认参数 - 调整为更保守的值
    noiseEstimationTime = 0.3; % 增加噪声估计时间
    alpha = 1.5;  % 降低过减因子,避免过度抑制
    beta = 0.02;  % 增加谱下限,保留更多信号
    gamma = 0.8;  % 增加平滑因子,减少音乐噪声
    
    % 解析可选参数
    for i = 1:2:length(varargin)
        switch varargin{i}
            case 'NoiseEstimationTime'
                noiseEstimationTime = varargin{i+1};
            case 'Alpha'
                alpha = varargin{i+1};
            case 'Beta'
                beta = varargin{i+1};
            case 'Gamma'
                gamma = varargin{i+1};
        end
    end
    
    N = length(noisySignal);
    
    % 参数设置 - 根据信号长度自适应调整
    frameSize = min(1024, 2^nextpow2(N/8)); % 自适应帧大小
    overlap = 0.75;   % 增加重叠率,减少边界效应
    hopSize = round(frameSize * (1 - overlap));
    numFrames = floor((N - frameSize) / hopSize) + 1;
    
    % ==================1、噪声估计 - 使用多段平均==========================
    noiseStartSamples = min(round(noiseEstimationTime * fs), round(0.2 * N));
    if noiseStartSamples < frameSize
        noiseStartSamples = frameSize * 2;
    end
    % 选择多段噪声样本进行平均
    numNoiseSegments = 3;
    noisePower = 0;
    
    for seg = 1:numNoiseSegments  % 循环3次,处理每一段噪声
    % 4.1 计算当前段噪声的起始/结束采样点(均匀分割)
    startSample = round((seg-1) * noiseStartSamples / numNoiseSegments) + 1;
    endSample = min(startSample + noiseStartSamples - 1, N);
    % 4.2 提取当前段的噪声信号
    noiseSegment = noisySignal(startSample:endSample);
    % 4.3 仅处理长度≥帧长的噪声段(确保能提取1帧数据做FFT)
        if length(noiseSegment) >= frameSize
            % 4.4 从当前噪声段中提取1帧数据(长度=frameSize)
            noiseFFT = customFFT(noiseSegment(1:frameSize));

            % 4.5 计算当前段噪声的功率谱(幅度平方),并累积到noisePower
            noisePower = noisePower + abs(noiseFFT).^2;
        end
    end
    avgNoisePower = noisePower / numNoiseSegments;
    %================2、分帧加窗======================================
    % 初始化输出信号
    cleanSignal = zeros(N, 1);
    window = hann(frameSize); % 使用汉宁窗,减少频谱泄漏
    previousMagnitude = zeros(frameSize, 1);
    for i = 1:numFrames
        % 提取当前帧
        startIdx = (i-1) * hopSize + 1;
        endIdx = startIdx + frameSize - 1;
        if endIdx > N
            % 处理最后一帧
            frame = [noisySignal(startIdx:end); zeros(endIdx - N, 1)];
        else
            frame = noisySignal(startIdx:endIdx);
        end
        frame = frame .* window;
        %===================3、频域转换==========================
        % 计算当前帧的FFT
        frameFFT = customFFT(frame);   % 原理:时域→频域,转换为复数信号
        frameMagnitude = abs(frameFFT);% 原理:提取幅度谱(信号+噪声的能量分布)
        framePhase = angle(frameFFT);  % 原理:提取相位谱(保留,后续重构用) 
        %==================4、谱减===============================
        posteriorSNR = (frameMagnitude.^2) ./ (avgNoisePower + eps);     % 计算后验信噪比
        adaptiveAlpha = alpha ./ (1 + posteriorSNR);    % 自适应过减因子 - 高信噪比区域使用较小的alpha    
        smoothedMagnitude = gamma * frameMagnitude + (1 - gamma) * previousMagnitude;   % 频谱平滑(减少音乐噪声)
        previousMagnitude = frameMagnitude;      
        cleanMagnitude = sqrt(max(smoothedMagnitude.^2 - adaptiveAlpha .* avgNoisePower, ... 
                                 beta * avgNoisePower));
        %==================5、还原为时域信号======================
        cleanFrameFFT = cleanMagnitude .* exp(1i * framePhase);
        cleanFrame = real(customIFFT(cleanFrameFFT));
        % 重叠相加
        if endIdx > N
            actualEnd = N - startIdx + 1;
            cleanSignal(startIdx:end) = cleanSignal(startIdx:end) + cleanFrame(1:actualEnd);
        else
            cleanSignal(startIdx:endIdx) = cleanSignal(startIdx:endIdx) + cleanFrame;
        end
    end
    
    % 归一化输出 - 保持原始信号的动态范围
    originalMax = max(abs(noisySignal));
    cleanMax = max(abs(cleanSignal));
    
    if cleanMax > 0
        cleanSignal = cleanSignal / cleanMax * originalMax;
    else
        cleanSignal = noisySignal; % 如果降噪失败,返回原始信号
    end
    
    noiseProfile = sqrt(mean(avgNoisePower));
end
相关推荐
MatpyMaster4 个月前
Matlab数字信号处理——基于谱减法与LMS自适应滤波的语音增强系统设计与实现
语音增强·谱减法·lms自适应滤波
简简单单做算法2 年前
基于PSD-ML算法的语音增强算法matlab仿真
算法·matlab·psd-ml·语音增强