【技术专辑】FSK用Python解释

本文将介绍FSK的一些背景知识,并演示如何在Python中编写模拟器。

 

推荐等级

 

中间

 

频移键控背景

 

频移键控(FSK)的目的是调制数字信号,使其可以无线传输。流行的无线标准蓝牙使用称为高斯FSK的略微修改的FSK形式。本文将重点介绍二进制FSK,它使用两个频率值来表示二进制值1和0.数据被转换为这些频率,传输,然后解调。有许多方法/电路来调制和解调FSK信号。本文将重点介绍一种比较平易近人的方法。

 

本文中建模的发射机假设基于数据值创建了两个不同的频率。这可以通过使用合成器或压控振荡器(VCO)在电路中实现。

 

本文中使用的接收器借用了模拟FM的概念。可以通过将频率变化转换为幅度变化来解调FM。然后,可以应用用于解调幅度调制(AM)的技术。接收器将使用微分器将频率转换为幅度,然后使用包络检波器+低通滤波器来移除载波频率并保留数据。然后使用数据限幅器  将模拟值转换为数字信号。 

 

【技术专辑】FSK用Python解释

 

该过程可以通过以下等式在数学上表示。

 

数据输入

 

【技术专辑】FSK用Python解释

 

VCO

 

VCO将数字信号转换为两个不同的频率,由fc + fdev和fc-fdev表示。

 

【技术专辑】FSK用Python解释

 

嘈杂的频道

 

通过空中传输信号会引入噪声。通过添加项n(t)来模拟该噪声。如果噪声变得太强,或者信号的幅度变得太弱,则无法解调数据。

 

【技术专辑】FSK用Python解释

 

微分

 

接收信号通过微分器,以便将数据信号与载波频率分开:

 

【技术专辑】FSK用Python解释

 

通过将幅度集中到一个项来简化这个等式,降低相移并且由于频率的不断变化而知道dm(t)/ dt为0:

 

【技术专辑】FSK用Python解释

 

这个例子忽略了相移,因为它是一个常数,我们可以解释它。在现实生活中,需要某种时钟恢复或比特同步方案。

 

信封检测器+滤波器

 

需要包络检测器将高频载波与调制到幅度上的低频数字数据分开。滤波器是低通类型,仅允许数字数据通过。

 

【技术专辑】FSK用Python解释

 

数据限幅器

 

数据限幅器消除了DC偏移和一些噪声,这些噪声会导致数字信号被正确读取出现问题。留下噪声项是因为限幅器无法消除所有噪声,如果噪声相对于信号(信噪比)足够大,则信号将变得不可读。在切片机之后我们留下了原始信号。

 

【技术专辑】FSK用Python解释

 

模拟

 

要求

 

•Python 2.7

 

•numpy

 

•matplotlib

 

•SciPy

 

数据输入和设置变量

 

代码的第一部分导入所需的库,设置FSK参数,并定义绘图功能。实际模拟首先创建一个随机零和一组数组,用作数据流。

 

                    import numpy as np

import pylab as pl

import scipy.signal.signaltools as sigtool

import scipy.signal as signal

from numpy.random import sample

 

#the following variables setup the system

Fc = 1000       #simulate a carrier frequency of 1kHz

Fbit = 50       #simulated bitrate of data

Fdev = 500      #frequency deviation, make higher than bitrate

N = 64          #how many bits to send

A = 1           #transmitted signal amplitude

Fs = 10000      #sampling frequency for the simulator, must be higher than twice the carrier frequency

A_n = 0.1       #noise peak amplitude

N_prntbits = 10 #number of bits to print in plots

 

