【问题标题】:How to obtain sound envelope using python如何使用python获取声音包络
【发布时间】:2015-09-02 13:55:23
【问题描述】:

你好,我是 python 的新手,也是声音信号分析的新手。我正在尝试获取出生歌曲(斑胸草雀)的信封。它的信号波动非常快,我尝试了不同的方法。例如,我尝试根据我发现的其他示例绘制信号并使用以下代码获取包络(我在代码中添加了 cmets 以理解它):

#Import the libraries
from pylab import *
import numpy
import scipy.signal.signaltools as sigtool
import scipy, pylab
from scipy.io import wavfile
import wave, struct
import scipy.signal as signal

#Open the txt file and read the wave file (also save it as txt file)

f_out = open('mike_1_44100_.txt', 'w')
w     = scipy.io.wavfile.read("mike_1_44100_.wav") #here your sound file

a=w[1]
f_out.write('#time #z' + '\n')

#I print to check
print 'vector w'
print w[0],w[1]
print w

i=w[1].size
p=numpy.arange(i)*0.0000226 #to properly define the time signal with    the sample rate

print 'vector p:'
print p 

x=numpy.dstack([p,a])

print 'vector x:'
print x[0]

#saving file
numpy.savetxt('mike_1_44100_.txt',x[0])

f_out.close()
print 'i:'
print i

# num is the number of samples in the resampled signal.
num= np.ceil(float(i*0.0000226)/0.0015)
print num

y_resample, x_resample = scipy.signal.resample(numpy.abs(a),num, p,axis=0, window=('gaussian',150))

#y_resample, x_resample = scipy.signal.resample(numpy.abs(a), num, p,axis=-1, window=0)

#Aplaying a filter 

W1=float(5000)/(float(44100)/2) #the frequency  for the cut over the sample frequency

(b, a1) = signal.butter(4, W1, btype='lowpass')
aaa=a
slp =1* signal.filtfilt(b, a1, aaa)

#Taking the abs value of the signal the resample and finaly aplying the hilbert transform

y_resample2 =numpy.sqrt(numpy.abs(np.imag(sigtool.hilbert(slp, axis=-1)))**2+numpy.abs(np.real(sigtool.hilbert(slp, axis=-1)))**2)

print 'x sampled'
#print x_resample
print 'y sampled'
#print  y_resample

xx=x_resample #[0]
yy=y_resample #[1]

#ploting with some style

plot(p,a,label='Time Signal') #to plot amplitud vs time
#plot(p,numpy.abs(a),label='Time signal')
plot(xx,yy,label='Resampled time signal Fourier technique Gauss window 1.5 ms ', linewidth=3)
#plot(ww,label='Window', linewidth=3)
#plot(p,y_resample2,label='Hilbert transformed sime signal', linewidth=3)

grid(True)
pylab.xlabel("time [s]")
pylab.ylabel("Amplitde")

legend()
show()

这里我尝试了两件事,第一是使用 scipy 的 resample 函数来获取包络,但是我对信号幅度有一些我不理解的问题(我上传了使用傅里叶技术获得的图像,但是系统不允许我):

第二种是使用希尔伯特变换来获取信封(现在我再次使用希尔伯特变换上传了图像,系统不允许我)运行我的代码并获得这两个图像是可能的。但是我把这个链接放在http://ceciliajarne.web.unq.edu.ar/?page_id=92&preview=true

现在“信封”又失败了。正如我在某些示例中看到的那样,我尝试对信号进行滤波,但是我的信号被衰减并且我无法获得包络。 谁能帮助我的代码或更好的想法来获取信封?可以使用任何鸟歌作为示例(我可以给你我的),但我需要看看会发生什么复杂的声音不是简单的信号,因为它非常不同(简单的声音两种技术都可以)。

我还尝试修改我在以下位置找到的代码:http://nipy.org/nitime/examples/mtm_baseband_power.html

但我无法为我的信号获得正确的参数,而且我不了解调制部分。我已经问过代码开发人员了,一直在等待答案。

【问题讨论】:

标签: python audio scipy signal-processing


【解决方案1】:

由于鸟鸣声的“调制频率”可能会比“载波频率”低得多,即使幅度迅速变化,可以通过获取信号的绝对值然后应用来获得包络的近似值一个长度为 20 毫秒的移动平均滤波器。

不过,您是否也对频率变化感兴趣,以充分描述歌曲的特征?在这种情况下,在移动窗口上进行傅里叶变换会为您提供更多信息,即作为时间函数的近似频率内容。这是我们人类听到的声音,有助于我们区分鸟类。

