【scipy 基礎】--傅里葉變換

来源:https://www.cnblogs.com/wang_yb/archive/2023/11/03/17806842.html
-Advertisement-
Play Games

傅里葉變換是一種數學變換,它可以將一個函數或信號轉換為另一個函數或信號,它可以將時域信號轉換為頻域信號,也可以將頻域信號轉換為時域信號。在很多的領域都有廣泛的應用,例如信號處理、通信、圖像處理、電腦科學、物理學、生物學等。 它最大的功能是能夠分析和提取信號的特征,將複雜的信號分解為簡單的信號。有人 ...


傅里葉變換是一種數學變換,它可以將一個函數或信號轉換為另一個函數或信號,它可以將時域信號轉換為頻域信號,也可以將頻域信號轉換為時域信號。
在很多的領域都有廣泛的應用,例如信號處理、通信、圖像處理、電腦科學、物理學、生物學等。

它最大的功能是能夠分析和提取信號的特征,將複雜的信號分解為簡單的信號。
有人甚至說傅里葉變換是一種可以讓我們看透世界本質的變換,將紛繁世界的表象中的本質顯現出來。

1. 簡介

從數學的角度來推導傅里葉變換的話,會涉及到很多的基本的數學概念,比如正交基,級數,正弦餘弦函數等等。
這裡主要是為了看懂和使用傅里葉變換,瞭解傅里葉變換中的主要概念即可,
Scipy庫會幫助我們處理其中的細節。

舉例來說,對於現實中遇到的如下一個原始信號(一般都是非周期性且無規律的):
image.png
這樣的信號,可以是聲音,可以是氣溫變化,可以是心電圖,甚至可以是股票漲跌情況等等。

原始的信號變化複雜,而且大部分情況都看不出什麼規律。
這時,傅里葉變換就能發揮作用了,它能夠將複雜無序的信號轉換為一系列簡單規則的信號。
比如上面的信號轉換之後變成下麵6個簡單的信號
image.png

另外,傅里葉變換是可逆的,它也能夠將變換後的多個簡單的信號還原成原始的複雜信號。

2. fft 模塊

Scipy中處理傅里葉變換有2個子模塊:fftfftpack
fftpack即將被淘汰,所以儘量使用fft模塊。

fft模塊中,傅里葉變換的主要函數有:

函數名 說明
fft 計算一維離散傅里葉變換
ifft 計算一維離散傅里葉逆變換
fft2 計算二維離散傅里葉變換
ifft2 計算二維離散傅里葉逆變換
fftn 計算N維離散傅里葉變換
ifftn 計算N維離散傅里葉逆變換

2.1. 變換示例

創建一個複合的信號:

import numpy as np
import matplotlib.pyplot as plt

# 生成 0~8pi 之間100個點
x = np.linspace(0, 8*np.pi, 100)

# 隨便生成6個不同的正弦信號
y1 = np.sin(x)
y2 = 4*np.sin(2*x)
y3 = 2*np.sin(4*x)
y4 = 8*np.sin(0.3*x)
y5 = 6*np.sin(0.8*x)
y6 = 0.5*np.sin(5*x)

y = y1 + y2 + y3 + y4 + y5 + y6

plt.plot(x, y)
plt.show()

image.png

下麵通過一維傅里葉變換,看看得到的結果:

from scipy import fft as spfft

fft_result = spfft.fft(y)
print(fft_result.shape)
# 運行結果
(100,)

fft_result[1:11]
# 運行結果(顯示前10個,總共100個)
array([ 99.548317    -0.j        , 273.43743482-274.69892934j,
       -10.91586207 +66.24943608j, 167.24328363-151.29814008j,
       -57.93543536 +49.80593353j, -30.50244642 +56.21303872j,
       -19.99077861 +37.24642604j, -13.54997057 +21.30562857j,
        35.119202  -161.91923934j, -17.17382544 +41.98143084j])


fft_result[-10:]
# 運行結果(顯示後10個,總共100個)
array([-13.61273919 -29.66475047j, -17.17382544 -41.98143084j,
        35.119202  +161.91923934j, -13.54997057 -21.30562857j,
       -19.99077861 -37.24642604j, -30.50244642 -56.21303872j,
       -57.93543536 -49.80593353j, 167.24328363+151.29814008j,
       -10.91586207 -66.24943608j, 273.43743482+274.69892934j])