def plot_data(y):

    #view the data in time and frequency domain

    #calculate the frequency domain for viewing purposes

    N_FFT = float(len(y))

    f = np.arange(0,Fs/2,Fs/N_FFT)

    w = np.hanning(len(y))

    y_f = np.fft.fft(np.multiply(y,w))

    y_f = 10*np.log10(np.abs(y_f[0:N_FFT/2]/N_FFT))

    pl.subplot(3,1,1)

    pl.plot(t[0:Fs*N_prntbits/Fbit],m[0:Fs*N_prntbits/Fbit])

    pl.xlabel('Time (s)')

    pl.ylabel('Frequency (Hz)')

    pl.title('Original VCO output versus time')

    pl.grid(True)

    pl.subplot(3,1,2)

    pl.plot(t[0:Fs*N_prntbits/Fbit],y[0:Fs*N_prntbits/Fbit])

    pl.xlabel('Time (s)')

    pl.ylabel('Amplitude (V)')

    pl.title('Amplitude of carrier versus time')

    pl.grid(True)

    pl.subplot(3,1,3)

    pl.plot(f[0:(Fc+Fdev*2)*N_FFT/Fs],y_f[0:(Fc+Fdev*2)*N_FFT/Fs])

    pl.xlabel('Frequency (Hz)')

    pl.ylabel('Amplitude (dB)')

    pl.title('Spectrum')

    pl.grid(True)

    pl.tight_layout()

    pl.show()

    

"""

Data in

"""

#generate some random data for testing

data_in = np.random.random_integers(0,1,N)

 

VCO

 

下一部分将比特流转换为正弦波,其频率取决于该比特是1还是0.原始比特流必须扩展以匹配模拟的采样频率。VCO的输出如下所示。请注意频率的变化取决于发送的位。

 

【技术专辑】FSK用Python解释

 

                    """

VCO

"""

t = np.arange(0,float(N)/float(Fbit),1/float(Fs), dtype=np.float)

#extend the data_in to account for the bitrate and convert 0/1 to frequency

m = np.zeros(0).astype(float)

for bit in data_in:

    if bit == 0:

        m=np.hstack((m,np.multiply(np.ones(Fs/Fbit),Fc+Fdev)))

    else:

        m=np.hstack((m,np.multiply(np.ones(Fs/Fbit),Fc-Fdev)))

#calculate the output of the VCO

y=np.zeros(0)

y=A * np.cos(2*np.pi*np.multiply(m,t))

plot_data(y)

      

嘈杂的频道

 

下一部分通过向发送信号添加正态分布值来模拟噪声信道。本例中的代码设置的噪声幅度为0.1,这样可以产生~14dB的信噪比。请注意时域中的噪声会破坏以下图表中的信号。

 

【技术专辑】FSK用Python解释

 

                    """

Noisy Channel

"""

#create some noise

noise = (np.random.randn(len(y))+1)*A_n

snr = 10*np.log10(np.mean(np.square(y)) / np.mean(np.square(noise)))

print "SNR = %fdB" % snr

y=np.add(y,noise)

#view the data after adding noise

plot_data(y)

      

微分器,包络检测器和低通滤波器

 

该差异很简单,只是一个离散的差异函数。使用希尔伯特变换完成包络检测。最后,使用截止频率为2 *比特率的100抽头FIR滤波器对信号进行低通滤波。这是一个相当极端的滤波器,特别是如果它将用于嵌入式系统。可以通过将截止频率更接近比特率并根据需要使用更少的抽头来优化滤波器。在下面的图中,过滤的数据在未过滤的数据之上绘制,以证明信号变换的深远影响。

 

 【技术专辑】FSK用Python解释

 

                    """

Differentiator

"""

y_diff = np.diff(y,1)

 

"""

Envelope detector + low-pass filter

"""

#create an envelope detector and then low-pass filter

y_env = np.abs(sigtool.hilbert(y_diff))

h=signal.firwin( numtaps=100, cutoff=Fbit*2, nyq=Fs/2)

y_filtered=signal.lfilter( h, 1.0, y_env)

#view the data after adding noise

N_FFT = float(len(y_filtered))

f = np.arange(0,Fs/2,Fs/N_FFT)

w = np.hanning(len(y_filtered))

y_f = np.fft.fft(np.multiply(y_filtered,w))

y_f = 10*np.log10(np.abs(y_f[0:N_FFT/2]/N_FFT))

pl.subplot(3,1,1)

pl.plot(t[0:Fs*N_prntbits/Fbit],m[0:Fs*N_prntbits/Fbit])

pl.xlabel('Time (s)')

