我是靠谱客的博主 彩色野狼,最近开发中收集的这篇文章主要介绍python 的Chirp功能,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

python 的Chirp功能

预期的学习目标(ILOS):
您应该
能够创建高斯白噪声信号并分析光谱含量(功率谱密度)和振幅分布(直方图)
能够在时间,频率和时频域中可视化线性和LGARITHMIC CHIRP/扫描信号
了解Python库的基本用途

# Let's do the ususal necessary and nice-to-have imports
%matplotlib inline
import matplotlib.pyplot as plt  # plotting
import numpy as np               # math

# imports we need in addition for this lab sheet
from IPython import display as ipd
import scipy.signal as sig

import seaborn as sns; sns.set() # optional styling ((un-)comment if you want)

随机信号 - 任务1
我们将在以下内容中处理随机信号。 可以使用numpys函数np.random.normal()生成具有正态分布的随机信号n [k]。

# create a normally distributed random signal of legth 1 second
noise=np.random.normal(size=8000)

plt.figure(figsize=(8,6))

# visualise the signal
plt.subplot(3,1,1)
plt.plot(noise)
plt.xlabel('$k$')
plt.ylabel('$n[k]$')

# show power spectral dendity
plt.subplot(3,1,2)
Omega, Pxx = sig.welch(noise)
plt.semilogy(Omega, Pxx)
plt.ylim([1e-7, 1e2])

plt.xlabel('normalised frequency $Omega$')

plt.ylabel('PSD${n[k]}$')
#plt.plot(1/len(noise)*np.abs(np.fft.fft(noise)**2))

# visualise the histogram
plt.subplot(3,1,3)
plt.hist(noise)
plt.xlabel('amplitude')
plt.ylabel('count')

plt.tight_layout()

# listen to the sound file
ipd.Audio(noise, rate=8000)

上图显示了时间域(上图)和频域中的噪声信号(就功率频谱密度,PSD,中间面板而言)。 虽然我们只能计算平方频谱以估计PSD,但此处应用的Welch方法向我们显示了一个差异较小的PSD。 下图显示了时域信号n [k]的幅度分布。

代码细节的解释:
plt.semilogx() # 将x轴设置为对数坐标轴
plt.semilogy() # 将y轴设置为对数坐标轴
plt.semilog() # x轴和y轴都设置为对数坐标
hist的参数非常多,但常用的有以下6个,只有第一个是必须的,后面5个可选
x: 作直方图所要用的数据,必须是一维数组。多维数组可以先进行扁平化再作图
bins: 直方图的柱数,可选项,默认为10
normed: 是否将得到的直方图向量归一化。默认为0
facecolor: 直方图颜色
edgecolor: 直方图边框颜色
alpha: 透明度
histtype: 直方图类型,‘bar’, ‘barstacked’, ‘step’, ‘stepfilled’
返回值:
n:直方图向量,是否归一化由参数normed设定。当normed取默认值时,n即为直方图各组内元素的数量(各组频数)
bins: 返回各个bin的区间范围
patches:返回每个bin里面包含的数据,是一个list

  • sig.welch()?

从PSD中,我们看到信号具有平坦的光谱,即是白噪声。 直方图揭示振幅值是正常分布的。 因此,我们可以得出结论,函数np.random.normal()会产生高斯白噪声。

定期重复的随机信号 - 任务2
为了在信号中添加一些结构,我们将通过连接长度p = 100个样品的随机信号的串联L/P重复来产生长度L = 8000样品的周期性随机信号。

L = 8000 # total length of signal
P = 100  # period

K = 250  # upper/lower limit for lag in ACF

