语音识别--光谱门控降噪

⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计7267字,阅读大概需要3分钟
🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号:不懂开发的程序猿
个人网站:https://jerry-jy.co/

❗❗❗知识付费,🈲止白嫖,有需要请后台私信或【文末】个人微信公众号联系我

语音识别--光谱门控降噪

  • 光谱门控降噪
    • 一、任务需求
    • 二、任务目标
          • 1、在噪声音频剪辑上计算 FFT
          • 2、通过噪声的 FFT 计算频率数据
          • 3、根据噪声的统计数据(以及算法的所需灵敏度)计算阈值
          • 4、对信号计算 FFT
          • 5、通过将信号 FFT 与阈值进行比较来确定掩膜
          • 6、使用滤波器在频率和时间上平滑掩膜
          • 7、掩码应用于信号的 FFT,并反转
    • 三、任务环境
          • 1、jupyter开发环境
          • 2、python3.6
          • 3、tensorflow2.4
    • 四、任务实施过程
      • 加载工具
      • 1、加载数据
      • 2、添加噪音
      • 3、去噪
    • 五、任务小结
  • 说明

光谱门控降噪


一、任务需求

本降噪方法使用了audacity的降噪方法

该降噪方法使用 Python 实现,可以降低语音、生物声学和生理信号等时域信号中的噪声。它依赖于一种称为“频谱门控”的方法,这是一种噪声门控方法。它的工作原理是计算信号(以及可选的噪声信号)的频谱图并估计该信号/噪声的每个频带的噪声阈值(或门)。该阈值用于计算掩码,该掩码将噪声选入频率变化阈值以下。

本方法要求两个输入:

原型噪声音频
要去除的信号

要求:使用audacity的降噪方法对音频进行降噪

二、任务目标

1、在噪声音频剪辑上计算 FFT
2、通过噪声的 FFT 计算频率数据
3、根据噪声的统计数据(以及算法的所需灵敏度)计算阈值
4、对信号计算 FFT
5、通过将信号 FFT 与阈值进行比较来确定掩膜
6、使用滤波器在频率和时间上平滑掩膜
7、掩码应用于信号的 FFT,并反转

三、任务环境

1、jupyter开发环境
2、python3.6
3、tensorflow2.4

四、任务实施过程

实验步骤

  1. 在噪声音频剪辑上计算 FFT
  2. 通过噪声的 FFT 计算频率数据
  3. 根据噪声的统计数据(以及算法的所需灵敏度)计算阈值
  4. 对信号计算 FFT
  5. 通过将信号 FFT 与阈值进行比较来确定掩码
  6. 使用过滤器在频率和时间上平滑蒙版
  7. 掩码应用于信号的 FFT,并反转

加载工具

import IPython
from scipy.io import wavfile
import scipy.signal
import numpy as np
import matplotlib.pyplot as plt
import librosa
%matplotlib inline

1、加载数据

原始语音内容如下:

"I know the human being and fish can coexist peacefully."
       – Saginaw, Michigan, September 29, 2000
wav_loc = "/home/jovyan/datas/fish.wav"
rate, data = wavfile.read(wav_loc)
data = data / 32768
IPython.display.Audio(data=data, rate=rate)
fig, ax = plt.subplots(figsize=(20,4))
ax.plot(data)

[<matplotlib.lines.Line2D at 0x7f564b8feb00>]

在这里插入图片描述
上图显示的是该语音对应的波形,横坐标是采样点

2、添加噪音

定义噪声生成器

  • 使用快速傅里叶变换生成噪声
  • 生成带限噪声
def fftnoise(f):
    f = np.array(f, dtype="complex")
    Np = (len(f) - 1) // 2
    phases = np.random.rand(Np) * 2 * np.pi
    phases = np.cos(phases) + 1j * np.sin(phases)
    f[1 : Np + 1] *= phases
    f[-1 : -1 - Np : -1] = np.conj(f[1 : Np + 1])
    return np.fft.ifft(f).real


def band_limited_noise(min_freq, max_freq, samples=1024, samplerate=1):
    freqs = np.abs(np.fft.fftfreq(samples, 1 / samplerate))
    f = np.zeros(samples)
    f[np.logical_and(freqs >= min_freq, freqs <= max_freq)] = 1
    return fftnoise(f)

