python计算短时自相关函数 音频信号_Tensorflow 2.0 信号处理
Tensorflow 2 信号处理
官方文档太简洁,因此有此文。
Tensorflow 2 Signal Processing API: https://www.tensorflow.org/api_docs/python/tf/signal
参考:https://www.tensorflow.org/versions/r1.10/api_guides/python/contrib.signal
tf.signal是用于信号处理原语的模块。所有操作都具有GPU支持并且可以微分。尽管该技术在许多领域都非常有用,但该模型对于构建可处理或生成音频的TensorFlow模型特别有用。
import tensorflow as tfimport matplotlib.pyplot as pltimport numpy as npimport soundfile as sfimport librosaWAV_FILE = './data/diarizationExample_sr16k_ac2_10s.wav'# 默认返回单声道x, fs = librosa.load(WAV_FILE, dtype=np.float32, sr=16000)plt.figure()plt.plot(x)plt.show()

构建(Frame)可变长序列
但处理可变长度的信号(比如音频)时,通常将它们分帧为多个固定长度的窗口(windows)。如果帧的步长小于帧的长度,则这些窗口会重叠。tf.signal.frame就是这么做的。
# signals = tf.compat.v1.placeholder(tf.float32, [None, 9152]) # 这是TensorFlow 1.x的静态图方式signals = [x]# frame_length与frame_step的单位为样本数(samples)# tf.signal.frame返回:[..., frames, frame_length, ...]# 本例中返回的是:[1, frames, frame_length]frames = tf.signal.frame(signals, frame_length=256, frame_step=64)# 生成幅度谱图magnitude_spectrograms = tf.abs(tf.signal.rfft(frames, fft_length=[256]))image = tf.expand_dims(magnitude_spectrograms, 3)plt.figure()plt.imshow(tf.transpose(magnitude_spectrograms[0,:,:].numpy()), origin='lower')plt.show()

直接对音频数据进行stft(短时傅里叶变换)
# 返回的`magnitude_spectrograms`是形状为[batch_size, ?, 129]张量的频谱图magnitude_spectrograms = tf.abs(tf.signal.stft( pcm, frame_length=256, frame_step=64, fft_length=256))plt.figure()plt.imshow(tf.transpose(magnitude_spectrograms[0,:,:].numpy()), origin='lower')plt.show()

# `spectrogram_patches` is a [batch_size, ?, 64, 129] tensor containing a# variable number of [64, 129] spectrogram patches per batch item.spectrogram_patches = tf.signal.frame( magnitude_spectrograms, frame_length=64, frame_step=16, axis=1)
重建帧序列并应用渐缩(tapering)窗口
tf.signal.overlap_and_add可用于从帧序列中重建音频信号。例如,以下代码重建了前面示例中产生的信号。
# 从上文中生成的`frames`重建音频信号`signals`。# 但是,重建生成的`reconstructed_signals`其振幅比原音频`signals`高。reconstructed_signals = tf.signal.overlap_and_add(frames, frame_step=64)plt.figure()plt.plot(reconstructed_signals[0])plt.show()

请注意,由于上面示例的frame_step是frame_length的25%,最终生成的重建音频比原始信号具有更大的幅度。为了弥补这一点,我们可以使用渐缩(tapering)窗口函数。如果窗口函数满足给定帧长的常量重叠相加(Constant Overlap-Add, COLA)属性,则它将恢复原始信号。
tf.signal.hamming_window与tf.signal.hann_window都满足COLA属性,重叠率为75%。
frame_length = 256frame_step = 64windowed_frames = frames * tf.signal.hann_window(frame_length)reconstructed_signals = tf.signal.overlap_and_add( windowed_frames, frame_step)plt.figure()plt.plot(reconstructed_signals[0])plt.show()