如果您不想要衰减,则不应应用巴特沃斯滤波器或移动平均,而应应用峰值检测。

移动平均:每个输出样本是例如的绝对值的平均值50 个先前的输入样本。输出会被衰减。

峰值检测:每个输出样本是例如绝对值的最大值50 个先前的输入样本。输出不会衰减。您可以在之后进行低通滤波器以摆脱剩余的楼梯“涟漪”。

你想知道为什么,例如巴特沃斯滤波器会衰减您的信号。如果您的截止频率足够高,它几乎没有,但它似乎被强烈衰减。您的输入信号不是载波(哨声)和调制(包络)的总和,而是乘积。过滤将限制频率内容。剩下的是频率分量(项)而不是因子。您会看到衰减的调制(包络),因为该频率分量确实存在于您的信号中,比原始包络弱得多,因为它没有添加到您的载波中,而是与它相乘。由于与包络相乘的载波正弦曲线并不总是处于最大值,因此包络将被调制过程“衰减”,而不是通过滤波分析。

简而言之:如果您直接想要(乘性)包络而不是由于与包络进行调制(乘法)而导致的(加法)频率分量,请采用峰值检测方法。

“Pythonish”伪代码中的峰值检测算法,只是为了理解。

# Untested, but apart from typos this should work fine
# No attention paid to speed, just to clarify the algorithm
# Input signal and output signal are Python lists
# Listcomprehensions will be a bit faster
# Numpy will be a lot faster

def getEnvelope (inputSignal):
    
    # Taking the absolute value
    
    absoluteSignal = []
    for sample in inputSignal:
        absoluteSignal.append (abs (sample))
    
    # Peak detection
    
    intervalLength = 50 # Experiment with this number, it depends on your sample frequency and highest "whistle" frequency
    outputSignal = []
    
    for baseIndex in range (intervalLength, len (absoluteSignal)):
        maximum = 0
        for lookbackIndex in range (intervalLength):
            maximum = max (absoluteSignal [baseIndex - lookbackIndex], maximum)
        outputSignal.append (maximum)
    
    return outputSignal

【讨论】:

  • jacdeh,谢谢。我取了信号的绝对值,并应用了一个从 20 到 300 Hz 不同频率的低通滤波器(巴特沃斯)。我在这个链接(第三个图)[链接](ceciliajarne.web.unq.edu.ar/envelope-problem/…)中包含了最好的结果。如果我将滤波器应用于完整信号或窗口,会有所不同吗?我对良好的包络重建感兴趣,我可以看到声波图的频率变化。我需要包络,我想了解为什么我的结果仍然是幅度衰减的信号。
  • 又一次编辑。不知道你是否会自动收到通知。谁能告诉我?
  • 谢谢。我没有收到通知...好的,我会研究您写给我的内容。我在想类似的事情。以下是我所说的情节:ceciliajarne.web.unq.edu.ar/envelope-problem我想现在你可以看到它们了。
  • 是的,我现在可以看到这些图了,虽然文字不可读。第三个情节中的读取线是信封,对吗?您看到的是,在最后 3 段中,包络更加衰减。这是因为载体的有效值较低(浅蓝色区域,相对于深蓝色区域)。你有问自己:我所说的信封是什么意思。可能您也想要信封内的浅蓝色区域。正如我所描述的那样,峰值检测就可以做到这一点。
  • 我已经添加了峰值检测算法
【解决方案2】:

可以使用相应analytic signal 的绝对值来计算信号的包络。 Scipy 实现了函数scipy.signal.hilbert 来计算解析信号。

来自其文档:

我们创建一个频率从 20 Hz 增加到 100 Hz 的啁啾,并应用幅度调制。

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert, chirp

duration = 1.0
fs = 400.0
samples = int(fs*duration)
t = np.arange(samples) / fs

signal = chirp(t, 20.0, t[-1], 100.0)
signal *= (1.0 + 0.5 * np.sin(2.0*np.pi*3.0*t))

幅度包络由解析信号的幅度给出。

analytic_signal = hilbert(signal)
amplitude_envelope = np.abs(analytic_signal)

看起来像

plt.plot(t, signal, label='signal')
plt.plot(t, amplitude_envelope, label='envelope')
plt.show()

它也可以用来计算瞬时频率(见文档)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2018-07-13
    相关资源
    最近更新 更多