PyQt5开发的DSP信号仿真系统

本文介绍了一款使用PyQt5开发的数字信号处理(DSP)信号仿真系统,包括系统的效果图展示、主要功能、波形生成及信号分析的代码实现和画图功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PyQt5开发的DSP信号仿真系统

1、效果图

在这里插入图片描述

2、功能

具备的功能:
1、生成基础信号波形[正弦波,脉冲函数,阶跃函数,斜坡函数,
锯齿波,方波,常见非周期波形,sinc函数]
2、各基础波形可以叠加
3、可展示FFT频谱、信号卷积、功率频谱密度估计
4、可以读取音频信号及分析
5、各种滤波器

3、生成波形代码

# -*- coding: utf-8 -*-

"""
@contact: 微信 1257309054
@file: dsp.py
@time: 2024/4/20 21:03
@author: LDC
"""
    def get_sin_period(self, signal_type='1'):
        # 生成正弦波
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)

            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value  # 频率 (赫兹)
            amplitude = self.amp_edit_value  # 振幅
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)

            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value_2  # 频率 (赫兹)
            amplitude = self.amp_edit_value_2  # 振幅

        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)

        # 生成正弦波采样数据
        samples = amplitude * np.sin(2 * np.pi * frequency * t)
        return t, samples

    def get_impulse_period(self, signal_type='1'):
        # 获取脉冲信号
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)

        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)

        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
        system = ([1, 32], [1, 4, 64])
        t1, samples = signal.impulse(system, T=t, N=int(sampling_rate * duration))
        return t1, samples

    def get_step_period(self, signal_type='1'):
        # 获取阶跃信号
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)
        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
        system = ([1, 32], [1, 4, 64])
        t1, samples = signal.step(system, T=t, N=int(sampling_rate * duration))
        return t1, samples

    def get_sawtooch_period(self, signal_type='1'):
        # 获取斜坡函数(三角波)
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)

            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value  # 频率 (赫兹)
            amplitude = self.amp_edit_value  # 振幅
            width = self.width_edit_value  # 宽度
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)
            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value_2  # 频率 (赫兹)
            amplitude = self.amp_edit_value_2  # 振幅
            width = self.width_edit_value_2  # 宽度
        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)

        samples = amplitude * signal.sawtooth(2 * np.pi * frequency * t, width)  # 等腰三角
        return t, samples

    def get_square_period(self, signal_type='1'):
        # 获取矩形波
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)

            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value  # 频率 (赫兹)
            amplitude = self.amp_edit_value  # 振幅
            width = self.width_edit_value  # 宽度
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)
            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value_2  # 频率 (赫兹)
            amplitude = self.amp_edit_value_2  # 振幅
            width = self.width_edit_value_2  # 宽度
        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)

        samples = amplitude * signal.square(2 * np.pi * frequency * t, width)  # 矩形波
        return t, samples

    def get_sinc_period(self, signal_type='1'):
        # 获取sinc曲线
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)

            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value  # 频率 (赫兹)
            amplitude = self.amp_edit_value  # 振幅
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)
            # 设置正弦波的频率和振幅
            frequency = self.freq_edit_value_2  # 频率 (赫兹)
            amplitude = self.amp_edit_value_2  # 振幅
        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
        samples = amplitude * np.sinc(t * frequency)  # sinc曲线
        return t, samples

    def rect_wave(self, x, c, c0, a):
        # 起点为c0,宽度为c,振幅为a的矩形波
        if x >= (c + c0):
            r = 0.0
        elif x < c0:
            r = 0.0
        else:
            r = a
        return r

    def get_square_not_period(self, signal_type='1'):
        # 获取非周期矩形
        if signal_type == '1':
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value  # 持续时间 (秒)
            width = self.width_edit_value # 宽度
            amplitude = self.amp_edit_value  # 振幅
            start_edit_value = self.start_edit_value # 起点
        else:
            # 设置采样率和持续时间
            sampling_rate = self.sampling_rate_edit_value_2  # 采样率 (每秒采样点数)
            duration = self.duration_edit_value_2  # 持续时间 (秒)
            width = self.width_edit_value_2 # 宽度
            amplitude = self.amp_edit_value_2  # 振幅
            start_edit_value = self.start_edit_value_2  # 起点
        # 生成时间序列
        t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
        samples = np.array([self.rect_wave(i, width, start_edit_value, amplitude) for i in t])
        return t, samples

