• python实现语音信号处理常用度量方法


    信噪比(SNR)

    有用信号功率与噪声功率的比(此处功率为平均功率),也等于幅度比的平方

    $$SNR(dB)=10log_{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)=10log_{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
    def compute_snr(labels, loss):
        sqrn_l2_norm = tf.sqrt(tf.reduce_mean(labels ** 2, axis=[1, 2]))
        snr = 20 * tf.log(sqrn_l2_norm / loss + 1e-8) / tf.log(10.)
        avg_snr = tf.reduce_mean(snr, axis=0)
        return avg_snr
    tensorflow版本

    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):
            pad_width = ref_wav.shape[0] - in_wav.shape[0]
            in_wav = np.pad(in_wav, (0, pad_width), 'constant')
        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}})=10log_{10}frac{MAX[s(n)]^2}{d^2(n)}$$

    $$SNR(dB)=10log_{10}frac{MAX[s(n)]^2}{frac{1}{N}sum_{n=0}^{N-1}[x(n)-s(n)]^2}=20log_{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 Softwaresource
    2. gcc -o PESQ *.c

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

    使用方式为:

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

    对数谱距离(Log Spectral Distance)

    对数谱距离Log Spectral Distance是两个频谱之间的距离度量(用分贝表示)。两个频谱$P(W)$和$hat{P}(w)$之间的对数谱距离被定义为:

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

    其中,$p(w)$和$hat{P}(w)$是功率谱。对数谱距离是时多对称的。

    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

    参考文献:

    非典型废言的CSDN博客

    视频质量度量指标

  • 相关阅读:
    linux kgdb 补丁
    linux kdb 内核调试器
    linux 使用 gdb
    linux 系统挂起
    linux oops 消息
    linux strace 命令
    linux ioctl 方法
    linux seq_file 接口
    [数据结构] 迷宫问题(栈和队列,深搜和广搜)
    简化浏览器地址栏訪问路径
  • 原文地址:https://www.cnblogs.com/LXP-Never/p/11071911.html
Copyright © 2020-2023  润新知