Python模拟调制

分享一下我用Python模拟的AM,PM,FM调制,起因就是刚开始了解调制的时候,有点理解不了,那模拟一下呗,然后就写了一个代码。
代码地址

先放一个AM的演示图
在这里插入图片描述

然后看一个程序调用,我不喜欢奇奇怪怪的操作,程序调用要符合操作逻辑:创建信息波和载波,然后生成调制信号波,最后画图。

fig = plt.figure() # 创建画布

# 初始化波的参数:频率和幅度
A = 2 # carrier wave amplitude 
m = 1  #  m is the amplitude sensitivity
mes_fre = 1 # message wave frequence 
car_fre = 10  # carrier  wave frequence 

# 创建信息波
signal = Signal()
mes_wave = SinWave(fre=mes_fre, Amp=A*m, Phi=0)
information_signal = signal + mes_wave
# 创建载波
carrier_signal = CosWave(fre=car_fre, Amp=A, Phi=0)
# 创建时间轴
time = np.arange(0, 2*np.pi, 0.01)
# 生成调制信号
am_sig = AM(information_signal, carrier_signal, A=A)

# 画出动图
ud = UpdateDist(fig, time, information_signal, carrier_signal, am_sig)
ani = animation.FuncAnimation(fig=fig,
                                func=ud,
                                frames=20,
                                interval=100,
                                blit=True)
plt.show()

我比较喜欢模块化应用,我在网上也调研了一部分的模拟代码,发现大多是一次性的工作,基本没有移植性。所以我就按照我的思想写了一个脚本,虽然代码会显得有点臃肿,但是移植性还是蛮不错的。接下来就分享一下我的思路,我不会讲调制的原理,就讲代码的实现方式。

创建大体的框架

1. 构建基本类变量

模拟的是调制,调制也就是两个信号的相互作用。信号也就是波的叠加,简化一下,载波(carrier wave)用单一频率的波表示,信号波(message wave)用波实现简单运算得到。这个时候还有点复杂,波的种类繁多,所以我就只考虑Sin和Cos波。对应到代码构造,我比较喜欢用类编程,于是就有了下面的结构

class Wavedef __init__(self, fre, Amp, Phi):
        # 定义波的公共属性:幅度、频率、相位
        pass 
    def __str__(self):
     # 打印波的信息,方便后期调试
     pass 

 class SinWave(Wave):
     # 继承 Wave 类,子类实现 波与波的乘法运算
     def __init__(self, fre, Amp, Phi, modu_wave=None):
         super().__init__(fre, Amp, Phi, modu_wave, info='Sin')

     def __call__(self, t):
         # 定义调用接口,实现将t带入运算
         pass
     def __mul__(self, scalar):
         # 定义 波与波 之间的乘法运算法则
         pass
        
     def __rmul__(self, scalar):
         # 也是 实现 波与波的运算 
         pass

 class CosWave(Wave):
     # 构造与 SinWave 类似,不同的只是乘法运算法则不同

 class Signal:
     def __init__(self, sig=None):
         # 初始化 "Signal", 可以是 Wave 也可以是 实数,内部用 list 保存
         pass

     def max_fre(self):
         # 获取 Signal 的最大频率
         pass

     def max_Amp(self):
         # 获取 Signal 的最大幅值
         pass

     def __iter__(self):
         # 使得 Signal 变为可迭代对象,满足 Signal*Wave的运算
         pass

     def __add__(self, sig):
         # Signal 满足加法运算
         pass

     def __radd__(self, sig):
         # Signal 满足加法运算
         pass

     def __call__(self, t):
         # Signal 满足可调用
         pass

     def __str__(self):
         # 打印 Signal 的信息,方便以后调试。
         pass
2. 完善调制函数

信号Signal和波Wave初始化完成后,需要考虑调制的函数。这里用3个函数表示三种调制就行了

