主题021:机器学习在电磁仿真中的应用

引言

机器学习(ML)和深度学习(DL)正在革命性地改变计算电磁学(CEM)的研究范式。传统电磁仿真方法如FDTD、FEM和MoM虽然精度高,但计算成本昂贵,特别是对于大规模参数扫描和优化设计。机器学习技术通过数据驱动的代理模型、物理约束的神经网络和智能优化算法,为电磁仿真提供了高效、快速的替代方案。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

机器学习在电磁学中的应用领域

1. 代理模型加速

  • 用神经网络替代耗时的全波仿真
  • 实现毫秒级的电磁响应预测
  • 支持实时参数优化和设计空间探索

2. 逆问题求解

  • 从期望的电磁响应反推结构设计
  • 自动天线/电路综合设计
  • 材料参数反演

3. 智能优化

  • 替代传统的遗传算法、粒子群优化
  • 学习历史优化经验加速收敛
  • 多目标优化与帕累托前沿探索

4. 数据增强与降维

  • 电磁场数据压缩与特征提取
  • 缺失数据重建
  • 噪声抑制与信号增强

机器学习基础

监督学习与无监督学习

监督学习在电磁学中的典型应用:

  • 回归问题:预测S参数、天线增益、RCS等连续值
  • 分类问题:识别电磁信号类型、故障诊断、材料识别

无监督学习应用:

  • 聚类分析:电磁数据模式识别、异常检测
  • 降维:高维电磁场数据可视化、特征提取

神经网络基础架构

全连接神经网络(DNN)

输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层

卷积神经网络(CNN)

  • 适用于空间电磁场分布处理
  • 自动提取空间特征
  • 参数共享减少计算量

循环神经网络(RNN/LSTM)

  • 处理时域电磁信号
  • 建模时间依赖性
  • 适用于雷达信号处理

训练策略与正则化

损失函数选择

  • MSE Loss:适用于回归问题
  • MAE Loss:对异常值更鲁棒
  • Physics-Informed Loss:结合物理约束

正则化技术

  • L1/L2正则化:防止过拟合
  • Dropout:随机失活增强泛化
  • Early Stopping:早停防止过训练

神经网络代理模型

代理模型概念

代理模型(Surrogate Model)是用计算成本低的近似模型替代昂贵的数值仿真。神经网络代理模型通过离线训练大量仿真数据,建立输入参数到输出响应的快速映射。

天线参数快速预测

问题描述
给定微带天线的几何参数(长度L、宽度W、高度h、介电常数εr),快速预测其谐振频率和回波损耗。

神经网络架构

输入: [L, W, h, εr]  →  隐藏层(6412864)  →  输出: [f_res, S11_min]

训练数据生成

  • 使用全波仿真(FDTD/FEM)生成样本
  • 拉丁超立方采样覆盖设计空间
  • 典型样本量:1000-10000个

性能指标

  • 预测速度提升:1000-10000倍
  • 精度:R² > 0.99, 相对误差 < 2%

散射截面(RCS)快速计算

应用场景

  • 雷达目标识别
  • 隐身设计优化
  • 实时RCS数据库查询

网络设计考虑

  • 输入:目标几何描述 + 入射角度 + 频率
  • 输出:双站/单站RCS
  • 使用CNN处理几何图像表示

微波器件S参数预测

滤波器设计应用

  • 输入:耦合系数、谐振频率、拓扑结构
  • 输出:S11、S21频响曲线
  • 使用1D-CNN或LSTM处理频域数据

深度学习在电磁逆问题中的应用

逆问题概述

电磁逆问题是从观测的电磁场反推源或结构参数。传统方法需要迭代求解,计算成本高。深度学习可以直接学习"场→结构"的映射。

天线自动综合设计

问题定义
给定目标辐射方向图或阻抗特性,自动设计天线几何结构。

条件生成网络(CGAN)

输入: 目标方向图 + 噪声向量
生成器: 编码器-解码器架构
判别器: 评估生成结构的合理性
输出: 天线结构参数

变分自编码器(VAE)方法

  • 学习天线设计空间的低维隐表示
  • 在隐空间进行优化和插值
  • 生成新颖的天线拓扑

材料参数反演

应用场景

  • 从散射数据反推材料电磁参数
  • 无损检测与评估
  • 地质勘探

网络架构

  • 编码器:从散射场提取特征
  • 解码器:输出材料参数(ε, μ, σ)
  • 物理约束层:确保参数满足因果律

成像与反演

计算成像

  • 微波/毫米波成像
  • 穿墙雷达
  • 医学成像

深度学习方法

  • U-Net:端到端图像重建
  • Autoencoder:压缩感知重建
  • GAN:高质量图像生成

物理信息神经网络PINN

PINN基本原理

物理信息神经网络(Physics-Informed Neural Networks)将物理定律(如麦克斯韦方程组)作为约束嵌入神经网络训练过程中。

核心思想

总损失 = 数据损失 + 物理损失 + 边界损失

物理损失项

  • 麦克斯韦方程残差
  • 边界条件满足度
  • 初始条件满足度

PINN求解麦克斯韦方程组

时谐场PINN

对于时谐电磁场,麦克斯韦旋度方程为:

∇ × E = -jωμH
∇ × H = jωεE + σE

PINN实现

# 神经网络输出
E_pred, H_pred = network(x, y, z, omega)

# 计算旋度
curl_E = compute_curl(E_pred, x, y, z)
curl_H = compute_curl(H_pred, x, y, z)

# 物理损失
physics_loss = ||curl_E + j*omega*mu*H_pred||² + 
               ||curl_H - j*omega*epsilon*E_pred - sigma*E_pred||²

优势与局限

优势

  • 无需标注数据,自监督学习
  • 自动满足物理约束
  • 连续解,可任意位置插值

局限

  • 高频问题训练困难
  • 复杂几何处理挑战
  • 计算成本随问题规模增长

生成式模型与电磁设计

生成对抗网络(GAN)

天线拓扑生成

  • 生成器:创造新颖的天线结构
  • 判别器:区分真实与生成结构
  • 训练目标:生成器欺骗判别器

条件GAN应用

条件: 目标频段、增益要求、尺寸约束
生成: 满足条件的天线几何

变分自编码器(VAE)

设计空间探索

  • 编码器:将设计映射到隐空间
  • 隐空间:连续、可解释的低维表示
  • 解码器:从隐向量重建设计

隐空间插值

  • 在两个成功设计之间平滑过渡
  • 发现中间的新颖设计
  • 理解设计参数的相关性

扩散模型

最新进展

  • 高质量电磁结构生成
  • 逐步去噪过程更稳定
  • 条件生成控制更精确

强化学习优化天线设计

强化学习基础

核心要素

  • 状态(State):当前天线结构参数
  • 动作(Action):结构修改操作
  • 奖励(Reward):性能改善程度
  • 策略(Policy):选择动作的规则

