《DNK210使用指南 -CanMV版 V1.0》第三十二章 音訊FFT實驗

正点原子發表於2024-10-22

第三十二章 音訊FFT實驗

1)實驗平臺:正點原子DNK210開發板

2)章節摘自【正點原子】DNK210使用指南 - CanMV版 V1.0

3)購買連結:https://detail.tmall.com/item.htm?&id=782801398750

4)全套實驗原始碼+手冊+影片下載地址:http://www.openedv.com/docs/boards/k210/ATK-DNK210.html

5)正點原子官方B站:https://space.bilibili.com/394620890

6)正點原子K210技術交流企鵝群:605557868

本章將介紹CanMV下FFT的應用,透過將時域採集到的音訊資料透過FFT為頻域。透過本章的學習,讀者將學習到CanMV下控制FFT加速器進行FFT的使用。
本章分為如下幾個小節:
32.1 maix.FFT模組介紹
32.2 硬體設計
32.3 程式設計
32.4 執行驗證

32.1 maix.FFT模組介紹
Kendryte K210片上擁有一個FFT Accelerator(快速傅立葉變換加速器)可以實現以硬體的方式對FFT的基2時分運算加速,Kendryte K210上的FFT Accelerator特點如下所示:

  1. 支援多種運算長度,即支援64點、128點、256點以及512點運算
  2. 支援兩種運算模式,即FFT以及IFFT運算
  3. 支援可配的輸入資料寬度,即支援32bit以及64bit輸入
  4. 支援可配的輸入資料排列方式,即支援虛部、實部交替,純實部以及實部、虛部分離三種資料排列方式
  5. 支援可配的資料搬運方式,即CPU搬運和DMA搬運
    在CanMV中可以使用CanMV提供的maix.FFT模組操作Kendryte K210上的FFT Accelerator。maix.FFT模組可以對輸入資料進行傅立葉變換並返回相應的頻率幅值,可以將時域訊號轉換為頻域訊號。
    maix.FFT模組提供了run()函式,用於對輸入的時域資料進行FFT,run()函式如下所示:
FFT.run(byte=None, points=64, shift=0, direction=1)

run()函式用於對輸入的時域資料進行FFT,運算過程會自動呼叫硬體上的FFTAccelerator,並會同時佔用DMAC Channel3和DMAC Channel4。
byte指的是輸入的時域資料,需要為bytearray型別。
points指的是FFT的運算長度,可以是64、128、256或512,預設為64。
shift指的是偏移,預設為0。
direction指的是運算模式,當為1時,為FFT,當為0時,是IFFT。
run()函式會返回一個list物件,表示計算後的頻域資料,list有points個元組,每個元組都有2個元素,第一個元素為實部,第二個元素為虛部。
run()函式的使用示例如下所示:

from maix import FFT
data = bytearray(64)
res = FFT.run(data, 64)

maix.FFT模組提供了amplitude()函式,用於計算FFT後各個頻率點的幅值,amplitude()函式如下所示:

FFT.amplitude(res)

amplitude()函式用於計算FFT後各個頻率點的幅值,從而能夠直觀地看到頻域下資料的狀態。
res指的是FFT.run()函式運算後返回的頻域資料。
amplitude()函式的使用示例如下所示:

from maix import FFT
data = bytearray(64)
res = FFT.run(data, 64)
amp = FFT.amplitude(res)

32.2 硬體設計
32.2.1 例程功能

  1. 獲取板載數字麥克風的音訊資料作為時域資料輸入maix.FFT模組進行FFT得到頻域資料後,計算頻域資料各個頻率點的幅值並在LCD上進行直觀的影像顯示

32.2.2 硬體資源

  1. 數字麥克風
    IIS_SDIN- IO30
    IIS_BCK- IO32
    IIS_LRCK- IO33

32.2.3 原理圖
本章實驗內容,需要獲取板載數字麥克風的音訊資料。
DNK210開發板上的數字麥克風的連線原理圖,如下所示:

圖32.2.3.1 數字功放NS4168連線原理圖

關於該數字麥克風的使用方法,可參考MSM261S4030H0R的資料手冊——《MSM261S4030H0R.pdf》,讀者可在A盤à硬體資料à晶片資料下找到這份文件。

32.3 程式設計
32.3.1 maix.FFT模組介紹
有關maix.FFT模組的介紹,請見第32.1小節《maix.FFT模組介紹》。

32.3.2 程式流程圖

圖32.3.2.1 音訊FFT實驗流程圖

32.3.3 main.py程式碼
main.py中的指令碼程式碼如下所示:

from board import board_info
from fpioa_manager import fm
from maix import GPIO
from maix import I2S
from maix import FFT
import lcd
import image
lcd.init()
img = image.Image(size=(lcd.width(), lcd.height()))
SAMPLE_RATE = 38640
SAMPLE_POINTS = 1024
FFT_POINTS = 512
HIST_NUM = 50
fm.register(board_info.SPK_CTRL, fm.fpioa.GPIO0)
fm.register(board_info.MIC_WS, fm.fpioa.I2S0_WS)
fm.register(board_info.MIC_SCLK, fm.fpioa.I2S0_SCLK)
fm.register(board_info.MIC_SDIN, fm.fpioa.I2S0_IN_D0)
spk_ctl = GPIO(GPIO.GPIO0, GPIO.OUT)
spk_ctl.value(0)
i2s_dev = I2S(I2S.DEVICE_0)
i2s_dev.channel_config(I2S.CHANNEL_0, I2S.RECEIVER, align_mode=I2S.STANDARD_MODE)
i2s_dev.set_sample_rate(SAMPLE_RATE)
hist_width = int(lcd.width() / HIST_NUM)
while True:
   data = i2s_dev.record(SAMPLE_RATE)
    # 對時域資料進行FFT
    res= FFT.run(data.to_bytes(), FFT_POINTS)
    # 計算頻域資料各頻率點的幅值
    amp= FFT.amplitude(res)
    img.clear()
    for hist in range(HIST_NUM):
       if amp[hist] > lcd.height():
           hist_height = lcd.height()
       else:
           hist_height = amp[hist]
       img.draw_rectangle(hist * hist_width, lcd.height() - hist_height, hist_width, hist_height, lcd.WHITE, 1, True)
    lcd.display(img)
    del data
    del res
    del amp

可以看到一開始是先完成分配IO、初始化LCD、GPIO、I2S,為透過I2S獲取板載數字揚聲器的音訊資料做準備。
然後便是在一個迴圈中不斷地透過I2S獲取音訊資料,然後將音訊資料作為時域資料輸入進行FFT運算,得到頻域資料的計算結果後,再計算頻域資料各頻率點的幅值,最後將各頻率點的幅值透過直方圖的形式在LCD上進行顯示。

32.4 執行驗證
將DNK210開發板連線CanMV IDE,點選CanMV IDE上的“開始(執行指令碼)”按鈕後,便了看到LCD上顯示了板載數字麥克風採集到音訊資料的頻譜圖,如下圖所示:

圖32.4.1 LCD顯示頻譜圖

相關文章