pl.ylabel('Frequency (Hz)')

pl.title('Original VCO output vs. time')

pl.grid(True)

pl.subplot(3,1,2)

pl.plot(t[0:Fs*N_prntbits/Fbit],np.abs(y[0:Fs*N_prntbits/Fbit]),'b')

pl.plot(t[0:Fs*N_prntbits/Fbit],y_filtered[0:Fs*N_prntbits/Fbit],'g',linewidth=3.0)

pl.xlabel('Time (s)')

pl.ylabel('Amplitude (V)')

pl.title('Filtered signal and unfiltered signal vs. time')

pl.grid(True)

pl.subplot(3,1,3)

pl.plot(f[0:(Fc+Fdev*2)*N_FFT/Fs],y_f[0:(Fc+Fdev*2)*N_FFT/Fs])

pl.xlabel('Frequency (Hz)')

pl.ylabel('Amplitude (dB)')

pl.title('Spectrum')

pl.grid(True)

pl.tight_layout()

pl.show()

 

截断器

 

截断器取整个滤波信号的平均值,并将其用作判定阈值,以确定位是1还是0.该位决定是在位周期的中心完成的。结果保存到数组并与原始数据进行比较以查找位错误。位错误百分比将打印到控制台。

 

                    """

slicer

"""

#calculate the mean of the signal

mean = np.mean(y_filtered)

#if the mean of the bit period is higher than the mean, the data is a 0

rx_data = []

sampled_signal = y_filtered[Fs/Fbit/2:len(y_filtered):Fs/Fbit]

for bit in sampled_signal:

    if bit > mean:

        rx_data.append(0)

    else:

        rx_data.append(1)

 

bit_error=0