计算频谱图(Spectrogram)
频谱图是信号的时频分解,表示随时间变化的频率内容。计算频谱图最常见的方法是采用短时傅立叶变换(Short-time Fourier Transform, STFT)的大小,tf.signal.stft使用方式如下:
# `stfts`是一个complex64张量,表示`signals`中每个信号的短时傅立叶变换。# 其形状为[batch_size,?,fft_unique_bins] # 其中fft_unique_bins = fft_length // 2 + 1 = 513。stfts = tf.signal.stft(signals, frame_length=1024, frame_step = 512, fft_length=1024)# 功率谱图是复值STFT的平方幅度。 # 形状为[batch_size,?,513]的float32张量。power_spectrograms = tf.math.real(stfts * tf.math.conj(stfts))# 能量谱/振幅谱图是复值STFT的大小。 # 形状为[batch_size,?,513]的float32张量。magnitude_spectrograms = tf.abs(stfts)plt.figure()plt.imshow(tf.transpose(power_spectrograms[0]), origin='lower')plt.show()

plt.figure()plt.imshow(tf.transpose(magnitude_spectrograms[0]), origin='lower')plt.show()

我们可以使用功率谱图或幅度谱图;每个都有其优点。请注意,如果使用对数压缩,则功率谱图和幅度谱图的相差为2倍。
对数压缩
通常的做法是将非线性压缩(例如对数或幂律压缩)应用于频谱图。这有助于在频谱图的低能和高能区域中平衡细节的重要性,这与人类的听觉灵敏度更加接近(对低频更敏感)。
使用对数压缩时,最好使用稳定偏移量,以避免由零的奇点引起的高动态范围。
log_offset = 1e-6log_magnitude_spectrograms = tf.math.log(magnitude_spectrograms + log_offset)plt.figure()plt.imshow(tf.transpose(log_magnitude_spectrograms[0]), origin='lower')plt.show()

计算对数梅尔频谱图
当使用音频的频谱表示法时,梅尔音阶(mel scale)是一种常见的频率维度重新加权法(reweighting ),这样,音频的维数较低,并且在听觉上(perceptually)更相关。
tf.signal.linear_to_mel_weight_matrix生成一个矩阵,可用于将频谱图转换为mel scale。
# 将线性标度、幅度谱图扭曲为mel标度。sample_rate = fsnum_spectrogram_bins = magnitude_spectrograms.shape[-1]lower_edge_hertz, upper_edge_hertz, num_mel_bins = 80.0, 7600.0, 64linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix( num_mel_bins, num_spectrogram_bins, sample_rate, lower_edge_hertz, upper_edge_hertz)mel_spectrograms = tf.tensordot( magnitude_spectrograms, linear_to_mel_weight_matrix, 1)mel_spectrograms.set_shape(magnitude_spectrograms.shape[:-1].concatenate( linear_to_mel_weight_matrix.shape[-1:]))plt.figure()plt.imshow(tf.transpose(mel_spectrograms[0]), origin='lower')plt.show()

如果需要,请压缩梅尔频谱图幅度。例如,可以使用对数压缩(如上一节所述)。
顺序很重要!重新加权频率后压缩频谱图幅值与先压缩频谱图幅值再重新加权是不同的。根据梅尔音阶的感知(perceptual)合理性,从线性音阶进行转换意味着对相邻频带之间的强度或能量求和,即应在对数压缩之前应用它。对数压缩值的加权求和等于取对数前值的乘积,这几乎是没有道理的。
log_offset = 1e-6log_mel_spectrograms = tf.math.log(mel_spectrograms + log_offset)plt.figure()plt.imshow(tf.transpose(log_mel_spectrograms[0]), origin='lower')plt.show()

计算梅尔频率倒谱系数(MFCC)
MFCC: Mel-Frequency Cepstral Coefficients. 调用tf.signal.mfccs_from_log_mel_spectrograms以从对数幅度频谱图、梅尔标度频谱图(如上例中计算)计算MFCC:
num_mfccs = 13# 只取前 `num_mfccs` 个MFCCs.mfccs = tf.signal.mfccs_from_log_mel_spectrograms( log_mel_spectrograms)[..., :num_mfccs]plt.figure()plt.imshow(tf.transpose(mfccs[0]), origin='lower')plt.show()

