调制信号识别系列 (一):基准模型

调制信号识别系列 (一):基准模型

说明:本文包含对CNN和CNN+LSTM基准模型的复现,模型架构参考下述两篇文章

文章目录

  • 调制信号识别系列 (一):基准模型
    • 一、论文
      • 1、DL-PR: Generalized automatic modulation classification method based on deep learning with priori regularization
      • 2、A Deep Learning Approach for Modulation Recognition via Exploiting Temporal Correlations
    • 二、流程
      • 1、数据加载
      • 2、训练测试
      • 3、可视化
    • 三、模型
      • 1、CNN
      • 2、CNN+LSTM(DL-PR)
      • 3、CNN+LSTM
    • 四、对比
      • 1、论文1
      • 2、论文2
    • 五、总结

一、论文

1、DL-PR: Generalized automatic modulation classification method based on deep learning with priori regularization

  • https://www.sciencedirect.com/science/article/pii/S095219762300266X

image-20240707105742936

image-20240706174502716

2、A Deep Learning Approach for Modulation Recognition via Exploiting Temporal Correlations

  • 2018 IEEE 19th International Workshop on Signal Processing Advances in Wireless Communications (SPAWC)

  • https://ieeexplore.ieee.org/abstract/document/8445938

image-20240707114714838

Note that before each convolutional layer, we use the zero-padding method to control the spatial size of the output volumes. Specifically, we pad the input volume with two zeros around the border, thus the output volume of the second convolutional layer is of size 32 × 132. We then take 32 as the dimensionality of the input and 132 as the time steps in LSTM layer. Dropout method is also used to prevent the neural network from overfitting. Compared to architecture in [12], we can see that we replace the third dense fully-connected layer with a LSTM layer. Our simulations suggest that this replacement not only reduces the number of parameters by an order of magnitude, but also leads to a significant performance improvement.

请注意,在每个卷积层之前,我们使用零填充方法来控制输出卷的空间大小。具体来说,我们在输入量的边界周围填充两个零,因此第二个卷积层的输出量的大小为 32 × 132。然后我们将 32 作为输入的维度,将 132 作为 LSTM 层的时间步长。 Dropout方法也用于防止神经网络过拟合。与[12]中的架构相比,我们可以看到我们用 LSTM 层替换了第三个密集全连接层。我们的模拟表明,这种替换不仅将参数数量减少了一个数量级,而且还带来了显着的性能改进。

二、流程

1、数据加载

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset, random_split
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from torchsummary import summary
# 加载数据
csv_file_path = 'snr_data/output_data_snr_6.csv'
data_frame = pd.read_csv(csv_file_path)# 提取前256列数据并转换为张量
vectors = torch.tensor(data_frame.iloc[:, :256].values, dtype=torch.float32)# 将256维向量转换为2x128的矩阵形式
vectors = vectors.view(-1, 2, 128)# 划分训练集和测试集索引
train_size = int(0.8 * len(vectors))
test_size = len(vectors) - train_size
train_indices, test_indices = random_split(range(len(vectors)), [train_size, test_size])# 使用训练集的统计量进行归一化
train_vectors = vectors[train_indices]# 对IQ分量分别进行归一化
train_mean_I = train_vectors[:, 0, :].mean(dim=0, keepdim=True)
train_std_I = train_vectors[:, 0, :].std(dim=0, keepdim=True)train_mean_Q = train_vectors[:, 1, :].mean(dim=0, keepdim=True)
train_std_Q = train_vectors[:, 1, :].std(dim=0, keepdim=True)# 归一化整个数据集
vectors[:, 0, :] = (vectors[:, 0, :] - train_mean_I) / train_std_I
vectors[:, 1, :] = (vectors[:, 1, :] - train_mean_Q) / train_std_Q# 提取Mod_Type列并转换为数值标签
mod_types = data_frame['Mod_Type'].astype('category').cat.codes.values
labels = torch.tensor(mod_types, dtype=torch.long)# 创建TensorDataset
dataset = TensorDataset(vectors, labels)# 创建训练集和测试集
train_dataset = TensorDataset(vectors[train_indices], labels[train_indices])
test_dataset = TensorDataset(vectors[test_indices], labels[test_indices])# 创建DataLoader
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
# 替换模型架构

