python信号采样,信号生成及DFT的python实现方式

本文详细解读了离散傅立叶变换(DFT)的工作原理,通过矩阵乘法简化公式,指导读者如何用Python生成正弦信号并使用scipy FFT模块验证。还提供了自定义DFT的两种方法,适合初学者理解信号处理基础。
摘要由CSDN通过智能技术生成

DFT

DFT(Discrete Fourier Transform),离散傅里叶变化,可以将离散信号变换到频域,它的公式非常简单:

r5qpt0v0o2v.jpg

zqlfv0w4tuc.jpg离散频率下标为k时的频率大小

hn0gokaywlz.jpg 离散时域信号序列

h2l0ubduzcg.jpg 信号序列的长度,也就是采样的个数

如果你刚接触DFT,并且之前没有信号处理的相关经验,那么第一次看到这个公式,你可能有一些疑惑,为什么这个公式就能进行时域与频域之间的转换呢?

这里,我不打算去解释它,因为我水平有限,说的不清楚。相反,在这里我想介绍,作为一个程序员,如何如实现DFT

从矩阵的角度看DFT

DFT的公式,虽然简单,但是理解起来比较麻烦,我发现如果用矩阵相乘的角度来理解上面的公式,就会非常简单,直接上矩阵:

v12nimaxw0g.jpg

OK,通过上面的表示,我们很容易将DFT理解成为一种矩阵相乘的操作,这对于我们编码是很容易的。

Talk is cheap, show me the code

根据上面的理解,我们只需要构建出S SS矩阵,然后做矩阵相乘,就等得到DFT的结果

在这之前,我们先介绍如何生成正弦信号,以及如何用scipy中的fft模块进行DFT操作,以验证我们的结果是否正确

正弦信号

lu3ztwczrhp.jpg

A: 幅度

f: 信号频率

n: 时间下标

T: 采样间隔, 等于 1/fs,fs为采样频率

ϕ \phiϕ: 相位

下面介绍如何生成正弦信号

import numpy as np

import matplotlib.pyplot as plt

%matplotlib inline

def generate_sinusoid(N, A, f0, fs, phi):

'''

N(int) : number of samples

A(float) : amplitude

f0(float): frequency in Hz

fs(float): sample rate

phi(float): initial phase

return

x (numpy array): sinusoid signal which lenght is M

'''

T = 1/fs

n = np.arange(N) # [0,1,..., N-1]

x = A * np.cos( 2*f0*np.pi*n*T + phi )

return x

N = 511

A = 0.8

f0 = 440

fs = 44100

phi = 0

x = generate_sinusoid(N, A, f0, fs, phi)

plt.plot(x)

plt.show()

fdll254s4zo.jpg

# 另一种生成正弦信号的方法,生成时长为t的序列

def generate_sinusoid_2(t, A, f0, fs, phi):

'''

t (float) : 生成序列的时长

A (float) : amplitude

f0 (float) : frequency

fs (float) : sample rate

phi(float) : initial phase

returns

x (numpy array): sinusoid signal sequence

'''

T = 1.0/fs

N = t / T

return generate_sinusoid(N, A, f0, fs, phi)

A = 1.0

f0 = 440

fs = 44100

phi = 0

t = 0.02

x = generate_sinusoid_2(t, A, f0, fs, phi)

n = np.arange(0, 0.02, 1/fs)

plt.plot(n, x)

y5iccwsl1ug.jpg

Scipy FFT

介绍如何Scipy的FFT模块计算DFT

注意,理论上输入信号的长度必须是

stnucaq4zxv.jpg才能做FFT,而scipy中FFT却没有这样的限制

这是因为当长度不等于

stnucaq4zxv.jpg时,scipy fft默认做DFT

from scipy.fftpack import fft

# generate sinusoid

N = 511

A = 0.8

f0 = 440

fs = 44100

phi = 1.0

x = generate_sinusoid(N, A, f0, fs, phi)

# fft is

X = fft(x)

mX = np.abs(X) # magnitude

pX = np.angle(X) # phase

# plot the magnitude and phase

plt.subplot(2,1,1)

plt.plot(mX)

plt.subplot(2,1,2)

plt.plot(pX)

plt.show()

v1gkxs1bq2g.jpg

自己实现DFT

自己实现DFT的关键就是构造出S,有两种方式:

4ixg5ukygk0.jpg

def generate_complex_sinusoid(k, N):

'''

k (int): frequency index

N (int): length of complex sinusoid in samples

returns

c_sin (numpy array): the generated complex sinusoid (length N)

'''

n = np.arange(N)

c_sin = np.exp(1j * 2 * np.pi * k * n / N)

return np.conjugate(c_sin)

def generate_complex_sinusoid_matrix(N):

'''

N (int): length of complex sinusoid in samples

returns

c_sin_matrix (numpy array): the generated complex sinusoid (length N)

'''

n = np.arange(N)

n = np.expand_dims(n, axis=1) # 扩充维度,将1D向量,转为2D矩阵,方便后面的矩阵相乘

k = n

m = n.T * k / N # [N,1] * [1, N] = [N,N]

S = np.exp(1j * 2 * np.pi * m) # 计算矩阵 S

return np.conjugate(S)

# 生成信号,用于测试

N = 511

A = 0.8

f0 = 440

fs = 44100

phi = 1.0

x = generate_sinusoid(N, A, f0, fs, phi)

# 第一种方式计算DFT

X_1 = np.array([])

for k in range(N):

s = generate_complex_sinusoid(k, N)

X_1 = np.append(X_1, np.sum(x * s))

mX = np.abs(X_1)

pX = np.angle(X_1)

# plot the magnitude and phase

plt.subplot(2,1,1)

plt.plot(mX)

plt.subplot(2,1,2)

plt.plot(pX)

plt.show()

# 结果和scipy的结果基本相同

yyd3un50h50.jpg

# 第二种方法计算DFT

S = generate_complex_sinusoid_matrix(N)

X_2 = np.dot(S, x)

mX = np.abs(X_2)

pX = np.angle(X_2)

# plot the magnitude and phase

plt.subplot(2,1,1)

plt.plot(mX)

plt.subplot(2,1,2)

plt.plot(pX)

plt.show()

zzet4adleqs.jpg

总结

回顾了DFT的计算公式,并尝试用矩阵相乘的角度来理解DFT

介绍了两种生成正弦信号的方法

实现了两种DFT的计算方法

完整代码在这里

以上这篇信号生成及DFT的python实现方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持聚米学院。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值