音频处理5_时频谱1

news2024/12/27 21:02:26

介绍 时频谱,mel谱, MFCC

1. 概念

  • magnitude(幅值)& amplitude(振幅):

振幅指时域信号的瞬时强度或波的高度,它表示信号的最大偏离平均值的程度。
对于一个正弦波信号,振幅是从波的中心线到波峰(或波谷)的距离。

幅值是频域信号的强度,是傅里叶变换后,频谱中每个频率分量的大小。
幅值可以看作是复数频谱的模,即实部和虚部的平方和的平方根。

1.1 时频谱

即Spectrogram,通过时域信号转换得到

代码样例 (librosa库自带小号音频):

y, sr = librosa.load(librosa.example('trumpet')) #  y.shape = (117601,)  sr = 22050

n_fft = 2048
hop_length = 512
D = librosa.stft(y, n_fft=n_fft, hop_length=hop_length)  #计算STFT D.shape = (1025, 230)  

S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max) # 计算幅值谱 S_db.shape = (1025, 230)

total_duration = len(y) / sr # 总时长
time_steps = np.arange(D.shape[1]) * hop_length / sr # 时间步长

librosa.display.specshow(S_db, sr=sr, hop_length=hop_length, x_axis='time', y_axis='linear') #  y_axis=‘log’

x 轴:

  • 总时长(秒) total_duration = len(y) / sr = 117601/ 22050 = 5.33 seconds
  • 时间帧数 frame = signal_length/ hop_length(向上取整) = 117601/512 = 230
  • 时间步长: time_steps = total_duration / frame = 0.23 sec

y 轴:

  • 线性最大频率(Hz) = sr / 2 = 22050 / 2 = 11025 (log会被压缩,并放大低频刻度)
  • 频率点 = n f f t / 2 + 1 = 2048 / 2 + 1 = 1025 n_{fft} / 2 + 1 = 2048 / 2 + 1 = 1025 nfft/2+1=2048/2+1=1025 (y轴内的刻度数量)
  • 频率分辨率 = sr / n f f t n_{fft} nfft = 22050 / 2048 = 10.766

如果是log对数刻度,低中频范围更宽

结果1(stft的能量谱D, y为复数矩阵的绝对值):
在这里插入图片描述

结果2(计算幅值转分贝, 即y轴是S_db):

需要librosa.amplitude_to_db, 即

dB = 20 l o g 10 a m p l i t u d e n p . m a x 20log_{10}\frac{amplitude}{np.max} 20log10np.maxamplitude

np.max表述输入信号的最大值,用于归一化
在这里插入图片描述

结果3(y轴由线性linear,改为对数log):
在这里插入图片描述

中低频在y轴内更宽 (0-512Hz占一半,512-8192Hz占另一半)

1.2 梅尔频谱

梅尔尺度是一种非线性频率尺度,更接近于人耳的听觉感知。具体步骤如下:

  • 频谱平滑:应用梅尔滤波器组对 STFT 结果进行加权和求和,以得到梅尔频谱。

  • 频率分辨率:梅尔滤波器在低频部分有较高的分辨率,在高频部分有较低的分辨率,符合人耳对不同频率的感知特性。

  • 鲁棒性:平滑处理去除了频谱中的微小波动和噪声,使得提取的特征更加稳定和可靠。

包含冗余信息,反映频率能量分布,符合人耳听觉感知, mel谱如下:

在这里插入图片描述

2. MFCC音频转换

梅尔频率倒谱系数(MFCC)用于语音识别和音频分类中的常用特征。计算 MFCC 包括:

  1. 对音频信号进行短时傅里叶变换(STFT),得到频谱。
  2. 应用梅尔滤波器组,将频谱转换为梅尔频谱。
  3. 取对数梅尔频谱,再离散余弦变换(DCT)得到MFCC。

相比mel丢失一些信息, 对非线性关系敏感,低维度,特征独立,传统模型适用性强