生成噪声,并在原始音频上添加噪声

noise_len = 2 # 单位:秒
# 使用自定义函数生成噪声
noise = band_limited_noise(min_freq=4000, max_freq = 12000, samples=len(data), samplerate=rate)*30
# 将噪声裁剪成和原始音频同样长
noise_clip = noise[:rate*noise_len]
# 将噪声与原始音频叠加
audio_clip_band_limited = data+noise

演示添加噪声后的音频数据

fig, ax = plt.subplots(figsize=(20,4))
ax.plot(audio_clip_band_limited)
IPython.display.Audio(data=audio_clip_band_limited, rate=rate)

在这里插入图片描述
可以看到,添加噪声以后,声音的波形明显受到干扰,听起来也不够清楚。

3、去噪

自定义相关函数,用于降噪及演示降噪的过程

import time
from datetime import timedelta as td

# 短时傅立叶变换
def _stft(y, n_fft, hop_length, win_length):
    return librosa.stft(y=y, n_fft=n_fft, hop_length=hop_length, win_length=win_length)

# 逆短时傅立叶变换
def _istft(y, hop_length, win_length):
    return librosa.istft(y, hop_length, win_length)

# 将幅度谱图转换为 dB 标度的谱图。
def _amp_to_db(x):
    return librosa.core.amplitude_to_db(x, ref=1.0, amin=1e-20, top_db=80.0)

# 将 dB 标度的谱图转换为幅度谱图。
def _db_to_amp(x,):
    return librosa.core.db_to_amplitude(x, ref=1.0)

# 绘制频谱图
def plot_spectrogram(signal, title):
    fig, ax = plt.subplots(figsize=(20, 4))
    cax = ax.matshow(
        signal,
        origin="lower",
        aspect="auto",
        cmap=plt.cm.seismic,
        vmin=-1 * np.max(np.abs(signal)),
        vmax=np.max(np.abs(signal)),
    )
    fig.colorbar(cax)
    ax.set_title(title)
    plt.tight_layout()
    plt.show()

# 绘制统计量及滤波器
def plot_statistics_and_filter(
    mean_freq_noise, std_freq_noise, noise_thresh, smoothing_filter
):
    fig, ax = plt.subplots(ncols=2, figsize=(20, 4))
    plt_mean, = ax[0].plot(mean_freq_noise, label="Mean power of noise")
    plt_std, = ax[0].plot(std_freq_noise, label="Std. power of noise")
    plt_std, = ax[0].plot(noise_thresh, label="Noise threshold (by frequency)")
    ax[0].set_title("Threshold for mask")
    ax[0].legend()
    cax = ax[1].matshow(smoothing_filter, origin="lower")
    fig.colorbar(cax)
    ax[1].set_title("Filter for smoothing Mask")
    plt.show()