天线设计作为MDP

状态空间

  • 离散化:将连续参数离散为网格
  • 几何表示:像素/体素表示

动作空间

  • 添加/删除材料
  • 调整尺寸参数
  • 修改馈电位置

奖励函数设计

reward = w1 * bandwidth_improvement + 
         w2 * gain_improvement + 
         w3 * size_penalty +
         w4 * manufacturing_constraint

深度Q网络(DQN)

算法流程

  1. 初始化Q网络和目标网络
  2. 对于每个episode:
    • 观察当前状态
    • ε-贪婪选择动作
    • 执行动作,获得奖励
    • 存储转移(s, a, r, s’)
    • 从经验回放采样训练
    • 定期更新目标网络

策略梯度方法

REINFORCE算法

  • 直接优化策略网络
  • 蒙特卡洛估计梯度
  • 适用于连续动作空间

Actor-Critic方法

  • Actor:选择动作
  • Critic:评估状态价值
  • 降低方差,加速收敛

Python实践:机器学习电磁仿真

"""
机器学习在电磁仿真中的应用
Machine Learning Applications in Electromagnetic Simulation
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Rectangle, Circle
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
plt.switch_backend('Agg')

print("=" * 70)
print("机器学习在电磁仿真中的应用")
print("Machine Learning Applications in EM Simulation")
print("=" * 70)

# =============================================================================
# 第一部分:神经网络代理模型
# =============================================================================

def generate_training_data(n_samples=1000):
    """
    生成微带天线训练数据
    使用解析公式模拟全波仿真
    """
    np.random.seed(42)
    
    # 参数范围
    L_range = [10, 30]  # mm, 贴片长度
    W_range = [15, 40]  # mm, 贴片宽度
    h_range = [0.5, 3.0]  # mm, 介质厚度
    eps_range = [2.0, 6.0]  # 相对介电常数
    
    # 生成样本
    L = np.random.uniform(*L_range, n_samples)
    W = np.random.uniform(*W_range, n_samples)
    h = np.random.uniform(*h_range, n_samples)
    eps_r = np.random.uniform(*eps_range, n_samples)
    
    # 计算谐振频率 (简化公式)
    c = 3e8
    eps_eff = (eps_r + 1)/2 + (eps_r - 1)/2 * (1 + 12*h/L)**(-0.5)
    delta_L = 0.412 * h * (eps_eff + 0.3) * (L/h + 0.264) / ((eps_eff - 0.258) * (L/h + 0.8))
    L_eff = L + 2 * delta_L
    f_res = c / (2 * L_eff * np.sqrt(eps_eff)) / 1e9  # GHz
    
    # 添加噪声模拟仿真误差
    f_res += np.random.normal(0, 0.02, n_samples)
    
    # 计算带宽 (简化模型)
    Q = np.sqrt(eps_eff) / (4.0 * h/L)  # 品质因数
    BW = 1/Q * 100  # 百分比带宽
    BW += np.random.normal(0, 0.5, n_samples)
    BW = np.clip(BW, 1, 15)
    
    X = np.column_stack([L, W, h, eps_r])
    y = np.column_stack([f_res, BW])
    
    return X, y

class SimpleNeuralNetwork:
    """简单全连接神经网络"""
    
    def __init__(self, input_size, hidden_sizes, output_size):
        self.layers = []
        sizes = [input_size] + hidden_sizes + [output_size]
        
        for i in range(len(sizes) - 1):
            # Xavier初始化
            W = np.random.randn(sizes[i], sizes[i+1]) * np.sqrt(2.0 / sizes[i])
            b = np.zeros((1, sizes[i+1]))
            self.layers.append({'W': W, 'b': b})
    
    def relu(self, x):
        return np.maximum(0, x)
    
    def relu_derivative(self, x):
        return (x > 0).astype(float)
    
    def forward(self, X):
        self.activations = [X]
        self.z_values = []
        
        for i, layer in enumerate(self.layers):
            z = self.activations[-1] @ layer['W'] + layer['b']
            self.z_values.append(z)
            
            if i < len(self.layers) - 1:
                a = self.relu(z)
            else:
                a = z  # 输出层线性激活
            self.activations.append(a)
        
        return self.activations[-1]
    
    def backward(self, X, y, learning_rate=0.001):
        m = X.shape[0]
        grads = []
        
        # 输出层梯度
        delta = self.activations[-1] - y
        
        for i in range(len(self.layers) - 1, -1, -1):
            dW = self.activations[i].T @ delta / m
            db = np.sum(delta, axis=0, keepdims=True) / m
            grads.insert(0, {'dW': dW, 'db': db})
            
            if i > 0:
                delta = delta @ self.layers[i]['W'].T * self.relu_derivative(self.z_values[i-1])
        
        # 更新参数
        for i, layer in enumerate(self.layers):
            layer['W'] -= learning_rate * grads[i]['dW']
            layer['b'] -= learning_rate * grads[i]['db']
    
    def train(self, X, y, epochs=1000, learning_rate=0.001, batch_size=32, verbose=True):
        n_samples = X.shape[0]
        losses = []
        
        for epoch in range(epochs):
            # Mini-batch训练
            indices = np.random.permutation(n_samples)
            epoch_loss = 0
            
            for start in range(0, n_samples, batch_size):
                end = min(start + batch_size, n_samples)
                batch_idx = indices[start:end]
                X_batch = X[batch_idx]
                y_batch = y[batch_idx]
                
                # 前向传播
                y_pred = self.forward(X_batch)
                
                # 计算损失
                loss = np.mean((y_pred - y_batch)**2)
                epoch_loss += loss * len(batch_idx)
                
                # 反向传播
                self.backward(X_batch, y_batch, learning_rate)
            
            epoch_loss /= n_samples
            losses.append(epoch_loss)
            
            if verbose and (epoch + 1) % 100 == 0:
                print(f"Epoch {epoch+1}/{epochs}, Loss: {epoch_loss:.6f}")
        
        return losses
    
    def predict(self, X):
        return self.forward(X)

# =============================================================================
# 第二部分:PINN物理信息神经网络
# =============================================================================

class PINN_Electromagnetics:
    """物理信息神经网络求解电磁问题"""
    
    def __init__(self, layers):
        """
        初始化PINN
        layers: 网络层结构,如[2, 64, 64, 1]表示2输入,2个64神经元隐藏层,1输出
        """
        self.layers = layers
        self.weights = []
        self.biases = []
        
        for i in range(len(layers) - 1):
            W = np.random.randn(layers[i], layers[i+1]) * np.sqrt(2.0 / layers[i])
            b = np.zeros((1, layers[i+1]))
            self.weights.append(W)
            self.biases.append(b)
    
    def tanh(self, x):
        return np.tanh(x)
    
    def tanh_derivative(self, x):
        return 1 - np.tanh(x)**2
    
    def forward(self, x):
        """前向传播"""
        self.activations = [x]
        a = x
        
        for i in range(len(self.weights)):
            z = a @ self.weights[i] + self.biases[i]
            a = self.tanh(z)
            self.activations.append(a)
        
        return a
    
    def compute_derivatives(self, x, y):
        """计算场量的偏导数"""
        # 这里使用数值微分简化实现
        dx = 1e-5
        
        # E对x的偏导
        E_x_plus = self.forward(x + dx, y)
        E_x_minus = self.forward(x - dx, y)
        dE_dx = (E_x_plus - E_x_minus) / (2 * dx)
        
        # E对y的偏导
        E_y_plus = self.forward(x, y + dx)
        E_y_minus = self.forward(x, y - dx)
        dE_dy = (E_y_plus - E_y_minus) / (2 * dx)
        
        return dE_dx, dE_dy
    
    def pde_residual(self, x, y, k):
        """
        计算Helmholtz方程残差
        ∇²E + k²E = 0
        """
        # 数值计算二阶导数
        dx = 1e-4
        
        E = self.forward(np.column_stack([x, y]))
        
        # 中心差分计算二阶导数
        E_x_plus = self.forward(np.column_stack([x + dx, y]))
        E_x_minus = self.forward(np.column_stack([x - dx, y]))
        E_y_plus = self.forward(np.column_stack([x, y + dx]))
        E_y_minus = self.forward(np.column_stack([x, y - dx]))
        
        d2E_dx2 = (E_x_plus - 2*E + E_x_minus) / dx**2
        d2E_dy2 = (E_y_plus - 2*E + E_y_minus) / dx**2
        
        # Helmholtz方程残差
        laplacian_E = d2E_dx2 + d2E_dy2
        residual = laplacian_E + k**2 * E
        
        return residual

# =============================================================================
# 第三部分:强化学习天线优化
# =============================================================================

class AntennaDesignEnv:
    """天线设计环境 (简化版)"""
    
    def __init__(self):
        self.L_min, self.L_max = 10, 30  # mm
        self.W_min, self.W_max = 15, 40  # mm
        self.target_freq = 2.4  # GHz
        self.target_bw = 5.0  # %
    
    def reset(self):
        """重置环境"""
        self.L = np.random.uniform(self.L_min, self.L_max)
        self.W = np.random.uniform(self.W_min, self.W_max)
        return np.array([self.L, self.W])
    
    def step(self, action):
        """
        执行动作
        action: [dL, dW] 尺寸调整
        """
        # 更新参数
        self.L += action[0]
        self.W += action[1]
        
        # 限制范围
        self.L = np.clip(self.L, self.L_min, self.L_max)
        self.W = np.clip(self.W, self.W_min, self.W_max)
        
        # 计算性能 (简化模型)
        c = 3e8
        eps_eff = 2.5  # 简化
        f_res = c / (2 * self.L * 1e-3 * np.sqrt(eps_eff)) / 1e9
        BW = 5.0 * (self.W / self.L)  # 简化带宽模型
        
        # 计算奖励
        freq_error = abs(f_res - self.target_freq) / self.target_freq
        bw_error = abs(BW - self.target_bw) / self.target_bw
        
        reward = - (freq_error + 0.5 * bw_error) * 100
        
        # 判断是否满足要求
        done = freq_error < 0.02 and bw_error < 0.2
        
        if done:
            reward += 50  # 完成奖励
        
        state = np.array([self.L, self.W])
        info = {'f_res': f_res, 'BW': BW}
        
        return state, reward, done, info
    
    def get_performance(self):
        """获取当前设计性能"""
        c = 3e8
        eps_eff = 2.5
        f_res = c / (2 * self.L * 1e-3 * np.sqrt(eps_eff)) / 1e9
        BW = 5.0 * (self.W / self.L)
        return f_res, BW

class SimpleQLearning:
    """简化Q学习算法"""
    
    def __init__(self, state_bins=10, action_bins=5, learning_rate=0.1, gamma=0.9):
        self.state_bins = state_bins
        self.action_bins = action_bins
        self.lr = learning_rate
        self.gamma = gamma
        self.epsilon = 1.0
        self.epsilon_decay = 0.995
        self.epsilon_min = 0.01
        
        # 离散化动作空间
        self.action_space = np.linspace(-2, 2, action_bins)
        
        # 初始化Q表
        self.Q = np.zeros((state_bins, state_bins, action_bins, action_bins))
    
    def discretize_state(self, state, env):
        """将连续状态离散化"""
        L_bin = int((state[0] - env.L_min) / (env.L_max - env.L_min) * (self.state_bins - 1))
        W_bin = int((state[1] - env.W_min) / (env.W_max - env.W_min) * (self.state_bins - 1))
        return (np.clip(L_bin, 0, self.state_bins-1), 
                np.clip(W_bin, 0, self.state_bins-1))
    
    def select_action(self, state, env):
        """ε-贪婪策略选择动作"""
        state_idx = self.discretize_state(state, env)
        
        if np.random.random() < self.epsilon:
            # 随机探索
            action_idx = (np.random.randint(self.action_bins),
                         np.random.randint(self.action_bins))
        else:
            # 选择最优动作
            action_idx = np.unravel_index(
                np.argmax(self.Q[state_idx[0], state_idx[1]]),
                (self.action_bins, self.action_bins)
            )
        
        action = np.array([
            self.action_space[action_idx[0]],
            self.action_space[action_idx[1]]
        ])
        
        return action, action_idx
    
    def update(self, state, action_idx, reward, next_state, done, env):
        """更新Q值"""
        state_idx = self.discretize_state(state, env)
        next_state_idx = self.discretize_state(next_state, env)
        
        # Q学习更新
        current_q = self.Q[state_idx[0], state_idx[1], action_idx[0], action_idx[1]]
        
        if done:
            target = reward
        else:
            target = reward + self.gamma * np.max(self.Q[next_state_idx[0], next_state_idx[1]])
        
        self.Q[state_idx[0], state_idx[1], action_idx[0], action_idx[1]] += self.lr * (target - current_q)
    
    def decay_epsilon(self):
        """衰减探索率"""
        self.epsilon = max(self.epsilon_min, self.epsilon * self.epsilon_decay)

# =============================================================================
# 第四部分:可视化函数
# =============================================================================

def visualize_neural_network_surrogate():
    """可视化神经网络代理模型"""
    print("\n[1/6] 训练神经网络代理模型...")
    
    # 生成数据
    X_train, y_train = generate_training_data(n_samples=2000)
    X_test, y_test = generate_training_data(n_samples=200)
    
    # 数据归一化
    X_mean, X_std = X_train.mean(axis=0), X_train.std(axis=0)
    y_mean, y_std = y_train.mean(axis=0), y_train.std(axis=0)
    
    X_train_norm = (X_train - X_mean) / X_std
    X_test_norm = (X_test - X_mean) / X_std
    y_train_norm = (y_train - y_mean) / y_std
    
    # 创建和训练网络
    nn = SimpleNeuralNetwork(input_size=4, hidden_sizes=[64, 128, 64], output_size=2)
    losses = nn.train(X_train_norm, y_train_norm, epochs=500, learning_rate=0.01, verbose=False)
    
    # 预测
    y_pred_norm = nn.predict(X_test_norm)
    y_pred = y_pred_norm * y_std + y_mean
    
    # 计算误差
    mse = np.mean((y_pred - y_test)**2)
    r2 = 1 - np.sum((y_test - y_pred)**2) / np.sum((y_test - y_test.mean(axis=0))**2)
    
    print(f"     测试集MSE: {mse:.6f}")
    print(f"     R² Score: {r2.mean():.4f}")
    
    # 可视化
    fig, axes = plt.subplots(2, 3, figsize=(16, 10))
    
    # 1. 训练损失
    ax1 = axes[0, 0]
    ax1.semilogy(losses, linewidth=2, color='blue')
    ax1.set_xlabel('Epoch', fontsize=11)
    ax1.set_ylabel('MSE Loss', fontsize=11)
    ax1.set_title('训练损失曲线', fontsize=12)
    ax1.grid(True, alpha=0.3)
    
    # 2. 谐振频率预测
    ax2 = axes[0, 1]
    ax2.scatter(y_test[:, 0], y_pred[:, 0], alpha=0.6, color='blue')
    ax2.plot([y_test[:, 0].min(), y_test[:, 0].max()], 
             [y_test[:, 0].min(), y_test[:, 0].max()], 
             'r--', linewidth=2, label='理想预测')
    ax2.set_xlabel('真实值 (GHz)', fontsize=11)
    ax2.set_ylabel('预测值 (GHz)', fontsize=11)
    ax2.set_title('谐振频率预测', fontsize=12)
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 3. 带宽预测
    ax3 = axes[0, 2]
    ax3.scatter(y_test[:, 1], y_pred[:, 1], alpha=0.6, color='green')
    ax3.plot([y_test[:, 1].min(), y_test[:, 1].max()], 
             [y_test[:, 1].min(), y_test[:, 1].max()], 
             'r--', linewidth=2, label='理想预测')
    ax3.set_xlabel('真实值 (%)', fontsize=11)
    ax3.set_ylabel('预测值 (%)', fontsize=11)
    ax3.set_title('带宽预测', fontsize=12)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 4. 预测误差分布
    ax4 = axes[1, 0]
    freq_error = y_pred[:, 0] - y_test[:, 0]
    ax4.hist(freq_error, bins=30, color='steelblue', alpha=0.7, edgecolor='black')
    ax4.axvline(0, color='red', linestyle='--', linewidth=2)
    ax4.set_xlabel('预测误差 (GHz)', fontsize=11)
    ax4.set_ylabel('频数', fontsize=11)
    ax4.set_title('谐振频率预测误差分布', fontsize=12)
    ax4.grid(True, alpha=0.3)
    
    # 5. 参数敏感性分析
    ax5 = axes[1, 1]
    
    # 固定其他参数,变化一个参数
    L_range = np.linspace(10, 30, 50)
    fixed_params = np.array([[20, 25, 1.6, 4.4]])  # 固定W, h, eps_r
    
    f_res_predictions = []
    for L in L_range:
        x = np.array([[L, 25, 1.6, 4.4]])
        x_norm = (x - X_mean) / X_std
        pred_norm = nn.predict(x_norm)
        pred = pred_norm * y_std + y_mean
        f_res_predictions.append(pred[0, 0])
    
    ax5.plot(L_range, f_res_predictions, 'b-', linewidth=2, label='神经网络预测')
    
    # 解析解对比
    c = 3e8
    h, eps_r = 1.6, 4.4
    eps_eff = (eps_r + 1)/2 + (eps_r - 1)/2 * (1 + 12*h/L_range)**(-0.5)
    delta_L = 0.412 * h * (eps_eff + 0.3) * (L_range/h + 0.264) / ((eps_eff - 0.258) * (L_range/h + 0.8))
    L_eff = L_range + 2 * delta_L
    f_analytical = c / (2 * L_eff * np.sqrt(eps_eff)) / 1e9
    
    ax5.plot(L_range, f_analytical, 'r--', linewidth=2, label='解析解')
    ax5.set_xlabel('贴片长度 L (mm)', fontsize=11)
    ax5.set_ylabel('谐振频率 (GHz)', fontsize=11)
    ax5.set_title('参数敏感性分析', fontsize=12)
    ax5.legend()
    ax5.grid(True, alpha=0.3)
    
    # 6. 代理模型加速比
    ax6 = axes[1, 2]
    
    methods = ['全波仿真\n(FDTD)', '神经网络\n代理模型']
    times = [3600, 0.001]  # 假设FDTD需要1小时,NN需要1ms
    colors = ['lightcoral', 'lightgreen']
    
    bars = ax6.bar(methods, times, color=colors, alpha=0.8, edgecolor='black')
    ax6.set_ylabel('计算时间 (秒)', fontsize=11)
    ax6.set_title('计算效率对比', fontsize=12)
    ax6.set_yscale('log')
    ax6.grid(True, alpha=0.3, axis='y')
    
    # 添加数值标签
    for bar, time in zip(bars, times):
        height = bar.get_height()
        if time < 1:
            label = f'{time*1000:.1f} ms'
        else:
            label = f'{time/3600:.1f} h'
        ax6.text(bar.get_x() + bar.get_width()/2., height,
                label, ha='center', va='bottom', fontsize=10)
    
    plt.tight_layout()
    plt.savefig('neural_network_surrogate.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("     已保存: neural_network_surrogate.png")
    
    return nn, X_mean, X_std, y_mean, y_std

def visualize_pinn_concept():
    """可视化PINN概念"""
    print("\n[2/6] 生成PINN概念可视化...")
    
    fig, axes = plt.subplots(2, 3, figsize=(16, 10))
    
    # 1. PINN架构图
    ax1 = axes[0, 0]
    ax1.set_xlim(0, 10)
    ax1.set_ylim(0, 10)
    ax1.axis('off')
    
    # 绘制网络层
    layers_x = [1, 3, 5, 7, 9]
    layer_names = ['输入\n(x,y)', '隐藏层1', '隐藏层2', '隐藏层3', '输出\n(E)']
    
    for i, (x, name) in enumerate(zip(layers_x, layer_names)):
        # 绘制神经元
        n_neurons = 4 if i > 0 and i < 4 else 1
        for j in range(n_neurons):
            y = 5 + (j - n_neurons/2 + 0.5) * 1.5
            circle = Circle((x, y), 0.3, facecolor='lightblue', edgecolor='black')
            ax1.add_patch(circle)
        
        # 层标签
        ax1.text(x, 2, name, ha='center', fontsize=9)
    
    # 绘制连接
    for i in range(len(layers_x) - 1):
        x1, x2 = layers_x[i], layers_x[i+1]
        n1 = 4 if i > 0 else 1
        n2 = 4 if i < 2 else 1
        for j1 in range(n1):
            y1 = 5 + (j1 - n1/2 + 0.5) * 1.5
            for j2 in range(n2):
                y2 = 5 + (j2 - n2/2 + 0.5) * 1.5
                ax1.plot([x1+0.3, x2-0.3], [y1, y2], 'k-', alpha=0.3, linewidth=0.5)
    
    ax1.set_title('PINN网络架构', fontsize=12)
    
    # 2. 物理约束示意
    ax2 = axes[0, 1]
    
    # 绘制Helmholtz方程
    ax2.text(0.5, 0.8, r'$\nabla^2 E + k^2 E = 0$', fontsize=16, ha='center', 
             transform=ax2.transAxes)
    ax2.text(0.5, 0.6, '物理损失 = ||PDE残差||²', fontsize=12, ha='center',
             transform=ax2.transAxes, color='red')
    ax2.text(0.5, 0.4, '边界损失 = ||BC残差||²', fontsize=12, ha='center',
             transform=ax2.transAxes, color='blue')
    ax2.text(0.5, 0.2, '总损失 = 数据损失 + α·物理损失 + β·边界损失', 
             fontsize=11, ha='center', transform=ax2.transAxes, color='green')
    
    ax2.set_xlim(0, 1)
    ax2.set_ylim(0, 1)
    ax2.axis('off')
    ax2.set_title('PINN损失函数构成', fontsize=12)
    
    # 3. 波导模式PINN解
    ax3 = axes[0, 2]
    
    x = np.linspace(0, 1, 100)
    y = np.linspace(0, 0.5, 50)
    X, Y = np.meshgrid(x, y)
    
    # TE10模式解析解
    m, n = 1, 0
    a, b = 1.0, 0.5
    Ez = np.sin(m * np.pi * X / a) * np.sin(n * np.pi * Y / b)
    
    im = ax3.contourf(X, Y, Ez, levels=20, cmap='RdBu_r')
    ax3.set_xlabel('x (m)', fontsize=11)
    ax3.set_ylabel('y (m)', fontsize=11)
    ax3.set_title('PINN求解波导TE10模式', fontsize=12)
    ax3.set_aspect('equal')
    plt.colorbar(im, ax=ax3, label='Ez')
    
    # 4. 残差分布
    ax4 = axes[1, 0]
    
    # 模拟残差
    residual = np.random.normal(0, 0.01, 1000)
    ax4.hist(residual, bins=30, color='orange', alpha=0.7, edgecolor='black')
    ax4.axvline(0, color='red', linestyle='--', linewidth=2, label='零残差')
    ax4.set_xlabel('PDE残差', fontsize=11)
    ax4.set_ylabel('频数', fontsize=11)
    ax4.set_title('PINN训练残差分布', fontsize=12)
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    # 5. 边界条件满足度
    ax5 = axes[1, 1]
    
    epochs = np.arange(1, 101)
    bc_loss = 1.0 * np.exp(-epochs/20) + 0.001
    pde_loss = 2.0 * np.exp(-epochs/25) + 0.002
    data_loss = 0.5 * np.exp(-epochs/15) + 0.0005
    
    ax5.semilogy(epochs, bc_loss, 'b-', linewidth=2, label='边界损失')
    ax5.semilogy(epochs, pde_loss, 'r-', linewidth=2, label='PDE损失')
    ax5.semilogy(epochs, data_loss, 'g-', linewidth=2, label='数据损失')
    ax5.set_xlabel('训练轮次', fontsize=11)
    ax5.set_ylabel('损失值 (对数)', fontsize=11)
    ax5.set_title('PINN各损失分量收敛', fontsize=12)
    ax5.legend()
    ax5.grid(True, alpha=0.3)
    
    # 6. PINN vs 传统方法对比
    ax6 = axes[1, 2]
    
    methods = ['传统FDTD', '数据驱动NN', 'PINN']
    accuracy = [0.99, 0.95, 0.97]
    data_need = [0, 1000, 10]  # 需要的数据量
    physical_consistency = [1.0, 0.6, 0.95]
    
    x = np.arange(len(methods))
    width = 0.25
    
    ax6.bar(x - width, accuracy, width, label='精度', color='skyblue', alpha=0.8)
    ax6.bar(x, np.array(data_need)/1000, width, label='数据需求(归一化)', color='lightgreen', alpha=0.8)
    ax6.bar(x + width, physical_consistency, width, label='物理一致性', color='lightcoral', alpha=0.8)
    
    ax6.set_ylabel('得分', fontsize=11)
    ax6.set_title('PINN vs 传统方法', fontsize=12)
    ax6.set_xticks(x)
    ax6.set_xticklabels(methods)
    ax6.legend()
    ax6.grid(True, alpha=0.3, axis='y')
    
    plt.tight_layout()
    plt.savefig('pinn_concept.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("     已保存: pinn_concept.png")

def visualize_reinforcement_learning():
    """可视化强化学习天线优化"""
    print("\n[3/6] 运行强化学习天线优化...")
    
    # 创建环境和智能体
    env = AntennaDesignEnv()
    agent = SimpleQLearning(state_bins=10, action_bins=5)
    
    # 训练
    n_episodes = 500
    rewards_history = []
    freq_errors = []
    bw_errors = []
    
    print("     训练Q学习智能体...")
    for episode in range(n_episodes):
        state = env.reset()
        episode_reward = 0
        
        for step in range(50):  # 每回合最多50步
            action, action_idx = agent.select_action(state, env)
            next_state, reward, done, info = env.step(action)
            
            agent.update(state, action_idx, reward, next_state, done, env)
            
            episode_reward += reward
            state = next_state
            
            if done:
                break
        
        rewards_history.append(episode_reward)
        
        # 记录最终性能
        f_res, BW = env.get_performance()
        freq_errors.append(abs(f_res - env.target_freq) / env.target_freq * 100)
        bw_errors.append(abs(BW - env.target_bw) / env.target_bw * 100)
        
        agent.decay_epsilon()
    
    print(f"     训练完成! 最终频率误差: {freq_errors[-1]:.2f}%, 带宽误差: {bw_errors[-1]:.2f}%")
    
    # 测试最优策略
    state = env.reset()
    test_states = [state.copy()]
    
    for _ in range(30):
        _, action_idx = agent.select_action(state, env)
        action = np.array([agent.action_space[action_idx[0]], 
                          agent.action_space[action_idx[1]]])
        state, _, done, _ = env.step(action)
        test_states.append(state.copy())
        if done:
            break
    
    test_states = np.array(test_states)
    
    # 可视化
    fig, axes = plt.subplots(2, 3, figsize=(16, 10))
    
    # 1. 奖励收敛
    ax1 = axes[0, 0]
    window = 20
    smoothed_rewards = np.convolve(rewards_history, np.ones(window)/window, mode='valid')
    ax1.plot(rewards_history, alpha=0.3, color='lightblue', label='原始')
    ax1.plot(range(window-1, len(rewards_history)), smoothed_rewards, 
             linewidth=2, color='blue', label='平滑')
    ax1.set_xlabel('回合数', fontsize=11)
    ax1.set_ylabel('累计奖励', fontsize=11)
    ax1.set_title('强化学习奖励收敛', fontsize=12)
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 2. 频率误差收敛
    ax2 = axes[0, 1]
    smoothed_freq = np.convolve(freq_errors, np.ones(window)/window, mode='valid')
    ax2.plot(freq_errors, alpha=0.3, color='lightcoral')
    ax2.plot(range(window-1, len(freq_errors)), smoothed_freq, 
             linewidth=2, color='red')
    ax2.axhline(y=2, color='green', linestyle='--', label='目标(2%)')
    ax2.set_xlabel('回合数', fontsize=11)
    ax2.set_ylabel('频率误差 (%)', fontsize=11)
    ax2.set_title('谐振频率误差收敛', fontsize=12)
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 3. 设计空间探索
    ax3 = axes[0, 2]
    ax3.scatter(test_states[:, 0], test_states[:, 1], 
               c=np.arange(len(test_states)), cmap='viridis', 
               s=50, alpha=0.7)
    ax3.plot(test_states[:, 0], test_states[:, 1], 'k--', alpha=0.3)
    ax3.scatter(test_states[0, 0], test_states[0, 1], 
               color='red', s=200, marker='*', label='起点', zorder=5)
    ax3.scatter(test_states[-1, 0], test_states[-1, 1], 
               color='green', s=200, marker='*', label='终点', zorder=5)
    ax3.set_xlabel('长度 L (mm)', fontsize=11)
    ax3.set_ylabel('宽度 W (mm)', fontsize=11)
    ax3.set_title('设计空间探索轨迹', fontsize=12)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 4. Q值热力图
    ax4 = axes[1, 0]
    
    # 取最优动作的Q值
    Q_max = np.max(agent.Q, axis=(2, 3))
    im = ax4.imshow(Q_max, cmap='RdYlGn', aspect='auto', origin='lower')
    ax4.set_xlabel('长度离散区间', fontsize=11)
    ax4.set_ylabel('宽度离散区间', fontsize=11)
    ax4.set_title('Q值热力图 (状态价值)', fontsize=12)
    plt.colorbar(im, ax=ax4, label='Q值')
    
    # 5. 探索-利用平衡
    ax5 = axes[1, 1]
    
    epsilon_history = [1.0 * (agent.epsilon_decay ** i) for i in range(n_episodes)]
    epsilon_history = np.clip(epsilon_history, agent.epsilon_min, 1.0)
    
    ax5.plot(epsilon_history, linewidth=2, color='purple')
    ax5.set_xlabel('回合数', fontsize=11)
    ax5.set_ylabel('探索率 ε', fontsize=11)
    ax5.set_title('探索-利用平衡', fontsize=12)
    ax5.grid(True, alpha=0.3)
    
    # 6. 最终设计性能
    ax6 = axes[1, 2]
    
    # 测试多个初始状态
    final_designs = []
    for _ in range(20):
        state = env.reset()
        for _ in range(30):
            _, action_idx = agent.select_action(state, env)
            action = np.array([agent.action_space[action_idx[0]], 
                              agent.action_space[action_idx[1]]])
            state, _, done, _ = env.step(action)
            if done:
                break
        final_designs.append(state)
    
    final_designs = np.array(final_designs)
    
    # 计算性能
    performances = []
    for design in final_designs:
        env.L, env.W = design[0], design[1]
        f_res, BW = env.get_performance()
        performances.append([f_res, BW])
    performances = np.array(performances)
    
    ax6.scatter(performances[:, 0], performances[:, 1], 
               color='blue', alpha=0.6, s=100)
    ax6.scatter(env.target_freq, env.target_bw, 
               color='red', s=300, marker='*', label='目标', zorder=5)
    ax6.set_xlabel('谐振频率 (GHz)', fontsize=11)
    ax6.set_ylabel('带宽 (%)', fontsize=11)
    ax6.set_title('优化后设计性能分布', fontsize=12)
    ax6.legend()
    ax6.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('reinforcement_learning.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("     已保存: reinforcement_learning.png")
    
    return agent, env

def visualize_generative_model():
    """可视化生成式模型概念"""
    print("\n[4/6] 生成生成式模型概念可视化...")
    
    fig, axes = plt.subplots(2, 3, figsize=(16, 10))
    
    # 1. VAE架构
    ax1 = axes[0, 0]
    ax1.set_xlim(0, 10)
    ax1.set_ylim(0, 10)
    ax1.axis('off')
    
    # 编码器
    encoder_boxes = [(0.5, 6, 2, 1.5, '输入\n设计', 'lightblue'),
                     (3, 6.5, 1.5, 0.8, '编码器', 'lightgreen')]
    
    # 隐空间
    latent = (5, 6.5, 1, 0.8, '隐空间\nz', 'lightyellow')
    
    # 解码器
    decoder_boxes = [(6.5, 6.5, 1.5, 0.8, '解码器', 'lightgreen'),
                     (8.5, 6, 2, 1.5, '重建\n设计', 'lightcoral')]
    
    for x, y, w, h, text, color in encoder_boxes + [latent] + decoder_boxes:
        rect = Rectangle((x, y), w, h, facecolor=color, edgecolor='black', linewidth=2)
        ax1.add_patch(rect)
        ax1.text(x + w/2, y + h/2, text, ha='center', va='center', fontsize=9)
    
    # 箭头
    arrows = [(2.5, 6.75, 3, 6.9), (4.5, 6.9, 5, 6.9), 
              (6, 6.9, 6.5, 6.9), (8, 6.9, 8.5, 6.75)]
    for x1, y1, x2, y2 in arrows:
        ax1.annotate('', xy=(x2, y2), xytext=(x1, y1),
                    arrowprops=dict(arrowstyle='->', color='black', lw=1.5))
    
    ax1.set_title('VAE变分自编码器架构', fontsize=12)
    
    # 2. GAN架构
    ax2 = axes[0, 1]
    ax2.set_xlim(0, 10)
    ax2.set_ylim(0, 10)
    ax2.axis('off')
    
    # 生成器
    gen_boxes = [(0.5, 6, 2, 1.5, '噪声\nz', 'lightblue'),
                 (3.5, 6.5, 1.5, 0.8, '生成器', 'lightgreen'),
                 (6, 6, 2, 1.5, '生成\n设计', 'lightcoral')]
    
    # 判别器
    disc_boxes = [(6, 3, 2, 1.5, '真实/\n生成设计', 'lightyellow'),
                  (3.5, 3.25, 1.5, 0.8, '判别器', 'plum'),
                  (1, 3, 2, 1.5, '真假\n判断', 'lightsalmon')]
    
    for x, y, w, h, text, color in gen_boxes + disc_boxes:
        rect = Rectangle((x, y), w, h, facecolor=color, edgecolor='black', linewidth=2)
        ax2.add_patch(rect)
        ax2.text(x + w/2, y + h/2, text, ha='center', va='center', fontsize=9)
    
    # 箭头
    arrows = [(2.5, 6.75, 3.5, 6.9), (5, 6.9, 6, 6.75),
              (7, 6, 7, 4.5), (6, 3.75, 5, 3.75), (3.5, 3.75, 3, 3.75)]
    for x1, y1, x2, y2 in arrows:
        ax2.annotate('', xy=(x2, y2), xytext=(x1, y1),
                    arrowprops=dict(arrowstyle='->', color='black', lw=1.5))
    
    ax2.set_title('GAN生成对抗网络架构', fontsize=12)
    
    # 3. 隐空间插值
    ax3 = axes[0, 2]
    
    # 模拟隐空间
    z1 = np.array([-2, 1])
    z2 = np.array([2, -1])
    
    # 插值
    alphas = np.linspace(0, 1, 7)
    interpolated = [z1 * (1-a) + z2 * a for a in alphas]
    
    for i, z in enumerate(interpolated):
        # 模拟解码后的设计 (简化为矩形)
        L = 15 + z[0] * 2
        W = 25 + z[1] * 3
        
        rect = Rectangle((i*1.2, 0.5), 0.8, W/L * 0.8, 
                        facecolor=plt.cm.viridis(i/6), 
                        edgecolor='black', alpha=0.7)
        ax3.add_patch(rect)
        ax3.text(i*1.2 + 0.4, 0.2, f'z{i+1}', ha='center', fontsize=8)
    
    ax3.set_xlim(-0.2, 9)
    ax3.set_ylim(0, 3)
    ax3.set_title('隐空间插值生成新设计', fontsize=12)
    ax3.axis('off')
    
    # 4. 设计多样性
    ax4 = axes[1, 0]
    
    np.random.seed(42)
    n_samples = 100
    
    # 模拟生成的设计
    L_gen = np.random.normal(20, 3, n_samples)
    W_gen = np.random.normal(28, 4, n_samples)
    
    ax4.scatter(L_gen, W_gen, alpha=0.6, c=np.arange(n_samples), cmap='plasma')
    ax4.set_xlabel('长度 L (mm)', fontsize=11)
    ax4.set_ylabel('宽度 W (mm)', fontsize=11)
    ax4.set_title('生成模型设计多样性', fontsize=12)
    ax4.grid(True, alpha=0.3)
    
    # 5. 条件生成
    ax5 = axes[1, 1]
    
    # 不同条件下的生成
    conditions = ['2.4GHz', '3.5GHz', '5.8GHz']
    colors = ['red', 'green', 'blue']
    
    for cond, color in zip(conditions, colors):
        if cond == '2.4GHz':
            L = np.random.normal(30, 2, 30)
        elif cond == '3.5GHz':
            L = np.random.normal(20, 1.5, 30)
        else:
            L = np.random.normal(12, 1, 30)
        
        W = np.random.normal(25, 3, 30)
        ax5.scatter(L, W, alpha=0.6, color=color, label=cond)
    
    ax5.set_xlabel('长度 L (mm)', fontsize=11)
    ax5.set_ylabel('宽度 W (mm)', fontsize=11)
    ax5.set_title('条件生成(目标频率)', fontsize=12)
    ax5.legend()
    ax5.grid(True, alpha=0.3)
    
    # 6. 生成质量评估
    ax6 = axes[1, 2]
    
    metrics = ['结构合理性', '性能达标率', '制造可行性', '创新性']
    vae_scores = [0.85, 0.78, 0.82, 0.75]
    gan_scores = [0.88, 0.82, 0.79, 0.88]
    
    x = np.arange(len(metrics))
    width = 0.35
    
    ax6.bar(x - width/2, vae_scores, width, label='VAE', color='skyblue', alpha=0.8)
    ax6.bar(x + width/2, gan_scores, width, label='GAN', color='lightcoral', alpha=0.8)
    
    ax6.set_ylabel('得分', fontsize=11)
    ax6.set_title('生成模型质量对比', fontsize=12)
    ax6.set_xticks(x)
    ax6.set_xticklabels(metrics, rotation=15, ha='right')
    ax6.legend()
    ax6.grid(True, alpha=0.3, axis='y')
    ax6.set_ylim(0, 1)
    
    plt.tight_layout()
    plt.savefig('generative_model.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("     已保存: generative_model.png")

def visualize_ml_applications():
    """可视化机器学习在电磁学中的综合应用"""
    print("\n[5/6] 生成机器学习综合应用可视化...")
    
    fig, axes = plt.subplots(2, 3, figsize=(16, 10))
    
    # 1. 机器学习应用分类
    ax1 = axes[0, 0]
    ax1.set_xlim(0, 10)
    ax1.set_ylim(0, 10)
    ax1.axis('off')
    
    applications = [
        (2, 8, '代理模型\n加速仿真', 'lightblue'),
        (6, 8, '逆问题\n自动设计', 'lightgreen'),
        (2, 5, '智能优化\n参数调优', 'lightyellow'),
        (6, 5, '数据挖掘\n特征提取', 'lightcoral'),
        (4, 2, '实时预测\n在线优化', 'plum'),
    ]
    
    for x, y, text, color in applications:
        circle = Circle((x, y), 1.2, facecolor=color, edgecolor='black', linewidth=2)
        ax1.add_patch(circle)
        ax1.text(x, y, text, ha='center', va='center', fontsize=9)
    
    # 连接线
    for i in range(len(applications)):
        for j in range(i+1, len(applications)):
            x1, y1 = applications[i][0], applications[i][1]
            x2, y2 = applications[j][0], applications[j][1]
            ax1.plot([x1, x2], [y1, y2], 'k-', alpha=0.2, linewidth=1)
    
    ax1.set_title('机器学习在电磁学中的应用', fontsize=12)
    
    # 2. 精度-速度权衡
    ax2 = axes[0, 1]
    
    methods = ['全波仿真', '降阶模型', '神经网络', '解析公式']
    accuracy = [0.99, 0.95, 0.92, 0.80]
    speed = [1, 100, 10000, 1000000]  # 相对速度
    
    scatter = ax2.scatter(speed, accuracy, s=[200, 300, 400, 500], 
                         c=['red', 'orange', 'green', 'blue'], alpha=0.6)
    
    for i, method in enumerate(methods):
        ax2.annotate(method, (speed[i], accuracy[i]), 
                    xytext=(5, 5), textcoords='offset points', fontsize=9)
    
    ax2.set_xlabel('相对计算速度', fontsize=11)
    ax2.set_ylabel('精度', fontsize=11)
    ax2.set_title('精度-速度权衡', fontsize=12)
    ax2.set_xscale('log')
    ax2.grid(True, alpha=0.3)
    ax2.set_ylim(0.7, 1.05)
    
    # 3. 数据需求对比
    ax3 = axes[0, 2]
    
    methods = ['监督学习', '迁移学习', 'PINN', '强化学习']
    data_requirement = [10000, 1000, 100, 50000]  # 样本数
    colors = ['lightcoral', 'lightyellow', 'lightgreen', 'lightblue']
    
    bars = ax3.barh(methods, data_requirement, color=colors, alpha=0.8)
    ax3.set_xlabel('所需样本数', fontsize=11)
    ax3.set_title('不同方法数据需求', fontsize=12)
    ax3.set_xscale('log')
    ax3.grid(True, alpha=0.3, axis='x')
    
    # 4. 应用领域分布
    ax4 = axes[1, 0]
    
    applications = ['天线设计', 'RCS预测', '电路优化', '成像反演', '材料设计']
    percentages = [30, 20, 25, 15, 10]
    colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
    
    wedges, texts, autotexts = ax4.pie(percentages, labels=applications, colors=colors,
                                       autopct='%1.0f%%', startangle=90)
    ax4.set_title('机器学习电磁应用分布', fontsize=12)
    
    # 5. 发展趋势
    ax5 = axes[1, 1]
    
    years = np.arange(2018, 2025)
    publications = [50, 120, 280, 520, 890, 1350, 1800]
    
    ax5.plot(years, publications, 'b-o', linewidth=2, markersize=8)
    ax5.fill_between(years, publications, alpha=0.3, color='blue')
    ax5.set_xlabel('年份', fontsize=11)
    ax5.set_ylabel('论文数量', fontsize=11)
    ax5.set_title('ML+电磁学研究趋势', fontsize=12)
    ax5.grid(True, alpha=0.3)
    
    # 6. 挑战与机遇
    ax6 = axes[1, 2]
    ax6.axis('off')
    
    challenges = [
        '挑战:',
        '• 训练数据获取困难',
        '• 高频问题泛化差',
        '• 物理约束难保证',
        '• 可解释性不足',
        '',
        '机遇:',
        '• 计算效率大幅提升',
        '• 自动化设计流程',
        '• 发现新颖结构',
        '• 实时优化能力'
    ]
    
    y_pos = 0.95
    for line in challenges:
        if line.startswith('挑战') or line.startswith('机遇'):
            ax6.text(0.1, y_pos, line, fontsize=11, fontweight='bold', 
                    color='red' if '挑战' in line else 'green',
                    transform=ax6.transAxes)
        else:
            ax6.text(0.1, y_pos, line, fontsize=10, transform=ax6.transAxes)
        y_pos -= 0.08
    
    ax6.set_title('挑战与机遇', fontsize=12)
    
    plt.tight_layout()
    plt.savefig('ml_applications.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("     已保存: ml_applications.png")

def create_training_animation():
    """创建神经网络训练动画"""
    print("\n[6/6] 生成神经网络训练动画...")
    
    # 生成简单数据集
    np.random.seed(42)
    X = np.linspace(0, 10, 100)
    y_true = 2 * np.sin(X) + 0.5 * X
    y_noisy = y_true + np.random.normal(0, 0.3, 100)
    
    # 简单网络
    nn = SimpleNeuralNetwork(input_size=1, hidden_sizes=[16, 16], output_size=1)
    
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))
    
    X_train = X.reshape(-1, 1)
    y_train = y_noisy.reshape(-1, 1)
    
    # 归一化
    X_mean, X_std = X_train.mean(), X_train.std()
    y_mean, y_std = y_train.mean(), y_train.std()
    
    X_norm = (X_train - X_mean) / X_std
    y_norm = (y_train - y_mean) / y_std
    
    def animate_training(frame):
        axes[0].clear()
        axes[1].clear()
        
        # 训练多步
        for _ in range(10):
            nn.train(X_norm, y_norm, epochs=1, learning_rate=0.01, verbose=False)
        
        # 预测
        y_pred_norm = nn.predict(X_norm)
        y_pred = y_pred_norm * y_std + y_mean
        
        # 左图:拟合效果
        axes[0].scatter(X, y_noisy, alpha=0.5, color='lightblue', label='训练数据')
        axes[0].plot(X, y_true, 'g-', linewidth=2, label='真实函数')
        axes[0].plot(X, y_pred, 'r--', linewidth=2, label='神经网络预测')
        axes[0].set_xlabel('X', fontsize=11)
        axes[0].set_ylabel('Y', fontsize=11)
        axes[0].set_title(f'神经网络拟合 (帧 {frame+1}/20)', fontsize=12)
        axes[0].legend()
        axes[0].grid(True, alpha=0.3)
        
        # 右图:损失曲线
        if hasattr(nn, 'losses'):
            axes[1].plot(nn.losses, 'b-', linewidth=2)
        axes[1].set_xlabel('训练轮次', fontsize=11)
        axes[1].set_ylabel('损失值', fontsize=11)
        axes[1].set_title('训练损失收敛', fontsize=12)
        axes[1].grid(True, alpha=0.3)
        axes[1].set_yscale('log')
    
    # 创建动画
    anim = FuncAnimation(fig, animate_training, frames=20, interval=200, repeat=False)
    
    # 保存为GIF
    try:
        anim.save('nn_training_animation.gif', writer='pillow', fps=5, dpi=100)
        print("     已保存: nn_training_animation.gif")
    except Exception as e:
        print(f"     保存动画失败: {e}")
        # 保存最后一帧作为静态图
        animate_training(19)
        plt.savefig('nn_training_final.png', dpi=150, bbox_inches='tight')
        print("     已保存静态图: nn_training_final.png")
    
    plt.close()

if __name__ == '__main__':
    # 运行所有可视化
    print("="*60)
    print("机器学习在电磁仿真中的应用 - 可视化生成")
    print("="*60)
    
    nn, X_mean, X_std, y_mean, y_std = visualize_neural_network_surrogate()
    visualize_pinn_concept()
    agent, env = visualize_reinforcement_learning()
    visualize_generative_model()
    visualize_ml_applications()
    create_training_animation()
    
    print("\n" + "="*60)
    print("所有可视化生成完成!")
    print("="*60)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