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

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

说明:本文包含对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 / total

for epoch in range(num_epochs):
    # 训练阶段
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0
    for 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 / total
    train_losses.append(train_loss)
    train_accuracies.append(train_accuracy)
    
    # 测试阶段
    model.eval()
    running_loss = 0.0
    correct = 0
    total = 0
    with 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 / total
    test_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 x

model = CNNModel()
summary(model, (2, 128))

image-20240707115545394

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1           [-1, 64, 2, 125]             320
            Conv2d-2           [-1, 64, 2, 124]           8,256
         MaxPool2d-3            [-1, 64, 2, 62]               0
            Conv2d-4           [-1, 128, 2, 61]          16,512
            Conv2d-5           [-1, 128, 1, 60]          65,664
         MaxPool2d-6           [-1, 128, 1, 30]               0
            Conv2d-7           [-1, 256, 1, 29]          65,792
            Conv2d-8           [-1, 256, 1, 28]         131,328
            Linear-9                  [-1, 512]       3,670,528
           Linear-10                  [-1, 128]          65,664
           Linear-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 nn

class 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 filters
        self.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 size
        self.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 LSTM
        x = 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 LSTM

        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = 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的形状以适应LSTM
        x = x.squeeze(2).permute(0, 2, 1)  # 变为(batch_size, 128, 256)

        # 通过LSTM
        x, _ = 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.mfbz.cn/a/783563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何优化 PostgreSQL 中对于复杂数学计算的查询?

文章目录 一、理解复杂数学计算的特点二、优化原则(一)索引优化(二)查询重写(三)数据库配置调整(四)使用数据库内置函数的优势 三、具体的优化方案和示例(一)…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【加密导入密钥(C/C++)】

加密导入密钥(C/C) 以加密导入ECDH密钥对为例,涉及业务侧加密密钥的[密钥生成]、[协商]等操作不在本示例中体现。 具体的场景介绍及支持的算法规格。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 设备A&#xf…

【机器学习】——决策树模型

💻博主现有专栏: C51单片机(STC89C516),c语言,c,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux&#xf…

PHP宝藏神器多功能投票系统源码小程序

🎉发现宝藏神器!一键解锁“多功能投票小程序”的无限可能✨ 🌈 开篇安利:告别繁琐,拥抱高效! Hey小伙伴们,是不是经常为组织活动、收集意见而头疼不已?🤯 今天就要给大…

迭代器模式(大话设计模式)C/C++版本

迭代器模式 C #include <iostream> #include <string> #include <vector>using namespace std;// 迭代抽象类,用于定义得到开始对象、得到下一个对象、判断是否到结尾、当前对象等抽象方法&#xff0c;统一接口 class Iterator { public:Iterator(){};virtu…

Android约束布局的概念与属性(2)

目录 3&#xff0e;链式约束4&#xff0e;辅助线 3&#xff0e;链式约束 如果两个或以上控件通过下图的方式约束在一起&#xff0c;就可以认为是他们是一条链&#xff08;如图5为横向的链&#xff0c;纵向同理&#xff09;。 图5 链示意图 如图5所示&#xff0c;在预览图中选…

面向计算机类岗位人才需求分析研究 --基于前程无忧招聘网站的数据经验证据

1 引言 随着智能互联网的快速发展和一系列的技术变革&#xff0c;从而推动全国各行业进行政策的调整、资源的共享、产业的升级和信息的创新。结合国家的战略&#xff0c;政府明确的指出&#xff0c;建设国家大数据池意义重大。通过海量数据的支持与算法优化后的计算能力&#…

水果商城系统 SpringBoot+Vue

1、技术栈 技术栈&#xff1a;SpringBootVueMybatis等使用环境&#xff1a;Windows10 谷歌浏览器开发环境&#xff1a;jdk1.8 Maven mysql Idea 数据库仅供学习参考 【已经答辩过的毕业设计】 项目源码地址 2、功能划分 3、效果演示

Perforce发布白皮书,解读电动汽车初创公司如何加速进入市场并降低软件开发中的风险和成本

电动汽车&#xff08;EV&#xff09;领域的初创企业正迅速崛起&#xff0c;创新速度显著加快。然而&#xff0c;随着消费者对电动汽车需求的激增&#xff0c;老牌汽车制造商正加速进军这一市场&#xff0c;加剧了行业竞争。为在竞争中生存并发展&#xff0c;电动汽车初创企业必…