2、训练测试

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 50
train_losses = []
test_losses = []
train_accuracies = []
test_accuracies = []def calculate_accuracy(outputs, labels):_, predicted = torch.max(outputs, 1)total = labels.size(0)correct = (predicted == labels).sum().item()return correct / totalfor epoch in range(num_epochs):# 训练阶段model.train()running_loss = 0.0correct = 0total = 0for inputs, labels in train_loader:inputs = inputs.to(device)labels = labels.to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()correct += (outputs.argmax(1) == labels).sum().item()total += labels.size(0)train_loss = running_loss / len(train_loader)train_accuracy = correct / totaltrain_losses.append(train_loss)train_accuracies.append(train_accuracy)# 测试阶段model.eval()running_loss = 0.0correct = 0total = 0with torch.no_grad():for inputs, labels in test_loader:inputs = inputs.to(device)labels = labels.to(device)outputs = model(inputs)loss = criterion(outputs, labels)running_loss += loss.item()correct += (outputs.argmax(1) == labels).sum().item()total += labels.size(0)test_loss = running_loss / len(test_loader)test_accuracy = correct / totaltest_losses.append(test_loss)test_accuracies.append(test_accuracy)print(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}")print("Training complete.")

3、可视化

epochs = range(1, num_epochs + 1)plt.figure(figsize=(12, 5))# 绘制损失图像
plt.subplot(1, 2, 1)
plt.plot(epochs, train_losses, label='Train Loss')
plt.plot(epochs, test_losses, label='Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.title('Loss vs. Epochs')# 绘制准确率图像
plt.subplot(1, 2, 2)
plt.plot(epochs, train_accuracies, label='Train Accuracy')
plt.plot(epochs, test_accuracies, label='Test Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Accuracy vs. Epochs')plt.show()

三、模型

说明:下述模型均在SNR=6dB RadioML2016.10a数据集下的实验结果,仅使用原始的IQ分量信息,未使用数据增强,也未进行调参

1、CNN

class CNNModel(nn.Module):def __init__(self):super(CNNModel, self).__init__()self.conv1 = nn.Conv2d(1, 64, (1, 4), stride=1)self.conv2 = nn.Conv2d(64, 64, (1, 2), stride=1)self.pool1 = nn.MaxPool2d((1, 2))self.conv3 = nn.Conv2d(64, 128, (1, 2), stride=1)self.conv4 = nn.Conv2d(128, 128, (2, 2), stride=1)self.pool2 = nn.MaxPool2d((1, 2))self.conv5 = nn.Conv2d(128, 256, (1, 2), stride=1)self.conv6 = nn.Conv2d(256, 256, (1, 2), stride=1)self.fc1 = nn.Linear(256 * 1 * 28, 512)self.fc2 = nn.Linear(512, 128)self.fc3 = nn.Linear(128, 11)def forward(self, x):x = x.unsqueeze(1)  # 添加通道维度x = torch.relu(self.conv1(x))x = torch.relu(self.conv2(x))x = self.pool1(x)x = torch.relu(self.conv3(x))x = torch.relu(self.conv4(x))x = self.pool2(x)x = torch.relu(self.conv5(x))x = torch.relu(self.conv6(x))x = x.view(x.size(0), -1)x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)return xmodel = CNNModel()
summary(model, (2, 128))

image-20240707115545394

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1           [-1, 64, 2, 125]             320Conv2d-2           [-1, 64, 2, 124]           8,256MaxPool2d-3            [-1, 64, 2, 62]               0Conv2d-4           [-1, 128, 2, 61]          16,512Conv2d-5           [-1, 128, 1, 60]          65,664MaxPool2d-6           [-1, 128, 1, 30]               0Conv2d-7           [-1, 256, 1, 29]          65,792Conv2d-8           [-1, 256, 1, 28]         131,328Linear-9                  [-1, 512]       3,670,528Linear-10                  [-1, 128]          65,664Linear-11                   [-1, 11]           1,419
================================================================
Total params: 4,025,483
Trainable params: 4,025,483
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.63
Params size (MB): 15.36
Estimated Total Size (MB): 15.98

image-20240707115320324

image-20240707115331410

2、CNN+LSTM(DL-PR)

import torch
import torch.nn as nnclass CNNLSTMModel(nn.Module):def __init__(self):super(CNNLSTMModel, self).__init__()self.conv1 = nn.Conv2d(1, 32, (2, 3), stride=1, padding=(0,1))  # Adjusted input channels and filtersself.conv2 = nn.Conv2d(32, 32, (1, 3), stride=1, padding=(0,1))self.pool1 = nn.MaxPool2d((1, 2))self.conv3 = nn.Conv2d(32, 64, (1, 3), stride=1, padding=(0,1))self.conv4 = nn.Conv2d(64, 64, (1, 3), stride=1, padding=(0,1))self.pool2 = nn.MaxPool2d((1, 2))self.conv5 = nn.Conv2d(64, 128, (1, 3), stride=1, padding=(0,1))self.conv6 = nn.Conv2d(128, 128, (1, 3), stride=1, padding=(0,1))self.pool3 = nn.MaxPool2d((1, 2))self.lstm = nn.LSTM(128, 32, batch_first=True)  # Adjusted input size and LSTM hidden sizeself.fc1 = nn.Linear(32, 128)self.fc2 = nn.Linear(128, 11)def forward(self, x):#print("x:",x.shape)if x.dim() == 3:x = x.unsqueeze(1)  # 假设x的形状是[2, 128], 这将改变它为[1, 2, 128]#print("x.unsqueeze(0):",x.shape)x = torch.relu(self.conv1(x))x = torch.relu(self.conv2(x))x = self.pool1(x)x = torch.relu(self.conv3(x))x = torch.relu(self.conv4(x))x = self.pool2(x)x = torch.relu(self.conv5(x))x = torch.relu(self.conv6(x))x = self.pool3(x)# Prepare input for LSTMx = x.view(x.size(0), 16, 128)  # Adjusted view#print(x.shape)x, (hn, cn) = self.lstm(x)x = x[:, -1, :]  # Get the last output of the LSTMx = torch.relu(self.fc1(x))x = self.fc2(x)return xmodel = CNNLSTMModel()
summary(model,input_size=(1, 2, 128))

image-20240707115501540

==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
CNNLSTMModel                             [1, 11]                   --
├─Conv2d: 1-1                            [1, 32, 1, 128]           224
├─Conv2d: 1-2                            [1, 32, 1, 128]           3,104
├─MaxPool2d: 1-3                         [1, 32, 1, 64]            --
├─Conv2d: 1-4                            [1, 64, 1, 64]            6,208
├─Conv2d: 1-5                            [1, 64, 1, 64]            12,352
├─MaxPool2d: 1-6                         [1, 64, 1, 32]            --
├─Conv2d: 1-7                            [1, 128, 1, 32]           24,704
├─Conv2d: 1-8                            [1, 128, 1, 32]           49,280
├─MaxPool2d: 1-9                         [1, 128, 1, 16]           --
├─LSTM: 1-10                             [1, 16, 32]               20,736
├─Linear: 1-11                           [1, 128]                  4,224
├─Linear: 1-12                           [1, 11]                   1,419
==========================================================================================
Total params: 122,251
Trainable params: 122,251
Non-trainable params: 0
Total mult-adds (M): 4.32
==========================================================================================
Input size (MB): 0.00
Forward/backward pass size (MB): 0.20
Params size (MB): 0.49
Estimated Total Size (MB): 0.69
==========================================================================================

image-20240707115432051

image-20240707115443808

3、CNN+LSTM

# 定义结合CNN和LSTM的模型
class CNNLSTMModel(nn.Module):def __init__(self):super(CNNLSTMModel, self).__init__()self.conv1 = nn.Conv2d(1, 64, (1, 4), stride=1)self.conv2 = nn.Conv2d(64, 64, (1, 2), stride=1)self.pool1 = nn.MaxPool2d((1, 2))self.conv3 = nn.Conv2d(64, 128, (1, 2), stride=1)self.conv4 = nn.Conv2d(128, 128, (2, 2), stride=1)self.pool2 = nn.MaxPool2d((1, 2))self.conv5 = nn.Conv2d(128, 256, (1, 2), stride=1)self.conv6 = nn.Conv2d(256, 256, (1, 2), stride=1)self.lstm = nn.LSTM(256, 128, batch_first=True)self.fc1 = nn.Linear(128, 512)self.fc2 = nn.Linear(512, 128)self.fc3 = nn.Linear(128, 11)def forward(self, x):x = x.unsqueeze(1)  # 添加通道维度x = torch.relu(self.conv1(x))x = torch.relu(self.conv2(x))x = self.pool1(x)x = torch.relu(self.conv3(x))x = torch.relu(self.conv4(x))x = self.pool2(x)x = torch.relu(self.conv5(x))x = torch.relu(self.conv6(x))# 重新调整x的形状以适应LSTMx = x.squeeze(2).permute(0, 2, 1)  # 变为(batch_size, 128, 256)# 通过LSTMx, _ = self.lstm(x)# 取最后一个时间步的输出x = x[:, -1, :]# 全连接层x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)return x
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = CNNLSTMModel().to(device)
summary(model,input_size=(1, 2, 128))

image-20240707115530202

==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
CNNLSTMModel                             [1, 11]                   --
├─Conv2d: 1-1                            [1, 64, 2, 125]           320
├─Conv2d: 1-2                            [1, 64, 2, 124]           8,256
├─MaxPool2d: 1-3                         [1, 64, 2, 62]            --
├─Conv2d: 1-4                            [1, 128, 2, 61]           16,512
├─Conv2d: 1-5                            [1, 128, 1, 60]           65,664
├─MaxPool2d: 1-6                         [1, 128, 1, 30]           --
├─Conv2d: 1-7                            [1, 256, 1, 29]           65,792
├─Conv2d: 1-8                            [1, 256, 1, 28]           131,328
├─LSTM: 1-9                              [1, 28, 128]              197,632
├─Linear: 1-10                           [1, 512]                  66,048
├─Linear: 1-11                           [1, 128]                  65,664
├─Linear: 1-12                           [1, 11]                   1,419
==========================================================================================
Total params: 618,635
Trainable params: 618,635
Non-trainable params: 0
Total mult-adds (M): 19.33
==========================================================================================
Input size (MB): 0.00
Forward/backward pass size (MB): 0.59
Params size (MB): 2.47
Estimated Total Size (MB): 3.07
==========================================================================================

image-20240707115355065

image-20240707115406360

四、对比

1、论文1

image-20240707120612759

image-20240707120737565

本文的实验结果和论文1的结果比较类似,即使without priori regularization

2、论文2

image-20240707120151123

image-20240707120316218

五、总结

  • 对于RadioML2016.10a数据集来说,在信噪比不是特别低的情况下,使用CNN就表现的不错,在SNR=6dB可达91.82%,但是这里有个小技巧,在卷积过程中,先单独对IQ分量进行卷积,在convolution 4进行联合处理,一开始就使用2x2的卷积核效果较差。

image-20240707121309134

  • 实验结果表明,CNN+LSTM 优于 CNN,但涨幅不多

image-20240707121937158

image-20240707121959303

  • 完整的代码和数据集在GIthub:https://github.com/daetz-coder/RadioML2016.10a_Benchmark,为了方便使用,IQ分量保存在csv中,且仅提供了SNR=6dB的数据,如果需要更多类型的数据,请参考https://blog.csdn.net/a_student_2020/article/details/139800725

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/41228.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件架构之操作系统

第 2 章操作系统 本章主要介绍操作系统的基本概念及其形成、发展历史和主要类型,并指出操作系统的5 大管理功能。掌握操作系统原理的关键在于深入理解“一个观点、两条线索”。一个观点是以资源管理的观点来定义操作系统;两条线索是指操作系统如何管理计…

【计算机毕业设计】020基于weixin小程序订餐系统

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

100359.统计X和Y频数相等的子矩阵数量

1.题目描述 给你一个二维字符矩阵 grid,其中 grid[i][j] 可能是 X、Y 或 .,返回满足以下条件的子矩阵数量: 包含 grid[0][0]X 和 Y 的频数相等。至少包含一个 X。 示例 1: 输入: grid [["X","Y",…

密室逃脱——收集版修改测试

一、原版修改 1、导入资源 Unity Learn | 3D Beginner: Complete Project | URP 2、设置Scene 删除SampleScene,打开UnityTechnologies-3DBeginnerComplete下的MainScene 3、降低音量 (1) 打开Hierarchy面板上的Audio降低音量 (2) 打开Prefabs文件夹&#xf…

lnmp php7 安装ssh2扩展

安装ssh2扩展前必须安装libssh2包 下载地址: wget http://www.libssh2.org/download/libssh2-1.11.0.tar.gzwget http://pecl.php.net/get/ssh2-1.4.tgz (这里要换成最新的版本) 先安装 libssh2 再安装 SSH2: tar -zxvf libssh2-1.11.0.tar.gzcd libss…

【日志信息管理】管理日志信息的类

日志用于记录程序的执行记录包括程序的出错记录,程序致命退出原因,程序的正常执行记录。这样我们就可以很快的察觉程序的错误原因、执行状况等等,因此管理日志信息是非常重要的。 日志一般由以下部分组合: 日志时间、日志等级、…

Java 基础--File - IO流(2)

I/O流 定义 数据从硬盘流向内存为输入流,数据从内存流向硬盘为输出流。输入也叫读取数据,输出也叫写出数据。 IO分类 1.按照数据的流向分为:输入流和输出流 ①输入流:把数据从其他设备上读取到内存中的流 ②输出流&#xff1…

Qt 基础组件速学 事件过滤器

学习目标:理解事件过滤器 前置环境 运行环境:qt creator 4.12 学习内容和效果演示: Qt 提供了事件过滤器的机制,允许我们在事件到达目标对象之前对事件进行拦截和处理。这在以下情况下非常有用: 全局事件处理: 我们可以在应用程序级别安装一个事件过…

工控人最爱的PLC触摸屏一体机,有多香

PLC触摸屏一体机是什么 PLC触摸屏一体机,听起来可能有点技术化,但简单来说,它就是一个集成了可编程逻辑控制器(PLC)和触摸屏的智能设备。这种设备不仅能够执行自动化控制任务,还能实时显示和操作设备状态&a…

JVM原理(十九):JVM虚拟机内存模型

1. 硬件的效率与一致性 数据不安全的原因:缓存一致性的问题 共享内存多核系统:在多路处理器系统中,每个处理器都有自己的高速缓存,而他们又共享同一主内存。 线程先后执行结果不一致问题:除了增加高速缓存之外&#…

【Python】已解决:nltk.download(‘stopwords‘) 报错问题

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决:nltk.download(‘stopwords’) 报错问题 一、分析问题背景 在使用Python的自然语言处理库NLTK(Natural Language Toolkit)时&#xff0c…

CentOS 7安装Elasticsearch7.7.0和Kibana

一. 准备安装包 elasticsearch和kibana:官网历史版本找到并下载(https://www.elastic.co/cn/downloads/past-releases#elasticsearch)ik分词器:GitHub下载(https://github.com/infinilabs/analysis-ik/releases/tag/v…

设计模式之状态机模式

一、状态机模式介绍 状态机模式(State Machine Pattern)是一种用于描述对象行为的软件设计模式,属于行为型设计模式。在状态机模式中,对象的行为取决于其内部状态,并且在不同的状态下,对象可能会有不同的行…

STM32F103C8T6核心板原理图和PCB分享

PCB图 原理图 资料下载地址: 原理图PCB库: https://545c.com/d/45573183-61875742-29897c?p7526 (访问密码: 7526)

[go-zero] 简单微服务调用

文章目录 1.注意事项2.服务划分及创建2.1 用户微服务2.2 订单微服务 3.启动服务3.1 etcd 服务启动3.2 微服务启动3.3 测试访问 1.注意事项 go-zero微服务的注册中心默认使用的是Etcd。 本小节将以一个订单服务调用用户服务来简单演示一下,其实订单服务是api服务&a…

Java 使用sql查询mongodb

在现代应用开发中,关系型数据库和NoSQL数据库各有千秋。MongoDB作为一种流行的NoSQL数据库,以其灵活的文档模型和强大的扩展能力,受到广泛欢迎。然而,有时开发者可能更熟悉SQL查询语法,或者需要在现有系统中复用SQL查询…

【ARMv8/v9 GIC 系列 5.6 -- GIC 超优先级中断详细介绍】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 Interrupt superpriority超优先级中断的特性和应用Physical interface interrupt signalsPhysical Group 1 Non-NMI for Current Security StatePhysical Group 1 for Other Security State, or a Group 0 Non-NMIPhysical Group 1 …

进程控制-wait和waitpid进程回收

wait 阻塞函数 函数作用: 1. 阻塞并等待子进程退出 2. 回收子进程残留资源 3. 获取子进程结束状态(退出原因) pid_t wait(int *wstatus); 返回值: ‐1 : 回收失败,已经没有子进程了 >0 : 回收子进程对应的…

一种非凸全变差正则化的信号降噪方法(以模拟信号和轴承振动信号为例,MATLAB)

以旋转机械振动信号为例,由于旋转机械运行中背景噪声较强,振动信号需要进行降噪处理。常用的小波阈值降噪会在信号的不连续处产生虚假的波峰和伪吉布森震荡,而奇异值分解SVD去噪容易产生虚假分量,全变差去噪则不会出现这样的情况&…

深入理解JS逆向代理与环境监测

博客文章:深入理解JS逆向代理与环境监测 1. 引言 首先要明确JavaScript(JS)在真实网页浏览器环境和Node.js环境中有很多使用特性的区别。尤其是在环境监测和对象原型链的检测方面。本文将探讨如何使用JS的代理(Proxy&#xff09…