# 定义降噪函数
def removeNoise(
    audio_clip,
    noise_clip,
    n_grad_freq=2,
    n_grad_time=4,
    n_fft=2048,
    win_length=2048,
    hop_length=512,
    n_std_thresh=1.5,
    prop_decrease=1.0,
    verbose=False,
    visual=False,
):
    """根据仅包含噪声的剪辑从音频中去除噪声

    参数:
        audio_clip(数组):第一个参数。
        noise_clip(数组):第二个参数。
        n_grad_freq (int):使用掩码平滑处理多少个频率通道。
        n_grad_time (int):用掩码平滑的时间通道数。
        n_fft (int):STFT 列之间的帧数。
        win_length (int): 每帧音频都被 window() 窗口化。窗口的长度为“win_length”,然后用零填充以匹配“n_fft”。
        hop_length (int):STFT 列之间的帧数。
        n_std_thresh (int):比噪声的平均 dB(在每个频率级别)大多少个标准偏差被视为信号
        prop_decrease (float): 你应该在多大程度上减少噪音(1 = 全部,0 = 无)
        visual (bool): 是否绘制算法的步骤

    返回:
        数组:减去噪声的恢复信号

    """
    if verbose:
        start = time.time()
    # 对噪声应用短时傅里叶变换
    noise_stft = _stft(noise_clip, n_fft, hop_length, win_length)
    noise_stft_db = _amp_to_db(np.abs(noise_stft))  # 转换为dB频谱
    # 对噪声计算均值、标准差统计量
    mean_freq_noise = np.mean(noise_stft_db, axis=1)
    std_freq_noise = np.std(noise_stft_db, axis=1)
    noise_thresh = mean_freq_noise + std_freq_noise * n_std_thresh
    if verbose:
        print("STFT on noise:", td(seconds=time.time() - start))
        start = time.time()
    # 对信号应用短时傅里叶变换
    if verbose:
        start = time.time()
    sig_stft = _stft(audio_clip, n_fft, hop_length, win_length)
    sig_stft_db = _amp_to_db(np.abs(sig_stft))
    if verbose:
        print("STFT on signal:", td(seconds=time.time() - start))
        start = time.time()
    # 计算dB频谱掩码
    mask_gain_dB = np.min(_amp_to_db(np.abs(sig_stft)))
    print(noise_thresh, mask_gain_dB)

    # 在时间和频率上为掩码创建平滑过滤器
    smoothing_filter = np.outer(
        np.concatenate(
            [
                np.linspace(0, 1, n_grad_freq + 1, endpoint=False),
                np.linspace(1, 0, n_grad_freq + 2),
            ]
        )[1:-1],
        np.concatenate(
            [
                np.linspace(0, 1, n_grad_time + 1, endpoint=False),
                np.linspace(1, 0, n_grad_time + 2),
            ]
        )[1:-1],
    )
    smoothing_filter = smoothing_filter / np.sum(smoothing_filter)
    # 计算每个频率/时间窗的阈值
    db_thresh = np.repeat(
        np.reshape(noise_thresh, [1, len(mean_freq_noise)]),
        np.shape(sig_stft_db)[1],
        axis=0,
    ).T
    # 如果信号高于阈值则屏蔽
    sig_mask = sig_stft_db < db_thresh
    if verbose:
        print("Masking:", td(seconds=time.time() - start))
        start = time.time()
    # 使用平滑滤波器对掩码进行卷积
    sig_mask = scipy.signal.fftconvolve(sig_mask, smoothing_filter, mode="same")
    sig_mask = sig_mask * prop_decrease
    if verbose:
        print("Mask convolution:", td(seconds=time.time() - start))
        start = time.time()
    # 对信号应用掩码
    sig_stft_db_masked = (
        sig_stft_db * (1 - sig_mask)
        + np.ones(np.shape(mask_gain_dB)) * mask_gain_dB * sig_mask
    )  # 对真实值进行掩码
    sig_imag_masked = np.imag(sig_stft) * (1 - sig_mask)
    sig_stft_amp = (_db_to_amp(sig_stft_db_masked) * np.sign(sig_stft)) + (
        1j * sig_imag_masked
    )
    if verbose:
        print("Mask application:", td(seconds=time.time() - start))
        start = time.time()
    # 修复信号
    recovered_signal = _istft(sig_stft_amp, hop_length, win_length)
    recovered_spec = _amp_to_db(
        np.abs(_stft(recovered_signal, n_fft, hop_length, win_length))
    )
    if verbose:
        print("Signal recovery:", td(seconds=time.time() - start))
    if visual:
        plot_spectrogram(noise_stft_db, title="Noise")
    if visual:
        plot_statistics_and_filter(
            mean_freq_noise, std_freq_noise, noise_thresh, smoothing_filter
        )
    if visual:
        plot_spectrogram(sig_stft_db, title="Signal")
    if visual:
        plot_spectrogram(sig_mask, title="Mask applied")
    if visual:
        plot_spectrogram(sig_stft_db_masked, title="Masked signal")
    if visual:
        plot_spectrogram(recovered_spec, title="Recovered spectrogram")
    return recovered_signal

output = removeNoise(audio_clip=audio_clip_band_limited, noise_clip=noise_clip,verbose=True,visual=True)

上图依次为我们演示了:

  • 噪声的频谱图
  • 计算的掩膜的阈值
  • 用于平滑掩膜的滤波器
  • 原始信号对应的频谱图
  • 计算得到的掩膜频谱图
  • 经过掩膜处理的信号频谱图
  • 经过恢复后的声音信号频谱图

最后我们观察一下降噪以后得到的声音结果

