语音信号处理常用度量方法

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。语音信号处理常用度量方法,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

信噪比(SNR)

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

S

N

R

(

d

B

)

=

10

log

10

n

=

0

N

1

s

2

(

n

)

n

=

0

N

1

d

2

(

n

)

=

10

log

10

(

P

s

i

g

n

a

l

P

n

o

i

s

e

)

=

20

l

o

g

10

(

A

s

i

g

n

a

l

A

n

o

i

s

e

)

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)=10log10n=0N1d2(n)n=0N1s2(n)=10log10(PnoisePsignal)=20log10(AnoiseAsignal)

S

N

R

(

d

B

)

=

10

log

10

n

=

0

N

1

s

2

(

n

)

n

=

0

N

1

[

x

(

n

)

s

(

n

)

2

]

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

SNR(dB)=10log10n=0N1[x(n)s(n)2]n=0N1s2(n)

其中:

P

s

i

g

n

a

l

P_{signal}

Psignal为信号功率;

P

n

o

i

s

e

P_{noise}

Pnoise为噪声功率;

A

s

i

g

n

a

l

A_{signal}

Asignal为信号幅度;

A

n

o

i

s

e

A_{noise}

Anoise为噪声幅度值,功率等于幅度值的平方

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)

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

n

p

.

l

i

n

a

l

g

.

n

o

r

m

(

x

)

=

x

1

2

+

x

2

2

+

.

.

.

+

x

n

2

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

np.linalg.norm(x)=x12+x22+...+xn2

这个公式和上面是一样的

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)

表示信号的最大瞬时功率和噪声功率的比值,最大瞬时功率为语音数据中最大值得平方。

S

N

R

(

d

B

)

=

10

log

10

(

M

A

X

(

P

s

i

g

n

a

l

)

P

n

o

i

s

e

)

=

10

log

10

M

A

X

[

s

(

n

)

]

2

d

2

(

n

)

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

SNR(dB)=10log10(PnoiseMAX(Psignal))=10log10d2(n)MAX[s(n)]2

S

N

R

(

d

B

)

=

10

log

10

M

A

X

[

s

(

n

)

]

2

1

N

n

=

0

N

1

[

x

(

n

)

s

(

n

)

]

2

=

20

log

10

M

A

X

[

s

(

n

)

]

M

S

E

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}}

SNR(dB)=10log10N1n=0N1[x(n)s(n)]2MAX[s(n)]2=20log10MSE
MAX[s(n)]

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

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)

两个频谱之间的距离度量(用分贝表示)。两个频谱

P

(

W

)

P(W)

P(W)

P

^

(

w

)

\hat{P}(w)

P^(w)之间的对数谱距离被定义为:

D

L

S

=

1

2

π

π

π

[

10

log

10

P

(

w

)

P

^

(

w

)

]

2

d

w

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

DLS=2π1ππ[10log10P^(w)P(w)]2dw

其中,

p

(

w

)

p(w)

p(w)

P

^

(

w

)

\hat{P}(w)

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博客

视频质量度量指标

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/159207.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!