一、FFT 算法簡介
傅里葉變換 (Fourier Transform) 是將時域上的單一信號在頻域上進行分解的一種數學方法。它是計算機視覺和語音處理等領域的重要分支。但是,為了計算其進行傅里葉變換的過程 時間較長,不適用於實時處理。而通過快速傅里葉 變換 (Fast Fourier Transform, FFT) 算法處理,則可以大幅提高計算速度。
FFT 算法的主要思想是基於分治策略,將輸入信號分為偶數下標和奇數下標兩部分,各自計算後合併計算結果。如果 N 為 2 的冪,則 FFT 算法的複雜度為 O(N*log(N))。
二、使用 STM32FFT 庫實現 FFT
STM32FFT 庫是專門在 STM32F4xx、STM32F7xx 和 STM32F3xx 上實現 FFT 的庫。這個庫提供了兩種類型的 FFT:基於複數的 FFT 和基於實數的 FFT。由於大多數實際信號是實數類型,並且複數類型採用兩個浮點數進行表達,會有額外的計算量開銷。因此,基於實數的 FFT 更適用於實際應用場景。
下面是一個 STM32F4xx 系列上使用 STM32FFT 庫實現 FFT 的示例代碼。首先,要先配置時鐘和 ADC,並開啟 DMA 通道。
#define ADC_CONVERTED_DATA_BUFFER_SIZE 2048 static float32_t fft_input[ADC_CONVERTED_DATA_BUFFER_SIZE]; static float32_t fft_output[ADC_CONVERTED_DATA_BUFFER_SIZE]; // 時鐘配置 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // ADC 配置 ADC_InitTypeDef ADC_InitStruct; ADC_CommonInitTypeDef ADC_CommonInitStruct; DMA_InitTypeDef DMA_InitStruct; // ... // DMA 通道開啟 DMA_Cmd(DMA2_Stream0, ENABLE); // 等待 DMA 結束 while (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET) {} // FFT 計算 arm_rfft_fast_f32(&inst, fft_input, fft_output, 0); // DMA 通道關閉 DMA_Cmd(DMA2_Stream0, DISABLE);
三、預處理 FFT 數據
為了減少 FFT 計算的誤差,需要預處理數據。首先,應該去除直流分量,即將平均值從每個採樣值中減去,使得輸入區間變為 symmetrical interval。然後,將輸入區間從 [-1,1] 映射到 [0, 1],其中 [-1,0]、[0,1] 分別為頻域中的負數和正數區間。
下面是一個 STM32F4xx 系列上預處理 FFT 數據的示例代碼。
// 去除直流分量 for (int i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++) { fft_input[i] -= mean; } // 映射數據到 [0,1] 區間 for (int i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++) { fft_input[i] = fft_input[i] / (max - min) + 0.5f; } // 填充 0 memset(&fft_input[ADC_CONVERTED_DATA_BUFFER_SIZE], 0, sizeof(float32_t) * (ADC_CONVERTED_DATA_BUFFER_SIZE));
四、後處理 FFT 數據
我們可以通過 FFT 原理和公式將 FFT 輸出轉換回到時域。假設我們有一個長度為 N 的輸入信號,那麼通過 FFT 算法,我們將其轉換為一個長度為 N 的複數序列。在接下來的後處理 FFT 數據中,我們需要將其轉換回時域,以得到原始信號。
下面是一個 STM32F4xx 系列上預處理 FFT 數據的示例代碼。
// FFT 計算 arm_rfft_fast_f32(&inst, fft_input, fft_output, 0); // 去掉前面無用的數據 for (int i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++) { if (i < ADC_CONVERTED_DATA_BUFFER_SIZE / 2) { fft_output[i] = 0; } else { fft_output[i] = fft_output[i]; } } // IFFT 計算,結果存儲在 fft_input 內 arm_cfft_f32(&inst, fft_output, 1, 1); // 映射回時域 for (int i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++) { fft_input[i] = fft_input[i] * (max - min) / ADC_CONVERTED_DATA_BUFFER_SIZE - 0.5f; } // 增加直流分量 for (int i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++) { fft_input[i] += mean; } // DMA 通道關閉 DMA_Cmd(DMA2_Stream0, DISABLE);
五、總結
本文介紹了在 STM32F4xx 系列上使用 STM32FFT 庫實現 FFT 的方法。我們還討論了 FFT 計算前後的數據處理過程,並給出了示例代碼。這些代碼可以用於計算信號處理、計算機視覺等領域的算法,以實現實時處理。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/156870.html