Python音頻處理(一)——信號,波形與頻譜

前言

音頻處理屬於大學課程《多媒體技術》,什麼採樣率,頻譜等理論知識,博主這裏會慢慢的根據實際的代碼進行講解,不會一籠統的純理論知識一大堆擺上來,畢竟學習音頻處理是爲了我們處理日常生活中的工作。

關於音頻處理的方式,後面的代碼都會使用python語言進行處理,至於學完後可以幹啥,肯定是大家非常關係的,比如音樂的降噪,模擬某個人的聲音,提取音頻中重要的信息等,都可以通過python代碼實現,話不多說我們直接開始介紹。

波形

在Python語言中, 波形的讀寫需要用到別人寫好的thinkdsp.py代碼,比如,這裏我們需要讀取一個音頻並繪製其波形圖,代碼如下:

from matplotlib import pyplot
import thinkdsp

wave=thinkdsp.read_wave("aaa.wav")
wave.plot()
pyplot.show()

三行代碼就可以獲取到某個音頻文件的波形圖,而繪製圖形的代碼屬於matplotlib包,這段代碼顯示的效果如下圖所示:
圖形

頻譜

通過thinkdsp讀取進來的音頻文件返回的Wave,提供了一個make_spectrum,spectrum就是頻譜的意思,我們可以通過如下代碼,打印出音頻文件的頻譜:

import thinkdsp
import thinkplot

wave=thinkdsp.read_wave("aaa.wav")
spectrum=wave.make_spectrum()
spectrum.plot()
thinkplot.show()

這段代碼顯示的效果如下圖所示:
頻譜

Spectrum

Spectrum提供了3中修改頻譜的方法:

(1)low_pass:它加載一個低通濾波器,也就是說高於某個給定的截止頻率的頻率元素被按照一定因素衰減,也就是在大小上降低了。

(2)high_pass:它加載了一個高通濾波器,也就是說低於某個截止頻率的元素被衰減了。

(3)band_stop:它讓處於兩個截止頻率之間的波段內的頻率元素衰減了。

比如,我們這裏來看個例子,代碼如下:

import thinkdsp
import thinkplot

wave=thinkdsp.read_wave("aaa.wav")
spectrum=wave.make_spectrum()
spectrum.low_pass(cutoff=600,factor=0.01)
spectrum.plot()
thinkplot.show()
wave=spectrum.make_wave()
wave.write("bbb.wav")

這段代碼會移除明亮的高頻信號,所以其結果的聲音比較壓抑而且昏暗,使用低通濾波器後,得到的頻譜如下:
對比讀者可以對比一下上面兩個圖形的區別,上面最後兩行代碼是將spectrum轉化成Wave,然後保存到bbb.wav文件中,讀者可以試着代碼聽一下。

波形對象

thinkdsp.py裏面並沒有什麼複雜的東西。其提供的大部分函數只是對Numpy和SciPy函數的稀薄封裝。其中初始化的庫包括Signal,Wave和Spectrum。給定Signal,讀者就可以創建一個Wave。給定一個Wave,就可以創建一個Spectrum。Wave與Spectrum可以互相轉換。

Wave對象包括3個特性:包括信號參數的Numpy數組ys;信號開始採用和取值的事件點數組ts;每單位時間的採樣數framerate。時間的單位通常是秒,但也可以不是。

Wave還提供了三個只讀屬性:start,end和duration。如果修改了ts,這些屬性也會變更。我們來看一段代碼:

wave = thinkdsp.read_wave("aaa.wav")
#wave.scale(2)
#wave.shift(1)
wave.ys *= 2
wave.ts += 1
wave.write("bbb.wav")

上面的代碼時將波形擴大兩倍,晚一秒時間播放,註釋的代碼與ys,ts那兩行代碼是等價的,沒有任何不同。

信號對象

Signal是一個父類,它向各種信號提供通用的函數,比如make_wave。子類繼承了這些方法並提供evaluate,也就是在給定的時間序列內對信號取值。例如,Sinusoid是Signal的子類,定義如下:

class Sinusoid(thinkdsp.Signal):
    def __init__(self, freq=400, amp=1.0, offset=0, func=np.sin):
        thinkdsp.Signal.__init__()
        self.freq = freq
        self.amp = amp
        self.offset = offset
        self.func = func

參數的含義如下:

(1)freq:頻率,其含義爲每秒週期數,單位是Hz。

(2)amp:幅度。幅度的單位比較隨意,通常設定爲1.0,對應爲傳聲器的最大輸入或給揚聲器的最大輸出

(3)offset:其含義爲信號週期的起始。offset的單位爲弧度。

(4)func:它是一個python函數,用來指定時間點的信號求值。通常它不是np.sin就是np.cos,對應的分別是正弦信號和餘弦信號。

跟很多初始化的方法一樣,它也是把參數存起來以備未來使用。Signal提供了make_wave,如下所示:

def make_wave(self,duration=1,start=0,framerate=11025):
	n=round(duration*framerate)
	ts=start+np.arange(n)/framerate
	ys=self.evaluate(ts)
	return Wave(ys,ts,framerate=framerate)

start和duration分別表示開始的時間和持續的時間,單位爲秒.framerate是每秒幀率(採樣數)。n代表採樣的數量,而ts是採樣時間的Numpy數組。爲了計算ys,make_wave需要引入evaluate,它是由Sinusoid提供的:

def evaluate(self,ts):
	phases=PI*self.freq*ts+self.offset
	ys=self.amp*self.func(phases)
	return ys

下面我們來逐步地解析這個函數:

(1)self.freq是頻率,代表每秒週期數,而ts的各個元素都是以秒計的,所以它們的乘積是從其實時間開始的週期數。

(2)PI2是一個常數,也是常用圓的Π,這裏爲2Π。乘上PI2之後就把週期轉換成了相位。讀者可以把相位理解爲弧度形式的“從其實時間開始的週期數”,而每個週期的弧度爲2Π。

(3)self.offset是t=0時刻的相位,其作用是把信號在時域上向左或者向右移動一定的距離。

(4)如果self.func是np.sin或者np.cos,其值便是出於-1到1之間。

(5)乘上self.amp之後產生的信號範圍爲-self.amp到self.amp。

在數學意義上,evaluate的公式如下:

y=Acos(2πft+φ0)

其中A是幅度,f是頻率,t是時間,φ0是相位偏移。上面的代碼其實就是這段表達式的值,但是正如我們將要看到的,這段代碼提供了處理所有信號的構架,而不僅是三級函數信號的。

第一篇的內容就介紹到這裏,我們用到的thinkdsp以及thinkplot代碼可以在這裏下載,下載地址如下:點擊下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章