├── IO ├── s1_load_io.ipynb └── s2_Transformer-snr6.ipynb ├── README.md ├── SNR ├── -20.ipynb ├── -6.ipynb ├── 0.ipynb ├── 18.ipynb └── 6.ipynb ├── data └── data.txt ├── s0_DataLoader.ipynb ├── s0_DataLoader_val.ipynb ├── s1_mlp.ipynb ├── s2_cnn.ipynb ├── s3_resnet.ipynb └── snr_data └── dataLink.txt /IO/s2_Transformer-snr6.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "e587968c-fc63-4602-9eb9-7aa338ad064c", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "torch.Size([11000, 2, 128])\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "import torch\n", 19 | "import numpy as np\n", 20 | "from torch.utils.data import DataLoader, TensorDataset, random_split\n", 21 | "import pandas as pd\n", 22 | "import matplotlib.pyplot as plt\n", 23 | "from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n", 24 | "\n", 25 | "# 加载数据\n", 26 | "csv_file_path = 'snr_data/output_data_snr_6.csv'\n", 27 | "data_frame = pd.read_csv(csv_file_path)\n", 28 | "\n", 29 | "# 提取 I 和 Q 分量\n", 30 | "I_components = data_frame.iloc[:, :128].values\n", 31 | "Q_components = data_frame.iloc[:, 128:256].values\n", 32 | "\n", 33 | "# 将 I 和 Q 分量堆叠\n", 34 | "stacked_components = np.stack((I_components, Q_components), axis=1)\n", 35 | "\n", 36 | "# 转换为torch张量\n", 37 | "vectors = torch.tensor(stacked_components, dtype=torch.float32) # 形状为 [n_samples, 2, 128]\n", 38 | "\n", 39 | "# 归一化处理\n", 40 | "train_size = int(0.8 * len(vectors))\n", 41 | "train_vectors = vectors[:train_size]\n", 42 | "train_mean = train_vectors.mean(dim=0, keepdim=True)\n", 43 | "train_std = train_vectors.std(dim=0, keepdim=True)\n", 44 | "vectors = (vectors - train_mean) / train_std\n", 45 | "\n", 46 | "print(vectors.shape) # 输出形状应该是 [n_samples, 2, 128]\n", 47 | "\n", 48 | "# 提取Mod_Type列并转换为数值标签\n", 49 | "mod_types = data_frame['Mod_Type'].astype('category').cat.codes.values\n", 50 | "labels = torch.tensor(mod_types, dtype=torch.long)\n", 51 | "\n", 52 | "# 创建TensorDataset\n", 53 | "dataset = TensorDataset(vectors, labels)\n", 54 | "train_dataset, test_dataset = random_split(dataset, [train_size, len(vectors) - train_size])\n", 55 | "\n", 56 | "# 创建DataLoader\n", 57 | "train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\n", 58 | "test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 2, 64 | "id": "40d07c89-9055-4106-b229-103c19640717", 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "import torch\n", 69 | "import torch.nn as nn\n", 70 | "import torch.optim as optim\n", 71 | "from torch.nn import TransformerEncoder, TransformerEncoderLayer\n", 72 | "\n", 73 | "class SimpleTransformer(nn.Module):\n", 74 | " def __init__(self, input_dim, num_heads, num_layers, num_classes):\n", 75 | " super(SimpleTransformer, self).__init__()\n", 76 | " self.embedding = nn.Linear(128, input_dim) # 确保这里从128维映射到input_dim\n", 77 | " encoder_layers = TransformerEncoderLayer(d_model=input_dim, nhead=num_heads)\n", 78 | " self.transformer_encoder = TransformerEncoder(encoder_layer=encoder_layers, num_layers=num_layers)\n", 79 | " self.fc_out = nn.Linear(input_dim, num_classes)\n", 80 | " self.dropout = nn.Dropout(0.3)\n", 81 | "\n", 82 | " def forward(self, x):\n", 83 | " x = x.permute(1, 0, 2) # Rearrange input to seq_length, batch_size, features\n", 84 | " \n", 85 | " x = self.embedding(x)\n", 86 | " x = self.transformer_encoder(x)\n", 87 | " x = x.mean(dim=0) # Aggregate over the sequence\n", 88 | " x = self.dropout(x)\n", 89 | " x = self.fc_out(x)\n", 90 | " return x\n", 91 | "\n", 92 | "\n", 93 | "# Model instantiation\n", 94 | "model = SimpleTransformer(input_dim=16, num_heads=4, num_layers=2, num_classes=11)\n" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 3, 100 | "id": "ff69663f-2797-4890-a92d-b402eab67895", 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "criterion = nn.CrossEntropyLoss()\n", 105 | "optimizer = optim.Adam(model.parameters(), lr=0.005)\n" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 4, 111 | "id": "c32a6179-d032-4ebd-a947-7f1630d8e6a1", 112 | "metadata": {}, 113 | "outputs": [ 114 | { 115 | "name": "stdout", 116 | "output_type": "stream", 117 | "text": [ 118 | "Epoch [1/50], Train Loss: 2.0477, Train Accuracy: 0.1932, Test Loss: 1.8577, Test Accuracy: 0.2482\n", 119 | "Epoch [2/50], Train Loss: 1.7863, Train Accuracy: 0.2686, Test Loss: 1.6271, Test Accuracy: 0.3282\n", 120 | "Epoch [3/50], Train Loss: 1.5837, Train Accuracy: 0.3522, Test Loss: 1.4440, Test Accuracy: 0.4032\n", 121 | "Epoch [4/50], Train Loss: 1.4284, Train Accuracy: 0.4049, Test Loss: 1.3068, Test Accuracy: 0.4268\n", 122 | "Epoch [5/50], Train Loss: 1.3448, Train Accuracy: 0.4198, Test Loss: 1.3160, Test Accuracy: 0.4423\n", 123 | "Epoch [6/50], Train Loss: 1.2984, Train Accuracy: 0.4484, Test Loss: 1.3159, Test Accuracy: 0.4432\n", 124 | "Epoch [7/50], Train Loss: 1.2729, Train Accuracy: 0.4497, Test Loss: 1.2562, Test Accuracy: 0.4318\n", 125 | "Epoch [8/50], Train Loss: 1.2439, Train Accuracy: 0.4605, Test Loss: 1.2210, Test Accuracy: 0.4768\n", 126 | "Epoch [9/50], Train Loss: 1.2377, Train Accuracy: 0.4677, Test Loss: 1.2098, Test Accuracy: 0.4936\n", 127 | "Epoch [10/50], Train Loss: 1.1841, Train Accuracy: 0.4853, Test Loss: 1.1967, Test Accuracy: 0.4964\n", 128 | "Epoch [11/50], Train Loss: 1.1923, Train Accuracy: 0.4803, Test Loss: 1.1997, Test Accuracy: 0.4677\n", 129 | "Epoch [12/50], Train Loss: 1.1783, Train Accuracy: 0.4839, Test Loss: 1.1588, Test Accuracy: 0.4877\n", 130 | "Epoch [13/50], Train Loss: 1.1488, Train Accuracy: 0.5000, Test Loss: 1.1462, Test Accuracy: 0.4909\n", 131 | "Epoch [14/50], Train Loss: 1.1440, Train Accuracy: 0.4953, Test Loss: 1.0952, Test Accuracy: 0.5150\n", 132 | "Epoch [15/50], Train Loss: 1.1296, Train Accuracy: 0.5077, Test Loss: 1.1621, Test Accuracy: 0.5136\n", 133 | "Epoch [16/50], Train Loss: 1.1248, Train Accuracy: 0.5047, Test Loss: 1.0918, Test Accuracy: 0.5132\n", 134 | "Epoch [17/50], Train Loss: 1.1258, Train Accuracy: 0.5040, Test Loss: 1.1156, Test Accuracy: 0.5091\n", 135 | "Epoch [18/50], Train Loss: 1.1253, Train Accuracy: 0.5010, Test Loss: 1.1373, Test Accuracy: 0.5009\n", 136 | "Epoch [19/50], Train Loss: 1.1127, Train Accuracy: 0.4989, Test Loss: 1.0962, Test Accuracy: 0.5209\n", 137 | "Epoch [20/50], Train Loss: 1.0937, Train Accuracy: 0.5161, Test Loss: 1.1003, Test Accuracy: 0.4986\n", 138 | "Epoch [21/50], Train Loss: 1.0785, Train Accuracy: 0.5193, Test Loss: 1.1227, Test Accuracy: 0.5036\n", 139 | "Epoch [22/50], Train Loss: 1.0698, Train Accuracy: 0.5197, Test Loss: 1.1153, Test Accuracy: 0.5145\n", 140 | "Epoch [23/50], Train Loss: 1.0857, Train Accuracy: 0.5143, Test Loss: 1.1354, Test Accuracy: 0.4945\n", 141 | "Epoch [24/50], Train Loss: 1.0871, Train Accuracy: 0.5133, Test Loss: 1.1068, Test Accuracy: 0.5055\n", 142 | "Epoch [25/50], Train Loss: 1.0621, Train Accuracy: 0.5202, Test Loss: 1.1081, Test Accuracy: 0.5109\n", 143 | "Epoch [26/50], Train Loss: 1.0598, Train Accuracy: 0.5278, Test Loss: 1.1045, Test Accuracy: 0.5164\n", 144 | "Epoch [27/50], Train Loss: 1.0499, Train Accuracy: 0.5301, Test Loss: 1.0703, Test Accuracy: 0.5395\n", 145 | "Epoch [28/50], Train Loss: 1.0278, Train Accuracy: 0.5360, Test Loss: 1.0512, Test Accuracy: 0.5191\n", 146 | "Epoch [29/50], Train Loss: 1.0334, Train Accuracy: 0.5375, Test Loss: 1.0850, Test Accuracy: 0.5118\n", 147 | "Epoch [30/50], Train Loss: 1.0297, Train Accuracy: 0.5328, Test Loss: 1.0640, Test Accuracy: 0.5359\n", 148 | "Epoch [31/50], Train Loss: 1.0262, Train Accuracy: 0.5290, Test Loss: 1.0684, Test Accuracy: 0.5223\n", 149 | "Epoch [32/50], Train Loss: 1.0216, Train Accuracy: 0.5307, Test Loss: 1.0732, Test Accuracy: 0.5268\n", 150 | "Epoch [33/50], Train Loss: 1.0280, Train Accuracy: 0.5268, Test Loss: 1.0514, Test Accuracy: 0.5323\n", 151 | "Epoch [34/50], Train Loss: 1.0131, Train Accuracy: 0.5386, Test Loss: 1.0847, Test Accuracy: 0.5250\n", 152 | "Epoch [35/50], Train Loss: 1.0050, Train Accuracy: 0.5385, Test Loss: 1.0880, Test Accuracy: 0.5273\n", 153 | "Epoch [36/50], Train Loss: 1.0077, Train Accuracy: 0.5401, Test Loss: 1.0634, Test Accuracy: 0.5314\n", 154 | "Epoch [37/50], Train Loss: 0.9969, Train Accuracy: 0.5449, Test Loss: 1.1127, Test Accuracy: 0.5227\n", 155 | "Epoch [38/50], Train Loss: 1.0193, Train Accuracy: 0.5320, Test Loss: 1.0455, Test Accuracy: 0.5377\n", 156 | "Epoch [39/50], Train Loss: 0.9872, Train Accuracy: 0.5475, Test Loss: 1.0767, Test Accuracy: 0.5368\n", 157 | "Epoch [40/50], Train Loss: 1.0069, Train Accuracy: 0.5387, Test Loss: 1.0506, Test Accuracy: 0.5305\n", 158 | "Epoch [41/50], Train Loss: 0.9789, Train Accuracy: 0.5501, Test Loss: 1.0816, Test Accuracy: 0.5405\n", 159 | "Epoch [42/50], Train Loss: 0.9769, Train Accuracy: 0.5490, Test Loss: 1.0404, Test Accuracy: 0.5518\n", 160 | "Epoch [43/50], Train Loss: 0.9699, Train Accuracy: 0.5498, Test Loss: 1.0514, Test Accuracy: 0.5450\n", 161 | "Epoch [44/50], Train Loss: 0.9718, Train Accuracy: 0.5443, Test Loss: 1.0428, Test Accuracy: 0.5468\n", 162 | "Epoch [45/50], Train Loss: 0.9617, Train Accuracy: 0.5581, Test Loss: 1.0840, Test Accuracy: 0.5373\n", 163 | "Epoch [46/50], Train Loss: 0.9665, Train Accuracy: 0.5500, Test Loss: 1.0653, Test Accuracy: 0.5514\n", 164 | "Epoch [47/50], Train Loss: 0.9665, Train Accuracy: 0.5530, Test Loss: 1.0543, Test Accuracy: 0.5486\n", 165 | "Epoch [48/50], Train Loss: 0.9622, Train Accuracy: 0.5518, Test Loss: 1.0517, Test Accuracy: 0.5368\n", 166 | "Epoch [49/50], Train Loss: 0.9621, Train Accuracy: 0.5530, Test Loss: 1.0854, Test Accuracy: 0.5323\n", 167 | "Epoch [50/50], Train Loss: 0.9672, Train Accuracy: 0.5547, Test Loss: 1.0493, Test Accuracy: 0.5500\n", 168 | "Training complete.\n" 169 | ] 170 | } 171 | ], 172 | "source": [ 173 | "num_epochs = 50\n", 174 | "train_losses = []\n", 175 | "test_losses = []\n", 176 | "train_accuracies = []\n", 177 | "test_accuracies = []\n", 178 | "\n", 179 | "def calculate_accuracy(outputs, labels):\n", 180 | " _, predicted = torch.max(outputs, 1)\n", 181 | " total = labels.size(0)\n", 182 | " correct = (predicted == labels).sum().item()\n", 183 | " return correct / total\n", 184 | "\n", 185 | "for epoch in range(num_epochs):\n", 186 | " # 训练阶段\n", 187 | " model.train()\n", 188 | " running_loss = 0.0\n", 189 | " correct = 0\n", 190 | " total = 0\n", 191 | " for inputs, labels in train_loader:\n", 192 | " optimizer.zero_grad()\n", 193 | " outputs = model(inputs)\n", 194 | " loss = criterion(outputs, labels)\n", 195 | " loss.backward()\n", 196 | " optimizer.step()\n", 197 | " running_loss += loss.item()\n", 198 | " correct += (outputs.argmax(1) == labels).sum().item()\n", 199 | " total += labels.size(0)\n", 200 | " train_loss = running_loss / len(train_loader)\n", 201 | " train_accuracy = correct / total\n", 202 | " train_losses.append(train_loss)\n", 203 | " train_accuracies.append(train_accuracy)\n", 204 | " \n", 205 | " # 测试阶段\n", 206 | " model.eval()\n", 207 | " running_loss = 0.0\n", 208 | " correct = 0\n", 209 | " total = 0\n", 210 | " with torch.no_grad():\n", 211 | " for inputs, labels in test_loader:\n", 212 | " outputs = model(inputs)\n", 213 | " loss = criterion(outputs, labels)\n", 214 | " running_loss += loss.item()\n", 215 | " correct += (outputs.argmax(1) == labels).sum().item()\n", 216 | " total += labels.size(0)\n", 217 | " test_loss = running_loss / len(test_loader)\n", 218 | " test_accuracy = correct / total\n", 219 | " test_losses.append(test_loss)\n", 220 | " test_accuracies.append(test_accuracy)\n", 221 | " \n", 222 | " 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}\")\n", 223 | "\n", 224 | "print(\"Training complete.\")\n" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 5, 230 | "id": "f328aa84-0c13-4c7f-979a-5248d1ebc00e", 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "data": { 235 | "image/png": "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UC6//HIaNGjA+++/T0ZGBocPH+bcc8/l9NNPd9qCsHrLxe81qNn329SpU/nhhx/o168fADt27ODMM8/kqaeeIjo6mq+//poxY8aQk5NDQUEBw4cP5/HHH2fChAnFKRyhoaHExMSwYsUKevfuzYwZMyoce2pqKhEREXh6erJgwQJ27doFwNChQxk7dix33nknDRs2LD4vwJVXXslll13Gf/7znxr+TdYhq7+gILg53x2M5rkpv3PO4cE87PEpX44OwKNh1dI4vd3dOC3tF/KbDyQp+kni/xiL2/d3Me6v17l+cBuGd2yEu5uQmJ7Dmr0prI5LZXVcKimHc7mkVzNGd4vAe9mbthSchzcmN4OCjWtp6nkvz184pMq5zexZZhdDbv3J1ky+ag6ExBy9X8puWPIW0u0SbulyIadtS+KsjhVUqfALhUu/gD9egvlPwtqZ9pwXf2qbo5xswtvCJZ/Drj9h/ypoe7bTX7LeBNDubkLDAG8SNIBWqs5zc3NjxowZ3HbbbaSmppKfn88dd9xB27Ztufzyy0lNTcUYw2233UaDBg0YOXIkF154Id988025i7omT57M119/Xfx4yZIlTJo0id69ewP2Y+0ePXowb9487rnnHtzc3PD09OStt94iPT2d0aNHk52djTGGF1+sqKiQOlnV1Ptt586d7Nq1i759+xafu0WLFgQHB7N06VI+/fRTbrjhBh555BE8PT2ZPn06I0aMYNWqVcTGxuLl5cW5557L008/zd1338348eN59913Oe+88yoc+4QJExg5ciRdunQhNjaW9u3toq9OnTrx0EMPMWjQINzd3enRoweTJ08uPubhhx/m0ksvdd4v1QVy8wv5e/chVq7bwPXbf+ON/NG8+MU/NG/ox/lX3gVfTsfj78kQ9VLVTrjvb0jejsfpd3BDz27kNnqRRjMnMiT1K2787EyahvpSUGDYl2pn/EWgdXgAIvDBrO/oMuc9Opht5LU9D8+RLzLzu+84d+ODzPZ/DN+cbkAljUkAdi2G3561iyF9Q2HAnbY028ej4Kq5EFymufMvT9hBDH2Y04PDOL11WOXnd3ODgXdBdG/bsW/4EzWS4+1SzfvZr1og1f4owsViY2PN8uWVl32pyLmvLKJxsA8fTOpVw6NS6uS3YcMGOnSouVXmqvzfqYisMMbEumhIta68e7a+11xrxowZfPPN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\n", 236 | "text/plain": [ 237 | "
" 238 | ] 239 | }, 240 | "metadata": { 241 | "needs_background": "light" 242 | }, 243 | "output_type": "display_data" 244 | } 245 | ], 246 | "source": [ 247 | "epochs = range(1, num_epochs + 1)\n", 248 | "\n", 249 | "plt.figure(figsize=(12, 5))\n", 250 | "\n", 251 | "# 绘制损失图像\n", 252 | "plt.subplot(1, 2, 1)\n", 253 | "plt.plot(epochs, train_losses, label='Train Loss')\n", 254 | "plt.plot(epochs, test_losses, label='Test Loss')\n", 255 | "plt.xlabel('Epoch')\n", 256 | "plt.ylabel('Loss')\n", 257 | "plt.legend()\n", 258 | "plt.title('Loss vs. Epochs')\n", 259 | "\n", 260 | "# 绘制准确率图像\n", 261 | "plt.subplot(1, 2, 2)\n", 262 | "plt.plot(epochs, train_accuracies, label='Train Accuracy')\n", 263 | "plt.plot(epochs, test_accuracies, label='Test Accuracy')\n", 264 | "plt.xlabel('Epoch')\n", 265 | "plt.ylabel('Accuracy')\n", 266 | "plt.legend()\n", 267 | "plt.title('Accuracy vs. Epochs')\n", 268 | "\n", 269 | "plt.show()\n" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": 6, 275 | "id": "150539a5-5508-422e-9778-68f8083b2de7", 276 | "metadata": {}, 277 | "outputs": [ 278 | { 279 | "data": { 280 | "image/png": "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\n", 281 | "text/plain": [ 282 | "
" 283 | ] 284 | }, 285 | "metadata": { 286 | "needs_background": "light" 287 | }, 288 | "output_type": "display_data" 289 | } 290 | ], 291 | "source": [ 292 | "# 计算混淆矩阵\n", 293 | "all_labels = []\n", 294 | "all_predictions = []\n", 295 | "\n", 296 | "model.eval()\n", 297 | "with torch.no_grad():\n", 298 | " for inputs, labels in test_loader:\n", 299 | " outputs = model(inputs)\n", 300 | " _, predicted = torch.max(outputs, 1)\n", 301 | " all_labels.extend(labels.numpy())\n", 302 | " all_predictions.extend(predicted.numpy())\n", 303 | "\n", 304 | "# 绘制混淆矩阵\n", 305 | "cm = confusion_matrix(all_labels, all_predictions)\n", 306 | "disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=data_frame['Mod_Type'].astype('category').cat.categories)\n", 307 | "disp.plot(cmap=plt.cm.Blues)\n", 308 | "plt.show()\n" 309 | ] 310 | } 311 | ], 312 | "metadata": { 313 | "kernelspec": { 314 | "display_name": "Python 3 (ipykernel)", 315 | "language": "python", 316 | "name": "python3" 317 | }, 318 | "language_info": { 319 | "codemirror_mode": { 320 | "name": "ipython", 321 | "version": 3 322 | }, 323 | "file_extension": ".py", 324 | "mimetype": "text/x-python", 325 | "name": "python", 326 | "nbconvert_exporter": "python", 327 | "pygments_lexer": "ipython3", 328 | "version": "3.8.10" 329 | } 330 | }, 331 | "nbformat": 4, 332 | "nbformat_minor": 5 333 | } 334 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RadioML 2016.10a 识别调制方式 2 | 3 | **MLP、CNN、ResNet ** 4 | 5 | ![image-20240619100129670](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191001757.png) 6 | 7 | ![image-20240619100620198](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191006269.png) 8 | 9 | ```python 10 | X = [] 11 | lbl = [] 12 | for mod in mods: 13 | for snr in snrs: 14 | X.append(Xd[(mod,snr)]) 15 | for i in range(Xd[(mod,snr)].shape[0]): 16 | lbl.append((mod,snr)) 17 | X = np.vstack(X) 18 | file.close() 19 | 20 | ``` 21 | 22 | 23 | 24 | ![image-20240619100632708](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191006775.png) 25 | 26 | 27 | 28 | 上述论文的分类任务是识别和区分不同类型的无线电调制方式。 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 项目地址:https://github.com/daetz-coder/RadioML2016.10a_CNN 36 | 37 | 数据链接:https://pan.baidu.com/s/1sxyWf4M0ouAloslcXSJe9w?pwd=2016 38 | 提取码:2016 39 | ``` 40 | 41 | 42 | 43 | 下面介绍具体的处理方式,首先为了方便数据加载,根据SNR的不同划分为多个csv子文件 44 | 45 | ```python 46 | import pickle 47 | import pandas as pd 48 | 49 | # 指定pickle文件路径 50 | pickle_file_path = './data/RML2016.10a_dict.pkl' 51 | 52 | # 加载数据 53 | with open(pickle_file_path, 'rb') as file: 54 | data_dict = pickle.load(file, encoding='latin1') 55 | 56 | # 创建一个字典,用于按SNR组织数据 57 | data_by_snr = {} 58 | 59 | # 遍历数据字典,将数据按SNR分组 60 | for key, value in data_dict.items(): 61 | mod_type, snr = key 62 | if snr not in data_by_snr: 63 | data_by_snr[snr] = {} 64 | if mod_type not in data_by_snr[snr]: 65 | data_by_snr[snr][mod_type] = [] 66 | # 只保留1000条数据 67 | data_by_snr[snr][mod_type].extend(value[:1000]) 68 | 69 | # 创建并保存每个SNR对应的CSV文件 70 | for snr, mod_data in data_by_snr.items(): 71 | combined_df = pd.DataFrame() 72 | for mod_type, samples in mod_data.items(): 73 | for sample in samples: 74 | flat_sample = sample.flatten() 75 | temp_df = pd.DataFrame([flat_sample], columns=[f'Sample_{i}' for i in range(flat_sample.size)]) 76 | temp_df['Mod_Type'] = mod_type 77 | temp_df['SNR'] = snr 78 | combined_df = pd.concat([combined_df, temp_df], ignore_index=True) 79 | 80 | # 保存到CSV文件 81 | csv_file_path = f'output_data_snr_{snr}.csv' 82 | combined_df.to_csv(csv_file_path, index=False) 83 | print(f"CSV file saved for SNR {snr}: {csv_file_path}") 84 | 85 | print("Data processing complete. All CSV files saved.") 86 | 87 | ``` 88 | 89 | 90 | 91 | ## 一、模型划分 92 | 93 | 94 | 95 | ### 0、Baseline 96 | 97 | ```python 98 | import torch 99 | import torch.nn as nn 100 | import torch.optim as optim 101 | from torch.utils.data import DataLoader, TensorDataset, random_split 102 | import pandas as pd 103 | import numpy as np 104 | import matplotlib.pyplot as plt 105 | from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay 106 | 107 | # 加载数据 108 | csv_file_path = 'snr_data/output_data_snr_6.csv' 109 | data_frame = pd.read_csv(csv_file_path) 110 | 111 | # 提取前256列数据并转换为张量 112 | vectors = torch.tensor(data_frame.iloc[:, :256].values, dtype=torch.float32) 113 | 114 | # 划分训练集和测试集索引 115 | train_size = int(0.8 * len(vectors)) 116 | test_size = len(vectors) - train_size 117 | train_indices, test_indices = random_split(range(len(vectors)), [train_size, test_size]) 118 | 119 | # 使用训练集的统计量进行归一化 120 | train_vectors = vectors[train_indices] 121 | train_mean = train_vectors.mean(dim=0, keepdim=True) 122 | train_std = train_vectors.std(dim=0, keepdim=True) 123 | 124 | vectors = (vectors - train_mean) / train_std 125 | 126 | # 转置和重塑为16x16 若MLP 无需重构 127 | vectors = vectors.view(-1, 16, 16).unsqueeze(1).permute(0, 1, 3, 2) # 添加通道维度并进行转置 128 | 129 | 130 | # 提取Mod_Type列并转换为数值标签 131 | mod_types = data_frame['Mod_Type'].astype('category').cat.codes.values 132 | labels = torch.tensor(mod_types, dtype=torch.long) 133 | 134 | # 创建TensorDataset 135 | dataset = TensorDataset(vectors, labels) 136 | 137 | # 创建训练集和测试集 138 | train_dataset = TensorDataset(vectors[train_indices], labels[train_indices]) 139 | test_dataset = TensorDataset(vectors[test_indices], labels[test_indices]) 140 | 141 | # 创建DataLoader 142 | train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) 143 | test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False) 144 | 145 | ``` 146 | 147 | **这里需要加载具体模型** 148 | 149 | ```python 150 | criterion = nn.CrossEntropyLoss() 151 | optimizer = optim.Adam(model.parameters(), lr=0.001) 152 | ``` 153 | 154 | ```python 155 | num_epochs = 100 156 | train_losses = [] 157 | test_losses = [] 158 | train_accuracies = [] 159 | test_accuracies = [] 160 | 161 | def calculate_accuracy(outputs, labels): 162 | _, predicted = torch.max(outputs, 1) 163 | total = labels.size(0) 164 | correct = (predicted == labels).sum().item() 165 | return correct / total 166 | 167 | for epoch in range(num_epochs): 168 | # 训练阶段 169 | model.train() 170 | running_loss = 0.0 171 | correct = 0 172 | total = 0 173 | for inputs, labels in train_loader: 174 | optimizer.zero_grad() 175 | outputs = model(inputs) 176 | loss = criterion(outputs, labels) 177 | loss.backward() 178 | optimizer.step() 179 | running_loss += loss.item() 180 | correct += (outputs.argmax(1) == labels).sum().item() 181 | total += labels.size(0) 182 | train_loss = running_loss / len(train_loader) 183 | train_accuracy = correct / total 184 | train_losses.append(train_loss) 185 | train_accuracies.append(train_accuracy) 186 | 187 | # 测试阶段 188 | model.eval() 189 | running_loss = 0.0 190 | correct = 0 191 | total = 0 192 | with torch.no_grad(): 193 | for inputs, labels in test_loader: 194 | outputs = model(inputs) 195 | loss = criterion(outputs, labels) 196 | running_loss += loss.item() 197 | correct += (outputs.argmax(1) == labels).sum().item() 198 | total += labels.size(0) 199 | test_loss = running_loss / len(test_loader) 200 | test_accuracy = correct / total 201 | test_losses.append(test_loss) 202 | test_accuracies.append(test_accuracy) 203 | 204 | 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}") 205 | 206 | print("Training complete.") 207 | ``` 208 | 209 | ![image-20240619123116251](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191231313.png) 210 | 211 | 212 | 213 | ```python 214 | # 计算混淆矩阵 215 | all_labels = [] 216 | all_predictions = [] 217 | 218 | model.eval() 219 | with torch.no_grad(): 220 | for inputs, labels in test_loader: 221 | outputs = model(inputs) 222 | _, predicted = torch.max(outputs, 1) 223 | all_labels.extend(labels.numpy()) 224 | all_predictions.extend(predicted.numpy()) 225 | 226 | # 绘制混淆矩阵 227 | cm = confusion_matrix(all_labels, all_predictions) 228 | disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=data_frame['Mod_Type'].astype('category').cat.categories) 229 | disp.plot(cmap=plt.cm.Blues) 230 | plt.show() 231 | 232 | ``` 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | ### 1、MLP 241 | 242 | ```python 243 | from torchinfo import summary 244 | class SimpleNN(nn.Module): 245 | def __init__(self): 246 | super(SimpleNN, self).__init__() 247 | self.fc1 = nn.Linear(256, 128) 248 | self.fc2 = nn.Linear(128, 64) 249 | self.fc3 = nn.Linear(64, 11) # 有11种调制类型 250 | 251 | def forward(self, x): 252 | x = torch.relu(self.fc1(x)) 253 | x = torch.relu(self.fc2(x)) 254 | x = self.fc3(x) 255 | return x 256 | 257 | model = SimpleNN() 258 | # 打印模型结构和参数 259 | summary(model, input_size=(1, 256)) 260 | ``` 261 | 262 | 263 | 264 | ![image-20240619122355039](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191223096.png) 265 | 266 | 267 | 268 | ![image-20240619122600032](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191226093.png) 269 | 270 | ![image-20240619122623890](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191226949.png) 271 | 272 | 273 | 274 | ### 2、CNN 275 | 276 | ```python 277 | # 定义模型 278 | from torchinfo import summary 279 | class SimpleCNN(nn.Module): 280 | def __init__(self): 281 | super(SimpleCNN, self).__init__() 282 | self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1) 283 | self.bn1 = nn.BatchNorm2d(16) 284 | self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1) 285 | self.bn2 = nn.BatchNorm2d(32) 286 | self.dropout = nn.Dropout(0.3) 287 | self.fc1 = nn.Linear(32*4*4, 128) 288 | self.fc2 = nn.Linear(128, 64) 289 | self.fc3 = nn.Linear(64, 11) # 11种调制类型 290 | 291 | def forward(self, x): 292 | x = torch.relu(self.bn1(self.conv1(x))) 293 | x = torch.max_pool2d(x, 2) 294 | x = torch.relu(self.bn2(self.conv2(x))) 295 | x = torch.max_pool2d(x, 2) 296 | x = x.view(x.size(0), -1) 297 | x = torch.relu(self.fc1(x)) 298 | x = self.dropout(x) 299 | x = torch.relu(self.fc2(x)) 300 | x = self.dropout(x) 301 | x = self.fc3(x) 302 | return x 303 | 304 | model = SimpleCNN() 305 | summary(model, input_size=(1, 1,16,16)) 306 | ``` 307 | 308 | 309 | 310 | ![image-20240619122341650](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191223711.png) 311 | 312 | 313 | 314 | ![image-20240619122652005](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191226074.png) 315 | 316 | ![image-20240619122657948](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191334326.png) 317 | 318 | 319 | 320 | ### 3、ResNet 321 | 322 | ```python 323 | # 定义ResNet基本块 324 | from torchinfo import summary 325 | class BasicBlock(nn.Module): 326 | expansion = 1 327 | 328 | def __init__(self, in_planes, planes, stride=1): 329 | super(BasicBlock, self).__init__() 330 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 331 | self.bn1 = nn.BatchNorm2d(planes) 332 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 333 | self.bn2 = nn.BatchNorm2d(planes) 334 | self.shortcut = nn.Sequential() 335 | if stride != 1 or in_planes != self.expansion * planes: 336 | self.shortcut = nn.Sequential( 337 | nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False), 338 | nn.BatchNorm2d(self.expansion * planes) 339 | ) 340 | 341 | def forward(self, x): 342 | out = torch.relu(self.bn1(self.conv1(x))) 343 | out = self.bn2(self.conv2(out)) 344 | out += self.shortcut(x) 345 | out = torch.relu(out) 346 | return out 347 | 348 | # 定义ResNet 349 | class ResNet(nn.Module): 350 | def __init__(self, block, num_blocks, num_classes=11): 351 | super(ResNet, self).__init__() 352 | self.in_planes = 16 353 | 354 | self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False) 355 | self.bn1 = nn.BatchNorm2d(16) 356 | self.layer1 = self._make_layer(block, 16, num_blocks[0], stride=1) 357 | self.layer2 = self._make_layer(block, 32, num_blocks[1], stride=2) 358 | self.linear = nn.Linear(32*4*4*4, num_classes) 359 | 360 | def _make_layer(self, block, planes, num_blocks, stride): 361 | strides = [stride] + [1]*(num_blocks-1) 362 | layers = [] 363 | for stride in strides: 364 | layers.append(block(self.in_planes, planes, stride)) 365 | self.in_planes = planes * block.expansion 366 | return nn.Sequential(*layers) 367 | 368 | def forward(self, x): 369 | out = torch.relu(self.bn1(self.conv1(x))) 370 | out = self.layer1(out) 371 | out = self.layer2(out) 372 | out = torch.flatten(out, 1) 373 | out = self.linear(out) 374 | return out 375 | 376 | def ResNet18(): 377 | return ResNet(BasicBlock, [2, 2]) 378 | 379 | model = ResNet18() 380 | summary(model, input_size=(1, 1,16,16)) 381 | ``` 382 | 383 | 384 | 385 | ![image-20240619122312714](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191223780.png) 386 | 387 | ![image-20240619122714985](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191227050.png) 388 | 389 | ![image-20240619122722813](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191227867.png) 390 | 391 | 392 | 393 | 可以发现在三种模型下非常容易过拟合,为了探究是否是SNR的造成的影响,故修改SNR数值,进行下述实验 394 | 395 | 396 | 397 | ## 二、SNR划分 398 | 399 | 根据SNR的计算公式来看,`-20db`表示噪声的功率是信号的100倍,其余以此类推 400 | 401 | ![image-20240619125247448](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191252515.png) 402 | 403 | ### 1、SNR(-20) min 404 | 405 | ![image-20240619125210047](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191252112.png) 406 | 407 | 408 | 409 | ![image-20240619125216547](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191252623.png) 410 | 411 | 412 | 413 | ![image-20240619125223002](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191252074.png) 414 | 415 | 416 | 417 | ### 2、SNR(-6) 418 | 419 | ![image-20240619125029174](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191250263.png) 420 | 421 | ![image-20240619124938229](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191249296.png) 422 | 423 | 424 | 425 | ![image-20240619124944334](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191249401.png) 426 | 427 | 428 | 429 | 430 | 431 | ### 3、SNR(0) 432 | 433 | ![image-20240619125019091](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191250163.png) 434 | 435 | 436 | 437 | ![image-20240619124959152](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191249218.png) 438 | 439 | ![image-20240619125006416](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191250486.png) 440 | 441 | 442 | 443 | ### 4、SNR(6) 444 | 445 | ![image-20240619125047770](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191250836.png) 446 | 447 | ![image-20240619125110720](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191251787.png) 448 | 449 | ![image-20240619125117493](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191251561.png) 450 | 451 | 452 | 453 | ### 5、SNR(18) max 454 | 455 | ![image-20240619125138169](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191251223.png) 456 | 457 | ![image-20240619125145635](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191251708.png) 458 | 459 | ![image-20240619125151302](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191251377.png) 460 | 461 | 462 | 463 | 从实验结果来看,趋势还是比较符合预期,总体上SNR越大检测的性能越好,尤其是当`SNR=-20db`时无法区分任何一种类型 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | **AutoSMC: An Automated Machine Learning Framework for Signal Modulation Classification** 480 | 481 | 482 | 483 | ![image-20240619175509771](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191755826.png) 484 | 485 | ![image-20240619175436343](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191754428.png) 486 | 487 | 根据实验结果来看,在-6dB的表现情况在60%左右,6bB下在93%左右 488 | 489 | ![image-20240619175851152](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191758226.png) 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 在之前的两篇文章中仅仅是对数据直接重构分析,忽略了IQ分量应该共同进行描述描述 498 | 499 | + [RadioML2016.10.a数据加载和介绍-CSDN博客](https://blog.csdn.net/a_student_2020/article/details/139773893?spm=1001.2014.3001.5501) 500 | + [RadioML 2016.10a 调制方式识别-CSDN博客](https://blog.csdn.net/a_student_2020/article/details/139800725?spm=1001.2014.3001.5501) 501 | 502 | 本篇内容在于介绍并利用IQ分量,并介绍IQ分量的其他表达方式 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | ## 三、IQ 511 | 512 | 513 | 514 | ### 什么是 IQ 分量? 515 | 516 | 在无线通信中,信号通常表达为复数形式,这就是所谓的 I/Q 格式,其中: 517 | 518 | - **I** 代表 **In-phase** 分量,即信号的实部。 519 | - **Q** 代表 **Quadrature** 分量,即信号的虚部,与 I 分量正交(相位差 90 度)。 520 | 521 | 这种表示法使得信号可以在同一频带内携带更多的信息,并且有效地描述信号的振幅和相位,这对于调制和解调技术至关重要。 522 | 523 | ### 为什么使用 IQ 分量? 524 | 525 | 1. **容量增加**:使用 I 和 Q 两个正交分量,可以在同一频带宽度内传输双倍的数据,提高频谱效率。 526 | 2. **信号处理的灵活性**:I/Q 表示法可以方便地实施各种信号处理技术,如调制、解调、滤波和频谱分析。 527 | 3. **支持多种调制方案**:利用 I 和 Q 分量,可以实现各种调制技术,包括最常用的 QAM、QPSK 等。 528 | 4. **精确表达信号**:I/Q 数据能够精确描述信号的变化,包括幅度和相位的变化,这对于通信系统中信号的恢复非常重要。 529 | 530 | ### 如何还原原始波形? 531 | 532 | 从 I/Q 数据还原原始波形,主要是将这些复数数据转换为时域信号。这可以通过以下数学公式进行: 533 | 534 | ![image-20240619183323059](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191833111.png)其中,fc 是载波频率,t是时间。 535 | 536 | 这个公式显示了如何将 I 分量与余弦波(同相位)和 Q 分量与正弦波(正交相位)相乘后相减,从而构造出时域中的原始信号。 537 | 538 | ### 如何进行傅里叶变换? 539 | 540 | 傅里叶变换是将时域信号转换为频域信号的过程。对于 I/Q 数据,可以分别对 I 和 Q 分量进行傅里叶变换: 541 | 542 | 1. **对 I 和 Q 分量进行离散傅里叶变换(DFT)**:这通常通过快速傅里叶变换(FFT)算法实现。 543 | 2. **解析频谱**:对 I 和 Q 分量的变换结果可以组合起来分析整个信号的频谱特性。 544 | 545 | 例如,使用 NumPy 进行 FFT 可以这样实现: 546 | 547 | ```python 548 | import numpy as np 549 | I = np.array(...) # I 分量 550 | Q = np.array(...) # Q 分量 551 | complex_signal = I + 1j*Q # 构建复数信号 552 | fft_result = np.fft.fft(complex_signal) # 对复数信号进行 FFT 553 | 554 | ``` 555 | 556 | 557 | 558 | 559 | 560 | ## 四、信号还原 561 | 562 | ```python 563 | import pandas as pd 564 | import numpy as np 565 | 566 | # 加载数据 567 | df = pd.read_csv("output_data_multi.csv") 568 | 569 | # 提取 I 和 Q 分量 570 | I_components = df.loc[:, "Sample_0":"Sample_127"].values # 前128个样本为I分量 571 | Q_components = df.loc[:, "Sample_128":"Sample_255"].values # 接下来128个样本为Q分量 572 | 573 | # 重构数据为复数形式,其中 I 为实部,Q 为虚部 574 | complex_data = I_components + 1j * Q_components 575 | 576 | # 保留调制类型和信噪比信息 577 | mod_type = df["Mod_Type"] 578 | snr = df["SNR"] 579 | 580 | # 现在 complex_data 是一个包含复数信号的 NumPy 数组,mod_type 和 snr 是 Series 对象包含对应的调制类型和信噪比信息 581 | complex_data[:1] 582 | ``` 583 | 584 | ````python 585 | array([[-5.90147120e-03-0.00779554j, -2.34581790e-03-0.00781637j, 586 | -7.45061260e-04-0.00401967j, -5.34572450e-03-0.00511351j, 587 | -5.78941800e-03-0.00593952j, -3.69683500e-03-0.0065699j , 588 | -4.97868750e-03-0.00558479j, -6.56572800e-03-0.00529769j, 589 | -9.04932200e-03+0.00021024j, -4.83668640e-03-0.00604725j, 590 | -1.00837140e-02-0.00705299j, -4.53815700e-03-0.00768376j, 591 | -4.31498840e-03-0.00682943j, -5.13423300e-03-0.00526323j, 592 | -6.07567300e-03-0.00428441j, 1.18665890e-03-0.00823529j, 593 | -4.65670100e-03-0.00887949j, -6.95332750e-03-0.00665625j, 594 | -6.66823420e-03-0.00873265j, -6.43977240e-03-0.00415313j, 595 | -3.82532270e-03-0.00815829j, -8.38821850e-03-0.00602711j, 596 | -1.01344110e-02-0.01298266j, -6.90073200e-03-0.00686788j, 597 | -9.62839300e-03-0.00674923j, -1.55354580e-03-0.00403722j, 598 | -2.88469440e-03-0.00778409j, -4.51788800e-03-0.00531385j, 599 | 3.41027650e-03+0.00321187j, 7.41052260e-03-0.00500479j, 600 | 3.35769330e-03+0.00121511j, 7.62627900e-03+0.00072439j, 601 | 8.82679400e-03+0.00443489j, 3.42824610e-03+0.0083125j , 602 | 1.84084000e-03+0.00883208j, 6.41621460e-03+0.0059255j , 603 | -1.63305740e-04+0.00833821j, -2.24135860e-03+0.00718797j, 604 | -5.19226260e-03+0.00816119j, -3.63920980e-03+0.00870452j, 605 | -1.01316330e-02+0.00650418j, -6.39987200e-03+0.00439436j, 606 | -6.06458450e-03+0.00282486j, -7.66557640e-03+0.00216367j, 607 | -3.44835570e-03+0.00520329j, 4.42530580e-04+0.00740604j, 608 | 2.56719800e-03+0.00053031j, 4.74520000e-03+0.00502639j, 609 | 4.66336500e-03+0.00479635j, 6.47741840e-03+0.00892057j, 610 | 8.53952900e-03+0.00727959j, 4.98457070e-03+0.00410889j, 611 | 1.83550680e-04-0.00164091j, 2.53180620e-04+0.00032166j, 612 | -2.90070500e-03-0.00435043j, -5.35907460e-03-0.00534027j, 613 | -9.30814800e-03-0.00672173j, -5.05294140e-03-0.00410643j, 614 | -4.83987950e-03-0.00531335j, 1.17973956e-04-0.00456619j, 615 | -5.48875540e-04-0.00476122j, 8.79733360e-04-0.00262099j, 616 | 6.80832940e-03+0.00264574j, 8.02225800e-03+0.00791668j, 617 | 8.17798450e-03+0.00810155j, 6.84361200e-03+0.00856092j, 618 | 3.34831540e-03+0.00586885j, 2.62019620e-03+0.0090829j , 619 | -2.50967550e-03+0.00278104j, -6.09290500e-04-0.00458179j, 620 | -8.00378100e-03-0.00078458j, -1.06874220e-02+0.00190195j, 621 | -8.18693600e-03-0.00514773j, -9.52030600e-03-0.00967547j, 622 | -4.64970530e-03-0.00738798j, -1.15614310e-03-0.00874938j, 623 | 2.20692440e-03-0.00441817j, 4.98547300e-03-0.00172313j, 624 | 2.16765120e-03-0.00309234j, 6.35635430e-03-0.0008443j , 625 | 1.04583080e-02+0.00702607j, 7.48503440e-03+0.00947603j, 626 | 6.23615830e-03+0.00366654j, 2.93730760e-03+0.00918464j, 627 | 1.16433020e-03+0.00436038j, 2.31683560e-04+0.00822378j, 628 | -4.89262350e-03+0.00838072j, -3.32372940e-03+0.0072375j , 629 | -6.60865700e-03+0.00306395j, -4.91313600e-03+0.00747482j, 630 | -7.29229100e-03+0.00292273j, -6.01531470e-03+0.00505259j, 631 | -1.28758220e-03+0.00033149j, 4.22199520e-04+0.00930912j, 632 | 2.63322060e-04+0.00462913j, 3.07579040e-03+0.00658605j, 633 | 3.98740960e-03+0.00548608j, 3.42952720e-03+0.00639373j, 634 | 2.69522470e-03+0.00506808j, 7.13837430e-03+0.00556591j, 635 | 6.24447500e-03+0.00681962j, 6.12162850e-03+0.0091046j , 636 | 5.42381820e-03+0.00839265j, 1.00702720e-03+0.00871987j, 637 | 9.82678100e-04+0.01014247j, 1.36985770e-03+0.00758515j, 638 | 3.53600270e-03+0.00481515j, 4.30495700e-03+0.00565554j, 639 | 8.39837300e-03+0.00265674j, 8.00060500e-03-0.00235612j, 640 | 6.66820200e-03-0.00501084j, 8.24876000e-03-0.00279375j, 641 | 6.43996850e-03-0.00482372j, 1.07639670e-02-0.00445632j, 642 | 6.80366070e-03-0.00213765j, 2.71986000e-03-0.00170917j, 643 | 6.70633800e-05-0.00275444j, 2.20027730e-03-0.00213406j, 644 | 9.56511500e-04-0.00033254j, -1.03281380e-03-0.00055647j, 645 | -5.32025420e-03+0.00808902j, -7.41181000e-03+0.00666311j, 646 | -7.29165800e-03+0.00731658j, 1.09607930e-04+0.00554266j, 647 | -3.40843060e-03+0.00534808j, -3.26823540e-03+0.01032196j, 648 | -3.04144340e-03+0.00841506j, 5.69031200e-03+0.00544548j]]) 649 | ```` 650 | 651 | ### 1、还原信号 652 | 653 | ```python 654 | import numpy as np 655 | import matplotlib.pyplot as plt 656 | 657 | # 参数设置 658 | fs = 200e3 # 采样率,200kHz 659 | fc = 100e3 # 假设的载波频率,可以根据实际情况调整 660 | t = np.arange(128) / fs # 生成时间数组,对于每个样本128个点 661 | 662 | # 生成载波 663 | cos_wave = np.cos(2 * np.pi * fc * t) # 余弦载波 664 | sin_wave = np.sin(2 * np.pi * fc * t) # 正弦载波 665 | 666 | df = pd.read_csv("output_data_multi.csv") 667 | # 提取 I 和 Q 分量 668 | I_components = df.loc[:, "Sample_0":"Sample_127"].values # 前128个样本为I分量 669 | Q_components = df.loc[:, "Sample_128":"Sample_255"].values # 接下来128个样本为Q分量 670 | # 重构数据为复数形式,其中 I 为实部,Q 为虚部 671 | complex_data = I_components + 1j * Q_components 672 | 673 | # 选择一个样本进行还原,这里假设选择第一个样本 674 | sample_signal = complex_data[0] 675 | 676 | # 还原信号 677 | restored_signal = np.real(sample_signal) * cos_wave - np.imag(sample_signal) * sin_wave 678 | 679 | # 绘制还原的信号 680 | plt.figure(figsize=(10, 5)) 681 | plt.plot(t, restored_signal, label='Restored Signal') 682 | plt.title('Restored Signal from I/Q Components') 683 | plt.xlabel('Time (seconds)') 684 | plt.ylabel('Amplitude') 685 | plt.legend() 686 | plt.show() 687 | 688 | ``` 689 | 690 | ![image-20240619192457044](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191924136.png) 691 | 692 | 693 | 694 | ### 2、快速傅里叶变换 695 | 696 | 697 | 698 | ```python 699 | import pandas as pd 700 | import numpy as np 701 | import matplotlib.pyplot as plt 702 | # 加载数据 703 | df = pd.read_csv("output_data_multi.csv") 704 | 705 | # 提取 I 和 Q 分量 706 | I_components = df.loc[:, "Sample_0":"Sample_127"].values # 前128个样本为I分量 707 | Q_components = df.loc[:, "Sample_128":"Sample_255"].values # 接下来128个样本为Q分量 708 | 709 | # 重构数据为复数形式,其中 I 为实部,Q 为虚部 710 | complex_data = I_components + 1j * Q_components 711 | 712 | # 保留调制类型和信噪比信息 713 | mod_type = df["Mod_Type"] 714 | snr = df["SNR"] 715 | 716 | # 我们取第一个样本来进行FFT 717 | sample_signal = complex_data[1] 718 | 719 | # 对该样本进行快速傅里叶变换 720 | fft_result = np.fft.fft(sample_signal) 721 | 722 | # 计算频率轴的刻度 723 | n = len(sample_signal) 724 | frequency = np.fft.fftfreq(n, d=1/200000) # d 是采样间隔,对应的采样率是200kHz 725 | 726 | # 绘制FFT结果的幅度谱 727 | plt.figure(figsize=(12, 6)) 728 | plt.plot(frequency, np.abs(fft_result)) 729 | plt.title('Frequency domain of the signal') 730 | plt.xlabel('Frequency (Hz)') 731 | plt.ylabel('Amplitude') 732 | plt.grid(True) 733 | plt.show() 734 | ``` 735 | 736 | 737 | 738 | ### 3、频率域图 739 | 740 | ![image-20240619193338379](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191933445.png) 741 | 742 | 743 | 744 | 745 | 746 | ## 四、可视化 747 | 748 | 749 | 750 | ![image-20240619190218052](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191902109.png) 751 | 752 | 753 | 754 | 755 | 756 | ### 1、时间域图 757 | 758 | ```python 759 | import numpy as np 760 | import matplotlib.pyplot as plt 761 | 762 | # 假设 complex_data 包含了多个信号样本,我们取第一个样本 763 | sample_signal = complex_data[0] 764 | 765 | # 生成时间轴 766 | fs = 200000 # 采样率200kHz 767 | t = np.arange(len(sample_signal)) / fs # 时间向量 768 | 769 | # 绘制时间域图 770 | plt.figure(figsize=(12, 6)) 771 | plt.plot(t, np.real(sample_signal), label='Real Part') 772 | plt.plot(t, np.imag(sample_signal), label='Imaginary Part', linestyle='--') 773 | plt.title('Time Domain Signal') 774 | plt.xlabel('Time (seconds)') 775 | plt.ylabel('Amplitude') 776 | plt.legend() 777 | plt.grid(True) 778 | plt.show() 779 | 780 | ``` 781 | 782 | ![image-20240619190546978](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191905059.png) 783 | 784 | 785 | 786 | 787 | 788 | ### 2、 功率谱图 789 | 790 | 通过计算信号的傅里叶变换的平方的模来得到 791 | 792 | ```python 793 | # 对信号进行快速傅里叶变换 794 | fft_result = np.fft.fft(sample_signal) 795 | 796 | # 计算功率谱 797 | power_spectrum = np.abs(fft_result)**2 798 | 799 | # 生成频率轴 800 | n = len(sample_signal) 801 | frequency = np.fft.fftfreq(n, d=1/fs) 802 | 803 | # 绘制功率谱图 804 | plt.figure(figsize=(12, 6)) 805 | plt.plot(frequency, power_spectrum) 806 | plt.title('Power Spectrum') 807 | plt.xlabel('Frequency (Hz)') 808 | plt.ylabel('Power') 809 | plt.grid(True) 810 | plt.xlim([0, fs/2]) # 通常只显示正频率部分直到Nyquist频率 811 | plt.show() 812 | 813 | ``` 814 | 815 | ![image-20240619190555567](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406191905630.png) 816 | 817 | 818 | 819 | **时间域图**中,实部和虚部分别表示了信号的两个正交分量随时间的变化。 820 | 821 | **功率谱图**中,每个频率点的幅度平方表示了该频率成分的能量或功率。通常我们只关注到Nyquist频率(采样率的一半)的正频率部分。 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | ## 五、幅度或相位 830 | 831 | - 将 IQ (In-phase and Quadrature) 数据表示为单个值的一种常见方法是转换这些分量为幅度 (magnitude) 和相位 (phase)。这种表示有助于捕获信号的本质特性,尤其是在处理通信信号和频域分析时。幅度和相位能够提供关于信号强度和时间变化的信息,这在某些应用场景下比原始的 I 和 Q 分量更有用。 832 | 833 | ### 幅度和相位计算 834 | 835 | 幅度 AAA 和相位 ϕ\phiϕ 可以从 I 和 Q 分量通过以下公式计算得出: 836 | 837 | ![image-20240619202313975](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406192023038.png) 838 | 839 | 840 | 841 | 842 | 843 | ```python 844 | import torch 845 | 846 | # 假设 I_components 和 Q_components 是包含 I 和 Q 数据的张量 847 | I_components = torch.tensor(data_frame.iloc[:, :128].values, dtype=torch.float32) 848 | Q_components = torch.tensor(data_frame.iloc[:, 128:256].values, dtype=torch.float32) 849 | 850 | # 计算幅度和相位 851 | magnitude = torch.sqrt(I_components**2 + Q_components**2) 852 | phase = torch.atan2(Q_components, I_components) 853 | 854 | # 可以选择只使用幅度或相位,或者将它们作为两个特征组合使用 855 | features = torch.stack([magnitude, phase], dim=-1) # 按最后一个维度堆叠 856 | 857 | ``` 858 | 859 | ### 使用幅度和相位 860 | 861 | 1. **单一特征选择**:如果您想使用单个值来表示 IQ 数据,可以选择使用幅度或相位中的一个。通常,幅度在许多应用中都是非常有用的信息,因为它直接反映了信号的强度。 862 | 2. **特征工程**:您可以根据应用的具体需要决定是否需要额外处理这些特征,例如通过标准化或归一化来调整它们的尺度。 863 | 3. **模型输入**:计算得到的幅度或相位可以直接用作机器学习模型的输入,尤其是在信号处理和通信系统分析中。 864 | 865 | ### 优势和应用场景 866 | 867 | - **通信系统**:在处理调制信号时,幅度和相位常常提供了比原始 I/Q 分量更直观的信号特征。 868 | - **特征简化**:在某些情况下,使用幅度或相位可以简化问题的复杂性,减少需要处理的数据量。 869 | - **性能改进**:在某些机器学习任务中,这种转换可能会改善模型的性能,因为它能够捕获信号的关键特性。 870 | 871 | 总之,通过转换 I 和 Q 分量为幅度和相位,您可以从另一个角度捕捉信号的特性,这可能对于特定的应用场景(如信号分类、检测或其他分析任务)非常有用。这种方法在许多通信领域和信号处理应用中都得到了广泛的使用。 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | ## 六、其他表达方式 880 | 881 | 882 | 883 | ### 1、IQ堆叠(2,128) 884 | 885 | ```python 886 | # 提取 I 和 Q 分量 887 | I_components = data_frame.iloc[:, :128].values 888 | Q_components = data_frame.iloc[:, 128:256].values 889 | 890 | # 将 I 和 Q 分量堆叠 891 | stacked_components = np.stack((I_components, Q_components), axis=1) 892 | 893 | # 转换为torch张量 894 | vectors = torch.tensor(stacked_components, dtype=torch.float32) # 形状为 [n_samples, 2, 128] 895 | ``` 896 | 897 | 898 | 899 | 900 | 901 | ### 2、IQ线性展开(1,256) 902 | 903 | ```python 904 | # 提取前256列数据并转换为张量 905 | vectors = torch.tensor(data_frame.iloc[:, :256].values, dtype=torch.float32) 906 | ``` 907 | 908 | 909 | 910 | ### 3、幅度(1,128) 911 | 912 | ```python 913 | # 提取 I 和 Q 分量 914 | I_components = data_frame.iloc[:, :128].values 915 | Q_components = data_frame.iloc[:, 128:256].values 916 | 917 | # 计算幅度 918 | magnitude = np.sqrt(I_components**2 + Q_components**2) 919 | ``` 920 | 921 | ![image-20240620130003131](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406201300206.png) 922 | 923 | 924 | 925 | ### 4、相位(1,128) 926 | 927 | ```python 928 | phase = np.arctan2(Q_components, I_components) 929 | phase_tensor = torch.tensor(phase, dtype=torch.float32).unsqueeze(-1) # 添加特征维度 930 | 931 | ``` 932 | 933 | 934 | 935 | ### 5、幅度和相位堆叠(128,2) 936 | 937 | ```python 938 | magnitude = np.sqrt(I_components**2 + Q_components**2) 939 | phase = np.arctan2(Q_components, I_components) 940 | combined = np.stack((magnitude, phase), axis=-1) # 在特征维度上堆叠 941 | combined_tensor = torch.tensor(combined, dtype=torch.float32) 942 | 943 | ``` 944 | 945 | 946 | 947 | ### 6、幅度和相位展开(256,1) 948 | 949 | ```python 950 | magnitude = np.sqrt(I_components**2 + Q_components**2) 951 | phase = np.arctan2(Q_components, I_components) 952 | flattened = np.concatenate((magnitude, phase), axis=1) # 在序列长度维度上连接 953 | flattened_tensor = torch.tensor(flattened, dtype=torch.float32) 954 | 955 | ``` 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | ## 七、Transformer 966 | 967 | 给出其中的一种模型示例(SNR=6) 968 | 969 | ```python 970 | # 提取 I 和 Q 分量 971 | I_components = data_frame.iloc[:, :128].values 972 | Q_components = data_frame.iloc[:, 128:256].values 973 | 974 | # 将 I 和 Q 分量堆叠 975 | stacked_components = np.stack((I_components, Q_components), axis=1) 976 | 977 | # 转换为torch张量 978 | vectors = torch.tensor(stacked_components, dtype=torch.float32) # 形状为 [n_samples, 2, 128] 979 | 980 | ``` 981 | 982 | ```python 983 | class SimpleTransformer(nn.Module): 984 | def __init__(self, input_dim, num_heads, num_layers, num_classes): 985 | super(SimpleTransformer, self).__init__() 986 | self.embedding = nn.Linear(128, input_dim) # 确保这里从128维映射到input_dim 987 | encoder_layers = TransformerEncoderLayer(d_model=input_dim, nhead=num_heads) 988 | self.transformer_encoder = TransformerEncoder(encoder_layer=encoder_layers, num_layers=num_layers) 989 | self.fc_out = nn.Linear(input_dim, num_classes) 990 | self.dropout = nn.Dropout(0.3) 991 | 992 | def forward(self, x): 993 | x = x.permute(1, 0, 2) # Rearrange input to seq_length, batch_size, features 994 | 995 | x = self.embedding(x) 996 | x = self.transformer_encoder(x) 997 | x = x.mean(dim=0) # Aggregate over the sequence 998 | x = self.dropout(x) 999 | x = self.fc_out(x) 1000 | return x 1001 | 1002 | 1003 | # Model instantiation 1004 | model = SimpleTransformer(input_dim=16, num_heads=4, num_layers=2, num_classes=11) 1005 | ``` 1006 | 1007 | ![image-20240620133634184](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406201336255.png) 1008 | 1009 | ![image-20240620133643516](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406201336599.png) 1010 | 1011 | ![image-20240620133650961](https://daetz-image.oss-cn-hangzhou.aliyuncs.com/img/202406201336050.png) 1012 | 1013 | -------------------------------------------------------------------------------- /data/data.txt: -------------------------------------------------------------------------------- 1 | https://www.deepsig.ai/datasets/ 2 | RadioML 2016.10.a 3 | -------------------------------------------------------------------------------- /s0_DataLoader.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "dbb7e9c2-56c8-4c3b-93d1-4c7ee66ea543", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "CSV file saved for SNR 2: snr_data/output_data_snr_2.csv\n", 14 | "CSV file saved for SNR 8: snr_data/output_data_snr_8.csv\n", 15 | "CSV file saved for SNR -4: snr_data/output_data_snr_-4.csv\n", 16 | "CSV file saved for SNR 6: snr_data/output_data_snr_6.csv\n", 17 | "CSV file saved for SNR 12: snr_data/output_data_snr_12.csv\n", 18 | "CSV file saved for SNR -6: snr_data/output_data_snr_-6.csv\n", 19 | "CSV file saved for SNR -20: snr_data/output_data_snr_-20.csv\n", 20 | "CSV file saved for SNR -18: snr_data/output_data_snr_-18.csv\n", 21 | "CSV file saved for SNR 16: snr_data/output_data_snr_16.csv\n", 22 | "CSV file saved for SNR 10: snr_data/output_data_snr_10.csv\n", 23 | "CSV file saved for SNR 4: snr_data/output_data_snr_4.csv\n", 24 | "CSV file saved for SNR -2: snr_data/output_data_snr_-2.csv\n", 25 | "CSV file saved for SNR -8: snr_data/output_data_snr_-8.csv\n", 26 | "CSV file saved for SNR -12: snr_data/output_data_snr_-12.csv\n", 27 | "CSV file saved for SNR 0: snr_data/output_data_snr_0.csv\n", 28 | "CSV file saved for SNR -16: snr_data/output_data_snr_-16.csv\n", 29 | "CSV file saved for SNR -10: snr_data/output_data_snr_-10.csv\n", 30 | "CSV file saved for SNR 14: snr_data/output_data_snr_14.csv\n", 31 | "CSV file saved for SNR 18: snr_data/output_data_snr_18.csv\n" 32 | ] 33 | } 34 | ], 35 | "source": [ 36 | "import os\n", 37 | "import pickle\n", 38 | "import pandas as pd\n", 39 | "\n", 40 | "# 指定pickle文件路径\n", 41 | "pickle_file_path = './data/RML2016.10a_dict.pkl'\n", 42 | "\n", 43 | "# 加载数据\n", 44 | "with open(pickle_file_path, 'rb') as file:\n", 45 | " data_dict = pickle.load(file, encoding='latin1')\n", 46 | "\n", 47 | "# 创建一个字典,用于按SNR组织数据\n", 48 | "data_by_snr = {}\n", 49 | "\n", 50 | "# 遍历数据字典,将数据按SNR分组\n", 51 | "for key, value in data_dict.items():\n", 52 | " mod_type, snr = key\n", 53 | " if snr not in data_by_snr:\n", 54 | " data_by_snr[snr] = {}\n", 55 | " if mod_type not in data_by_snr[snr]:\n", 56 | " data_by_snr[snr][mod_type] = []\n", 57 | " # 只保留1000条数据\n", 58 | " data_by_snr[snr][mod_type].extend(value[:1000])\n", 59 | "\n", 60 | "# 创建输出文件夹\n", 61 | "output_folder = 'snr_data'\n", 62 | "os.makedirs(output_folder, exist_ok=True)\n", 63 | "\n", 64 | "# 创建并保存每个SNR对应的CSV文件\n", 65 | "for snr, mod_data in data_by_snr.items():\n", 66 | " combined_df = pd.DataFrame()\n", 67 | " for mod_type, samples in mod_data.items():\n", 68 | " for sample in samples:\n", 69 | " flat_sample = sample.flatten()\n", 70 | " temp_df = pd.DataFrame([flat_sample], columns=[f'Sample_{i}' for i in range(flat_sample.size)])\n", 71 | " temp_df['Mod_Type'] = mod_type\n", 72 | " temp_df['SNR'] = snr\n", 73 | " combined_df = pd.concat([combined_df, temp_df], ignore_index=True)\n", 74 | " \n", 75 | " # 保存到CSV文件\n", 76 | " csv_file_path = os.path.join(output_folder, f'output_data_snr_{snr}.csv')\n", 77 | " combined_df.to_csv(csv_file_path, index=False)\n", 78 | " print(f\"CSV file saved for SNR {snr}: {csv_file_path}\")\n", 79 | "\n", 80 | "print(\"Data processing complete. All CSV files saved.\")\n" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "id": "dcbc5d4f-0227-4e9a-a9a5-c56684b5aa8b", 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [] 90 | } 91 | ], 92 | "metadata": { 93 | "kernelspec": { 94 | "display_name": "Python 3 (ipykernel)", 95 | "language": "python", 96 | "name": "python3" 97 | }, 98 | "language_info": { 99 | "codemirror_mode": { 100 | "name": "ipython", 101 | "version": 3 102 | }, 103 | "file_extension": ".py", 104 | "mimetype": "text/x-python", 105 | "name": "python", 106 | "nbconvert_exporter": "python", 107 | "pygments_lexer": "ipython3", 108 | "version": "3.8.10" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 5 113 | } 114 | -------------------------------------------------------------------------------- /s0_DataLoader_val.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "1c351632-ecb3-4c09-a201-ff98bc3ae859", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | " Sample_0 Sample_1 Sample_2 Sample_3 Sample_4 Sample_5 Sample_6 \\\n", 14 | "0 0.004912 0.004668 0.003872 0.001715 0.001404 0.001284 0.000071 \n", 15 | "1 -0.006775 -0.006720 -0.006609 -0.008082 -0.007211 -0.006882 -0.008080 \n", 16 | "\n", 17 | " Sample_7 Sample_8 Sample_9 ... Sample_248 Sample_249 Sample_250 \\\n", 18 | "0 -0.000309 -0.001749 -0.002993 ... 0.007511 0.006131 0.008177 \n", 19 | "1 -0.007738 -0.005404 -0.009236 ... 0.008013 0.008215 0.007900 \n", 20 | "\n", 21 | " Sample_251 Sample_252 Sample_253 Sample_254 Sample_255 Mod_Type SNR \n", 22 | "0 0.006791 0.006800 0.008415 0.008392 0.005477 GFSK 6 \n", 23 | "1 0.007083 0.009813 0.008719 0.007377 0.005812 GFSK 6 \n", 24 | "\n", 25 | "[2 rows x 258 columns]\n" 26 | ] 27 | } 28 | ], 29 | "source": [ 30 | "import pandas as pd\n", 31 | "\n", 32 | "# 指定CSV文件路径\n", 33 | "csv_file_path = 'snr_data/output_data_snr_6.csv' # 替换为你的CSV文件路径\n", 34 | "\n", 35 | "# 加载CSV文件的前两行数据\n", 36 | "data_frame = pd.read_csv(csv_file_path, nrows=2)\n", 37 | "\n", 38 | "# 显示前两行数据\n", 39 | "print(data_frame)\n" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "id": "5f8d1f61-8806-46bd-b77a-ec06fe1b9c1d", 46 | "metadata": { 47 | "scrolled": true, 48 | "tags": [] 49 | }, 50 | "outputs": [ 51 | { 52 | "name": "stdout", 53 | "output_type": "stream", 54 | "text": [ 55 | "Vectors shape: (11000, 256)\n", 56 | "First two vectors:\n", 57 | " [[ 4.9117683e-03 4.6676123e-03 3.8715848e-03 1.7147671e-03\n", 58 | " 1.4037307e-03 1.2841291e-03 7.0785790e-05 -3.0855896e-04\n", 59 | " -1.7488907e-03 -2.9933940e-03 -2.5863461e-03 -3.0247940e-03\n", 60 | " -4.0848404e-03 -5.1142440e-03 -5.0528100e-03 -4.5607896e-03\n", 61 | " -3.8493872e-03 -4.8540113e-03 -3.9074930e-03 -3.8572848e-03\n", 62 | " -2.8727197e-03 -4.5465203e-03 -3.2830476e-03 -2.1306080e-03\n", 63 | " -2.3546522e-03 -1.6931555e-03 -2.7792891e-03 -4.2764320e-03\n", 64 | " -3.6861370e-03 -3.9759760e-03 -5.4031503e-03 -4.7911730e-03\n", 65 | " -5.6585856e-03 -4.0048664e-03 -3.6904593e-03 -4.7428490e-03\n", 66 | " -4.5117020e-03 -3.6836443e-03 -2.8316386e-03 -4.8449095e-03\n", 67 | " -2.0245523e-03 -2.1508980e-03 -3.2383779e-03 -4.2790445e-03\n", 68 | " -2.5620575e-03 -2.8708390e-03 -4.7139910e-03 -5.1454995e-03\n", 69 | " -5.5586340e-03 -4.8898380e-03 -4.9461164e-03 -4.8534926e-03\n", 70 | " -3.0809880e-03 -3.9539016e-03 -1.8376672e-03 -3.4635223e-03\n", 71 | " -1.7284491e-03 -3.1404619e-03 -3.9537030e-03 -3.6403990e-03\n", 72 | " -5.2360888e-03 -6.5306285e-03 -5.9838057e-03 -5.5168860e-03\n", 73 | " -7.3648244e-03 -6.2961450e-03 -8.0035760e-03 -7.4924270e-03\n", 74 | " -9.8138815e-03 -8.7405610e-03 -8.0384870e-03 -6.9477780e-03\n", 75 | " -6.7736940e-03 -9.0355470e-03 -8.5793410e-03 -7.7667000e-03\n", 76 | " -7.2584150e-03 -7.7140830e-03 -5.8781467e-03 -6.7585516e-03\n", 77 | " -6.2824020e-03 -7.0840283e-03 -7.8986800e-03 -5.8154166e-03\n", 78 | " -8.6347120e-03 -8.7837610e-03 -7.1233218e-03 -7.9787010e-03\n", 79 | " -7.5217360e-03 -7.2322500e-03 -8.2021780e-03 -7.2398754e-03\n", 80 | " -5.8293394e-03 -7.3368690e-03 -5.2655432e-03 -7.6094386e-03\n", 81 | " -6.7708483e-03 -5.1929657e-03 -6.4164223e-03 -5.3625987e-03\n", 82 | " -3.0775534e-03 -2.8415688e-03 -3.1552892e-03 -2.5094848e-03\n", 83 | " -3.5958980e-03 -3.4595730e-03 -2.7734921e-03 -4.2395685e-03\n", 84 | " -3.9771884e-03 -4.4826553e-03 -3.9509790e-03 -4.4395872e-03\n", 85 | " -5.4480580e-03 -2.9099798e-03 -4.1692670e-03 -4.4831117e-03\n", 86 | " -3.5717692e-03 -4.6019790e-03 -2.4589377e-03 -1.6404709e-03\n", 87 | " -1.7103028e-03 -1.3304467e-03 1.8072076e-03 1.1556245e-03\n", 88 | " 9.1404584e-04 1.6552019e-03 3.4356809e-03 3.5159700e-03\n", 89 | " 6.1680210e-03 7.9799540e-03 7.8408380e-03 6.3200320e-03\n", 90 | " 8.7371020e-03 7.8478310e-03 8.7245990e-03 7.4896743e-03\n", 91 | " 9.8816870e-03 7.7524920e-03 6.7367530e-03 7.7986820e-03\n", 92 | " 7.9558000e-03 4.9598390e-03 5.9623537e-03 5.5424010e-03\n", 93 | " 6.1734426e-03 7.1718735e-03 5.7000997e-03 6.6263536e-03\n", 94 | " 7.7582610e-03 7.3212176e-03 6.4080840e-03 8.0615170e-03\n", 95 | " 6.6630505e-03 8.8893790e-03 6.8720140e-03 5.3233877e-03\n", 96 | " 6.8937430e-03 6.2715050e-03 7.0057465e-03 6.3441596e-03\n", 97 | " 6.1293864e-03 5.5834698e-03 6.4600860e-03 6.5454566e-03\n", 98 | " 5.9661130e-03 6.4879200e-03 6.7330150e-03 6.4554433e-03\n", 99 | " 6.9554923e-03 7.1127150e-03 7.3735430e-03 9.6399010e-03\n", 100 | " 5.2107580e-03 5.2537940e-03 7.2564394e-03 6.5386600e-03\n", 101 | " 5.8681075e-03 6.7610857e-03 6.6922833e-03 5.9439670e-03\n", 102 | " 6.3702920e-03 6.7189704e-03 6.8053375e-03 8.2295910e-03\n", 103 | " 7.5442010e-03 7.2417550e-03 6.7078215e-03 7.6747984e-03\n", 104 | " 6.0393694e-03 5.8143176e-03 5.3567760e-03 3.9484636e-03\n", 105 | " 4.4168695e-03 6.2604180e-03 2.4582350e-03 1.2852855e-03\n", 106 | " 1.8096156e-03 5.3557360e-04 4.0060826e-04 1.5485990e-03\n", 107 | " 2.4538345e-03 5.0807535e-04 1.2075969e-03 1.3998107e-03\n", 108 | " 2.5911847e-04 2.1900290e-03 2.0386388e-03 2.3377400e-03\n", 109 | " 8.0153970e-04 3.5863800e-03 2.4726826e-03 2.6477520e-03\n", 110 | " 1.9975777e-03 2.3379801e-04 5.8119936e-04 4.7248017e-04\n", 111 | " 5.1227835e-04 -1.9111542e-03 4.7563744e-04 9.2102270e-04\n", 112 | " 1.0622123e-03 3.5024416e-03 4.8651720e-03 5.0152508e-03\n", 113 | " 5.2278778e-03 4.6368255e-03 5.9118470e-03 4.2460790e-03\n", 114 | " 5.8219386e-03 6.5527135e-03 6.9703970e-03 6.9825350e-03\n", 115 | " 7.2985520e-03 7.2946790e-03 9.0329265e-03 6.3789940e-03\n", 116 | " 6.8586227e-03 7.2157630e-03 6.0717220e-03 4.8797100e-03\n", 117 | " 7.0726150e-03 6.4709517e-03 4.5158230e-03 7.7634880e-03\n", 118 | " 6.7012007e-03 6.9690770e-03 4.9410450e-03 6.4642080e-03\n", 119 | " 7.5111470e-03 6.1307600e-03 8.1773360e-03 6.7911167e-03\n", 120 | " 6.7995493e-03 8.4154210e-03 8.3922020e-03 5.4767900e-03]\n", 121 | " [-6.7754070e-03 -6.7195487e-03 -6.6087544e-03 -8.0816140e-03\n", 122 | " -7.2114590e-03 -6.8815640e-03 -8.0797590e-03 -7.7381693e-03\n", 123 | " -5.4039950e-03 -9.2362970e-03 -8.4953360e-03 -7.7171694e-03\n", 124 | " -6.9611050e-03 -7.5321330e-03 -8.8746340e-03 -8.8257220e-03\n", 125 | " -7.1847662e-03 -8.5912800e-03 -7.9223940e-03 -7.1471800e-03\n", 126 | " -5.8189174e-03 -8.0344370e-03 -6.4420660e-03 -7.3134983e-03\n", 127 | " -8.6593850e-03 -7.4809603e-03 -7.5411630e-03 -7.8252400e-03\n", 128 | " -7.9255100e-03 -7.6138107e-03 -9.3583710e-03 -7.8231530e-03\n", 129 | " -6.1424190e-03 -7.6260710e-03 -7.8205760e-03 -5.0906930e-03\n", 130 | " -7.5205060e-03 -4.6465470e-03 -3.2197854e-03 -4.6791923e-03\n", 131 | " -5.2974788e-03 -5.6291030e-03 -5.1281160e-03 -5.2323610e-03\n", 132 | " -4.7212723e-03 -6.9146380e-03 -7.0973530e-03 -6.5045264e-03\n", 133 | " -8.3938070e-03 -6.8570115e-03 -6.8560160e-03 -7.1901684e-03\n", 134 | " -7.5522720e-03 -7.6727990e-03 -6.5040165e-03 -7.1285980e-03\n", 135 | " -8.4311190e-03 -8.7723880e-03 -7.2493170e-03 -8.7280410e-03\n", 136 | " -8.1187110e-03 -9.5333540e-03 -7.7912617e-03 -9.0125360e-03\n", 137 | " -7.1664834e-03 -8.5631320e-03 -8.9602850e-03 -8.8441440e-03\n", 138 | " -8.0383180e-03 -6.7282445e-03 -7.1482863e-03 -5.8973110e-03\n", 139 | " -5.5687370e-03 -5.6767480e-03 -4.4454946e-03 -6.1033214e-03\n", 140 | " -3.0305610e-03 -3.8846668e-03 -2.3297686e-03 -3.1008585e-03\n", 141 | " -4.9431290e-03 -4.6284054e-03 -5.2910065e-03 -6.0865907e-03\n", 142 | " -5.6185657e-03 -6.9185207e-03 -8.4751400e-03 -8.3537280e-03\n", 143 | " -7.6566640e-03 -9.0643190e-03 -9.5800840e-03 -8.4312890e-03\n", 144 | " -7.2725043e-03 -8.8361870e-03 -6.5343175e-03 -7.8737050e-03\n", 145 | " -7.2685587e-03 -6.7889085e-03 -8.7106960e-03 -6.9176946e-03\n", 146 | " -8.0418890e-03 -6.0699596e-03 -5.6665750e-03 -6.4079480e-03\n", 147 | " -6.4782360e-03 -7.4090795e-03 -6.9712214e-03 -6.5847617e-03\n", 148 | " -3.5920998e-03 -3.2344845e-03 -2.0246955e-03 -1.7835624e-03\n", 149 | " -9.9079380e-04 6.3029365e-05 2.7960534e-05 1.6548726e-03\n", 150 | " 1.6929797e-03 1.0301904e-03 2.0799432e-03 4.6232440e-04\n", 151 | " 1.1154478e-03 1.3488553e-03 6.3110080e-04 2.3752942e-03\n", 152 | " -1.2487286e-03 -1.8009752e-03 -1.6163592e-03 -2.5732780e-03\n", 153 | " -2.6023055e-03 -1.2790810e-03 5.3796486e-04 -5.3183700e-04\n", 154 | " 1.0415622e-03 1.2610720e-03 2.2001930e-03 3.2873725e-04\n", 155 | " 2.7251497e-03 1.3069557e-04 1.6150533e-03 -2.8250986e-04\n", 156 | " 3.1651070e-04 1.7060769e-03 -1.4647869e-03 -4.9172214e-04\n", 157 | " 8.9056610e-04 9.7862580e-04 -6.0417474e-04 -8.0751260e-04\n", 158 | " 2.4833267e-03 4.3243598e-04 1.8382855e-03 1.4228395e-03\n", 159 | " 1.8320791e-03 1.0008240e-03 4.1800263e-04 1.1048785e-03\n", 160 | " 8.9701630e-06 7.4762414e-05 -1.6201035e-03 -2.9171514e-03\n", 161 | " -2.2829745e-03 -5.4147276e-03 -5.2746683e-03 -6.2145954e-03\n", 162 | " -6.1859100e-03 -4.9078404e-03 -4.8686060e-03 -5.6976940e-03\n", 163 | " -6.5644980e-03 -4.6559980e-03 -5.0027610e-03 -4.2181950e-03\n", 164 | " -4.4955720e-03 -2.3140586e-03 -2.5775563e-03 -2.3079210e-03\n", 165 | " -2.3597270e-03 -6.5208050e-04 9.5156030e-06 7.3438330e-04\n", 166 | " 1.0885611e-03 3.2928705e-03 2.5307840e-03 3.0619174e-04\n", 167 | " 2.7000804e-03 2.5174816e-03 1.7529479e-03 1.7126302e-03\n", 168 | " -7.3960243e-04 5.3998185e-05 -6.3025720e-04 -6.4144730e-04\n", 169 | " 3.4633678e-04 1.5863270e-03 1.4264204e-03 1.0096965e-03\n", 170 | " 1.8593185e-03 4.4202230e-03 2.3258438e-03 3.7278219e-03\n", 171 | " 4.6301920e-03 5.1625893e-03 4.1149524e-03 5.5557056e-03\n", 172 | " 6.7703794e-03 4.9462240e-03 5.5732330e-03 6.6202840e-03\n", 173 | " 6.5051517e-03 6.3532600e-03 5.6431960e-03 6.7921750e-03\n", 174 | " 5.6814025e-03 4.5644315e-03 3.6164196e-03 4.0879073e-03\n", 175 | " 3.4027510e-03 1.5197112e-03 1.7525064e-03 7.1024685e-04\n", 176 | " 5.6740694e-04 -5.9914850e-04 -7.5190320e-05 -9.2013425e-04\n", 177 | " -3.0809720e-04 -1.2558812e-03 4.2062308e-04 1.2463048e-03\n", 178 | " 1.9489942e-03 3.9190570e-03 2.7345820e-03 3.8598892e-03\n", 179 | " 3.2737376e-03 4.5753177e-03 4.4646790e-03 5.9615746e-03\n", 180 | " 7.0727435e-03 6.6374950e-03 7.1397980e-03 6.9622880e-03\n", 181 | " 6.6432315e-03 8.7403410e-03 8.4871380e-03 7.2054393e-03\n", 182 | " 7.6812506e-03 7.3318337e-03 6.4314440e-03 7.0256510e-03\n", 183 | " 8.0126530e-03 8.2147110e-03 7.8997845e-03 7.0832400e-03\n", 184 | " 9.8132890e-03 8.7185195e-03 7.3771270e-03 5.8120040e-03]]\n", 185 | "First two Mod Types: ['GFSK' 'GFSK']\n" 186 | ] 187 | } 188 | ], 189 | "source": [ 190 | "import pandas as pd\n", 191 | "\n", 192 | "# 指定CSV文件路径\n", 193 | "csv_file_path = 'snr_data/output_data_snr_6.csv' # 替换为你的CSV文件路径\n", 194 | "\n", 195 | "# 加载CSV文件\n", 196 | "data_frame = pd.read_csv(csv_file_path)\n", 197 | "\n", 198 | "# 提取前256列数据\n", 199 | "vectors = data_frame.iloc[:, :256].values\n", 200 | "\n", 201 | "# 提取Mod_Type列(倒数第二列)\n", 202 | "mod_types = data_frame['Mod_Type'].values\n", 203 | "\n", 204 | "# 打印前几行数据以验证\n", 205 | "print(\"Vectors shape:\", vectors.shape)\n", 206 | "print(\"First two vectors:\\n\", vectors[:2])\n", 207 | "print(\"First two Mod Types:\", mod_types[:2])\n" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 3, 213 | "id": "c002a5ed-8376-4c90-b54e-78306fc9bf01", 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "name": "stdout", 218 | "output_type": "stream", 219 | "text": [ 220 | "Mod_Type: QAM64, Number of samples: 1000\n", 221 | "Mod_Type: AM-DSB, Number of samples: 1000\n", 222 | "Mod_Type: CPFSK, Number of samples: 1000\n", 223 | "Mod_Type: PAM4, Number of samples: 1000\n", 224 | "Mod_Type: 8PSK, Number of samples: 1000\n", 225 | "Mod_Type: GFSK, Number of samples: 1000\n", 226 | "Mod_Type: BPSK, Number of samples: 1000\n", 227 | "Mod_Type: WBFM, Number of samples: 1000\n", 228 | "Mod_Type: AM-SSB, Number of samples: 1000\n", 229 | "Mod_Type: QAM16, Number of samples: 1000\n", 230 | "Mod_Type: QPSK, Number of samples: 1000\n" 231 | ] 232 | } 233 | ], 234 | "source": [ 235 | "import pandas as pd\n", 236 | "\n", 237 | "# 指定CSV文件路径\n", 238 | "csv_file_path = 'snr_data/output_data_snr_6.csv' # 替换为你的CSV文件路径\n", 239 | "\n", 240 | "# 加载CSV文件\n", 241 | "data_frame = pd.read_csv(csv_file_path)\n", 242 | "\n", 243 | "# 提取前256列数据\n", 244 | "vectors = data_frame.iloc[:, :256].values\n", 245 | "\n", 246 | "# 提取Mod_Type列(倒数第二列)\n", 247 | "mod_types = data_frame['Mod_Type'].values\n", 248 | "\n", 249 | "# 创建一个字典,用于存储每种类型的数据\n", 250 | "type_dict = {}\n", 251 | "\n", 252 | "# 遍历每个Mod_Type,将对应的向量存储到字典中\n", 253 | "for mod_type in set(mod_types):\n", 254 | " type_dict[mod_type] = vectors[mod_types == mod_type]\n", 255 | "\n", 256 | "# 打印每种类型的数据数量\n", 257 | "for mod_type, data in type_dict.items():\n", 258 | " print(f\"Mod_Type: {mod_type}, Number of samples: {data.shape[0]}\")\n" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "id": "9d98b624-1553-4432-8441-0af830ded6ed", 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [] 268 | } 269 | ], 270 | "metadata": { 271 | "kernelspec": { 272 | "display_name": "Python 3 (ipykernel)", 273 | "language": "python", 274 | "name": "python3" 275 | }, 276 | "language_info": { 277 | "codemirror_mode": { 278 | "name": "ipython", 279 | "version": 3 280 | }, 281 | "file_extension": ".py", 282 | "mimetype": "text/x-python", 283 | "name": "python", 284 | "nbconvert_exporter": "python", 285 | "pygments_lexer": "ipython3", 286 | "version": "3.8.10" 287 | } 288 | }, 289 | "nbformat": 4, 290 | "nbformat_minor": 5 291 | } 292 | -------------------------------------------------------------------------------- /snr_data/dataLink.txt: -------------------------------------------------------------------------------- 1 | 链接:https://pan.baidu.com/s/1sxyWf4M0ouAloslcXSJe9w?pwd=2016 2 | 提取码:2016 --------------------------------------------------------------------------------