4、信号分析代码

    def btn_create_clicked(self):
        # 生成原始波形
        signal1 = self.signal_select.currentText()
        if signal1 == '正弦波':
            t, samples = self.get_sin_period()
        if signal1 == '脉冲函数':
            t, samples = self.get_impulse_period()
        elif signal1 == '阶跃函数':
            t, samples = self.get_step_period()
        elif signal1 == '斜坡函数':
            t, samples = self.get_sawtooch_period()
        elif signal1 == '方波':
            t, samples = self.get_square_period()
        elif signal1 == 'sinc曲线':
            t, samples = self.get_sinc_period()
        elif signal1 == '矩形(非周期)':
            t, samples = self.get_square_not_period()


        signal2 = self.signal_select_2.currentText()
        if signal2 == '正弦波':
            t2, samples2 = self.get_sin_period(signal_type='2')
        if signal2 == '脉冲函数':
            t2, samples2 = self.get_impulse_period(signal_type='2')
        elif signal2 == '阶跃函数':
            t2, samples2 = self.get_step_period(signal_type='2')
        elif signal2 == '斜坡函数':
            t2, samples2 = self.get_sawtooch_period(signal_type='2')
        elif signal2 == '方波':
            t2, samples2 = self.get_square_period(signal_type='2')
        elif signal2 == 'sinc曲线':
            t2, samples2 = self.get_sinc_period(signal_type='2')
        elif signal2 == '矩形(非周期)':
            t2, samples2 = self.get_square_not_period(signal_type='2')

        self.x_t1 = t
        self.x_t2 = t2
        self.is_create_samples = True
        self.samples1 = samples
        self.samples2 = samples2
        self.canvas9.figure.clear()  # 清空画布
        ax = self.fig9.add_subplot(111)
        # 调整图像大小

        ax.cla()  # TODO:删除原图,让画布上只有新的一次的图
        ax.plot(t, samples, color='red', label='s1')
        ax.plot(t2, samples2, color='blue', label='s2')
        ax.set_title('original Signal')
        ax.set_xlabel('T(s)')
        ax.set_ylabel('Am')
        ax.legend()
        self.fig9.subplots_adjust(left=None, bottom=0.2, right=None, top=None, wspace=None, hspace=None)
        self.canvas9.draw()  # TODO:这里开始绘制

    def btn_fft_clicked(self):
        # 分析按钮:生成fft
        if self.is_create_samples == False:
            return
        X = np.fft.fft(self.samples1)  # 计算信号的FFT
        freq = np.fft.fftfreq(len(self.samples1), 1 / self.sampling_rate_edit_value)  # 计算对应的频率数组

        X2 = np.fft.fft(self.samples2)  # 计算信号的FFT
        freq2 = np.fft.fftfreq(len(self.samples2), 1 / self.sampling_rate_edit_value_2)  # 计算对应的频率数组
        self.canvas10.figure.clear()  # 清空画布
        ax = self.fig10.add_subplot(111)
        # 调整图像大小

        ax.cla()  # TODO:删除原图,让画布上只有新的一次的图
        ax.plot(freq, np.abs(X), color='red', label='s1')
        ax.plot(freq2, np.abs(X2), color='blue', label='s2')
        ax.set_title('FFT of original Signal')
        ax.set_xlabel('Frequency (Hz)')
        ax.set_ylabel('Amplitude')
        ax.legend()
        self.fig10.subplots_adjust(left=None, bottom=0.2, right=None, top=None, wspace=None, hspace=None)
        self.canvas10.draw()

    def btn_con_clicked(self):
        # 卷积按钮
        if self.is_create_samples == False:
            return
        f = signal.convolve(self.samples1, self.samples2) # 卷积

        self.canvas11.figure.clear()  # 清空画布
        ax = self.fig11.add_subplot(111)
        # 调整图像大小
        ax.cla()  # TODO:删除原图,让画布上只有新的一次的图
        ax.plot(f, color='red', label='s1 convolve s2')
        ax.set_title('convolve of original Signal')
        ax.set_xlabel('T(s)')
        ax.set_ylabel('Amplitude')
        ax.legend()
        self.fig11.subplots_adjust(left=None, bottom=0.2, right=None, top=None, wspace=None, hspace=None)
        self.canvas11.draw()
    
    def btn_spe_clicked(self):
        # 频谱按钮:功率频谱密度估计
        if self.is_create_samples == False:
            return
        # 计算信号的PSd
        freqs1, psd1 = signal.periodogram(self.samples1, self.sampling_rate_edit_value)  # 计算信号的功率频谱密度
        freqs2, psd2  = signal.periodogram(self.samples2, self.sampling_rate_edit_value_2)  # 计算信号的功率频谱密度
        self.canvas12.figure.clear()  # 清空画布
        ax = self.fig12.add_subplot(111)
        # 调整图像大小

        ax.cla()  # TODO:删除原图,让画布上只有新的一次的图
        ax.plot(freqs1, psd1, color='red', label='s1')
        ax.plot(freqs2, psd2, color='blue', label='s2')
        ax.set_title('PSD of original Signal')
        ax.set_xlabel('Frequency (Hz)')
        ax.set_ylabel('Amplitude')
        ax.legend()
        self.fig12.subplots_adjust(left=None, bottom=0.2, right=None, top=None, wspace=None, hspace=None)
        self.canvas12.draw()

5、画图代码

    def Timelayout_(self):
        self.fig5 = plt.figure()
        self.canvas5 = FigureCanvas(self.fig5)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas5)
        self.graphicsView_5.setLayout(layout)  # 设置好布局之后调用函数

        self.fig6 = plt.figure()
        self.canvas6 = FigureCanvas(self.fig6)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas6)
        self.graphicsView_6.setLayout(layout)  # 设置好布局之后调用函数

        self.fig7 = plt.Figure()
        self.canvas7 = FigureCanvas(self.fig7)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas7)
        self.graphicsView_7.setLayout(layout)  # 设置好布局之后调用函数

        self.fig8 = plt.Figure()
        self.canvas8 = FigureCanvas(self.fig8)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas8)
        self.graphicsView_8.setLayout(layout)  # 设置好布局之后调用函数

        # 原始波形
        self.fig9 = plt.Figure()
        self.canvas9 = FigureCanvas(self.fig9)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas9)
        self.graphicsView_base1.setLayout(layout)  # 设置好布局之后调用函数

        # fft波形
        self.fig10 = plt.Figure()
        self.canvas10 = FigureCanvas(self.fig10)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas10)
        self.graphicsView_fft.setLayout(layout)  # 设置好布局之后调用函数

        # 卷积波形
        self.fig11 = plt.Figure()
        self.canvas11 = FigureCanvas(self.fig11)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas11)
        self.graphicsView_con.setLayout(layout)  # 设置好布局之后调用函数

        # 频谱波形
        self.fig12 = plt.Figure()
        self.canvas12 = FigureCanvas(self.fig12)
        layout = QVBoxLayout()  # 垂直布局
        layout.addWidget(self.canvas12)
        self.graphicsView_spec.setLayout(layout)  # 设置好布局之后调用函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东木月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值