整合预处理和Mel谱的转换步骤:

  • 预加重滤波(Pre-Emphasis),
  • 音频切片 (Slide / Framing)
  • 窗口函数 (Window)
  • 傅里叶变换 (Filter Bank)
  • 离散余弦变换(DCT)
  • 均值归一化 (Normalize)

2.1预加重滤波

预加重是一种用于放大信号高频分量的计算。

  • 用于提高音频信噪比,增强主要信号成分的幅度,相对于噪声,主信号能量比例更高,从而提高信号的质量和清晰度,使信号更容易被检测和分析。

  • 若高频分量的幅度较低,会导致信号在频谱上看起来不均衡。通过对信号进行滤波或调整,可以增强高频分量的幅度,使其与低频分量更平衡,提高信号的频谱均衡性。

公式: y ( t ) = x ( t ) − α ⋅ x ( t − 1 ) , α = 0.97 y(t) =x(t)−\alpha⋅x(t−1), \alpha = 0.97 y(t)=x(t)αx(t1),α=0.97
在这里插入图片描述

y, sr = librosa.load(librosa.example('trumpet'))
y  = y[0:int(3.5 * sr)] # 取前3.5秒(之后没声音)
pre_emphasis = 0.97
y_preemphasized = np.append(y[0], y[1:] - pre_emphasis * y[:-1])

注:均值归一化可实现大部分预加重效果

2.2 音频切片

信号中的频率会随着时间而变化,因此,对整个信号进行傅立叶变换是没有意义的,会随着时间推移而丢失信号的频率。假设信号中的频率在很短的时间内是稳定的,对短时间的信号片段(帧)进行傅立叶变换,再通过连接相邻帧来获得信号的频率轮廓,可以得到良好的信号频率近似值。

在语音处理中,典型的帧大小通常在20毫秒(ms)到40ms之间,相邻帧之间有50%的重叠(+/-10%)。比较常见的设置是帧大小为25ms(frame_size = 0.025 sec = 25ms),帧间隔为10ms(15ms,frame_stride = 0.01 sec)。

  • trumpet的一个frame(这里除去重叠,约15ms)如图:
    在这里插入图片描述

  • 显示完整wave和frame如图:
    在这里插入图片描述

代码如下:

frame_size = 0.025
frame_stride = 0.01 # 10ms stide 帧移时间,非重叠部分。意味着frame之间间隔(重叠)有 25- 10 = 15ms

frame_length = frame_size * sample_rate  # seconds to samples
frame_step = frame_stride * sample_rate

signal_length = len(y_preemphasized) # 117601 个采样点
frame_length = int(round(frame_length)) # 每个frame 551个采样点,每个0.025秒
frame_step = int(round(frame_step)) # 帧移采样点部分,非重合部分为220个采样点,即10ms
num_frames = int(numpy.ceil(float(numpy.abs(signal_length - frame_length)) / frame_step))  # 533,Make sure that we have at least 1 frame


pad_signal_length = num_frames * frame_step + frame_length # 117260(没有覆盖全部杨本点) + 511 = 117811 
z = numpy.zeros((pad_signal_length - signal_length)) # 117811 - 117601 = 210 覆盖全部样本点需要额外210个点
pad_signal = numpy.append(y_preemphasized, z) # 填充210个点,保证覆盖全部样本点

