語音識別是機器通過識別和理解過程把人類的語音信號轉變為相應文本或命令的技術,其根本目的是研究出一種具有聽覺功能的機器。本設計研究孤立詞語音識別系統及其在STM32嵌入式平臺上的實現。識別流程是:預濾波、ADC、分幀、端點檢測、預加重、加窗、特征提取、特征匹配。端點檢測(VAD)采用短時幅度和短時過零率相結合。檢測出有效語音后,根據人耳聽覺感知特性,計算每幀語音的Mel頻率倒譜系數(MFCC)。然后采用動態時間彎折(DTW)算法與特征模板相匹配,最終輸出識別結果。先用Matlab對上述算法進行仿真,經多次試驗得出算法中所需各系數的最優值。然后將算法移植到STM32嵌入式平臺,移植過程中根據嵌入式平臺存儲空間相對較小、計算能力也相對較弱的實際情況,對算法進行優化。最終設計并制作出基于STM32的孤立詞語音識別系統。
從技術上講,語音識別屬于多維模式識別和智能接口的范疇。它是一項集聲學、語音學、計算機、信息處理、人工智能等于一身的綜合技術,可廣泛應用在信息處理、通信和電子系統、自動控制等領域。
國際上對語音識別的研究始于20世紀50年代。由于語音識別本身所固有的難度,人們提出了各種條件下的研究任務,并有此產生了不同的研究領域。這些領域包括:針對說話人,可分為特定說話人語音識別和非特定說話人語音識別;針對詞匯量,可劃分為小詞匯量、中詞匯量和大詞匯量的識別,按說話方式,可分為孤立詞識別和連續語音等。最簡單的研究領域是特定說話人、小詞匯量、孤立詞的識別,而最難的研究領域是非特定人、大詞匯量、連續語音識別。
在進入新世紀之前,語音識別技術大都只在特定行業或場所中使用或者僅僅停留在實驗室,處于探索和試驗中。最近十年由于消費電子行業的興起和移動互聯網技術的爆發。越來越多的自動化和自能化產品走進人們的日常生活。語音識別技術也隨之進入大眾的視線,并開始為更多人所了解和使用。例如語音門禁、智能電視上的語音換臺、智能手機上的語音撥號、語音控制等等。語音識別技術正在由過去的實驗探索邁入實用化階段。我們有理由相信會有越來越多的產品用到語音識別技術,它與人工智能能技術的結合將會是一個重要的發展方向。語音識別技術最終會改變人與機器之間的交互方式,使之更加自然、便捷、輕松。
本設計的孤立詞語音識別是語音識別技術中較為基本的,算法實現也較簡單,適合于在嵌入式平臺中實現一些簡單的語音控制功能。以往類似系統大都基于ARM9、ARM11、DSP、SOC等。這些平臺系統規模較大、開發和維護的難度較大、成本也相對較高。STM32是意法半導體(ST)公司推出的基于ARM Cortex-M3內核的高性能單片機。上市之后,由于其出色的性能、低廉的價格,很快被運用到眾多產品中。經測試,STM32F103VET6單片機擁有能夠滿足本系統孤立詞語音識別所需的運算和存儲能力。所以在本系統中采用STM32F103VET6作為主控制器,采集并識別語音信號。以低廉的成本,高效的算法完成了孤立詞語音識別的設計目標。本系統主要涉及的內容如下述:
語音信號的采集和前端放大、防混疊濾波、模數轉換。
語音信號預處理,包括預加重、分幀、加窗。
語音信號端點檢測,檢測輸入信號中有效語音的起始和結束點
語音信號特征提取。提取有效語音中每幀語音信號的Mel頻率倒譜系數(MFCC)系數。
模板訓練,對每個語音指令采集多個語音樣本,根據語音樣本獲取每個語音指令的特征模板。
特征匹配,使用動態時間規整(DWT)算法計算輸入語音信號與各模板的匹配距離。識別輸入的語音信號。
第一章 方案論證及選擇1.1系統設計任務要求本系統利用單片機設計了一個孤立詞語音識別系統,能夠識別0~9、 “上”、“下”、“左”、“右”14個漢語語音指令。系統通過觸摸式LCD與用戶交互。
本設計的主要要求如下:
1.采集外部聲音信號,轉換為數字信號并存儲。
2.在采集到的聲音信號中找出有效語音信號的開始和結束點。
3.分析檢測到的有效語音,得出語音信號特征。
4.對每個待識別的語音指令,建立特征模版。
5.比較輸入語音信號特征與特征模版,識別輸入的語音信號
6.顯示系統操作界面,并能夠接受用戶控制。
1.2硬件選擇1.2.1 硬件方案總體介紹系統硬件由音頻放大模塊、MCU、觸摸屏、電源四部分組成。音頻放大模塊完成對外部聲音信號的采集和放大。將聲音信號轉化為電信號,并放大到0~3V。MCU的ADC參考電壓為其電源電壓3.3V。音頻放大模塊的輸出信號不超出MCU ADC的電壓范圍,并且能夠獲得最大的量化精度。MCU對音頻放大模塊輸入的聲音信號進行AD轉換。然后提取并識別信號特征。另外,MCU還控制觸摸屏的顯示和讀取觸摸屏點擊位置。觸摸屏負責顯示操作界面,并接收用戶操作。電源為電池供電。
系統硬件結構圖如圖1.1所示。
圖1.1系統硬件總體結構圖
1.2.2 MCU選擇傳統上孤立詞語音識別多采用語音識別專用芯片,例如凌陽SPCE061A、LD3320等。此種方案設計簡單,開發周期較短,但可拓展性較差,一般只能識別特定的語音,或者識別語音指令的個數有限制。且專用芯片價格一般相對較高,對系統成本控制不利。
STM32F103VET6是意法半導體(ST)推出的高性能32位Cortex-M3內核單片機,帶有ADC、DAC、USB、CAN、SDIO、USART、SPI、IIC、FSMC、RTC、TIM、GPIO、DMA等大量片上外設。Cortex-M3內核屬于ARM公司推出的最新架構ARMv7中的M系列,側重于低成本、低功耗、高性能。其最高主頻可達72MHz, 1.25 DMIPS/MHz的運算能力,三級流水線另加分支預測,并且還帶有單周期乘法器和硬件除法器。相比較ARM7TDMI內核,Cortex-M3在性能上有較大的提升。
STM32F103VET6內置3個一共21通道的12位ADC,采樣頻率最高可達1MHz。12通道DMA控制器,可訪問系統Flash、SRAM、片上外設,能夠處理內存到外設、外設到內存的DMA請求。11個16位定時器,其中T1、T2、T3、T4、T5、T8可連接到ADC控制器,在每次定時器捕獲/比較事件到來時自動觸發ADC開始一次A/D轉換。A/D轉換完成后可自動觸發DMA控制器將轉換后的數據依次傳送至SRAM的數據緩沖區。因此STM32F103VET6能夠進行精確且高效的A/D轉換。能夠滿足音頻信號采集的需求。
STM32F103VET6的FSMC(Flexible Static Memory Controller,可變靜態存儲控制器)能夠根據不同的外部存儲器類型,發出相應的數據/地址/控制信號類型以匹配信號的速度。FSMC連接至LCD控制器,可將LCD控制器配置為外部NOR Flash。在系統需要訪問LCD時,自動生成滿足LCD控制器要求的讀寫時序,能夠精確、快速地完成對LCD界面顯示的控制。內置3個最高可達18Mbit/s的SPI控制器,與觸摸屏控制器相連能夠實現觸摸屏點擊位置檢測。
本系統中采集一個漢語語音指令。錄音時間長度2s,以8KHz 16bit采樣率對語音進行采集,所需存儲空間為32KB,另外加上語音處理、特征提取及特征匹配等中間步驟所需RAM空間不會超過64KB。而STM32F103VET6帶有512KB Flash和64KB RAM。所以STM32F103VET6在程序空間上能夠滿足。語音識別中最耗時的部分是特征提取中的快速傅立葉變換換。一般來說,孤立詞語音識別中有效語音時間長度小于1s。語音信號一般10~30ms為一幀,本系統中按20ms一幀,幀移(相鄰兩幀的重疊部分)10ms,這樣一個語音指令不超過100幀。在8KHz 16bit的采樣率下,20ms為160采樣點 。STM32固件庫所提供的16位、1024點FFT,在內核以72MHz運行時每次運算僅需2.138ms。完成100幀數據的FFT所需時間為213.8ms,加上其他處理所需時間,識別一個語音指令耗時不會超過0.5s。所以在程序運行時間上STM32F103VET6也能夠滿足需要,能夠進行實時的孤立詞語音識別。
基于以上論證,本系統選用STM32F103VET6作為主控MCU。
1.2.3音頻信號采集方案選擇音頻信號采集多采用音頻編解碼芯片,例如UDA1341、VS1003等。此類芯片能夠提供豐富的功能,且系統一致性較好,但它們成本較高。本系統是一個低成本解決方案,并且只需要采集音頻信號。因此不宜采用那些專用的音頻編解碼芯片。
在本系統的音頻放大模塊中使用小型話筒完成聲電信號轉換,兩個9014三極管構成兩級共基極放大電路。在每一級中加電壓負反饋,穩定放大倍數。
語音信號的頻帶為300~3400Hz,根據抽樣定理,抽樣頻率設為8000Hz就足以完成對語音信號的采集。在本系統中TIM1被設置為ADC觸發信號源。TIM時鐘源為系統時鐘72MHz。經100分頻,變為720KHz。計數模式為向上遞增,自動重載值為90,即計數值從0遞增到90再返回0。比較匹配值設為0~90間任意一個數值 ,則每秒可發出8000次比較匹配事件。ADC每秒完成8000次A/D轉換,即抽樣頻率為8KHz。
1.2.4顯示及操作界面選擇觸摸屏作為一種新的輸入設備,它是目前最簡單、方便、自然的一種人機交互方式。LCD觸摸屏是一種可接收觸摸點擊輸入信號的感應式液晶顯示裝置。當接觸或點擊屏幕時,觸摸控制器可讀取觸摸點位置,如此可通過屏幕直接接受用戶的操作。相比較機械式按鈕,觸摸屏在操作上更加直觀生動。綜合考慮,本設計中采用2.5寸240×320分辨率的LCD觸摸屏實現界面顯示和操作。
1.3算法選擇1.3.1軟件算法總體介紹對采集到的音頻信號進行預處理、端點檢測、特征提取、模板訓練、特征匹配的一些列處理,最終識別輸入語音。
系統軟件流程圖如下圖所示。
1.3.2預處理算法選擇語音信號的預處理主要包括: ADC、分幀、數據加窗、預加重。
語音信號的頻率范圍通常取100Hz~3400Hz,因為這個頻段包含絕大部分的語音信息,對語音識別的意義最大。根據采樣定律,要不失真地對3400Hz的信號進行采樣,需要的最低采樣率是6800Hz。為了提高精度,常用的A/D采樣率在8kHz到12kHz。
語音信號有一個重要的特性:短時性。由于人在說話中,清音與濁音交替出現,并且每種音通常只延續很短的一段時間。因此,從波形上看,語音信號具有很強的“時變特性”。在濁音段落中它有很強的周期性,在清音段落中又具有噪聲特性,而且濁音和清音的特征也在不斷變化之中。如圖1.4所示,其特性是隨時間變化的,所以它是一個非穩態過程。但從另一方面看,由于語音的形成過程是與發音器官的運動密切相關的,這種物理性的運動比起聲音振動速度來說是緩慢的(如圖1.5所示)。因此在一個短時間范圍內,其特性變化很小或保持不變,可以將其看做一個準穩態過程。我們可以用平穩過程的分析處理方法來分析處理語音信號。
圖1.4 語音“7”的時域波形
圖1.5 語音“7”清音段和濁音段的20ms短時波形
基于以上考慮,對語音信號的分析處理必須采用短時分析法,也就是分幀。語音信號通常在10ms~30ms之間保持相對平穩。在本設計中,每幀取20ms。為了使前后幀之間保持平滑過渡,幀移10ms,即前后幀之間交疊10ms。
為了便于后續語音處理,需對分幀后的信號加窗。加窗方式如式(1-1)。
(1-1)
式中Y(n)是加窗后的信號,y(n)是輸入信號,w(n)是窗函數,N是幀長。
窗函數可以選擇矩形窗,即
(1-2)
圖1.6 矩形窗時域、頻域示意圖
或其他形式窗函數,如漢明窗
(1-3)
圖1.7 漢明窗時域、頻域示意圖
這些窗函數的頻率響應都具有低通特性,但不同的窗函數形狀將影響分幀后短時特征的特性。圖1.7和圖1.8分別給出了160點矩形窗和漢明窗的時域和頻域示意圖。從圖中可以看出漢明窗的帶寬大約是同樣寬度矩形窗帶寬的兩倍。同時,在通帶外漢明窗的衰減比矩形窗大得多。矩形窗的主瓣較小,旁瓣較高;而漢明窗具有最寬的主瓣寬度和最低的旁瓣高度。
對語音信號分析來說,窗函數的形狀是非常重要的,矩形窗的譜平滑性較好,但波形細節易丟失,并且矩形窗會產生泄露現象。而漢明窗可以有效地克服泄露現象,應用范圍也最為廣泛。基于以上論述,本設計選用漢明窗作為窗函數。圖1.9和圖1.10分別給出了一幀濁音加矩形窗和漢明窗后的時域和頻域效果。
圖1.8 加矩形窗
圖1.9 加漢明窗
由于人的發聲器官的固有特性,語音從嘴唇輻射將有6dB/倍頻的衰減。此種效應主要表現在高頻信息的損失,對語音信號的特征提取會造成不利的影響。因此,必須對信號進行高頻提升,即對信號進行高頻的補償,使得信號頻譜平坦化,以便于進行頻譜分析或聲道參數分析。預加重可以用具有6dB/倍頻提升高頻特性的預加重數字濾波器實現。預加重濾波器一般是一階的,其系統函數和差分方程如式(1-4)
(1-4)
其中y(n)為提升后的輸出值,x(n)和x(n-1)分別為當前時刻和前一時刻的輸入值。u接近于1,典型取值在0.94~0.97之間。本設計取0.95。預加重效果如圖1.11所示。
圖1.10 預加重效果圖
1.3.3端點檢測算法選擇語音端點檢測(VAD),也稱為語音活動性檢測,主要應用在語音處理中的語音編解碼,語音識別及單信道語音增強等領域。語音端點檢測的基本方法可以用一句話來表達:從輸入信號中提取一個或一系列的對比特征參數,然后將其和一個或一系列的門限閥值進行比較(如圖3-2)。如果超過門限則表示當前為有音段;否則表示當前為無音段。門限閥值通常是根據無音段時的特征確定的。但是由于語音和環境噪聲的不斷變化,使得這一判決過程變得非常復雜。通常語音端點檢測是在語音幀的基礎上進行的,語音幀的長度在10ms~30ms不等。一個好的語音端點檢測算法必須具有對各種噪聲的魯棒性,同時要簡單、適應性能好、時延小、且易于實時實現。
在高信噪比的情況下,常用的檢測方法大體上有以下幾種:短時能量、短時過零率。這些方法都是利用了語音和噪聲的特征參數,因此判別效果較好。并且它們實現簡單,計算量相對較小,因而得到廣泛的應用。
短時能量定義如下式:
(1-6)
式中N為幀長,E為一幀的短時能量值。
短時能量主要有以下幾個方面的應用:首先短時能量可以區分清音和濁音,因為濁音的能量要比清音的大得多;其次可以用短時能量對有聲段和無聲段進行判定,以及連字分界等。短時能量由于是對信號進行平方運算,因而人為增加了高低信號之間的差距。更重要的的是平方運算的結果很大,容易產生數據溢出。解決這些問題的簡單方法是采用短時平均幅度值來表示能量的變化。其定義如下:
(1-7)
短時過零率是語音信號時域分析中最簡單的一種特征,它指每幀內信號通過零值的次數,定義如下:
(1-8)
式中,sgn(x)是符號函數,即
(1-9)
根據以上定義,清音由于類似于白噪聲,所以過零率較高。濁音的能量集中于低頻段,所以濁音信號的短時過零率較低。噪聲的短時過零率較高,這主要是因為語音信號的能量主要集中在較低的頻率范圍內,而噪聲信號的能量主要集中于較高的頻段。這樣計算的短時過零率容易受到噪聲干擾。解決這個問題的方法是對上述定義稍作修改,即設置一個門限T,將過零率的含義修改為跨過正負門限的次數。修改后的定義如下式:
(1-10)
這樣計算的短時過零率就有一定的抗干擾能力,即使存在隨機噪聲,只要它不超過正負門限所構成的帶,就不會產生虛假過零率。
綜合考慮設計需要和系統處理能力,本設計采用短時幅度值和改進后的短時過零率判斷語音起始和結束點。分別為短時幅度和短時過零率設置門限值。每次識別前,選定語音段前300ms作為背景噪聲,用以確定這兩個門限值,實現對背景噪聲的自適應。具體的端點檢測方法如下。
判斷語音起始點,要求能夠濾除突發性噪聲。突發性噪聲可以引起短時能量或過零率的數值很高,但是往往不能維持足夠長的時間,如門窗的開關,物體的碰撞等引起的噪聲,這些都可以通過設定最短時間門限來判別。超過兩門限之一或全部,并且持續時間超過有效語音最短時間門限,返回最開始超過門限的時間點,將其標記為有效語音起始點。判斷語音結束點,要求不能丟棄連詞中間短暫的有可能被噪聲淹沒的“寂靜段”。這可以通過設定無聲段最長時間門限來判別。同時低于兩門限,并且持續時間超過無聲最長時間門限,返回最開始低于門限的時間點,將其標記為有效語音結束點。
圖1.12和圖1.13分別給出了上述算法在一般信噪比和低信噪比情況下的端點檢測效果。從圖中可以看出上述算法能夠適應一般的背景噪聲。在背景噪聲較高時,上述算法無法準確判斷語音起始結束點。但經過試驗,當信噪比低至圖1.13所示時時人耳也很難準確辨識語音。所以上述算法在實際使用中能夠滿足端點檢測的需求。
圖1.11 一般信噪比下的端點檢測效果
圖1.12 低信噪比下的端點檢測效果
1.3.4特征提取算法選擇在語音識別系統中,模擬語音信號在完成A/D轉換后成為數字信號。此時的語音信號為時域的信號,時域的信號難以進行分析和處理,而且數據量龐大。通常的做法是對時域信號進行變換,提取其中某種特定的參數,通過一些更加能反映語音本質特征的參數來進行語音識別。特征提取是識別過程中一個非常重要的環節,選取的特征直接影響到識別的結果。不同的特征對不同語音的敏感度也不一樣,優秀的語音特征應該對不同字音距離較大,而相同字音距離較小。
另外,特征值的數目也是一個重要的問題。在滿足使用要求的情況下,所使用的特征數應該盡量減少,以減少所涉及的計算量。但是過少的特征有可能無法恰當的描述原始語音,以致識別率下降。語音特征的提取方法是整個語音識別的基礎,因此受到了廣泛的重視。通過近幾十年的發展,目前語音特征的提取方法主要有以下三類:
1.基于線性預測分析的提取方法。這一類的典型代表是線性預測倒譜系數LPCC。
2.基于頻譜分析的提取方法。這一類的典型代表是Mel頻率倒譜系數MFCC。
3.基于其它數字信號處理技術的特征分析方法。如小波分析、時頻分析、人工神經網絡分析等。
目前的孤立詞語音識別系統大多采用前兩種語音特征提取方法。在本文中,借鑒前人對LPCC系數和MFCC系數的總結對比,采用Mel頻標倒譜系數MFCC。
人類的耳蝸實質上相當于一個濾波器組,耳蝸的濾波作用在1000Hz以下為線性尺度,而1000Hz以上為對數尺度,這就使得人耳對低頻信號的分辨率高于對高頻信號的分辨率。根據這一特性,研究者根據心理學實驗得到了類似于耳蝸作用的一組濾波器組,這就是Mel頻率濾波器組。Mel頻率可以用如下公式表示:
(1-11)
圖1.13 Mel頻率與實際頻率的對應關系
對頻率軸的不均勻劃分是MFCC特征區別于普通倒譜特征的最重要特點。將頻率按照式(1-11)和圖1.13變換到Mel域后,Mel帶通濾波器組的中心頻率是按照Mel頻率刻度均勻排列的。在本設計中,MFCC倒譜系數的計算過程如下述。
1.對語音信號預加重、分幀、加漢明窗處理,然后進行短時傅里葉變換,得出頻譜。
2.取頻譜平方,得能量譜。并用24個Mel三角帶通濾波器進行濾波;由于每個頻帶的分量在人耳中是疊加的,因此將每個濾波器頻帶內的能量進行疊加,輸出Mel功率譜。
3.對每個濾波器的輸出值取對數,得到相應頻帶的對數功率譜。然后對24個對數功率進行反離散余弦變換得到12個MFCC系數,反離散余弦變換如式(1-12),式中M=24,L=12。
(1-12)
在本設計中采集語音信號的抽樣頻率是8000Hz,頻率范圍是0Hz~4000Hz。在此頻率范圍內的Mel三角帶通濾波器組如下圖所示:
圖1.14 Mel三角濾波器組
與LPCC參數相比,MFCC參數具有以下優點:
1.語音的信息大多集中在低頻部分,而高頻部分易受環境噪聲干擾。MFCC參數將線性頻標轉化為Mel頻標。強調語音的低頻信息,從而突出了有利于識別的信息,屏蔽了噪聲的干擾。
2.MFCC參數沒有任何前提假設,在各種情況下均可使用。而LPCC參數需要假定所處理的信號為AR信號,對于動態特性較強的輔音,這個假設并不是嚴格成立的。
因此,MFCC參數的抗噪聲特性是優于LPCC參數的。在本設計中,采用的語音特征參數均為MFCC參數。
1.3.5特征匹配算法選擇要建立一個性能良好的語音識別系統僅有好的語音特征還不夠,還要有適當的語音識別的模型和算法。在現階段,語音識別的過程是根據模式匹配的原則,計算未知語音模式與語音模板庫中的每一個模板的距離測度,從而得到最佳的匹配模式。目前,語音識別所應用的模型匹配方法主要有動態時間彎折(DTW:Dynamic Time Warping)、隱馬爾可夫模型(HMM:Hidden Markov Model)和人工神經網絡(ANN:Artificial Neural Networks)等。當今孤立詞識別領域最常用的識別算法是DTW和HMM。
DTW算法是較早的一種模式匹配和模型訓練技術,它應用動態規劃的方法成功解決了語音信號特征參數序列比較時時長不等的難題,在孤立詞語音識別中獲得了良好的性能。DTW算法是建立在動態規劃(DP:Dynamic Programming)的理論基礎上的。動態規劃是一個很有效的方法來求取一個問題的最佳解。其中心思想簡單的說可以描述為:在一條最佳的路徑上,其中任意一條子路徑也都必須是相關子問題的最佳路徑,否則原路徑就不是最佳路徑。
HMM算法是數學上一類重要的雙重隨機模型,用概率統計的方法描述時變語音信號,很好的描述了語音信號的整體非平穩性和局部平穩性。HMM的各狀態對應語音信號的各平穩段,各狀態之間以一定轉移概率相聯系,是一種較為理想的語音模型。HMM模型屬于統計語音識別,適用于大詞匯量、非特定人的語音識別系統。隨著現代計算機技術的迅猛發展,計算機的運算速度迅速提高,隱馬爾科夫模型分析方法也得到了廣泛利用。該算法在識別階段計算量較少,適應性強,但是需要大量的前期訓練工作,對系統資源的要求較多。
用于孤立詞識別,DTW算法與HMM算法在相同的環境條件下,識別效果相差不大,但是HMM算法要復雜得多,這主要體現在HMM算法在訓練階段需要提供大量的語音數據,通過反復計算才能得到模型參數,而DTW算法的訓練中幾乎不需要額外的計算。所以在孤立詞語音識別中,DTW算法得到更廣泛的應用。
綜合比較DTW算法的工作量小,不需要大量的語音數據,而且DTW算法適合孤立詞語音識別,且容易實現,節省系統資源,比較方便移植到嵌入式系統中。所以本系統選擇DTW算法作為語音識別的核心算法。下面介紹DTW算法及其實現方法。
假設參考模板的特征矢量序列為,輸入語音特征矢量序列為 ,輸入語音特征矢量序列為 。DTW算法就是要尋找一個最佳的時間規整函數,使待測語音的時間軸j非線性地映射到參考模板的時間軸i上,使總的累積失真量最小。
設時間規整函數為
(1-13)
式中N為匹配路徑長度, 表示第n個匹配點是參考模板的第i(n)個特征矢量與待測模板的第j(n)個特征矢量構成。兩者之間的距離 稱為局部匹配距離。DTW算法就是通過局部優化的方法實現匹配距離總和最小。
一般時間規整函數滿足一下約束:
1.單調性,規整函數單調增加。
2.起點終點約束,起點對起點,終點對終點。
3.連續性,不允許跳過任何一點。
4.最大規整量不超過某一極限值。
M為窗寬。規整函數所處的區域位于平行四邊形內,本設計中將平行四邊形的約束區域端點放寬3點。局部路徑約束,用于限制當第n步時,后幾步存在幾種可能的路徑。本設計中DTW規整區域和局部路徑如圖1.16、圖1.17所示。
圖1.15 放寬端點限制的DTW規整區域
圖1.16 DTW局部路徑
本設計中DTW算法計算步驟:
1.初始化。令i(0)=j(0)=0,i(N)=I,j(N)=J,確定一個如圖1.16所示的規整約束區域Reg。它由一平行四邊形變化而來。此平行四邊形有兩個位于(1,1)和(I,J)的頂點,相鄰兩條邊的斜率分別為2和1/2。
2.按照如圖1.17所示的路徑遞推求累計匹配距離。第n步匹配距離如下式
(1-14)
3.累計匹配距離除匹配步數,得歸一化匹配距離。即輸入特征與特征模板之間的匹配距離。計算輸入特征與每一特征模板的匹配距離,匹配距離最小的特征模板與輸入特征有最大的相似性。
第二章 系統設計2.1硬件設計2.1.1 MCU及其最小系統電路設計經過第一章的論證,選用意法半導體公司的STM32F103VET6單片機。
MCU輸入時鐘由8MHz晶振提供,經MCU內部PLL倍頻至72MHz。在每一個電源引腳上并接0.1uF去耦電容,以提高MCU電源穩定性和抗干擾性。
2.1.2 音頻信號采集電路設計音頻信號采集電路原理圖如下
圖2.6 音頻信號采集原理圖
2.1.3 LCD接口電路設計本設計中顯示器件選用2.4英寸TFT LCD顯示屏,LCD驅動器是ILI9325 。
Thin Film Transistor (薄膜場效應晶體管),是指液晶顯示器上的每一液晶象素點都是由集成在其后的薄膜晶體管來驅動。從而可以做到高速度高亮度高對比度顯示屏幕信息。
ILI9325 是一個262144色的單芯片TFT LCD SoC 驅動。 它提供240×320的分辨率, 172,800字節的圖形數據RAM ,并且帶有內部電源電路。它與控制器的接口可設置為16位并口、8位并口、SPI接口。在本設計中為了提高顯示數據的傳輸速率,采用了STM32F103VET6的FSMC(可變靜態存儲控制器)的16位并口作為MCU和ILI9325的接口。將ILI9325的數據和控制接口映射為外部存儲器。MCU傳送控制命令或顯示數據時,自動生成相應的時序,避免了傳統上采用IO口模擬時序,提高了數據傳輸效率。
2.2軟件設計2.2.1 語音預處理算法設計語音信號預處理包括: 語音信號采集、分幀、數據加窗、預加重。
語音信號采集就是將外部模擬的語音信號,轉換為MCU可處理和識別的數字信號的過程。在本設計中,通過MCU內部的定時器、模數轉換器以及DMA控制器實現了對音頻信號采集模塊輸入語音信號的數字化。其處理流程如下圖所示。
圖2.9 語音信號數字化流程圖
在程序中,控制語音信號采集的函數如下。
1void record(void)
2{
3 delay_ms(atap_len_t); //延時,規避點擊屏幕發出的噪聲
4 TIM_Cmd(TIM1, ENABLE); //開啟定時器,開始信號采集
5 GUI_ClrArea(&(Label[G_ctrl])); //顯示操作提示
6
7 GUI_DispStr(&(Label[G_ctrl]),“錄音中”);
8 delay_ms(atap_len_t); //開始說話之前,錄制一小段背景聲音,用以實現背景噪聲自適應
9 //提示開始說話
10 set_label_backclor(&(Label[G_spk]), spk_clor);
11 //等待緩沖區數據更新完畢
12 while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
13 TIM_Cmd(TIM1, DISABLE); //數據采集結束,關閉定時器
14 DMA_ClearFlag(DMA1_FLAG_TC1); //清數據傳輸完成標志,以備下次使用
15 //提示開始處理采集到的數據
16 set_label_backclor(&(Label[G_spk]), prc_clor);
17}
分幀就是將采集到的語音數據分割成相同長度的片段,以用于短時分析。本設計中取20ms即160點為一幀,幀移10ms即80點。為了適應MCU存儲空間有限的實際情況,分幀并沒有被單獨設計和占用單獨的空間,而是在讀語音數據緩沖區的時候按照幀長幀移的順序依次讀取。
由于端點檢測屬于時域分析,并不需要加窗和預加重,所以本設計中,分幀和預加重都加在端點檢測之后提取MFCC之前。
2.2.2 端點檢測算法設計本設計采用短時幅度和短時過零率相結合的端點檢測算法。
首先去緩沖區前300ms作為背景噪聲,提取背景噪聲參數。用于后續端點檢測。背景噪聲參數由以下結構體定義。
1typedef struct
2{
3 u32 mid_val; //語音段中值 相當于有符號的0值 用于短時過零率計算
4 u16 n_thl; //噪聲閾值,用于短時過零率計算
5 u16 z_thl; //短時過零率閾值,超過此閾值,視為進入過渡段。
6 u32 s_thl; //短時累加和閾值,超過此閾值,視為進入過渡段。
7}atap_tag; //自適應參數
提取函數為void noise_atap(const u16* noise,u16 n_len,atap_tag* atap),其提取過程如下。
圖2.10 背景噪聲參數提取流程
然后根據提取到的短時過零率和短時幅度計算有效語音起始和結束點。有效語音端點由以下結構體定義。
1typedef struct
2{
3 u16 *start; //起始點
4 u16 *end; //結束點
5}valid_tag; //有效語音段
端點檢測函數為void VAD(const u16 *vc, u16 buf_len, valid_tag *valid_voice, atap_tag *atap_arg)。其流程圖如下。
圖2.11 端點檢測流程
2.2.3 特征提取算法設計及優化本設計選用12階MFCC作為語音特征。此步是整個算法流程中最耗時也是優化空間最大的部分。因此,在程序設計中,沿用經典算法的同時做了大量的針對STM32嵌入式平臺的優化工作。優化的中心思想是:盡量少使用或不使用浮點運算;使用整型數,其運算結果應盡量大以減少舍入噪聲,但必須保證數據不會溢出;空間換時間。
FFT函數是u32* fft(s16* dat_buf, u16 buf_len)。它封裝了了ST提供的STM32固件庫里的void cr4_fft_1024_stm32(void *pssOUT, void *pssIN, u16 Nbin)函數。cr4_fft_1024_stm32()輸入參數是有符號數,包括實數和虛數,但語音數據只包括實數部分,虛數用0填充,fft點數超出輸入數據長度時,超過部分用0填充。cr4_fft_1024_stm32()輸出數據包括實數和虛數,應該取其絕對值,即平方和的根。
語音特征用如下結構體定義。
1typedef struct
2{
3 u16 save_sign; //存儲標記 用于判斷flash中特征模板是否有效
4 u16 frm_num; //幀數
5 s16 mfcc_dat[vv_frm_max*mfcc_num]; //MFCC轉換結果
6}v_ftr_tag;
獲取MFCC的函數是void get_mfcc(valid_tag *valid, v_ftr_tag *v_ftr, atap_tag *atap_arg)。獲取MFCC的一般步驟在上一章已有論述,在此介紹移植到MCU上需做的優化。
預加重的高通濾波系數為0.95,如果直接使用,則需要進行浮點運算,盡量避免,故使用y(n)=x(n)-x(n-1)×95/100。加漢明窗窗函數值如果每次都要重新計算,則需要進行三角函數運算,耗時嚴重,效率低下。但其數值是一定的,因此事先計算好160點的漢明窗值。存于數組中const u16 hamm[],使用時直接讀取。FFT函數直接輸入ADC轉換過的值-2048~2047,其輸出頻譜幅值過小,舍入誤差較大。數據輸入前需作放大處理。vc_temp[ i]=(s16)(temp*hamm[ i]/(hamm_top/10));此句代碼在實現加窗的同時,將語音數據放大10倍。Mel三角濾波器的中心頻率和數值的計算涉及到對數運算,不宜直接計算,也實現計算好的數值存于Flash中,使用時直接讀取。還有其他的優化措施,詳見附件代碼。
void get_mfcc(valid_tag *valid, v_ftr_tag *v_ftr, atap_tag *atap_arg)函數流程如下。
圖2.12 特征提取流程
2.2.4模板訓練算法設計
本設計模板訓練采用冗余模板算法,即每個語音指令存儲4個特征模板,識別時輸入特征分別與每個特征模板相比較,匹配距離最小的,就是識別結果。這4個特征模板存儲于MCU Flash后端,模板訓練時,將模板存于指定的Flash地址。為了保證保存的特征模板不被擦除或被其他代碼或數據占用,需設置編譯器的地址范圍。
2.2.5特征匹配算法設計
本設計特征匹配算法采用 DTW(動態時間彎折)。其原理在上一章已有論述,在此不再贅述。其流程如下。
圖2.13 特征匹配流程
2.2.6顯示界面設計本設計在觸摸式LCD上實現了簡單的GUI操作界面。能夠顯示中英文文本框、按鈕。
最基本元素為GUI_Area,定義如下。
1typedef struct
2{
3 u16 Left; //區域離屏幕左邊界的距離 像素
4 u16 Top; //區域離屏幕上邊界的距離 像素
5 u16 Width; //區域寬度 像素
6 u16 Height; //區域高度 像素
7 u16 BackColor; //區域背景色
8 u16 ForeColor; //區域前景色
9}GUI_Area;
在此基礎上實現了以下函數。
1void wait_touch(void); //等待屏幕點擊
2u8 touch_area(GUI_Area *area); //判斷是否點擊指定區域
3void GUI_HideArea(GUI_Area *Area); //隱藏區域 顯示屏幕前景色
4void GUI_ClrArea(GUI_Area *Area); //清除區域 顯示區域背景色
5void GUI_DispStr(GUI_Area *Area,const u8 *str); //在區域內顯示字符串
6void GUI_printf(GUI_Area *Area,char *fmt, 。。。); //printf函數在區域內的實現
配合顯示界面,主函數流程如下。
圖2.14 主程序流程
第三章 系統制作及調試結果3.1系統制作與調試本系統的制作調試主要分為Matlab仿真、硬件調試、軟件調試。
經過初步的分析設計后,Matlab中仿真算法。調節算法細節,直至能夠較好地實現所需功能,再將其移植到MCU平臺上。在設計制作硬件電路的同時,調試穿插進行,應用系統的硬件調試和軟件調試是分不開的,許多硬件故障是在調試軟件時才發現的。但通常是先排除系統中明顯的硬件故障后才和軟件結合起來調試,如此有利于問題的分析和解決,不會造成問題的積累,從而可以節約大量的調試時間。軟件編程中,首先完成單元功能模塊的調試,然后進行系統調試,整體上采用硬件調試的調試方法。
3.2制作與調試結果經過制作與調試,實現了系統預設功能。實物圖如下。
圖3.1 實物圖 歡迎界面
圖3.2 實物圖 模板訓練界面
圖3.3 實物圖 語音識別界面
結 論原理樣機經過設計方案論證,設計了相應的硬件電路和系統軟件,制作了電路原理樣機并進行單機調試,結果表明,所設計的電路和軟件能完成基本的測試功能。
采用STM32F103VET6單片機構建語音識別系統,通過此系統對語音信號進行采集、前端放大、AD轉換、預處理、MFCC特征提取、模板訓練、DTW特征匹配的一系列步驟,完成孤立詞語音識別的預期目標。
本設計目前也存在一些不足,例如語音信號采集模塊的動態范圍不足,當說話聲音較大或較小時,會出現無法識別的現象,需加上自動增益控制功能。語音識別時,錄音控制不方便,最好能夠改進為完全通過語音控制。特征模板僅僅用12階MFCC略顯不足,可添加MFCC一階差分。
參考文獻[1] 韓紀慶、張磊、鄭鐵然。 語音信號處理。 北京:清華大學出版社[M],2004年9月
[2] 董辰輝、彭雪峰。 MATLAB 2008 全程指南。 北京:電子工業出版社[M],2009年3月
[3] 張雪英。 數字語音處理及MATLAB仿真。 北京:電子工業出版社[M],2011年7月
[4] 趙力。 語音信號處理 第2版。 北京:機械工業出版社[M],2011年6月
[5] 陳程。 機載環境下的語音識別技術及實現[J]。電子科技大學碩士學位論文,2008年5月
[6] 蔣子云。 基于ARM嵌入式孤立詞語音識別系統研究與實現[J]。 中南大學碩士學位論文, 2009年5月
[7] 白順先。 漢語孤立字語音識別技術的研究[J]。 西南交通大學碩士學位論文, 2009年6月
[8] 童紅。 孤立詞語音識別系統的技術研究[J]。 江蘇大學碩士學位論文, 2009年6月
[9] 汪冰。 小詞匯非特定人的孤立詞語音識別系統的研究與設計[J]。 廣東工業大學碩士學位論文, 2008年5月
[10] 黃振華。 孤立詞識別中的說話人歸一化技術[J]。 上海大學碩士學位論文, 2009年1月
開源
/********* main.C **********/
#include “includes.h”
#include “VAD.H”
#include “MFCC.H”
#include “DTW.H”
#include “GUI.H”
#include “flash.h”
#include “delay.h”
u16 VcBuf[VcBuf_Len];
atap_tag atap_arg;
valid_tag valid_voice[max_vc_con];
v_ftr_tag ftr;
typedef struct
{
u8 str[3];
}comm_tag;
comm_tag commstr[]={“0 ”,“1 ”,“2 ”,“3 ”,“4 ”,“5 ”,“6 ”,“7 ”,“8 ”,“9 ”,“上”,“下”,“前”,“后”,“左”,“右”,“大”,“小”};
#define sel_clor BRED
#define dis_sel_clor GRED
#define spk_clor BRED
#define prc_clor GRED
#define save_ok 0
#define VAD_fail 1
#define MFCC_fail 2
#define Flash_fail 3
void disp_comm(u8 comm)
{
GUI_ClrArea(&(Label[comm]));
GUI_DispStr(&(Label[comm]),(u8 *)(commstr[comm-G_comm_fst].str));
}
void set_comm_backclor(u8 comm, u16 backclor)
{
Label[comm].BackColor=backclor;
disp_comm(comm);
}
void set_label_backclor(GUI_Area *Label, u16 backclor)
{
Label-》BackColor=backclor;
GUI_ClrArea(Label);
}
void disp_home(void)
{
GUI_ClrArea(&Screen);
GUI_ClrArea(&(Label[G_wel]));
GUI_DispStr(&(Label[G_wel]),“歡迎使用”);
GUI_ClrArea(&(Label[G_neme]));
GUI_DispStr(&(Label[G_neme]),“孤立詞語音識別測試系統”);
GUI_ClrArea(&(Label[G_prc]));
GUI_DispStr(&(Label[G_prc]),“模板訓練”);
GUI_ClrArea(&(Label[G_recg]));
GUI_DispStr(&(Label[G_recg]),“語音識別”);
GUI_ClrArea(&(Label[G_designer]));
GUI_DispStr(&(Label[G_designer]),“設計者:宋健”);
}
void record(void)
{
delay_ms(atap_len_t); //延時,避免點擊屏幕發出的噪聲
TIM_Cmd(TIM1, ENABLE); //開啟定時器,開始信號采集
GUI_ClrArea(&(Label[G_ctrl])); //顯示操作提示
GUI_DispStr(&(Label[G_ctrl]),“錄音中”);
//開始說話之前,錄制一小段背景聲音,用以實現背景噪聲自適應
delay_ms(atap_len_t);
//提示開始說話
set_label_backclor(&(Label[G_spk]), spk_clor);
//等待緩沖區數據更新完畢
while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
//數據采集結束,關閉定時器
TIM_Cmd(TIM1, DISABLE);
//清數據傳輸完成標志,以備下次使用
DMA_ClearFlag(DMA1_FLAG_TC1);
//提示開始處理采集到的數據
set_label_backclor(&(Label[G_spk]), prc_clor);
}
void disp_mdl_prc(void)
{
u16 i;
GUI_ClrArea(&Screen);
set_label_backclor(&(Label[G_cap]), BRED);
GUI_DispStr(&(Label[G_cap]),“開始訓練”);
for(i=G_comm_fst;i《=G_comm_lst;i++)
{
disp_comm(i);
}
GUI_ClrArea(&(Label[G_return]));
GUI_DispStr(&(Label[G_return]),“返回”);
}
u8 save_mdl(u16 *v_dat, u32 addr)
{
noise_atap(v_dat,atap_len,&atap_arg);
VAD(v_dat, VcBuf_Len, valid_voice, &atap_arg);
if(valid_voice[0].end==((void *)0))
{
return VAD_fail;
}
get_mfcc(&(valid_voice[0]),&ftr,&atap_arg);
if(ftr.frm_num==0)
{
return MFCC_fail;
}
return save_ftr_mdl(&ftr, addr);
}
void prc(void)
{
u32 i;
u8 prc_start=0;
u8 comm=G_comm_fst;
u8 prc_count=0;
u32 addr;
//v_ftr_tag *sav_ftr;
disp_mdl_prc();
set_comm_backclor(comm,sel_clor);
while(1)
{
wait_touch();
if(touch_area(&(Label[G_return])))
{
Label[G_cap].BackColor=GREEN;
Label[comm].BackColor=dis_sel_clor;
disp_home();
return;
}
else if(touch_area(&(Label[G_cap])))
{
delay_ms(150);
if(prc_start==0)
{
GUI_ClrArea(&(Label[G_cap]));
GUI_DispStr(&(Label[G_cap]),“停止訓練”);
prc_start=1;
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),“開始”);
GUI_ClrArea(&(Label[G_spk]));
GUI_ClrArea(&(Label[G_count]));
GUI_DispStr(&(Label[G_count]),“已訓練0次”);
}
else
{
GUI_ClrArea(&(Label[G_cap]));
GUI_DispStr(&(Label[G_cap]),“開始訓練”);
prc_start=0;
prc_count=0;
GUI_HideArea(&(Label[G_ctrl]));
GUI_HideArea(&(Label[G_spk]));
GUI_HideArea(&(Label[G_stus]));
GUI_HideArea(&(Label[G_count]));
}
}
else if((touch_area(&(Label[G_ctrl])))&&(prc_start==1))
{
record();
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),“提取中”);
addr=ftr_start_addr+(comm-G_comm_fst)*size_per_comm+prc_count*size_per_ftr;
if(save_mdl(VcBuf, addr)==save_ok)
{
prc_count++;
GUI_ClrArea(&(Label[G_count]));
GUI_printf(&(Label[G_count]),“已訓練%d次”,prc_count);
if(prc_count==ftr_per_comm)
{
prc_count=0;
}
GUI_ClrArea(&(Label[G_stus]));
GUI_DispStr(&(Label[G_stus]),“語音有效”);
/*
sav_ftr=(v_ftr_tag *)addr;
USART1_printf(“mask=%d ”,sav_ftr-》save_sign);
USART1_printf(“frm_num=%d”,sav_ftr-》frm_num);
for(i=0;i《((sav_ftr-》frm_num)*mfcc_num);i++)
{
USART1_printf(“%d,”,sav_ftr-》mfcc_dat[i]);
}
*/
}
else
{
GUI_ClrArea(&(Label[G_stus]));
GUI_DispStr(&(Label[G_stus]),“語音無效”);
}
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),“開始”);
}
else if(prc_start==0)
{
for(i=G_comm_fst;i《=G_comm_lst;i++)
{
if(touch_area(&(Label[i])))
{
set_comm_backclor(comm,dis_sel_clor);
comm=i;
set_comm_backclor(comm,sel_clor);
break;
}
}
}
}
}
u8* spch_recg(u16 *v_dat, u32 *mtch_dis)
{
u16 i;
u32 ftr_addr;
u32 min_dis;
u16 min_comm;
u32 cur_dis;
v_ftr_tag *ftr_mdl;
noise_atap(v_dat, atap_len, &atap_arg);
VAD(v_dat, VcBuf_Len, valid_voice, &atap_arg);
if(valid_voice[0].end==((void *)0))
{
*mtch_dis=dis_err;
USART1_printf(“VAD fail ”);
return (void *)0;
}
get_mfcc(&(valid_voice[0]),&ftr,&atap_arg);
if(ftr.frm_num==0)
{
*mtch_dis=dis_err;
USART1_printf(“MFCC fail ”);
return (void *)0;
}
i=0;
min_comm=0;
min_dis=dis_max;
for(ftr_addr=ftr_start_addr; ftr_addr《ftr_end_addr; ftr_addr+=“size_per_ftr)
{
ftr_mdl=(v_ftr_tag*)ftr_addr;
//USART1_printf(”save_mask=%d “,ftr_mdl-》save_sign);
cur_dis=((ftr_mdl-》save_sign)==save_mask)?dtw(&ftr,ftr_mdl):dis_err;
//USART1_printf(”cur_dis=%d “,cur_dis);
if(cur_dis《min_dis)
{
min_dis=cur_dis;
min_comm=i;
}
i++;
}
min_comm/=ftr_per_comm;
//USART1_printf(”recg end “);
*mtch_dis=min_dis;
return (commstr[min_comm].str);
}
void disp_recg(void)
{
GUI_ClrArea(&Screen);
GUI_ClrArea(&(Label[G_cap]));
GUI_DispStr(&(Label[G_cap]),”語音識別“);
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),”開始“);
GUI_ClrArea(&(Label[G_spk]));
GUI_ClrArea(&(Label[G_return]));
GUI_DispStr(&(Label[G_return]),”返回“);
}
void recg(void)
{
u8 *res;
u32 dis;
u32 recg_count=0;
disp_recg();
while(1)
{
wait_touch();
if(touch_area(&(Label[G_return])))
{
disp_home();
return;
}
else if(touch_area(&(Label[G_ctrl])))
{
record();
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),”識別中“);
res=spch_recg(VcBuf, &dis);
if(dis!=dis_err)
{
recg_count++;
GUI_ClrArea(&(Label[G_recg_res]));
GUI_printf(&(Label[G_recg_res]),”識別結果:%s“,(s8 *)res);
GUI_ClrArea(&(Label[G_mtch_dis]));
GUI_printf(&(Label[G_mtch_dis]),”匹配距離:%d“,dis);
GUI_ClrArea(&(Label[G_stus]));
GUI_DispStr(&(Label[G_stus]),”語音有效“);
GUI_ClrArea(&(Label[G_count]));
GUI_printf(&(Label[G_count]),”已識別%d次“,recg_count);
}
else
{
GUI_HideArea(&(Label[G_recg_res]));
GUI_HideArea(&(Label[G_mtch_dis]));
GUI_ClrArea(&(Label[G_stus]));
GUI_DispStr(&(Label[G_stus]),”語音無效“);
}
GUI_ClrArea(&(Label[G_ctrl]));
GUI_DispStr(&(Label[G_ctrl]),”開始“);
}
}
}
int main(void)
{
BSP_Init();
USART1_printf(”SYS Init OK!“);
USART1_printf(”CPU Speed:%ld MHz“, BSP_CPU_ClkFreq() / 1000000L);
disp_home();
while(1)
{
wait_touch();
if(touch_area(&(Label[G_prc])))
{
prc();
}
else if(touch_area(&(Label[G_recg])))
{
recg();
}
}
}
評論
查看更多