fig, ax = plt.subplots(nrows=1,ncols=1, figsize=(20,4))
plt.plot(output, color='black')
ax.set_xlim((0, len(output)))
plt.show()
# 播放声音样本
IPython.display.Audio(data=output, rate=44100)

在这里插入图片描述

五、任务小结

本实验完成光谱门控降噪方法对声音进行降噪处理。通过本实验我们学习到了光谱门控降噪的相关知识,需要掌握以下知识点:

  • 通过噪声的傅里叶变换计算得到噪声相关特征
  • 通过对信号计算傅里叶变换,确定阈值,从而确定掩膜/掩码
  • 对声音掩膜应用滤波器,实现降噪

–end–

说明

本实验(项目)/论文若有需要,请后台私信或【文末】个人微信公众号联系我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/599265.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis 使用记录

redis 使用记录 下载运行配置文件启动 参考 下载 github: Redis for Windows 或者从百度网盘下载 Redis version 3.2.100 链接: https://pan.baidu.com/s/1kxNOuZFunvVhVy1cfQzCDA?pwdpibh 运行 双击运行 运行效果 如果出错&#xff1a;查看是否项目路径是否包含中文 配…

矩阵快速幂

要想知道矩阵快速幂&#xff0c;我们先了解一下什么叫快速幂和矩阵乘法 一、快速幂 快速幂算法是用来快速计算指数表达式的值的&#xff0c;例如 210000000,普通的计算方法 2*2*2*2…10000000次&#xff0c;如果一个数字的计算都要计算那么多次的话&#xff0c;那么这个程序一…

Windows10系统中CANoe字体异常问题解决办法

Windows10系统中CANoe/CANalyzer字体异常问题解决办法 一、问题: 在Windows10中文系统中,CANoe/CANalyzer的一些窗口会显示异常的字体,大部分其他窗口的字体却是正常的? 异常的字体如下: 二、问题说明 CANoe/CANalyzer的开发过程中使用了多种对话框技术。一些对话框使…

SparkSQL与Hive整合 、SparkSQL函数操作

SparkSQL与Hive整合 SparkSQL和Hive的整合&#xff0c;是一种比较常见的关联处理方式&#xff0c;SparkSQL加载Hive中的数据进行业务处理&#xff0c;同时将计算结果落地回Hive中。 整合需要注意的地方 1)需要引入hive的hive-site.xml&#xff0c;添加classpath目录下面即可…

循环链表 -- c语言实现

#pragma once // 带头双向循环链表增删查改实现 #include<stdlib.h> #include<stdio.h> #include<assert.h>typedef int LTDataType;typedef struct ListNode {LTDataType data;struct ListNode* next;struct ListNode* prev; }ListNode;//双链表申请一个新节…

吴恩达深度学习笔记:深度学习的 实践层面 (Practical aspects of Deep Learning)1.13-1.14

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第一周&#xff1a;深度学习的 实践层面 (Practical aspects of Deep Learning)1.13 梯度检验&#…

图片批量旋转方向怎么弄的?有没有一键批量旋转图片到一定角度的方法

我们在处理很多张图片的时候&#xff0c;有时候需要批量的将这些图片旋转一个角度&#xff0c;比如说我们需要批量向右旋转 30 度&#xff0c;如果我们只需要调整一两张图片的话&#xff0c;我们使用 ps 就可以旋转我们的图片&#xff0c;但是如果我们有很多张图片都需要批量的…

排序算法之希尔排序(缩小增量排序)

希尔排序是插入排序的优化&#xff0c;如果不了解插入排序可以看排序算法之插入排序-CSDN博客这篇博客&#xff0c;希尔排序算法通过对原始数据集使用 gap 分组的方法&#xff0c;先将数据分组进行插入排序&#xff0c;随着排序的进行&#xff0c;逐渐减小 gap 的值&#xff0c…

代码随想录算法训练营DAY44|C++动态规划Part6|完全背包理论基础、518.零钱兑换II、377. 组合总和 Ⅳ

文章目录 完全背包理论基础完全背包问题的定义与01背包的核心区别为什么完全背包的循环顺序可以互换&#xff1f;CPP代码 ⭐️518.零钱兑换II思路CPP代码 ⭐️377. 组合总和 Ⅳ思路CPP代码 扩展题 完全背包理论基础 卡码网第52题 文章链接&#xff1a;完全背包理论基础 视频链接…