机器学习与模式识别_清华大学出版社

contents 前言第1章 绪论1.1 引言1.2 基本术语1.3 假设空间1.4 归纳偏好1.5 发展历程1.6 应用现状 第2章 模型评估与选择2.1 经验误差与过拟合2.2 评估方法2.3 性能度量2.3.1 回归任务2.3.2 分类任务 2.4 比较检验2.5 偏差与方差2.5.1 偏差-方差分解2.5.2 偏差-方差窘境 第3章 …

新技术引领商业智能新时代:从 AI 到自助分析的演变

最新技术资源&#xff1a; https://www.grapecity.com.cn/resources/ 引言&#xff1a;商业智能的新技术浪潮 在当今数据驱动的世界中&#xff0c;技术进步不断改变着商业智能&#xff08;BI&#xff09;领域。特别是人工智能&#xff08;AI&#xff09;和自助分析工具的发展&…

python 10个自动化脚本

目录 &#x1f31f; 引言 &#x1f4da; 理论基础 &#x1f6e0;️ 使用场景与代码示例 场景一&#xff1a;批量重命名文件 场景二&#xff1a;自动下载网页内容 场景三&#xff1a;数据清洗 场景四&#xff1a;定时执行任务 场景五&#xff1a;自动化邮件发送 场景六…

10分钟使用网站构建框架hugo本地搭建个人网站并快速上线详细教程

文章目录 前言1. 安装环境2. 配置环境变量与hugo安装2.1 创建程序目录2.2 配置环境变量2.3 查看程序版本 3. 创建博客网站3.1 创建站点3.2 在站点中创建一篇文章3.3 为网站添加主题 4. 本地访问测试5. 安装内网穿透工具6. 配置公网地址7. 配置固定公网地址 前言 今天和大家分享…

压测引擎数据库设计(上)

压测引擎数据库设计&#xff08;上&#xff09; 引言 在当今快速发展的互联网时代&#xff0c;软件质量保证和性能测试变得尤为重要。自动化测试平台&#xff0c;提供了一套完整的解决方案&#xff0c;以确保软件产品在发布前能够满足性能和稳定性的要求。本文将深入探讨滴云自…

启发式防御大模型越狱攻击

前言 在本文中&#xff0c;我们来分析、复现几个典型的启发式的防御工作&#xff0c;用于防御面向大语言模型的越狱攻击。 Self Examination 首先来看Self Examination方法。 这是一种简单的零样本防御LLM攻击的方法&#xff0c;旨在防止用户接触到由LLMs诱导产生的有害或恶…

ROS编译错误: fatal error: test_pkg/test_pkg.h: 没有那个文件

在ROS安装完毕后编译ros工作空间&#xff0c;出现了以下错误: 解决方法: 删除工作空间&#xff0c;重建再重新编译

【数据结构】单链表:数据结构中的舞者,穿梭于理论与实践的舞池

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 数据结构与算法 先赞后看&#xff0c;已成习惯 创作不易&#xff0c;多多支持&#xff01; 一、链表的概念和结构 1.1 链表的概念 在上一篇文章中&#xff0c;我们了解了线性表(linear list)&#xff0c;并且学习了其…

你认为最优美的数据结构是什么?

并查集算是&#xff0c;巧妙的不行&#xff0c;让人为之一惊。 在学习数据结构Q的时候&#xff0c;老师多少会提到并查集&#xff0c;他的应用也是超级广泛。本文首先会通过案例来对并查集有一个介绍。然后给出并查集的java实现。 刚好我有一些资料&#xff0c;是我根据网友给…

【Altium】AD-网络版一个用户非人为异常占用多个License的解决方法

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 当出现一个用户同时占用多个授权&#xff0c;又无法单独释放一个授权的情况下&#xff0c;该如何解决。 2、 问题场景 一个用户获取网络版授权后&#xff0c;AD会自动重复获取授权&#xff0c;直到该license下所有授…

怎么给电子文档批量盖骑缝章或公章?

怎么给电子文档批量盖骑缝章或公章?假如你有100个PDF电子文档要同时盖缝章&#xff0c;如果不借助专业的盖电子骑缝章软件&#xff0c;还真不好干。下面讲述如何利用e-章宝批量盖电子骑缝章。 1.在软件中导入待批量盖章的PDF文件 如下图&#xff0c;在“待盖章PDF文件”区域…