indices = numpy.tile(numpy.arange(0, frame_length), (num_frames, 1)) + numpy.tile(numpy.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T
# frames的索引 [0, 550], [220, 770], [440, 990], [660,1210]…, [117040, 117590]

第一个frame前220( frame_stride * sample_rate)个点是独立的,即10ms不是重叠的;另外330即15ms是重叠的,

最后一个frame的后 pad_signal(210个点)是0填充的

剩下的frame都是前后重叠的

2.3 窗口函数

对每一帧应用一个窗口函数,这里应用hamming窗,类似正态分布的加权函数。

图中展示了200个样本(x轴),对应加权系数(y轴)的hamming函数:
在这里插入图片描述

代码如下:

# 生成200个样本的Hamming窗口
hamming_window = np.hamming(200) # frame_length = 200
# frames *= 0.54 - 0.46 * numpy.cos((2 * numpy.pi * n) / (frame_length - 1))  # Explicit Implementation **

# 归一化使得振幅为1
hamming_window /= np.max(hamming_window)

2.4 傅里叶变换

对每一帧进行快速傅里叶变换(Fast Fourier Transform,FFT), 更具体来说是离散傅里叶变换(DFT)的一种方法: 短时傅里叶变换(Short-Time Fourier-Transform, STFT),

这里的FFT函数为:

F F T ( x k ) = ∑ n = 0 N − 1 x k e − i 2 π N k ∗ n FFT(x_k) = \sum_{n=0}^{N-1} x_k e^{-i \frac{2\pi}{N} k*n} FFT(xk)=n=0N1xkeiN2πkn

这里的k是第k个frame,N是n_fft, 即一个frame所含的样本点(通常为256 or 512), 代码如下:

mag_frames = numpy.absolute(numpy.fft.rfft(frames, N)) # Magnitude of the FFT

之后计算功率谱:

pow_frames = ((1.0 / N) * ((mag_frames) ** 2)) # Power Spectrum

2.5 滤波器组(Filter Bank)

选择滤波器组的数量(通常是40个),并计算各个滤波器的频率。

滤波器组是一组三角形波,用于拟合声波

  • 为了迎合人的感知,滤波器在低频区域较密,在高频区域则较散
  • 每个滤波器是一个三角型频率波,线性下降至相邻滤波器的中心频率处时,响应为 0
  • 每个滤波器对一定频率范围内的频率成分有最大的灵敏度,而对超出该范围的频率成分灵敏度逐渐减小

如图展示 10个三角滤波器(num_mel = 10),为适应人类感知,低频密,且振幅高:
在这里插入图片描述

下图是另一种展示方式:
在这里插入图片描述

  • 滤波器组输出函数:

1. librosa.filters.mel

	librosa.filters.mel 是 Librosa 库中的一个函数,用于生成梅尔滤波器(Mel filter bank)。

梅尔滤波器是一组滤波器,用于将频谱转换为梅尔频谱,这是语音和音频信号处理中常用的一种表示方法。

2. 输入参数:

	sr (number [scalar]): 采样率。默认值为 22050。
	n_fft (int > 0 [scalar]): FFT 的大小。默认值为 2048。
	n_mels (int > 0 [scalar]): 梅尔滤波器的数量。默认值为 128。
	fmin (float >= 0 [scalar]): 最低频率(赫兹)。默认值为 0.0。
	fmax (float > 0 [scalar] or None): 最高频率(赫兹)。如果为 None,则使用 sr / 2.0。
	htk (bool): 如果为 True,使用 HTK 公式来计算梅尔频率。默认值为 False。
	norm (None or 'slaney'): 如果为 None,不进行归一化。如果为 'slaney',则归一化滤波器总和以满足 Slaney 的标准。默认值为 'slaney'。
	dtype (np.dtype): 输出数组的数据类型。默认值为 np.float32。

3. 返回值

	mel_basis :  shape=(n_mels, 1 + n_fft/2), 每一行代表一个梅尔滤波器。

2.6 Mel频谱

有了特定数量的梅尔组频率,转为对应的梅尔谱步骤如下

  • 转换频率轴:首先将频率轴从赫兹转换为 Mel 频率轴。

high_freq_mel = (2595 * numpy.log10(1 + (sample_rate / 2) / 700)) # Convert Hz to Mel

  • 定义滤波器中心频率:在 Mel 频率轴上等间隔划分40个点作为滤波器的中心频率。

mel_points = numpy.linspace(low_freq_mel, high_freq_mel, num_mel + 2)

  • 构建滤波器:将这些中心频率转换回赫兹,然后在赫兹频率轴上构建三角滤波器。

fbank,通过for循环完成三角滤波器设置

  • 应用滤波器:将三角滤波器应用于功率谱,以提取各个滤波器的频带能量。

filter_banks = numpy.dot(pow_frames, fbank.T)

整体代码如下:


num_mel = 40
low_freq_mel = 0
N = 512 # NFFT

frames = pad_signal[indices.astype(numpy.int32, copy=False)] # (533, 551)
frames *= numpy.hamming(frame_length)
mag_frames = numpy.absolute(numpy.fft.rfft(frames, N))  # Magnitude of the FFT (533, 257)
pow_frames = ((1.0 / N) * ((mag_frames) ** 2))  # Power Spectrum (533, 257)

high_freq_mel = (2595 * numpy.log10(1 + (sample_rate / 2) / 700))  # Convert Hz to Mel
mel_points = numpy.linspace(low_freq_mel, high_freq_mel, num_mel + 2)  # Equally spaced in Mel scale
hz_points = (700 * (10**(mel_points / 2595) - 1))  # Convert Mel to Hz
bin = numpy.floor((N + 1) * hz_points / sample_rate)

fbank = numpy.zeros((num_mel, int(numpy.floor(N / 2 + 1)))) # (num_mel, N /2 + 1)
for m in range(1, num_mel + 1):   # 依次制作不同频率的三角滤波器
    f_m_minus = int(bin[m - 1])   # left
    f_m = int(bin[m])             # center
    f_m_plus = int(bin[m + 1])    # right

    for k in range(f_m_minus, f_m):
        fbank[m - 1, k] = (k - bin[m - 1]) / (bin[m] - bin[m - 1])
    for k in range(f_m, f_m_plus):
        fbank[m - 1, k] = (bin[m + 1] - k) / (bin[m + 1] - bin[m])

filter_banks = numpy.dot(pow_frames, fbank.T) # (533,257) x (257, num_mel) = (533, 257)
filter_banks = numpy.where(filter_banks == 0, numpy.finfo(float).eps, filter_banks)  # 替换0值,方便转db
filter_banks = 20 * numpy.log10(filter_banks)  # 通过log将梅尔组各个三角频率的能量值转换为分贝(dB)
  • filter_banks可视化:
    在这里插入图片描述

  • 均值归一化 (Normalize)

filter_banks -= (numpy.mean(filter_banks, axis=0) + 1e-8)

代码就一行,用于提升信噪比效果, 这里看不出太大区别
在这里插入图片描述

2.7 离散余弦变换(DCT)

mel谱的滤波组内,各滤波器相关性强,即存在冗余。

离散余弦变换(DCT)是将滤波器组的信号转换为不同频率的余弦函数,均匀各频率的信息分布,降低相关性。

DCT变换后能量更紧凑,通常集中在前面几个离散系数中,即mel频率倒谱系数(MFCCs)。

  • MFCCs的倒谱系数

对于语音识别,通常保留第2-13个倒谱系数。

第0个系数代表整体信息,无法区分音素。

第1个系数代表低频信息,通常是噪声。

第2-13个倒谱系数:包含音素的重要特征。

第14个以上:捕捉细节和滤波器的快速变化,受噪音和瞬变影响较大,贡献小。

0-12的MFCCs系数可视化:
在这里插入图片描述

代码:

from scipy.fftpack import dct  # Apply DCT to the filter banks
num_ceps = 12
mfcc = dct(filter_banks, type=2, axis=1, norm='ortho')[:, 1:(num_ceps + 1)]
  • 正弦提升

以弱化更高的 MFCC,提高噪声信号中的语音识别能力。

效果如图:
在这里插入图片描述

代码如下,这里cep_lifter用于控制提升程度

cep_lifter = 22 # 22-27
(nframes, ncoeff) = mfcc.shape
n = numpy.arange(ncoeff)
lift = 1 + (cep_lifter / 2) * numpy.sin(numpy.pi * n / cep_lifter)
mfcc *= lift  

Reference

  • https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html
  • https://github.com/disanda/d_code/tree/master/3.Audio/5_mel_num

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

根据RTL图编写Verilog程序

目录 描述 输入描述: 输出描述: 参考代码 描述 根据以下RTL图,使用 Verilog HDL语言编写代码,实现相同的功能,并编写testbench验证功能。 输入描述: clk:系统时钟信号 rst_n:…

第11章 规划过程组(二)(11.9估算活动持续时间)

第11章 规划过程组(二)11.9估算活动持续时间,在第三版教材第393~395页;文字图片音频方式 第一个知识点:主要工具与技术 1、类比估算 是一种使用相似活动或项目的历史数据,来估算当前活动或项目的持续时间或…

【运维】Windows server 2022 开启 telnet 功能

控制面板》启动或关闭Windows 功能 仪表盘》添加角色和功能》功能》telnet客户端

使用Python+OpenCV实现姿态估计--20240705

姿态估计使用Opencv+Mediapipe来时实现 什么是Mediapipe? Mediapipe是主要用于构建多模式音频,视频或任何时间序列数据的框架。借助MediaPipe框架,可以构建令人印象深刻的ML管道,例如TensorFlow,TFLite等推理模型以及媒体处理功能。 安装命令: pip install mediapipe如果…

回顾 DTC 2024 大会——聚焦数据技术创新:揭秘下一代纯实时搜索引擎 INFINI Pizza

2024 年 4 月 12 日至 13 日,备受瞩目的第十三届“数据技术嘉年华”(DTC2024)在北京新云南皇冠假日酒店盛大开幕。本次大会由中国 DBA 联盟(ACDU)与墨天轮社区联合主办,以“智能云原生一体化——DB 与 AI 协…

通过IDEA生成webapp及web.xml配置文件

1、选择File->Project Structure 2、选择Modules-> + -> Web 有的springboot工程选择是war工程,这个web可能已经存在了。 如果不存在,就手动创建,创建后,需要修改pom.xml中的配置 <packaging>war</packaging> 3、创建webapp根目录 这步重点就是创建…

Camera Raw:编辑 - 配置文件

Camera Raw “编辑”模块中的配置文件 Profile面板为照片编辑提供了一个坚实的基础&#xff0c;能够显著改善照片的初始外观&#xff0c;使编辑过程更加高效和灵活。 使用配置文件&#xff0c;可以控制如何呈现照片中的颜色和色调。配置文件旨在作为照片编辑的起点和基础。 ◆ …

在BI软件上使用SQL查询其实很简单

如何在BI软件上使用SQL查询&#xff1f; 我理解在BI上使用SQL是对原始数据进行查询、筛选、清洗&#xff0c;这一点主流BI工具像power BI&#xff0c;tableau、superset都可以支持。 你只需要写好SQL代码&#xff0c;对数据里的相关表进行查询&#xff0c;就可以对查询后的新…

C++ | Leetcode C++题解之第221题最大正方形

题目&#xff1a; 题解&#xff1a; class Solution { public:int maximalSquare(vector<vector<char>>& matrix) {if (matrix.size() 0 || matrix[0].size() 0) {return 0;}int maxSide 0;int rows matrix.size(), columns matrix[0].size();vector<…

warning: GOPATH set to GOROOT (D:\go) has no effect

warning: GOPATH set to GOROOT (D:\go) has no effect gopath 设置一下&#xff0c;并且不要和 goroot 设置成同一个目录

学习笔记——动态路由——OSPF(特殊区域)

十、OSPF特殊区域 1、技术背景 早期路由器靠CPU计算转发&#xff0c;由于硬件技术限制问题&#xff0c;因此资源不是特别充足&#xff0c;因此是要节省资源使用&#xff0c;规划是非常必要的。 OSPF路由器需要同时维护域内路由、域间路由、外部路由信息数据库。当网络规模不…

Vue3中为Ant Design Vue中Modal.confirm自定义内容

在一次业务开发时代码时&#xff0c;碰到了一种既想要Modal.confirm样式&#xff0c;又想要定制其content内容的情况。 大部分情况下&#xff0c;使用Modal.method()这种方式时&#xff0c;可能content内容固定都是字符串&#xff0c;那如果想要做更高级的交互怎么办&#xff…

RTK_ROS_导航(1): GNSS里程计

目录 1. RTK 配置2. ROS驱动3. RTK融合IMU实现里程计4. 纯RTK的定位信息5. 即将实现导航&#xff0c;正在更新中&#xff0c;如果遇到问题&#xff0c;欢迎CSDN讨论... 1. RTK 配置 4G CORS 4G 网络 户外有信号&#xff0c;不能实现RTK&#xff0c;就恢复出厂设置输出报文信…

kafka底层原理性能优化详解:大案例解析(第29天)

系列文章目录 一、Kafka简介 二、Kafka架构设计 三、消息传递机制 四、实例说明&#xff08;案例解析&#xff09; 五、kafka性能优化(案例解析) 文章目录 系列文章目录前言一、Kafka简介二、Kafka架构设计1. Producer&#xff08;生产者&#xff09;&#xff1a;2. Broker&am…

Check if a fine-tuned OpenAI model was successfully deleted

题意&#xff1a;检查微调后的OpenAI模型是否已成功删除 问题背景&#xff1a; I am doing some work with the OpenAI API with Python. Im working with fine-tuning and I am working on deleting an existing model and starting over again. I want to be able to check …

Hive 高可用分布式部署详细步骤

目录 系统版本说明 hive安装包下载及解压 上传mysql-connector-java的jar包 配置环境变量 进入conf配置文件中&#xff0c;将文件重命名 在hadoop集群上创建文件夹 创建本地目录 修改hive-site.xml文件 同步到其他的节点服务器 修改node02中的配置 hive-site.xml 修改…

上海-LM科技(面经)

上海-LM科技 hr电话面 个人简介 个人信息的询问 是否知道芋道框架 技术面 算法题 14. 最长公共前缀&#xff08;写出来即可&#xff09; 聊一下Docker Docker核心概念总结Docker实战 聊一下AOP Spring AOP详解 聊一下JWT JWT 基础概念详解JWT 身份认证优缺点分析 Spring…

【C++】类和对象(中)--下篇

个人主页~ 类和对象上 类和对象中-上篇 类和对象 五、赋值运算符重载1、运算符重载2、赋值运算符重载3、前置和后置重载 六、const成员七、日期类的实现Date.hDate.cpptest.cpptest1测试结果test2测试结果test3测试结果test4测试结果test5测试结果test6测试结果test7测试结果 八…

【Dison夏令营 Day 12】如何用 Python 构建数独游戏

通过本综合教程&#xff0c;学习如何使用 Pygame 在 Python 中创建自己的数独游戏。本指南涵盖安装、游戏逻辑、用户界面和计时器功能&#xff0c;是希望创建功能性和可扩展性数独益智游戏的爱好者的理想之选。 数独是一种经典的数字谜题&#xff0c;多年来一直吸引着谜题爱好…

【Elasticsearch】Elasticsearch倒排索引详解

文章目录 &#x1f4d1;引言一、倒排索引简介二、倒排索引的基本结构三、Elasticsearch中的倒排索引3.1 索引和文档3.2 创建倒排索引3.3 倒排索引的存储结构3.4 词典和倒排列表的优化 四、倒排索引的查询过程4.1 过程4.2 示例 五、倒排索引的优缺点5.1 优点5.2 缺点 六、倒排索…