# generate periodic random signal
np.random.seed(1) # this ensures that always the same "random" signal is generated
x0 = np.random.normal(size=P)
x  = np.tile(x0, L//P)

plt.figure(figsize=(8, 4))
#plt.stem(x[:2*K], basefmt='C0:', use_line_collection=True)
plt.plot(x[:2*K])
plt.xlim(0, 2*K)
plt.xlabel('$k$')
plt.ylabel('$x[k]$')
plt.title('First '+str(2*K)+'samples of a periodically repeated noise signal')
plt.grid(True)

# listen to the sound file
ipd.Audio(x, rate=8000)

代码细节的解释:
np.random.normal()的意思是一个正态分布,normal这里是正态的意思。我在看孪生网络的时候看到这样的一个例子:numpy.random.normal(loc=0,scale=1e-2,size=shape) ,意义如下:
参数loc(float):正态分布的均值,对应着这个分布的中心。loc=0说明这一个以Y轴为对称轴的正态分布,
参数scale(float):正态分布的标准差,对应分布的宽度,scale越大,正态分布的曲线越矮胖,scale越小,曲线越高瘦。
参数size(int 或者整数元组):输出的值赋在shape里,默认为None

调用签名:plt.stem(x, y)
x:制定棉棒的x轴基线上的位置
y:绘制棉棒的长度
linefmt:棉棒的样式
markerfmt:棉棒末端的样式
basefmt:指定基线的样式

chirp信号,又称扫描信号 - 任务3
定义所谓的线性频率chirp或简单的线性chir。 随着时间的流逝,该信号通过不同的频率扫描。
该chirp信号的瞬时频率f(t)随时间呈线性增加,即用常数a:
f(t)= f0+ at
更确切地说,在时间t,chirp信号的瞬时角频率f(t)是正弦曲线参数的衍生物除以2π,因此f(t)= t。

def generate_chirp(t1=0,t2=10,fs=8000):
    '''
    Generates a chirp signal by implementing $x(t)=sin(pi t^2)$
    
    Input:
        t1: float, optional
            start time (in seconds), default: start at 0 seconds
        t2: float, optional
            end time (in seconds), default: end at 10 seconds
        fs: float, optional
            sampling frequency in Hz, default: 8000 Hz
    Output:
        chirp signal
    
    Example use:
        x=generate_chirp(50,70,fs)
    '''
    length=t2-t1 # signlal length in seconds
    t = np.linspace(t1, t2, length*fs) # time vector from t1 to t2
    return np.sin(np.pi*t**2)

在实验室4的末尾已经解释了以下辅助功能,并计算出比L长的两个功率。 当您要计算正确的DFT/FFT长度时,在此处重新提供该函数。

# Helper function to give us the next power of two larger than the signal length 
def nextPowerOf2(L):
    '''
    Calculates the smallest power of 2 which is bigger than the length of input variable L
    
    This helper function can be used to calculate an appropriate 
    length for an DFT which is longer than the signal length L and is a power of 2.
    
    Input:
        L: int
            signal length
    Output:
        p: integer which is greater or equal than n and a power of 2
    
    Examples:
        for L in range(20):
            print('nextPowerOf2(L) for L='+str(L)+' is '+str(nextPowerOf2(L)))
            
        x=ones(11)
        L_FFT=nextPowerOf2(len(x))
    '''
    return int(np.max([2,2**np.ceil(np.log2(L))]))

fs=8000      # sampling frequency
t1=0         # time 1 in seconds (start time)
t2=8         # time 2 in seconds (end time)

# use our function to generate the chirp signal
x=generate_chirp(t1,t2,fs)

# plot chirp signal
plt.figure(figsize=(12, 4))
plt.subplot(1,2,1)
t = np.linspace(t1, t2, (t2-t1)*fs) # time vector from t1 to t2 for plotting
plt.plot(t,x)
plt.ylabel('$x_{mathrm{chirp}}(t)$')
plt.xlabel('$t$ in sec')
plt.title('Linear Chirp $x_{mathrm{chirp}}(t)=mathrm{sin}(pi t^2)$ between t='+str(t1)+' sec and t='+str(t2)+' sec')

# compute and plot magnitude spectrum
L_FFT=nextPowerOf2(len(x))
X = np.fft.rfft(x,n=L_FFT)
f = np.fft.rfftfreq(L_FFT, d=1./fs)

plt.subplot(1,2,2)
plt.plot(f, 20*np.log10(np.abs(X)))
plt.xlabel('frequency $f$')
plt.ylabel('$|X[f]|$ in dB')
#plt.ylim([0, 50])
plt.grid(True)


# listen to the sound file
ipd.Audio(x, rate=fs)

上图的左面板显示了时域中生成的CHIRP信号。 随着时间的推移频率增加的正弦信号(即,以后t的更快振荡)可见。 目前,频谱似乎更难解释,并且音频无法感知,但是希望当我们进一步实验时,这会变得清晰。
代码细节的解释:
np.rint()是根据四舍五入取整
np.ceil()是向上取整,与四舍五入无关

在np.fft中,有fft和rfft可以选择。
如果样本数据的总数量为N,fft函数返回N个变换后的数据,但是这N个数据是左右对称的,即有效的实际数据只有N/2+1个。
而rfft直接只返回N/2+1个数据,可以不用处理直接使用。

  • d=1./fs equals d=1/fs?

为了获得更多的洞察力,我们使用xlim()命令在上方右图中的频率图中进行缩放。

plt.plot(f, 20*np.log10(np.abs(X)))
plt.xlabel('frequency $f$')
plt.ylabel('$|X[f]|$ in dB')
plt.xlim([0, 50])
plt.grid(True)

我们现在看到,实际上存在(或多或少)平坦的频率范围(大约在0 Hz和≈8Hz之间),该频率与上面得出的瞬时频率的推导,即f(t)= t。

注意:您的音频设备(扬声器或耳机)无法以如此低的频率复制信号。 这就是为什么在生成的CHIRP信号播放期间没有声音的原因。

让我们分析以下时间参数的扫描时间T1 = 50秒至T2 = 100秒。我们现在看到,实际上存在(或多或少)平坦的频率范围(大约在0 Hz和≈8Hz之间),该频率与上面得出的瞬时频率的推导,即f(t)= t。

注意:您的音频设备(扬声器或耳机)无法以如此低的频率复制信号。 这就是为什么在生成的CHIRP信号播放期间没有声音的原因。

让我们分析以下时间参数的扫描时间T1 = 50秒至T2 = 100秒。

t1=50        # time 1 in seconds (start time)
t2=100       # time 2 in seconds (end time)

# use our function to generate the chirp signal
x=generate_chirp(t1,t2,fs)

# plot chirp signal
plt.figure(figsize=(12, 4))
plt.subplot(1,2,1)
t = np.linspace(t1, t2, (t2-t1)*fs) # time vector from t1 to t2
plt.plot(t,x)
plt.ylabel('$x_{mathrm{chirp}}(t)$')
plt.xlabel('$t$ in sec')
plt.title('Linear Chirp $x_{mathrm{chirp}}(t)=mathrm{sin}(pi t^2)$ between t='+str(t1)+' sec and t='+str(t2)+' sec')

# compute and plot magnitude spectrum
L_FFT=nextPowerOf2(len(x))
X = np.fft.rfft(x,n=L_FFT)
f = np.fft.rfftfreq(L_FFT, d=1./fs)

plt.subplot(1,2,2)
plt.plot(f, 20*np.log10(np.abs(X)))
plt.xlabel('frequency $f$')
plt.ylabel('$|X[f]|$ in dB')
#plt.ylim([0, 50])
plt.grid(True)

plt.tight_layout()

# listen to the sound file
ipd.Audio(x, rate=fs)

左图(时域中的CHIRP信号)现在不再非常直观,因为信号的给定长度有太多振荡。

但是,现在我们应该能够在播放期间感知信号。 当您在一定时间内收听信号时,您应该能够感知频率的增加。 请注意,信号的长度为T1 -T2 = 20秒。 查看频谱,我们现在已经看到有一个频谱平坦的频率范围。

再次,我们放大了光谱图:

plt.plot(f, 20*np.log10(np.abs(X)))
plt.xlabel('frequency $f$')
plt.ylabel('$|X[f]|$ in dB')
plt.xlim([0, 200])
plt.grid(True)

同样,我们看到频谱在分析的频率范围内是平坦的。

让我们尝试T1 = 300秒至T2 = 400秒。

t1=300       # time 1 in seconds (start time)
t2=400       # time 2 in seconds (end time)

# use our function to generate the chirp signal
x=generate_chirp(t1,t2,fs)

# plot chirp signal
plt.figure(figsize=(12, 4))
plt.subplot(1,2,1)
t = np.linspace(t1, t2, (t2-t1)*fs) # time vector from t1 to t2
plt.plot(t,x)
plt.ylabel('$x_{mathrm{chirp}}(t)$')
plt.xlabel('$t$ in sec')
plt.title('Linear Chirp $x_{mathrm{chirp}}(t)=mathrm{sin}(pi t^2)$ between t='+str(t1)+' sec and t='+str(t2)+' sec')

# compute and plot magnitude spectrum
L_FFT=nextPowerOf2(len(x))
X = np.fft.rfft(x,n=L_FFT)
f = np.fft.rfftfreq(L_FFT, d=1./fs)

plt.subplot(1,2,2)
plt.plot(f, 20*np.log10(np.abs(X)))
plt.xlabel('frequency $f$')
plt.ylabel('$|X[f]|$ in dB')
#plt.ylim([0, 50])
plt.grid(True)

plt.tight_layout()

# listen to the sound file
ipd.Audio(x, rate=fs)

频率范围再次较高(与前两个示例相比),Chirp扫描的频率范围是平坦的。

注意:频率图(正确)显示了一个平坦的频谱,但是我们认为信号是正弦的,即只有一个频率的信号,但随着时间的推移,信号是一个频率,但随着时间的推移变化(扫描到选定的频率范围)。 因此,在以下内容中同时同时对Anaylse光谱和时间是有意义的。

任务4: Scipy的Chirp功能
到目前为止创建的(CHIRP)信号以固定速度不同。 Scipy.Signal库提供了一个函数Chirp(),它比我们之前创建的功能更灵活。 参见例如 :

scipy.signal.chirp(t, f0, t1, f1, method='linear', phi=0, vertex_zero=True)[sour

在下文中,“ Hz”应解释为“单位周期”;这里没有要求该单元仅一秒。重要的区别在于,旋转单位是循环,而不是弧度。同样,t可以是空间而不是时间的测量。

参数
t:array_like评估波形的时间。
f0:float时间t = 0时的频率(例如Hz)。
t1:float指定F1的时间。
f1:float时间T1时波形的频率(例如Hz)。
方法{“线性”,“二次”,“对数”,“双曲线”},可选频率扫描。如果没有给出,则假定线性。
Phi:float,可选相位偏移,以度为单位。默认值为0。
Vertex_zero:bool,可选仅当方法为“二次”时才使用此参数。它确定频率图的顶点是在t = 0或t = t1时。
返回
y:ndarray一个数量阵列,该数组包含在t处评估的信号,并以所需的时间变化频率。

以下代码在T0 = 0秒和T1 = 5秒时创建和可视化f0 = 10 Hz和F1 = 6 Hz之间的CHIRP信号。 请注意,生成信号的长度的长度可能与T1不同。

fs=8000   # sampling frequency
length=10 # signlal length in seconds

t = np.linspace(0, length, length*fs) # time vector

f0 = 10         # frequency in Hz at time t_0=0
f1 = 6          # frequency in Hz at time t_1
t1 = 0.5*length # frequency in Hz at time t=0
x = sig.chirp(t, f0=f0, f1=f1, t1=t1, method='linear')

# plot time domain chirp
plt.figure(figsize=(12,10))
plt.subplot(3,1,1)
plt.plot(t, x)
plt.title('Linear Chirp, $f(t=0)='+str(f0)+'$ Hz, $f(t='+str(t1)+')='+str(f1)+'$ Hz')
plt.ylabel('$x_{mathrm{chirp}}(t)$')
plt.xlabel('$t$ in sec')

# compute and plot magnitude spectrum

L = 4*9192        # DFT length (we need a relatively large number here for high frequency resolution)
overlap = 4096  # also large overlap to get some time resolution between segments

plt.subplot(3,1,2)
f = np.fft.rfftfreq(L, 1/fs)
plt.plot(f, 20*np.log10(abs(np.fft.rfft(x,L))))
plt.xlim([0, 50])
plt.xlabel('$f$ in Hz')
plt.ylabel('$|X_{mathrm{chirp}}[f]|$ in dB')
plt.grid(True)

# plot spectrogram of chirp
plt.subplot(3,1,3)
plt.specgram(x,NFFT=L, Fs=fs, noverlap=overlap)
plt.colorbar()  # add a colorbar to the spectrogram
plt.ylim(0,50)
plt.grid(False)
plt.title('Spectrogram of Linear Chirp, $f(t=0)='+str(f0)+'$ Hz, $f(t='+str(t1)+')='+str(f1)+'$ Hz')
plt.ylabel('$f$ in Hz')
plt.xlabel('$t$ in sec')

plt.tight_layout()

ipd.Audio(x, rate=fs) # this will not be audible since frequency range is too low.

上面的图可视化时域信号xChirp(t)(顶部面板),频谱| xchirp(f)| (中间面板)和频谱图(下面板),即chirp(频谱)如何随着时间的流逝而发展。
请注意,上面生成的CHIRP的频率范围再次太低,无法在播放时感知声音。

以下代码生成并可视化时间和频率变量更改为f0 = 100 Hz,f1 = 3 kHz和T1 = 10秒。
请注意,删除Ylim()命令以沿频率方向放大频谱图,从而适应频谱图的参数。

fs=8000   # sampling frequency
length=10 # signlal length in seconds

t = np.linspace(0, length, length*fs) # time vector

f0 = 100    # frequency in Hz at time t_0=0
f1 = 3000   # frequency in Hz at time t_1
t1 = length # frequency in Hz at time t=0

x = sig.chirp(t, f0=f0, f1=f1, t1=t1, method='linear')

# plot time domain chirp
plt.figure(figsize=(12,10))
plt.subplot(2,1,1)
plt.plot(t, x)
#plt.plot(t[0:2*1280], chp2[0:2*1280]) # only show the initial samples of the chirp
plt.title('Linear Chirp, $f(t=0)='+str(f0)+'$ Hz, $f(t='+str(t1)+')='+str(f1)+'$ Hz')
plt.ylabel('$x_{mathrm{chirp}}(t)$')
plt.xlabel('$t$ in sec')

# plot spectrogram of chirp
L = 1024        # DFT length (since we don't want to zoom in we can take relatively 'normal' values)
overlap = 512  

plt.subplot(2,1,2) 
plt.specgram(x,NFFT=L, Fs=fs, noverlap=overlap)
plt.colorbar()  # add a colorbar to the spectrogram
#plt.ylim(0,50) 
plt.grid(False)
plt.title('Spectrogram of Linear Chirp, $f(t=0)='+str(f0)+'$ Hz, $f(t='+str(t1)+')='+str(f1)+'$ Hz')
plt.ylabel('$f$ in Hz')
plt.xlabel('$t$ in sec')

plt.tight_layout()

ipd.Audio(x, rate=fs)

可选:频谱图和控制配色栏的配色栏
查看上方的图时,我们可能希望正确对齐时间轴并放置颜色棒。 不幸的是,在这方面,Matplotlib不是用户友好的。

使用模块GridSpec允许对齐具有带有和不具有配色栏的元素的图。 以下示例证明了这一点,该示例将GridSpec-Constructor与字典GridSpec_kw指定的关键字一起使用。 反过来,该字典是Plt.subplot的参数之一,它创建了一个图形和一组子图。

基本上,创建了4个轴,左两个用于时域信号(左上)和频谱图(左下)。 右下方用于绘制配色栏,右上方为空。

# let's create a signal again

fs=8000   # sampling frequency
length=10 # signlal length in seconds

t = np.linspace(0, length, length*fs) # time vector

f0 = 100    # frequency in Hz at time t_0=0
f1 = 3000   # frequency in Hz at time t_1
t1 = length # frequency in Hz at time t=0

x = sig.chirp(t, f0=f0, f1=f1, t1=t1, method='linear')

# create time-frequency plot with properly placed colourbar

fig, ax = plt.subplots(2, 2, gridspec_kw={'width_ratios':  [1, 0.05], 
                                          'height_ratios': [1, 2]}, figsize=(8, 4))
ax[0, 0].plot(t, x, color='gray')
ax[0, 0].set_xlabel('Time (seconds)')
ax[0, 0].set_ylabel('Amplitude')

ax[0, 0].set_xlim([min(t), max(t)])   # display the whole signal
#ax[0, 0].set_xlim([0, 0.75]) # only display the first 0.75 sec
ax[0, 0].set_ylim([-1.2, 1.2])
ax[0, 1].set_axis_off() # do not display the axis in right upper corner


spec,_,_,im = ax[1, 0].specgram(x,NFFT=1024, Fs=fs, noverlap=512)
#im = ax[1, 0].imshow(10*np.log10(spec), aspect='auto', origin='lower', extent=[t1, t2, 0, 50])
plt.colorbar(mappable=im, cax=ax[1, 1])
ax[1, 0].set_xlabel('Time (seconds)')
ax[1, 0].set_ylabel('$f$ in Hz')
ax[1, 0].grid(False)
ax[1, 1].set_ylabel('Magnitude')

plt.tight_layout()

最后

以上就是彩色野狼为你收集整理的python 的Chirp功能的全部内容,希望文章能够帮你解决python 的Chirp功能所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部