def AM(information_signal, carrier_signal, A):
    # AM 幅度调制,A 是调幅的参数,参考AM调制的原理
    pass

def PM(information_signal, carrier_signal):
    # PM 相位调制 
    pass

def FM(information_signal, carrier_signal, h=1):
    # FM 频率调制,h是调频参数 参考FM调制的原理
    pass
3. 构建作图函数

创建画图类 UpdateDist

class UpdateDist:
    # 画动图时候推荐采用类编程,比函数好管理
    def __init__(self, fig, x, *func_y):
        # 初始化刚开始的图像显示,我这里初始化了三个波
        pass
    
    def __call__(self, i):
        # 调用函数,这里的 i 也就是 t=i 时刻函数的图像,这样达到了动态显示的效果
        pass

代码的完善

对代码的完善就是对上面框架的缝缝补补,有时候可能会修改框架,上面的框架是我推翻了一次原框架后的结果。不过上面的框架还是适用于 AM 调制,因为 AM 调制本质就是几个波的乘法运算,而 PM 和 FM 是修改了波的相位,于是我就加了一个 modu_wave 变量

class CosWave(Wave):
    def __init__(self, fre, Amp, Phi, modu_wave=None):
        # modu_wave 默认为 None ,如果 PM 和 FM 时需要传入
        super().__init__(fre, Amp, Phi, modu_wave, info='Cos')
        self.modu_wave = modu_wave
        
    
class SinWave(Wave):
    def __init__(self, fre, Amp, Phi, modu_wave=None):
        super().__init__(fre, Amp, Phi, modu_wave, info='Sin')
        self.modu_wave = modu_wave

代码的具体实现,点击获取原文可以查看。

关于代码中的一些函数的解释

我在代码中用了几个 __mul____add__等以__开头结尾的函数,这是python的魔法函数,它是python的一种协议。比如如果实现了函数 __add__,就可以使用 + 运算。

  1. __add____radd__

    # 比如这里有两个波
    test1_wave = CosWave(fre= 2, Amp=0.5, Phi=0)
    test2_wave = CosWave(fre= 3, Amp=0.5, Phi=0)
    # 实现了 __add__ 函数后 载波信号可以这么写
    signal = Signal()
    information_signal = signal  + test1_wave + test2_wave
    # 实现了 __radd__ 函数后,前后式子可以调换位置
    information_signal = test1_wave + signal + test2_wave
    
    # tip: 我这里只在 Signal 中实现了 + 法运算,所以 下面的写法会报错
    # test_wave = test1_wave + test2_wave # 报错
    # 原因嘛,我觉得 Signal 实现 + 就够使用了
    

    可以看看波的样子
    在这里插入图片描述

  2. __mul____rmul__

    # __mul__ 表示乘法运算
    # 还是上面的两个波,我可以直接这么写
    information_signal = signal  + test1_wave * test2_wave
    # 同理 实现了 __rmul__ 后可以换位置
    information_signal = signal  + test2_wave * test1_wave
    

    看看波的样子
    在这里插入图片描述

  3. __call__

    # 实现 # call 函数后,类变量可以和函数一样调用
    # 上面的波举例,我要是想知道 t=1 时函数的幅值我就可以这么写
    A1 = test1_wave(1) # 0.5
    A2 = test2_wave(1) # 0.5
    
  4. __str__

    # 实现函数后 可以使用 str(func) 打印函数
    # 接着上面的例子, 程序结果放在 '#' 后面
    print(test1_wave) # CosWave(Frequency is 2,Amplitude is 0.5,Initial phase is 0),modulate wave is None
    print(test2_wave) # CosWave(Frequency is 2,Amplitude is 0.5,Initial phase is 0),modulate wave is None
    

总结

以上就是我分享的这次代码的细节部分,点击阅读全文获取代码。最后放几个 PM 和 FM 调制的图,我曾经对着这个图呆了一早上。
代码地址

FM
PM

  • 13
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值