【C++】C++11--- 类的新功能

目录 类的新功能 默认成员函数 示例 类成员变量初始化 强制生成默认函数的关键字default 禁止生成默认函数的关键字delete 类的新功能 默认成员函数 构造函数析构函数拷贝构造函数拷贝赋值重载取地址重载const取地址重载 C11在原先的6个默认成员函数的基础上&#xff0c…

PHP基于vscode医院安全不良事件管理系统源码(AEMS)前端vue2+element+后端laravel8不良事件上报与闭环管理

PHP基于vscode医院安全不良事件管理系统源码&#xff08;AEMS&#xff09;前端vue2element后端laravel8不良事件上报与闭环管理 医院不良事件上报与管理系统结合现代医院管理思路&#xff0c;遵照PDCA全面质量循环管理方法而设计&#xff0c;并在多家大型三甲医院成熟运用。系统…

第29章-SR技术概述

1. SR技术的产生背景 2. SR技术的基本概念 3. SR技术的基本原理 1. SR技术的产生背景 1.1 传统的路由器设备因其转发性能较低 ① 最长匹配算法的缺点&#xff0c;需要遍历整个路由表&#xff1b; ② 早期路由器多采用通用CPU进行转发处理&#xff0c;性能有限&#xff1b; ③…

word:三线表的绘制【攻略】

word&#xff1a;三线表的绘制【攻略】 前言版权推荐word&#xff1a;三线表的绘制效果简单方法另外的方法 最后 前言 2024-5-7 18:25:08 以下内容源自《【攻略】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客…

Linux--基础IO(文件描述符fd)

目录 1.回顾一下文件 2.理解文件 下面就是系统调用的文件操作 文件描述符fd&#xff0c;fd的本质是什么&#xff1f; 读写文件与内核级缓存区的关系 据上理论我们就可以知道&#xff1a;open在干什么 3.理解Linux一切皆文件 4.C语言中的FILE* 1.回顾一下文件 先来段代码…

Upload-labs 靶场通关解析(上)

前言 文件上传漏洞是一种常见的网络安全漏洞&#xff0c;存在于许多Web应用程序中。攻击者利用这个漏洞可以上传恶意文件到目标服务器&#xff0c;从而执行各种恶意操作&#xff0c;如执行恶意代码、获取敏感信息、控制服务器等。 文件上传漏洞的原理是&#xff0c;Web应用程…

(✌)粤嵌—2024/5/7—除自身以外数组的乘积

代码实现&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* productExceptSelf(int *nums, int numsSize, int *returnSize) {// 左乘积int l[numsSize];l[0] 1;for (int i 1; i < numsSize; i) {l[i] l[i - 1] * nums[…

PyQt6--Python桌面开发(1.安装配置环境)

一.PyQt6简介 PyQt&#xff1a;PyQt是一个功能强大且成熟的GUI框架&#xff0c;基于Qt库。它提供了丰富的组件、布局和主题选项&#xff0c;以及强大的功能和灵活性。PyQt的优点是它具有现代化的外观和丰富的功能&#xff0c;适用于复杂的GUI应用程序。然而&#xff0c;由于Py…

VMware导入ova/ovf虚拟机文件

1.文件-打开-ova文件 2.为新虚拟机起名称 3.等待导入 4.导入完成&#xff0c;可以开始使用 参考链接&#xff1a;VMware导入ova/ovf虚拟机文件

数仓分层——ODS、DW、ADS

一、什么是数仓分层 数据仓库分层是一种组织和管理数据仓库的结构化方法&#xff0c;它将数据仓库划分为不同的层次或级别&#xff0c;每个层次具有特定的功能和目的。这种分层方法有助于管理数据仓库中的数据流程、数据处理和数据访问&#xff0c;并提供一种清晰的结构来支持…

ArrayList线程安全问题解决方案

jdk8 Stream API的出现大大简化了我们对于集合元素的处理代码&#xff0c;对于串行流来说&#xff0c;无需考虑线程安全问题&#xff1b;但是&#xff0c;对于并行流来说&#xff0c;由于它是以多线程的方式并行处理同一个集合中的数据元素的&#xff0c;因此&#xff0c;存在着…