for i in range(0,len(data_in)):

    if rx_data[i#&93; != data_in[i]:

        bit_error+=1

print "bit errors = %d" % bit_error

print "bit error percent = %4.2f%%" % (float(bit_error)/float(N)*100)

 

结果

 

在信噪比非常小之前,不会开始发生误码。作为示例,变量A_n变为0.45,这产生~2dB的SNR。在这个级别中,在64位中,只发现一个是错误。以下是一些图表,展示了信号在此SNR值下的噪声。

 

带噪声的传输信号

 

【技术专辑】FSK用Python解释

 

收到后的图

 

 【技术专辑】FSK用Python解释

 

完整代码

 

                    import numpy as np

import pylab as pl

import scipy.signal.signaltools as sigtool

import scipy.signal as signal

from numpy.random import sample

 

#the following variables setup the system

Fc = 1000       #simulate a carrier frequency of 1kHz

Fbit = 50       #simulated bitrate of data

Fdev = 500      #frequency deviation, make higher than bitrate

N = 64          #how many bits to send

A = 1           #transmitted signal amplitude

Fs = 10000      #sampling frequency for the simulator, must be higher than twice the carrier frequency

A_n = 0.10      #noise peak amplitude

N_prntbits = 10 #number of bits to print in plots

 

def plot_data(y):

    #view the data in time and frequency domain

    #calculate the frequency domain for viewing purposes

    N_FFT = float(len(y))

    f = np.arange(0,Fs/2,Fs/N_FFT)

    w = np.hanning(len(y))

    y_f = np.fft.fft(np.multiply(y,w))

    y_f = 10*np.log10(np.abs(y_f[0:N_FFT/2]/N_FFT))

    pl.subplot(3,1,1)

    pl.plot(t[0:Fs*N_prntbits/Fbit],m[0:Fs*N_prntbits/Fbit])

    pl.xlabel('Time (s)')

    pl.ylabel('Frequency (Hz)')

    pl.title('Original VCO output versus time')

    pl.grid(True)

    pl.subplot(3,1,2)

    pl.plot(t[0:Fs*N_prntbits/Fbit],y[0:Fs*N_prntbits/Fbit])

    pl.xlabel('Time (s)')

    pl.ylabel('Amplitude (V)')

    pl.title('Amplitude of carrier versus time')

    pl.grid(True)

    pl.subplot(3,1,3)

    pl.plot(f[0:(Fc+Fdev*2)*N_FFT/Fs],y_f[0:(Fc+Fdev*2)*N_FFT/Fs])

    pl.xlabel('Frequency (Hz)')

    pl.ylabel('Amplitude (dB)')

    pl.title('Spectrum')

    pl.grid(True)

    pl.tight_layout()

    pl.show()

    

"""

Data in

"""

#generate some random data for testing

data_in = np.random.random_integers(0,1,N)

 

"""

VCO

"""

t = np.arange(0,float(N)/float(Fbit),1/float(Fs), dtype=np.float)

#extend the data_in to account for the bitrate and convert 0/1 to frequency

m = np.zeros(0).astype(float)

for bit in data_in:

    if bit == 0:

        m=np.hstack((m,np.multiply(np.ones(Fs/Fbit),Fc+Fdev)))

    else:

        m=np.hstack((m,np.multiply(np.ones(Fs/Fbit),Fc-Fdev)))

#calculate the output of the VCO

y=np.zeros(0)

y=A * np.cos(2*np.pi*np.multiply(m,t))

plot_data(y)

 

"""

Noisy Channel

"""

#create some noise

noise = (np.random.randn(len(y))+1)*A_n

snr = 10*np.log10(np.mean(np.square(y)) / np.mean(np.square(noise)))

print "SNR = %fdB" % snr

y=np.add(y,noise)

#view the data after adding noise

plot_data(y)

 

"""

Differentiator

"""

y_diff = np.diff(y,1)

 

"""

Envelope detector + low-pass filter

"""

#create an envelope detector and then low-pass filter

y_env = np.abs(sigtool.hilbert(y_diff))

h=signal.firwin( numtaps=100, cutoff=Fbit*2, nyq=Fs/2)

y_filtered=signal.lfilter( h, 1.0, y_env)

#view the data after adding noise

N_FFT = float(len(y_filtered))

f = np.arange(0,Fs/2,Fs/N_FFT)

w = np.hanning(len(y_filtered))

y_f = np.fft.fft(np.multiply(y_filtered,w))

y_f = 10*np.log10(np.abs(y_f[0:N_FFT/2]/N_FFT))

pl.subplot(3,1,1)

pl.plot(t[0:Fs*N_prntbits/Fbit],m[0:Fs*N_prntbits/Fbit])

pl.xlabel('Time (s)')

pl.ylabel('Frequency (Hz)')

pl.title('Original VCO output vs. time')

pl.grid(True)

pl.subplot(3,1,2)

pl.plot(t[0:Fs*N_prntbits/Fbit],np.abs(y[0:Fs*N_prntbits/Fbit]),'b')

pl.plot(t[0:Fs*N_prntbits/Fbit],y_filtered[0:Fs*N_prntbits/Fbit],'g',linewidth=3.0)

pl.xlabel('Time (s)')

pl.ylabel('Amplitude (V)')

pl.title('Filtered signal and unfiltered signal vs. time')

pl.grid(True)

pl.subplot(3,1,3)

pl.plot(f[0:(Fc+Fdev*2)*N_FFT/Fs],y_f[0:(Fc+Fdev*2)*N_FFT/Fs])

pl.xlabel('Frequency (Hz)')

pl.ylabel('Amplitude (dB)')

pl.title('Spectrum')

pl.grid(True)

pl.tight_layout()

pl.show()

 

"""

slicer

"""

#calculate the mean of the signal

mean = np.mean(y_filtered)

#if the mean of the bit period is higher than the mean, the data is a 0

rx_data = []

sampled_signal = y_filtered[Fs/Fbit/2:len(y_filtered):Fs/Fbit]

for bit in sampled_signal:

    if bit > mean:

        rx_data.append(0)

    else:

        rx_data.append(1)

 

bit_error=0

for i in range(0,len(data_in)):

    if rx_data[i] != data_in[i]:

        bit_error+=1

print "bit errors = %d" % bit_error

print "bit error percent = %4.2f%%" % (float(bit_error)/float(N)*100)

  • 【技术专辑】FSK用Python解释已关闭评论
    A+
发布日期:2019年03月04日  所属分类:参考设计