# 信噪比(SNR)

$$SNR(dB)=10\log_{10}\frac{\sum_{n=0}^{N-1}s^2(n)}{\sum_{n=0}^{N-1}d^2(n)}=10*\log_{10}(\frac{P_{signal}}{P_{noise}})=20*log_{10}(\frac{A_{signal}}{A_{noise}})$$

$$SNR(dB)=10\log_{10}\frac{\sum_{n=0}^{N-1}s^2(n)}{\sum_{n=0}^{N-1}[x(n)-s(n)^2]}$$

$P_{signal}$为信号功率；$P_{noise}$为噪声功率；$A_{signal}$为信号幅度；$A_{noise}$为噪声幅度值，功率等于幅度值的平方

MATLAB版本代码

# 信号与噪声长度应该一样
function snr=SNR_singlech(Signal,Noise)

P_signal = sum(Signal-mean(Signal)).^2;     # 信号的能量
P_noise = sum(Noise-mean(Noise)).^2;     # 噪声的能量
snr = 10 * log10(P_signal/P_noise)
View Code

python代码

def numpy_SNR(origianl_waveform, target_waveform):
# 单位 dB
signal = np.sum(origianl_waveform ** 2)
noise = np.sum((origianl_waveform - target_waveform) ** 2)
snr = 10 * np.log10(signal / noise)
return snr

$$np.linalg.norm(x)=\sqrt{x_1^2+x_2^2+...+x_n^2}$$

def wav_snr(ref_wav, in_wav):# 如果ref wav稍长，则用0填充in_wav
if (abs(in_wav.shape[0] - ref_wav.shape[0]) < 10):
else:
print("错误：参考wav与输入wav的长度明显不同")
return -1

# 计算 SNR
norm_diff = np.square(np.linalg.norm(in_wav - ref_wav))
if (norm_diff == 0):
print("错误：参考wav与输入wav相同")
return -1

ref_norm = np.square(np.linalg.norm(ref_wav))
snr = 10 * np.log10(ref_norm / norm_diff)
return snr

# 峰值信噪比(PSNR)

$$SNR(dB)=10*\log _{10}(\frac{MAX(P_{signal})}{P_{noise}})=10\log_{10}\frac{MAX[s(n)]^2}{d^2(n)}$$

$$SNR(dB)=10\log_{10}\frac{MAX[s(n)]^2}{\frac{1}{N}\sum_{n=0}^{N-1}[x(n)-s(n)]^2}=20\log_{10}\frac{MAX[s(n)]}{\sqrt{MSE}}$$

import numpy as np

def psnr(ref_wav, in_wav):
MSE = numpy.mean((ref_wav - in_wav) ** 2)
MAX = np.max(ref_wav)       # 信号的最大平时功率
return 20 * np.log10(MAX / np.sqrt(MSE))

# 分段信噪比(SegSNR)

由于语音信号是一种缓慢变化的短时平稳信号，因而在不同时间段上的信噪比也应不一样。为了改善上面的问题，可以采用分段信噪比。分段信噪比即是先对语音进行分帧，然后对每一帧语音求信噪比，最好求均值。

MATLAB版本的代码

function [segSNR] = Evaluation(clean_speech,enhanced)

N = 25*16000/1000; %length of the segment in terms of samples
M = fix(size(clean_speech,1)/N); %number of segments
segSNR = zeros(size(enhanced));
for i = 1:size(enhanced,1)
for m = 0:M-1
sum1 =0;
sum2 =0;
for n = m*N +1 : m*N+N
sum1 = sum1 +clean_speech(n)^2;
sum2 = sum2 +(enhanced{i}(n) - clean_speech(n))^2;
end
r = 10*log10(sum1/sum2);
if r>55
r = 55;
elseif r < -10
r = -10;
end

segSNR(i) = segSNR(i) +r;
end
segSNR(i) = segSNR(i)/M;
end
View Code

python代码

def SegSNR(ref_wav, in_wav, windowsize, shift):
if len(ref_wav) == len(in_wav):
pass
else:
print('音频的长度不相等!')
minlenth = min(len(ref_wav), len(in_wav))
ref_wav = ref_wav[: minlenth]
in_wav = in_wav[: minlenth]
# 每帧语音中有重叠部分，除了重叠部分都是帧移，overlap=windowsize-shift
# num_frame = (len(ref_wav)-overlap) // shift
# num_frame = (len(ref_wav)-windowsize+shift) // shift
num_frame = (len(ref_wav) - windowsize) // shift + 1  # 计算帧的数量

SegSNR = np.zeros(num_frame)
# 计算每一帧的信噪比
for i in range(0, num_frame):

noise_frame_energy = np.sum(ref_wav[i * shift, i * shift+windowsize] ** 2)  # 每一帧噪声的功率
speech_frame_energy = np.sum(in_wav[i * shift, i * shift+windowsize] ** 2)  # 每一帧信号的功率
SegSNR[i] = np.log10(speech_frame_energy / noise_frame_energy)

return 10 * np.mean(SegSNR)

# 对数拟然对比度(log Likelihood Ratio Measure)

坂仓距离测度是通过语音信号的线性预测分析来实现的。ISD基于两组线性预测参数（分别从原纯净语音和处理过的语音的同步帧得到）之间的差异。LLR可以看成一种坂仓距离（Itakura Distance,IS）但是IS距离需要考虑模型增益。而LLR不需要考虑模型争议引起的幅度位移，更重视整体谱包络的相似度。

# PESQ

PESQ是用于语音质量评估的一种方法，ITU提供了C语言代码，下载请点击这里，但是在使用之前我们需要先编译C脚本，生成可执行文件exe

1. cd \Software\source
2. gcc -o PESQ *.c

经过编译，会在当前文件夹生成一个pesq.exe的可执行文件

1. 命令行进入pesq.exe所在的文件夹
2. 执行命令：pesq 采样率 "原始文件路径名" "劣化文件路径名”
3. 回车
4. 等待结果即可，值越大，质量越好。
• 例如：pesq +16000 raw.wav processed.wav

# 对数谱距离(Log Spectral Distance)

$$D_{LS}=\sqrt{\frac{1}{2\pi}\int_{-\pi}^{\pi}[10*\log _{10}\frac{P(w)}{\hat{P}(w)}]^2dw}$$

def numpy_LSD(origianl_waveform, target_waveform):
""" 比较原始和目标音频之间的对数谱距离（LSD），也称为对数谱失真，
是两个频谱之间的距离测量值（以dB表示） """

print("数据形状为", origianl_waveform.shape)
print("数据类型为", type(origianl_waveform))

original_spectrogram = librosa.core.stft(origianl_waveform, n_fft=2048)
target_spectrogram = librosa.core.stft(target_waveform, n_fft=2048)

original_log = np.log10(np.abs(original_spectrogram) ** 2)
target_log = np.log10(np.abs(target_spectrogram) ** 2)
original_target_squared = (original_log - target_log) ** 2
target_lsd = np.mean(np.sqrt(np.mean(original_target_squared, axis=0)))

return target_lsd

# 参考文献：

posted @ 2019-09-11 17:02  凌逆战  阅读(...)  评论(...编辑  收藏