觀察快速傅里葉轉換之後得到的結果:

  1. 轉換的結果中,每個元素都是複數
  2. 前10個元素中,除去第一個,剩下的元素和後10個元素相比,實部相同,虛部相反

傅里葉變換之後,可以得到兩個描述信號的圖形:

  1. 頻譜圖:各個頻率的波的振幅信息
  2. 相點陣圖:各個頻率的波的相位信息,相位就是波在特定時間所處的位置

頻譜信息可以通過 np.abs 方法計算得出:

fig = plt.figure(figsize=[8,4])
ax1 = fig.add_subplot(121) 
data = np.abs(fft_result)
ax1.plot(data)
ax1.set_title("雙邊頻譜圖")

ax2 = fig.add_subplot(122) 
data = np.abs(fft_result[:50])
ax2.plot(data)
ax2.set_title("單邊頻譜圖")

plt.show()

image.png

相位信息可以通過 np.angle 方法計算得出:

fig = plt.figure(figsize=[8,4])
ax1 = fig.add_subplot(121) 
data = np.angle(fft_result)
ax1.plot(data)
ax1.set_title("雙邊相點陣圖")

ax2 = fig.add_subplot(122) 
data = np.angle(fft_result[:50])
ax2.plot(data)
ax2.set_title("單邊相點陣圖")

plt.show()

image.png

從這兩個圖中就能得變換後各個頻率的信號的頻率,振幅,相位信息。

2.2. 逆變換示例

逆變換就是將變換後的信號還原為原始信號。

因為傅里葉變換並沒有任何信息的損失,所以逆變換之後可以看出信號的波形沒有任何改變。

data = spfft.ifft(fft_result)

# 逆變換之後,忽略虛部的數字
plt.plot(x, np.real(data))
plt.show()

image.png

3. 應用

最後,利用傅里葉變換,我們試著做一個改變聲音效果的小例子。

首先,讀取一段音頻,Scipy就可以直接讀取wav文件。

import scipy.io.wavfile as wav

# 讀取音頻,返回采樣率和採樣的數值
rate, all_samples = wav.read("/path/to/fft-test.wav")
print(rate)
print(all_samples[1000:1010])
# 運行結果
16000
[122 133 149 151 165 151 160 159 155 151]

plt.plot(all_samples)
plt.show()

image.png
音頻文件是網上隨便找的一段英語對話。

接著,對讀取的信號做傅里葉變換,觀察變換後的結果:

dd = spfft.rfft(all_samples)
plt.plot(np.abs(dd))
plt.show()

image.png
註意,這裡用了 rfft函數,不是之前的fft函數,
兩者的區別在於fft的結果是複數,會形成對稱的雙邊圖,就像上一節介紹的那樣。
rfft的結果是實數,且是單邊的,如上圖所示。

這兩個函數根據實際情況選擇使用,都可以對信號進行傅里葉變換。
因為我後面的處理不需要雙邊的信息,所以這裡用 rfft 函數來做傅里葉變換。

3.1. 處理一

第一種處理,我嘗試把頻率20000HZ以上的信號都去掉,看看音頻的效果有什麼變化。

new_data = dd.copy()
# 20000HZ以上頻率的數據設為0
new_data[20000:] = 0

fig = plt.figure(figsize=[8,4])
ax1 = fig.add_subplot(121) 
ax1.plot(np.abs(new_data))

ax2 = fig.add_subplot(122) 
ax2.plot(np.abs(dd))

plt.show()

image.png

處理之後的信號逆變換為原始信號,再保存為wav音頻文件,看音頻的變化效果。

new_data = spfft.irfft(new_data)
new_data = np.rint(new_data)
new_data = new_data.astype("int16")

wav.write("/path/to/fft-test-1.wav", rate, new_data) 

轉換後的音頻和原音頻比,聽起來聲音更加悶一些,模糊一些。

3.2. 處理二

這次與處理一相反,把20000HZ以下的信號去掉。

new_data = dd.copy()
# new_data[20000:] = 0
new_data[:20000] = 0

fig = plt.figure(figsize=[8,4])
ax1 = fig.add_subplot(121) 
ax1.plot(np.abs(new_data))

