2017-07-08 61 views
1

我試圖從20-30秒錄製的心跳音頻的.wav文件中提取單個心跳。每次心跳都從一個名爲「lub」的高強度聲音(峯值)開始,然後另一個心跳從下一個高峯重複。如何使用python提取一段音頻文件?

像什麼庫使用,任何可用的算法,可輔導等

回答

0

使用標準庫波模塊加載音頻。然後將數據轉換爲numpy數組,然後使用scipy或scikits的峯值檢測算法。

一些代碼:

import wave 
wf = wave.open("file.wav", "r") 
fs = wf.getframerate() 
nc = wf.getnchannels() 
sw = wf.getsampwidth() 
nf = wf.getnframes() 
data = wf.readframes(nf) 
wf.close() 

import numpy as np 
dt = {1: np.int8, 2: np.int16, 4: np.int32} 
a = np.fromstring(data, dtype=dt[sw]) 

現在你陣列上執行峯值檢測。您可以使用例如scikits talkbox的算法(這裏是該功能的複製粘貼):



def findpeaks (x, neighbours=50): 
    """ 
    Peak seeking algorithm from scikits talkbox. 
    Returns indexes of peaks in the x curve. 
    """ 
    peaks = [] 
    nx = x.size 

    assert 2 * neighbours + 1 <= nx 

    if nx == 1: 
     return [0] 
    elif nx == 2: 
     if x[0] > x[1]: 
      peaks.append(0) 
     else: 
      peaks.append(1) 
     return peaks 

    # Handle points which have less than neighs samples on their left 
    for i in xrange(neighbours): 
     cur = x[i] 
     m = x[i+1] 
     # look at the left of the current position 
     for j in xrange(i): 
      if m < x[j]: 
       m = x[j] 
     # look at the right of the current position 
     for j in xrange(i+1, i+neighbours): 
      if m < x[j]: 
       m = x[j] 

     if cur > m: 
      peaks.append(i) 
      #assert(pkcnt <= (nx/neighbours + 1)) 

    # Handle points which have at least neighs samples on both their left 
    # and right 
    for i in xrange(neighbours, nx - neighbours): 
     cur = x[i] 
     m = x[i+1] 
     # look at the left 
     for j in xrange(i - neighbours, i): 
      if m < x[j]: 
       m = x[j] 
     # look at the right 
     for j in xrange(i+1, i+neighbours): 
      if m < x[j]: 
       m = x[j] 

     if cur > m: 
      peaks.append(i) 
      #assert(pkcnt <= (nx/neighbours + 1)) 

    # Handle points which have less than neighs samples on their right 
    for i in xrange(nx - neighbours, nx): 
     cur = x[i] 
     m = x[i-1] 
     # look at the left 
     for j in xrange(i - neighbours, i): 
      if m < x[j]: 
       m = x[j] 

     # look at the right 
     for j in xrange(i+1, nx): 
      if m < x[j]: 
       m = x[j] 

     if cur > m: 
      peaks.append(i) 
      #assert(pkcnt <= (nx/neighbours + 1)) 

    return peaks 

peaks = findpeaks(a) 
# And now you get the segment of a signal by slicing it: 
# For example (assuming you checked what peaks you want and if they were found at all): 
s = a[peaks[0]:peaks[1]] # Let say you want first two peaks regardless the sign 

# As you can see, this concrete algo is not strictly numpy dependant. You just have to change line nx = x.size into nx = len(x) to avoid it completely. 
# So you can "throw" numpy away by loading wave data into a list like this: 

import struct 
dt = {1: "c", 2: "h", 4: "l"} 
a = struct.unpack("<"+dt[sw], data) 
# And then you use a as demonstrated above i.e. as an array. But numpy will give you more flexibility, speed and options to work on. 

相關問題