ax2 = fig.add_subplot(122) 
ax2.plot(np.abs(dd))

plt.show()

image.png

然後同樣的把信號逆變換回去,並保存為wav文件。

new_data = spfft.irfft(new_data)
new_data = np.rint(new_data)
new_data = new_data.astype("int16")

wav.write("/path/to/fft-test-2.wav", rate, new_data) 

這次的聲音聽起來很遙遠,像是長途電話的感覺。

4. 總結

本篇主要介紹了傅里葉變換是什麼,以及如何使用Scipy庫來進行傅里葉變換。
目的是瞭解和使用傅里葉變換,而不是從數學角度去推導傅里葉變換。

最後的小例子雖然簡單,但見微知著,僅僅刪除了一些頻率的信號,聲音效果就隨之變化。
如果把不同聲音的文件中,影響音調,音色的頻率分析出來,就可以製作一個變聲器,
把自己的聲音變成男聲女聲,兒童老人等等。

進一步,用二維傅里葉變換的話,可以分析圖像,把圖像中的主要頻率找出來,
深入下去既可以做圖像修複,也可以做圖像識別等等。

Scipy庫中還有多維傅里葉變換,可以分析現實情況下更加複雜的信號。

5. 附錄

文中用到的完整代碼(ipynb格式)和一個音頻文件,可以從下麵的地址下載:
scipy-fft-sample.zip:
https://url11.ctfile.com/f/45455611-910542660-6d7e0f?p=6872
(訪問密碼: 6872)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 歡迎訪問我的GitHub 這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos 本篇概覽 -《Go語言基準測試(benchmark)三部曲》已近尾聲,經歷了《基礎篇》和《記憶體篇》的實戰演練,相信您已熟練掌握了基準測試的常規操作以及各種 ...
  • 歸併排序和快速排序一樣,都是基於分治思想的應用。 通過遞歸,不斷將原數列分為兩個數列,然後再分別使其有序,最後通過歸併將兩個有序子數列合併為新的有序數列。 ...
  • 早在Java7的時候就被提出,但由於其複雜性,不斷跳票,直到Java9才有,那麼Java模塊化到底是什麼,在實際開發中又有什麼用呢? ...
  • 之前對接支付寶商家扣款的時候,在簽約協議的部分卡了很久,今天把之前遇到的簽約問題彙總記錄一下~ 協議簽約流程 首先幫大家捋一下簽約的順序,便於直觀理解: 其次還需要知道的是,支付寶的商家扣款的簽約介面有兩個: 一個是單獨簽約介面: 另一個是支付並簽約介面: 這兩個介面都可以簽約,主要區別在於簽約的時 ...
  • HashMap簡介 HashMap是Java語言中的一種集合類,它實現了Map介面,用於存儲Key-Value對。它基於哈希表數據結構,通過計算Key的哈希值來快速定位Value的位置,從而實現高效的插入、刪除和查找操作。下麵我們對照著JAVA1.8中的HashMap源碼來分析一下它的內部實現邏輯 ...
  • 在Go編程語言中處理數據時,經常會遇到數組和切片。這兩者是不同的數據結構,有各自的特性和用途。本文將對Go中的數組和切片進行比較,以幫助大家更好地理解它們。 1. 長度不同 一個主要的區別是長度。在Go中,數組是具有固定長度的數據結構,一旦創建,其大小不可更改。相比之下,切片具有動態大小,可以在運行 ...
  • 集合類不安全 List不安全 單線程情況下集合類和很多其他的類都是安全的,因為同一時間只有一個線程在對他們進行修改,但是如果是多線程情況下,那麼集合類就不一定是安全的,可能會出現一條線程正在修改的同時另一條線程啟動來對這個集合進行修改,這種情況下就會導致發生併發修改異常(在jdk11的環境下多次測試 ...
  • Spring Boot 是一種廣泛使用且非常流行的企業級高性能框架。以下是一些最佳實踐和一些技巧,我們可以使用它們來改進 Spring Boot 應用程式並使其更加高效。這篇文章會有點長,完整讀完文章需要一些時間。 1.正確的包目錄風格 正確的包目錄將有助於輕鬆理解代碼和應用程式的流程。 我們可以使 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...