打造现代化雷达电子对抗仿真界面 第二篇:雷达电子对抗仿真系统核心功能实现

摘要

本文将深入实现一个完整的雷达电子对抗仿真系统,重点围绕单脉冲导引头的交叉眼对抗场景。我们将从仿真模型建立、UI界面设计、数据可视化、实时交互等方面展开,展示如何利用tkinter/ttk构建功能完整、界面美观、响应迅速的专业仿真系统。


目录

  1. 引言:单脉冲导引头与交叉眼对抗原理

  2. 仿真系统架构设计

  3. 单脉冲导引头仿真模型实现

  4. 交叉眼干扰算法实现

  5. 仿真系统UI设计

  6. 实时数据可视化

  7. 多线程与性能优化

  8. 仿真结果分析与展示

  9. 系统测试与验证

  10. 总结与展望


1. 引言:单脉冲导引头与交叉眼对抗原理

1.1 单脉冲导引头原理

单脉冲导引头是精密跟踪雷达的核心,通过比较和通道(Σ)与差通道(Δ)的信号实现角度精确测量:

1.2 交叉眼干扰原理

交叉眼干扰通过两个协同工作的干扰机产生相干干扰信号:

1.3 仿真目标

构建一个完整的仿真系统,包含:

  • 单脉冲导引头跟踪模型

  • 交叉眼干扰效应模拟

  • 实时可视化界面

  • 性能评估工具


2. 仿真系统架构设计

2.1 系统架构

python 复制代码
"""
system_architecture.py

仿真系统架构定义
"""
from dataclasses import dataclass
from typing import Dict, List, Any, Tuple, Callable
from enum import Enum
import threading
import queue

class SystemMode(Enum):
    """系统运行模式"""
    SIMULATION = "simulation"      # 仿真模式
    REAL_TIME = "real_time"        # 实时模式
    ANALYSIS = "analysis"          # 分析模式
    TRAINING = "training"          # 训练模式

@dataclass
class SystemConfig:
    """系统配置"""
    mode: SystemMode = SystemMode.SIMULATION
    update_rate: float = 50.0  # Hz
    data_buffer_size: int = 1000
    enable_logging: bool = True
    log_level: str = "INFO"
    
class RadarSimulationSystem:
    """雷达仿真系统核心类"""
    
    def __init__(self, config: SystemConfig = None):
        self.config = config or SystemConfig()
        self.modules = {}
        self.data_bus = DataBus()
        self.event_manager = EventManager()
        self.simulation_engine = SimulationEngine()
        self.ui_controller = UIController()
        
    def initialize(self):
        """初始化系统"""
        # 初始化各个模块
        self.modules = {
            'seeker': MonopulseSeeker(),
            'jammer': CrossEyeJammer(),
            'target': TargetModel(),
            'environment': EnvironmentModel(),
            'visualization': VisualizationEngine()
        }
        
        # 设置数据流
        self._setup_data_flow()
        
        # 启动系统
        self._start_system()
        
    def _setup_data_flow(self):
        """设置数据流"""
        # 定义模块间的数据流
        data_flows = [
            ('target', 'seeker', 'target_info'),
            ('seeker', 'jammer', 'seeker_state'),
            ('jammer', 'seeker', 'jamming_signal'),
            ('seeker', 'visualization', 'tracking_data'),
            ('environment', 'seeker', 'env_conditions')
        ]
        
        for source, target, data_type in data_flows:
            self.data_bus.connect(source, target, data_type)
            
    def _start_system(self):
        """启动系统"""
        # 启动各个模块
        for name, module in self.modules.items():
            if hasattr(module, 'start'):
                module.start()
                
        # 启动事件循环
        self.event_manager.start()
        
    def run_simulation(self, duration: float):
        """运行仿真"""
        self.simulation_engine.run(duration)
        
    def get_performance_metrics(self) -> Dict[str, Any]:
        """获取性能指标"""
        metrics = {
            'tracking_accuracy': self._calculate_tracking_accuracy(),
            'jamming_effectiveness': self._calculate_jamming_effect(),
            'system_response_time': self._measure_response_time(),
            'resource_utilization': self._get_resource_usage()
        }
        return metrics

3. 单脉冲导引头仿真模型实现

3.1 数学模型实现

python 复制代码
"""
monopulse_seeker_model.py

单脉冲导引头详细仿真模型
"""
import numpy as np
from dataclasses import dataclass, field
from typing import Tuple, List, Optional
import math
from scipy import signal
import numpy.typing as npt

@dataclass
class SeekerParameters:
    """导引头详细参数"""
    # 天线参数
    antenna_type: str = "planar_array"
    array_size: Tuple[int, int] = (8, 8)  # 阵列大小
    element_spacing: float = 0.5  # 波长倍数
    
    # 信号参数
    center_frequency: float = 10e9  # Hz
    bandwidth: float = 1e6  # Hz
    pulse_width: float = 1e-6  # s
    prf: float = 1000  # Hz
    duty_cycle: float = 0.001
    
    # 性能参数
    beamwidth_azimuth: float = 3.0  # 度
    beamwidth_elevation: float = 3.0  # 度
    antenna_gain: float = 30.0  # dBi
    sidelobe_level: float = -20.0  # dB
    noise_figure: float = 3.0  # dB
    dynamic_range: float = 60.0  # dB
    
    # 跟踪参数
    tracking_bandwidth: float = 10.0  # Hz
    angle_resolution: float = 0.01  # 度
    max_tracking_rate: float = 10.0  # 度/秒
    
    # 校准参数
    channel_imbalance: float = 0.1  # 通道不平衡度
    phase_error: float = 5.0  # 度
    calibration_error: float = 0.05  # 校准误差

@dataclass
class TargetState:
    """目标状态"""
    range: float  # 距离 (m)
    azimuth: float  # 方位角 (度)
    elevation: float  # 俯仰角 (度)
    range_rate: float  # 径向速度 (m/s)
    azimuth_rate: float  # 方位角速度 (度/秒)
    elevation_rate: float  # 俯仰角速度 (度/秒)
    rcs: float  # 雷达截面积 (m²)
    snr: float  # 信噪比 (dB)
    
class MonopulseSeekerModel:
    """单脉冲导引头详细模型"""
    
    def __init__(self, params: SeekerParameters = None):
        self.params = params or SeekerParameters()
        self.initialize_antenna_pattern()
        self.initialize_signal_processor()
        
        # 状态变量
        self.current_azimuth = 0.0
        self.current_elevation = 0.0
        self.angle_error_azimuth = 0.0
        self.angle_error_elevation = 0.0
        self.tracking_lock = False
        self.signal_power = 0.0
        self.noise_power = 0.0
        
        # 数据记录
        self.angle_history: List[Tuple[float, float]] = []
        self.error_history: List[Tuple[float, float]] = []
        self.snr_history: List[float] = []
        
    def initialize_antenna_pattern(self):
        """初始化天线方向图"""
        # 计算阵列因子
        self.array_factor = self._calculate_array_factor()
        
        # 计算和差方向图
        self.sum_pattern, self.diff_pattern_az, self.diff_pattern_el = \
            self._calculate_monopulse_patterns()
            
    def _calculate_array_factor(self) -> npt.NDArray:
        """计算阵列因子"""
        rows, cols = self.params.array_size
        dx = dy = self.params.element_spacing
        
        # 创建角度网格
        theta = np.linspace(-np.pi/2, np.pi/2, 181)
        phi = np.linspace(0, 2*np.pi, 361)
        Theta, Phi = np.meshgrid(theta, phi)
        
        # 计算阵列因子
        k = 2 * np.pi
        array_factor = np.zeros_like(Theta)
        
        for m in range(rows):
            for n in range(cols):
                phase = k * dx * m * np.sin(Theta) * np.cos(Phi) + \
                        k * dy * n * np.sin(Theta) * np.sin(Phi)
                array_factor += np.exp(1j * phase)
                
        return array_factor
        
    def _calculate_monopulse_patterns(self) -> Tuple[npt.NDArray, npt.NDArray, npt.NDArray]:
        """计算单脉冲方向图"""
        rows, cols = self.params.array_size
        half_rows = rows // 2
        
        # 计算和方向图 (全阵列)
        sum_array = np.ones((rows, cols))
        
        # 计算方位差方向图 (左右半阵列)
        diff_array_az = np.zeros((rows, cols))
        diff_array_az[:half_rows, :] = 1.0
        diff_array_az[half_rows:, :] = -1.0
        
        # 计算俯仰差方向图 (上下半阵列)
        half_cols = cols // 2
        diff_array_el = np.zeros((rows, cols))
        diff_array_el[:, :half_cols] = 1.0
        diff_array_el[:, half_cols:] = -1.0
        
        # 计算方向图
        sum_pattern = self._compute_pattern(sum_array)
        diff_pattern_az = self._compute_pattern(diff_array_az)
        diff_pattern_el = self._compute_pattern(diff_array_el)
        
        return sum_pattern, diff_pattern_az, diff_pattern_el
        
    def _compute_pattern(self, weighting: npt.NDArray) -> npt.NDArray:
        """计算方向图"""
        rows, cols = weighting.shape
        dx = dy = self.params.element_spacing
        
        # 创建角度网格
        theta = np.linspace(-np.pi/2, np.pi/2, 181)
        phi = np.linspace(0, 2*np.pi, 361)
        Theta, Phi = np.meshgrid(theta, phi)
        
        k = 2 * np.pi
        pattern = np.zeros_like(Theta, dtype=complex)
        
        for m in range(rows):
            for n in range(cols):
                phase = k * dx * m * np.sin(Theta) * np.cos(Phi) + \
                        k * dy * n * np.sin(Theta) * np.sin(Phi)
                pattern += weighting[m, n] * np.exp(1j * phase)
                
        return np.abs(pattern)
        
    def initialize_signal_processor(self):
        """初始化信号处理器"""
        # 设计匹配滤波器
        self.matched_filter = self._design_matched_filter()
        
        # 设计角误差提取器
        self.error_extractor = self._design_error_extractor()
        
        # 设计跟踪滤波器
        self.tracking_filter = self._design_tracking_filter()
        
    def _design_matched_filter(self):
        """设计匹配滤波器"""
        # 脉冲压缩匹配滤波器
        t = np.linspace(-self.params.pulse_width, self.params.pulse_width, 1001)
        pulse = np.sinc(2 * self.params.bandwidth * t)
        return pulse
        
    def _design_error_extractor(self):
        """设计角误差提取器"""
        # 单脉冲误差提取曲线
        angles = np.linspace(-self.params.beamwidth_azimuth/2, 
                            self.params.beamwidth_azimuth/2, 101)
        error_curve = 2 * angles / self.params.beamwidth_azimuth
        return np.poly1d(np.polyfit(angles, error_curve, 3))
        
    def _design_tracking_filter(self):
        """设计跟踪滤波器"""
        # 二阶跟踪滤波器
        omega_n = 2 * np.pi * self.params.tracking_bandwidth
        zeta = 0.7  # 阻尼系数
        
        b = [omega_n**2]
        a = [1, 2*zeta*omega_n, omega_n**2]
        
        return signal.TransferFunction(b, a)
        
    def update_target(self, target_state: TargetState, jamming_signal: Optional[Tuple] = None):
        """
        更新目标状态并计算角误差
        
        参数:
            target_state: 目标状态
            jamming_signal: 干扰信号 (sigma, delta_az, delta_el)
        """
        # 计算目标回波信号
        echo_signal = self._calculate_echo_signal(target_state)
        
        # 计算和差通道信号
        sigma, delta_az, delta_el = self._calculate_monopulse_signals(
            target_state.azimuth, target_state.elevation, echo_signal
        )
        
        # 添加干扰信号
        if jamming_signal:
            sigma_j, delta_az_j, delta_el_j = jamming_signal
            sigma += sigma_j
            delta_az += delta_az_j
            delta_el += delta_el_j
            
        # 计算噪声
        noise = self._calculate_noise()
        sigma += noise
        delta_az += noise
        delta_el += noise
        
        # 计算信噪比
        self.signal_power = np.mean(np.abs(sigma)**2)
        self.noise_power = np.mean(np.abs(noise)**2)
        snr_linear = self.signal_power / self.noise_power
        self.snr_history.append(10 * np.log10(snr_linear))
        
        # 计算角误差
        self.angle_error_azimuth = self._extract_angle_error(sigma, delta_az, 'azimuth')
        self.angle_error_elevation = self._extract_angle_error(sigma, delta_el, 'elevation')
        
        # 更新跟踪状态
        self._update_tracking_state(target_state)
        
        # 记录历史数据
        self.angle_history.append((self.current_azimuth, self.current_elevation))
        self.error_history.append((self.angle_error_azimuth, self.angle_error_elevation))
        
        return self.angle_error_azimuth, self.angle_error_elevation
        
    def _calculate_echo_signal(self, target_state: TargetState) -> npt.NDArray:
        """计算目标回波信号"""
        # 计算距离延迟
        delay = 2 * target_state.range / 3e8  # 光速
        
        # 计算多普勒频移
        doppler_shift = 2 * target_state.range_rate * self.params.center_frequency / 3e8
        
        # 生成发射信号
        t = np.linspace(0, self.params.pulse_width, 1000)
        transmit_signal = np.exp(1j * 2 * np.pi * self.params.center_frequency * t)
        
        # 添加多普勒效应
        doppler_signal = transmit_signal * np.exp(1j * 2 * np.pi * doppler_shift * t)
        
        # 添加距离衰减
        range_loss = 1 / (target_state.range**2)
        
        # 添加RCS影响
        rcs_factor = np.sqrt(target_state.rcs)
        
        return doppler_signal * range_loss * rcs_factor
        
    def _calculate_monopulse_signals(self, azimuth: float, elevation: float, 
                                    echo_signal: npt.NDArray) -> Tuple[npt.NDArray, npt.NDArray, npt.NDArray]:
        """计算和差通道信号"""
        # 计算天线方向图响应
        sum_response = self._pattern_response(azimuth, elevation, 'sum')
        diff_az_response = self._pattern_response(azimuth, elevation, 'diff_az')
        diff_el_response = self._pattern_response(azimuth, elevation, 'diff_el')
        
        # 计算通道信号
        sigma = echo_signal * sum_response
        delta_az = echo_signal * diff_az_response
        delta_el = echo_signal * diff_el_response
        
        return sigma, delta_az, delta_el
        
    def _pattern_response(self, azimuth: float, elevation: float, pattern_type: str) -> complex:
        """计算方向图在特定方向的响应"""
        # 将角度转换为弧度
        az_rad = np.deg2rad(azimuth)
        el_rad = np.deg2rad(elevation)
        
        # 计算方向余弦
        u = np.sin(az_rad) * np.cos(el_rad)
        v = np.sin(el_rad)
        
        # 选择方向图
        if pattern_type == 'sum':
            pattern = self.sum_pattern
        elif pattern_type == 'diff_az':
            pattern = self.diff_pattern_az
        elif pattern_type == 'diff_el':
            pattern = self.diff_pattern_el
        else:
            raise ValueError(f"未知的方向图类型: {pattern_type}")
            
        # 查找最近的网格点
        theta_idx = int((az_rad + np.pi/2) / np.pi * 180)
        phi_idx = int(el_rad / (2*np.pi) * 360)
        
        # 确保索引在范围内
        theta_idx = max(0, min(180, theta_idx))
        phi_idx = max(0, min(360, phi_idx))
        
        return pattern[phi_idx, theta_idx]
        
    def _calculate_noise(self) -> npt.NDArray:
        """计算噪声信号"""
        # 计算噪声功率
        noise_power_db = 10 * np.log10(self.noise_power) if self.noise_power > 0 else -100
        noise_power_linear = 10 ** (noise_power_db / 10)
        
        # 生成复高斯噪声
        noise_real = np.random.normal(0, np.sqrt(noise_power_linear/2), 1000)
        noise_imag = np.random.normal(0, np.sqrt(noise_power_linear/2), 1000)
        
        return noise_real + 1j * noise_imag
        
    def _extract_angle_error(self, sigma: npt.NDArray, delta: npt.NDArray, 
                            angle_type: str) -> float:
        """提取角误差"""
        # 计算复比
        complex_ratio = np.mean(delta) / np.mean(sigma)
        
        # 提取误差曲线值
        error_curve_value = np.real(complex_ratio)
        
        # 应用误差提取曲线
        angle_error = self.error_extractor(error_curve_value)
        
        # 添加校准误差
        if angle_type == 'azimuth':
            calibration_error = self.params.calibration_error
        else:
            calibration_error = self.params.calibration_error
            
        angle_error += np.random.normal(0, calibration_error)
        
        return angle_error
        
    def _update_tracking_state(self, target_state: TargetState):
        """更新跟踪状态"""
        # 更新当前指向角度
        if self.tracking_lock:
            # 应用跟踪滤波器
            self.current_azimuth += self.angle_error_azimuth
            self.current_elevation += self.angle_error_elevation
            
            # 限制角度变化率
            max_rate = self.params.max_tracking_rate
            az_rate = self.angle_error_azimuth * self.params.update_rate
            el_rate = self.angle_error_elevation * self.params.update_rate
            
            if abs(az_rate) > max_rate:
                self.current_azimuth = self.current_azimuth - self.angle_error_azimuth
                self.current_azimuth += np.sign(self.angle_error_azimuth) * max_rate / self.params.update_rate
                
            if abs(el_rate) > max_rate:
                self.current_elevation = self.current_elevation - self.angle_error_elevation
                self.current_elevation += np.sign(self.angle_error_elevation) * max_rate / self.params.update_rate
                
        else:
            # 如果未锁定,更新为当前目标角度
            self.current_azimuth = target_state.azimuth
            self.current_elevation = target_state.elevation
            
        # 检查跟踪锁定
        self._check_tracking_lock()
        
    def _check_tracking_lock(self):
        """检查跟踪锁定状态"""
        # 计算角误差大小
        error_magnitude = np.sqrt(
            self.angle_error_azimuth**2 + 
            self.angle_error_elevation**2
        )
        
        # 计算信噪比
        current_snr = self.snr_history[-1] if self.snr_history else 0
        
        # 锁定条件
        lock_conditions = [
            error_magnitude < self.params.beamwidth_azimuth * 0.1,  # 角误差小于波束宽度的10%
            current_snr > 10,  # 信噪比大于10dB
            len(self.snr_history) > 10  # 有足够的历史数据
        ]
        
        # 如果所有条件满足,则锁定
        if all(lock_conditions):
            self.tracking_lock = True
        elif error_magnitude > self.params.beamwidth_azimuth * 0.5:
            # 如果角误差过大,则失锁
            self.tracking_lock = False
            
    def get_current_state(self) -> Dict[str, Any]:
        """获取当前状态"""
        return {
            'azimuth': self.current_azimuth,
            'elevation': self.current_elevation,
            'angle_error_azimuth': self.angle_error_azimuth,
            'angle_error_elevation': self.angle_error_elevation,
            'tracking_lock': self.tracking_lock,
            'signal_power': self.signal_power,
            'noise_power': self.noise_power,
            'snr': self.snr_history[-1] if self.snr_history else 0
        }
        
    def get_performance_metrics(self) -> Dict[str, Any]:
        """获取性能指标"""
        if not self.error_history:
            return {}
            
        # 计算角误差统计
        az_errors = [e[0] for e in self.error_history]
        el_errors = [e[1] for e in self.error_history]
        
        metrics = {
            'rms_azimuth_error': np.sqrt(np.mean(np.array(az_errors)**2)),
            'rms_elevation_error': np.sqrt(np.mean(np.array(el_errors)**2)),
            'max_azimuth_error': np.max(np.abs(az_errors)),
            'max_elevation_error': np.max(np.abs(el_errors)),
            'mean_snr': np.mean(self.snr_history) if self.snr_history else 0,
            'tracking_lock_ratio': np.mean([1 if self.tracking_lock else 0]),
            'angle_error_history': self.error_history,
            'snr_history': self.snr_history
        }
        
        return metrics
        
    def reset(self):
        """重置导引头状态"""
        self.current_azimuth = 0.0
        self.current_elevation = 0.0
        self.angle_error_azimuth = 0.0
        self.angle_error_elevation = 0.0
        self.tracking_lock = False
        self.signal_power = 0.0
        self.noise_power = 0.0
        self.angle_history.clear()
        self.error_history.clear()
        self.snr_history.clear()

# 测试函数
def test_monopulse_seeker():
    """测试单脉冲导引头模型"""
    import matplotlib.pyplot as plt
    
    # 创建导引头实例
    params = SeekerParameters()
    seeker = MonopulseSeekerModel(params)
    
    # 创建目标状态
    target = TargetState(
        range=10000,
        azimuth=1.0,
        elevation=0.5,
        range_rate=-100,
        azimuth_rate=0.1,
        elevation_rate=0.05,
        rcs=5.0,
        snr=20.0
    )
    
    # 运行仿真
    n_steps = 100
    az_errors = []
    el_errors = []
    az_target = []
    el_target = []
    
    for i in range(n_steps):
        # 更新目标位置
        target.azimuth += 0.1 * np.sin(i * 0.1)
        target.elevation += 0.05 * np.cos(i * 0.1)
        
        # 更新导引头
        az_error, el_error = seeker.update_target(target)
        
        # 记录数据
        az_errors.append(az_error)
        el_errors.append(el_error)
        az_target.append(target.azimuth)
        el_target.append(target.elevation)
        
    # 绘制结果
    fig, axes = plt.subplots(2, 2, figsize=(12, 8))
    
    # 方位角跟踪
    axes[0, 0].plot(az_target, label='目标方位角')
    axes[0, 0].plot([s['azimuth'] for s in [seeker.get_current_state()]], 
                   label='导引头方位角')
    axes[0, 0].set_xlabel('时间步')
    axes[0, 0].set_ylabel('方位角 (度)')
    axes[0, 0].legend()
    axes[0, 0].grid(True)
    
    # 方位角误差
    axes[0, 1].plot(az_errors)
    axes[0, 1].set_xlabel('时间步')
    axes[0, 1].set_ylabel('方位角误差 (度)')
    axes[0, 1].set_title('方位角误差曲线')
    axes[0, 1].grid(True)
    
    # 俯仰角跟踪
    axes[1, 0].plot(el_target, label='目标俯仰角')
    axes[1, 0].plot([s['elevation'] for s in [seeker.get_current_state()]], 
                   label='导引头俯仰角')
    axes[1, 0].set_xlabel('时间步')
    axes[1, 0].set_ylabel('俯仰角 (度)')
    axes[1, 0].legend()
    axes[1, 0].grid(True)
    
    # 俯仰角误差
    axes[1, 1].plot(el_errors)
    axes[1, 1].set_xlabel('时间步')
    axes[1, 1].set_ylabel('俯仰角误差 (度)')
    axes[1, 1].set_title('俯仰角误差曲线')
    axes[1, 1].grid(True)
    
    plt.tight_layout()
    plt.show()
    
    # 打印性能指标
    metrics = seeker.get_performance_metrics()
    print("性能指标:")
    for key, value in metrics.items():
        if not key.endswith('history'):
            print(f"  {key}: {value:.4f}")

if __name__ == "__main__":
    test_monopulse_seeker()

4. 交叉眼干扰算法实现

4.1 交叉眼干扰数学模型

python 复制代码
"""
cross_eye_jamming.py

交叉眼干扰算法实现
"""
import numpy as np
from dataclasses import dataclass, field
from typing import Tuple, List, Optional, Dict, Any
import math
from enum import Enum

class JammerType(Enum):
    """干扰机类型"""
    COHERENT = "coherent"      # 相干干扰
    INCOHERENT = "incoherent"  # 非相干干扰
    NOISE = "noise"           # 噪声干扰
    DECEPTION = "deception"   # 欺骗干扰

@dataclass
class JammerParameters:
    """干扰机参数"""
    # 干扰机位置
    position1: Tuple[float, float, float] = (0, 100, 0)  # (x, y, z) 单位: 米
    position2: Tuple[float, float, float] = (0, -100, 0)  # (x, y, z) 单位: 米
    
    # 干扰信号参数
    jamming_frequency: float = 10e9  # Hz
    bandwidth: float = 10e6  # Hz
    power: float = 1000  # W
    polarization: str = "horizontal"  # 极化方式
    
    # 交叉眼参数
    phase_difference: float = 180.0  # 相位差 (度)
    amplitude_imbalance: float = 0.1  # 幅度不平衡
    time_delay: float = 1e-9  # 时间延迟 (s)
    
    # 调制参数
    modulation_type: str = "cw"  # 调制类型
    modulation_depth: float = 0.5  # 调制深度
    modulation_rate: float = 1000  # Hz
    
    # 系统参数
    antenna_gain: float = 20.0  # dBi
    beamwidth: float = 30.0  # 度
    pointing_accuracy: float = 0.1  # 度

@dataclass
class JammerState:
    """干扰机状态"""
    enabled: bool = True
    power_level: float = 1.0
    frequency_offset: float = 0.0
    phase_offset: float = 0.0
    modulation_enabled: bool = True
    beam_direction: Tuple[float, float] = (0, 0)  # (azimuth, elevation)
    
class CrossEyeJammer:
    """交叉眼干扰机"""
    
    def __init__(self, params: JammerParameters = None, 
                 seeker_params: Optional[SeekerParameters] = None):
        self.params = params or JammerParameters()
        self.seeker_params = seeker_params
        
        # 状态变量
        self.state = JammerState()
        self.effective_phase_diff = self.params.phase_difference
        self.effective_amplitude_ratio = 1.0 - self.params.amplitude_imbalance
        
        # 性能指标
        self.jamming_to_signal_ratio = 0.0
        self.angle_error_enhancement = 1.0
        self.tracking_error = 0.0
        
        # 历史数据
        self.jamming_history: List[Dict[str, Any]] = []
        
    def calculate_jamming_signal(self, target_state: TargetState, 
                                 seeker_state: Dict[str, Any],
                                 time: float) -> Tuple[complex, complex, complex]:
        """
        计算干扰信号
        
        参数:
            target_state: 目标状态
            seeker_state: 导引头状态
            time: 当前时间
            
        返回:
            (sigma_jamming, delta_az_jamming, delta_el_jamming)
        """
        if not self.state.enabled:
            return 0j, 0j, 0j
            
        # 计算干扰机到导引头的几何关系
        geometry = self._calculate_geometry(target_state, seeker_state)
        
        # 计算干扰信号
        jamming_signal = self._generate_jamming_waveform(time)
        
        # 计算天线方向图响应
        antenna_response = self._calculate_antenna_response(geometry)
        
        # 计算交叉眼效应
        cross_eye_effect = self._calculate_cross_eye_effect(geometry)
        
        # 合成干扰信号
        sigma_jamming = (jamming_signal * antenna_response['sum'] * 
                        cross_eye_effect['sum'])
        delta_az_jamming = (jamming_signal * antenna_response['diff_az'] * 
                           cross_eye_effect['diff_az'])
        delta_el_jamming = (jamming_signal * antenna_response['diff_el'] * 
                           cross_eye_effect['diff_el'])
        
        # 计算干信比
        self.jamming_to_signal_ratio = self._calculate_jsr(sigma_jamming, target_state)
        
        # 计算角误差增强因子
        self.angle_error_enhancement = self._calculate_angle_error_enhancement(
            sigma_jamming, delta_az_jamming, delta_el_jamming
        )
        
        # 记录历史
        self._record_history(time, sigma_jamming, delta_az_jamming, delta_el_jamming)
        
        return sigma_jamming, delta_az_jamming, delta_el_jamming
        
    def _calculate_geometry(self, target_state: TargetState, 
                           seeker_state: Dict[str, Any]) -> Dict[str, Any]:
        """计算几何关系"""
        # 导引头位置 (假设在原点)
        seeker_pos = np.array([0, 0, 0])
        
        # 干扰机位置
        jammer1_pos = np.array(self.params.position1)
        jammer2_pos = np.array(self.params.position2)
        
        # 计算目标方向
        target_az = np.deg2rad(target_state.azimuth)
        target_el = np.deg2rad(target_state.elevation)
        
        # 计算干扰机相对位置
        r1 = jammer1_pos - seeker_pos
        r2 = jammer2_pos - seeker_pos
        
        # 计算距离和角度
        geometry = {
            'range1': np.linalg.norm(r1),
            'range2': np.linalg.norm(r2),
            'azimuth1': np.arctan2(r1[1], r1[0]),
            'elevation1': np.arcsin(r1[2] / np.linalg.norm(r1)),
            'azimuth2': np.arctan2(r2[1], r2[0]),
            'elevation2': np.arcsin(r2[2] / np.linalg.norm(r2)),
            'baseline_vector': jammer2_pos - jammer1_pos,
            'baseline_length': np.linalg.norm(jammer2_pos - jammer1_pos)
        }
        
        return geometry
        
    def _generate_jamming_waveform(self, time: float) -> complex:
        """生成干扰波形"""
        # 基础载波
        carrier = np.exp(1j * 2 * np.pi * 
                        (self.params.jamming_frequency + self.state.frequency_offset) * 
                        time)
        
        # 相位调制
        phase_mod = np.exp(1j * self.state.phase_offset)
        
        # 幅度调制
        if self.state.modulation_enabled and self.params.modulation_type != "cw":
            amplitude_mod = 1 + self.params.modulation_depth * np.sin(
                2 * np.pi * self.params.modulation_rate * time
            )
        else:
            amplitude_mod = 1.0
            
        # 时间延迟
        time_delay = np.exp(-1j * 2 * np.pi * 
                           self.params.jamming_frequency * 
                           self.params.time_delay)
        
        # 功率控制
        power_factor = np.sqrt(self.params.power * self.state.power_level)
        
        return carrier * phase_mod * amplitude_mod * time_delay * power_factor
        
    def _calculate_antenna_response(self, geometry: Dict[str, Any]) -> Dict[str, complex]:
        """计算天线方向图响应"""
        # 简化模型:假设干扰机天线有方向性
        # 实际应用中应根据天线方向图计算
        
        # 计算干扰机1的响应
        az1 = geometry['azimuth1']
        el1 = geometry['elevation1']
        
        # 波束指向误差
        beam_az, beam_el = self.state.beam_direction
        beam_az_rad = np.deg2rad(beam_az)
        beam_el_rad = np.deg2rad(beam_el)
        
        # 计算角度差
        az_error1 = az1 - beam_az_rad
        el_error1 = el1 - beam_el_rad
        
        # 计算天线增益
        beamwidth_rad = np.deg2rad(self.params.beamwidth)
        gain1 = self.params.antenna_gain * np.exp(
            -2.77 * (az_error1**2 + el_error1**2) / beamwidth_rad**2
        )
        
        # 计算干扰机2的响应
        az2 = geometry['azimuth2']
        el2 = geometry['elevation2']
        az_error2 = az2 - beam_az_rad
        el_error2 = el2 - beam_el_rad
        gain2 = self.params.antenna_gain * np.exp(
            -2.77 * (az_error2**2 + el_error2**2) / beamwidth_rad**2
        )
        
        # 转换为线性
        gain1_linear = 10**(gain1 / 10)
        gain2_linear = 10**(gain2 / 10)
        
        # 计算和差响应
        sum_response = gain1_linear + gain2_linear
        diff_response = gain1_linear - gain2_linear
        
        return {
            'sum': sum_response,
            'diff_az': diff_response * np.exp(1j * np.deg2rad(self.effective_phase_diff)),
            'diff_el': diff_response * np.exp(1j * np.deg2rad(self.effective_phase_diff))
        }
        
    def _calculate_cross_eye_effect(self, geometry: Dict[str, Any]) -> Dict[str, complex]:
        """计算交叉眼效应"""
        # 计算基线向量
        baseline = geometry['baseline_vector']
        baseline_length = geometry['baseline_length']
        
        # 计算波程差
        # 简化模型:假设目标在基线中垂线上
        wave_number = 2 * np.pi * self.params.jamming_frequency / 3e8
        path_difference = baseline_length * np.sin(geometry['azimuth1'])
        
        # 计算相位差
        phase_difference = wave_number * path_difference
        
        # 计算交叉眼增益
        cross_eye_gain = 2 * np.abs(np.sin(phase_difference / 2))
        
        # 计算和差通道的交叉眼效应
        sum_effect = cross_eye_gain
        diff_effect = cross_eye_gain * np.exp(1j * np.deg2rad(self.effective_phase_diff))
        
        return {
            'sum': sum_effect,
            'diff_az': diff_effect * self.effective_amplitude_ratio,
            'diff_el': diff_effect * self.effective_amplitude_ratio
        }
        
    def _calculate_jsr(self, jamming_signal: complex, target_state: TargetState) -> float:
        """计算干信比"""
        # 计算干扰功率
        jamming_power = np.abs(jamming_signal)**2
        
        # 估计信号功率
        # 简化模型:使用自由空间传播公式
        wavelength = 3e8 / self.params.jamming_frequency
        signal_power = (target_state.rcs * self.params.power * 
                       (wavelength**2) / 
                       ((4 * np.pi)**3 * target_state.range**4))
        
        if signal_power > 0:
            jsr_linear = jamming_power / signal_power
            return 10 * np.log10(jsr_linear)
        else:
            return 100.0  # 很大的值,表示完全被干扰
            
    def _calculate_angle_error_enhancement(self, sigma_j: complex, 
                                          delta_az_j: complex, 
                                          delta_el_j: complex) -> float:
        """计算角误差增强因子"""
        # 计算干扰引起的角误差
        error_az_j = np.abs(np.real(delta_az_j / sigma_j)) if np.abs(sigma_j) > 0 else 0
        error_el_j = np.abs(np.real(delta_el_j / sigma_j)) if np.abs(sigma_j) > 0 else 0
        
        # 计算增强因子
        enhancement = np.sqrt(error_az_j**2 + error_el_j**2)
        
        return enhancement
        
    def _record_history(self, time: float, sigma_j: complex, 
                       delta_az_j: complex, delta_el_j: complex):
        """记录历史数据"""
        record = {
            'time': time,
            'sigma_amplitude': np.abs(sigma_j),
            'sigma_phase': np.angle(sigma_j),
            'delta_az_amplitude': np.abs(delta_az_j),
            'delta_az_phase': np.angle(delta_az_j),
            'delta_el_amplitude': np.abs(delta_el_j),
            'delta_el_phase': np.angle(delta_el_j),
            'jsr': self.jamming_to_signal_ratio,
            'enhancement': self.angle_error_enhancement
        }
        self.jamming_history.append(record)
        
    def optimize_parameters(self, target_state: TargetState, 
                           seeker_state: Dict[str, Any]) -> Dict[str, float]:
        """优化干扰参数"""
        # 计算最优相位差
        optimal_phase = self._calculate_optimal_phase(target_state, seeker_state)
        
        # 计算最优幅度比
        optimal_amplitude = self._calculate_optimal_amplitude(target_state, seeker_state)
        
        # 更新参数
        self.effective_phase_diff = optimal_phase
        self.effective_amplitude_ratio = optimal_amplitude
        
        return {
            'optimal_phase': optimal_phase,
            'optimal_amplitude_ratio': optimal_amplitude
        }
        
    def _calculate_optimal_phase(self, target_state: TargetState, 
                                seeker_state: Dict[str, Any]) -> float:
        """计算最优相位差"""
        # 简化模型:根据几何关系计算最优相位
        geometry = self._calculate_geometry(target_state, seeker_state)
        
        # 计算基线角度
        baseline_az = np.arctan2(geometry['baseline_vector'][1], 
                               geometry['baseline_vector'][0])
        
        # 计算目标相对角度
        target_az = np.deg2rad(target_state.azimuth)
        
        # 计算最优相位
        optimal_phase = 180 * np.sin(target_az - baseline_az)
        
        return optimal_phase
        
    def _calculate_optimal_amplitude(self, target_state: TargetState, 
                                    seeker_state: Dict[str, Any]) -> float:
        """计算最优幅度比"""
        # 简化模型:根据距离比计算最优幅度
        geometry = self._calculate_geometry(target_state, seeker_state)
        
        # 计算距离比
        range_ratio = geometry['range1'] / geometry['range2']
        
        # 计算最优幅度比
        optimal_amplitude = 1 / range_ratio
        
        return min(optimal_amplitude, 0.9)  # 限制最大值
        
    def get_performance_metrics(self) -> Dict[str, Any]:
        """获取性能指标"""
        if not self.jamming_history:
            return {}
            
        jsr_values = [record['jsr'] for record in self.jamming_history]
        enhancement_values = [record['enhancement'] for record in self.jamming_history]
        
        metrics = {
            'mean_jsr': np.mean(jsr_values),
            'max_jsr': np.max(jsr_values),
            'mean_enhancement': np.mean(enhancement_values),
            'max_enhancement': np.max(enhancement_values),
            'jamming_efficiency': np.mean(enhancement_values) / np.mean(jsr_values) 
                                if np.mean(jsr_values) > 0 else 0,
            'jamming_history': self.jamming_history
        }
        
        return metrics
        
    def reset(self):
        """重置干扰机"""
        self.state = JammerState()
        self.effective_phase_diff = self.params.phase_difference
        self.effective_amplitude_ratio = 1.0 - self.params.amplitude_imbalance
        self.jamming_to_signal_ratio = 0.0
        self.angle_error_enhancement = 1.0
        self.tracking_error = 0.0
        self.jamming_history.clear()

# 测试函数
def test_cross_eye_jammer():
    """测试交叉眼干扰机"""
    import matplotlib.pyplot as plt
    
    # 创建干扰机实例
    jammer_params = JammerParameters()
    jammer = CrossEyeJammer(jammer_params)
    
    # 创建目标状态
    target = TargetState(
        range=10000,
        azimuth=1.0,
        elevation=0.5,
        range_rate=-100,
        azimuth_rate=0.1,
        elevation_rate=0.05,
        rcs=5.0,
        snr=20.0
    )
    
    # 创建导引头状态
    seeker_state = {
        'azimuth': 0.0,
        'elevation': 0.0,
        'tracking_lock': True
    }
    
    # 运行仿真
    n_steps = 200
    time_step = 0.01
    jsr_values = []
    enhancement_values = []
    
    for i in range(n_steps):
        time = i * time_step
        
        # 更新目标位置
        target.azimuth = 1.0 + 0.5 * np.sin(0.1 * i)
        
        # 更新导引头指向
        seeker_state['azimuth'] = target.azimuth + np.random.normal(0, 0.1)
        
        # 计算干扰信号
        sigma_j, delta_az_j, delta_el_j = jammer.calculate_jamming_signal(
            target, seeker_state, time
        )
        
        # 记录数据
        jsr_values.append(jammer.jamming_to_signal_ratio)
        enhancement_values.append(jammer.angle_error_enhancement)
        
    # 绘制结果
    fig, axes = plt.subplots(2, 2, figsize=(12, 8))
    
    # 干信比变化
    axes[0, 0].plot(jsr_values)
    axes[0, 0].set_xlabel('时间步')
    axes[0, 0].set_ylabel('干信比 (dB)')
    axes[0, 0].set_title('干信比变化曲线')
    axes[0, 0].grid(True)
    
    # 角误差增强因子
    axes[0, 1].plot(enhancement_values)
    axes[0, 1].set_xlabel('时间步')
    axes[0, 1].set_ylabel('角误差增强因子')
    axes[0, 1].set_title('角误差增强因子变化')
    axes[0, 1].grid(True)
    
    # 干扰信号幅度
    sigma_amps = [record['sigma_amplitude'] for record in jammer.jamming_history]
    axes[1, 0].plot(sigma_amps)
    axes[1, 0].set_xlabel('时间步')
    axes[1, 0].set_ylabel('干扰信号幅度')
    axes[1, 0].set_title('干扰信号幅度变化')
    axes[1, 0].grid(True)
    
    # 干扰信号相位
    sigma_phases = [record['sigma_phase'] for record in jammer.jamming_history]
    axes[1, 1].plot(sigma_phases)
    axes[1, 1].set_xlabel('时间步')
    axes[1, 1].set_ylabel('干扰信号相位 (rad)')
    axes[1, 1].set_title('干扰信号相位变化')
    axes[1, 1].grid(True)
    
    plt.tight_layout()
    plt.show()
    
    # 打印性能指标
    metrics = jammer.get_performance_metrics()
    print("干扰机性能指标:")
    for key, value in metrics.items():
        if not key.endswith('history'):
            print(f"  {key}: {value:.4f}")

if __name__ == "__main__":
    test_cross_eye_jammer()

5. 仿真系统UI设计

5.1 完整仿真系统UI实现

python 复制代码
"""
radar_simulation_ui.py

完整的雷达电子对抗仿真系统UI
"""
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import threading
import queue
import time
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
from typing import Dict, List, Any, Optional
import json

from monopulse_seeker_model import MonopulseSeekerModel, SeekerParameters, TargetState
from cross_eye_jamming import CrossEyeJammer, JammerParameters

class RadarSimulationUI:
    """雷达仿真系统主界面"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("雷达电子对抗仿真系统 - 单脉冲导引头交叉眼对抗")
        self.root.geometry("1400x900")
        
        # 初始化模型
        self.seeker = None
        self.jammer = None
        self.target = None
        
        # 仿真状态
        self.simulation_running = False
        self.simulation_paused = False
        self.simulation_time = 0.0
        self.simulation_step = 0
        
        # 数据队列
        self.data_queue = queue.Queue()
        self.command_queue = queue.Queue()
        
        # 性能数据
        self.performance_history = {
            'time': [],
            'az_error': [],
            'el_error': [],
            'jsr': [],
            'enhancement': [],
            'snr': [],
            'lock_status': []
        }
        
        # 构建UI
        self.setup_styles()
        self.create_menu()
        self.create_main_interface()
        
        # 初始化系统
        self.initialize_system()
        
    def setup_styles(self):
        """设置样式"""
        style = ttk.Style()
        style.theme_use('clam')
        
        # 自定义样式
        style.configure('Title.TLabel',
                       font=('微软雅黑', 20, 'bold'),
                       foreground='#2C3E50')
        
        style.configure('Subtitle.TLabel',
                       font=('微软雅黑', 12, 'bold'),
                       foreground='#34495E')
        
        style.configure('Status.TLabel',
                       font=('Consolas', 10),
                       background='#ECF0F1',
                       foreground='#2C3E50',
                       padding=3)
        
        style.configure('Warning.TLabel',
                       font=('Consolas', 10, 'bold'),
                       foreground='#E74C3C',
                       background='#FADBD8')
        
    def create_menu(self):
        """创建菜单栏"""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="新建仿真", command=self.new_simulation)
        file_menu.add_command(label="打开配置", command=self.load_config)
        file_menu.add_command(label="保存配置", command=self.save_config)
        file_menu.add_separator()
        file_menu.add_command(label="导出数据", command=self.export_data)
        file_menu.add_command(label="保存图像", command=self.save_plot)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        
        # 仿真菜单
        sim_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="仿真", menu=sim_menu)
        sim_menu.add_command(label="启动仿真", command=self.start_simulation)
        sim_menu.add_command(label="暂停仿真", command=self.pause_simulation)
        sim_menu.add_command(label="停止仿真", command=self.stop_simulation)
        sim_menu.add_separator()
        sim_menu.add_command(label="重置仿真", command=self.reset_simulation)
        
        # 视图菜单
        view_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="视图", menu=view_menu)
        
        # 主题子菜单
        theme_menu = tk.Menu(view_menu, tearoff=0)
        view_menu.add_cascade(label="主题", menu=theme_menu)
        theme_menu.add_command(label="浅色主题", command=lambda: self.set_theme('light'))
        theme_menu.add_command(label="深色主题", command=lambda: self.set_theme('dark'))
        
        # 帮助菜单
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="用户手册", command=self.show_help)
        help_menu.add_command(label="关于", command=self.show_about)
        
    def create_main_interface(self):
        """创建主界面"""
        # 主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 标题栏
        self.create_title_bar(main_container)
        
        # 主要内容区域
        content_frame = ttk.Frame(main_container)
        content_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 左侧控制面板
        left_panel = ttk.Frame(content_frame, width=300)
        left_panel.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 5))
        left_panel.pack_propagate(False)
        
        self.create_control_panel(left_panel)
        
        # 中央显示区域
        center_panel = ttk.Frame(content_frame)
        center_panel.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        self.create_display_panel(center_panel)
        
        # 右侧状态面板
        right_panel = ttk.Frame(content_frame, width=350)
        right_panel.pack(side=tk.RIGHT, fill=tk.Y, padx=(5, 0))
        right_panel.pack_propagate(False)
        
        self.create_status_panel(right_panel)
        
        # 底部状态栏
        self.create_status_bar(main_container)
        
    def create_title_bar(self, parent):
        """创建标题栏"""
        title_frame = ttk.Frame(parent)
        title_frame.pack(fill=tk.X, pady=(0, 10))
        
        title_label = ttk.Label(title_frame,
                               text="单脉冲导引头交叉眼对抗仿真系统",
                               style='Title.TLabel')
        title_label.pack(side=tk.LEFT)
        
        # 系统状态指示器
        self.system_status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(title_frame,
                                textvariable=self.system_status_var,
                                style='Status.TLabel')
        status_label.pack(side=tk.RIGHT, padx=10)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        # 使用Notebook组织控制选项
        control_notebook = ttk.Notebook(parent)
        control_notebook.pack(fill=tk.BOTH, expand=True)
        
        # 导引头参数标签页
        seeker_tab = ttk.Frame(control_notebook)
        self.create_seeker_controls(seeker_tab)
        control_notebook.add(seeker_tab, text="导引头参数")
        
        # 干扰机参数标签页
        jammer_tab = ttk.Frame(control_notebook)
        self.create_jammer_controls(jammer_tab)
        control_notebook.add(jammer_tab, text="干扰机参数")
        
        # 目标参数标签页
        target_tab = ttk.Frame(control_notebook)
        self.create_target_controls(target_tab)
        control_notebook.add(target_tab, text="目标参数")
        
        # 环境参数标签页
        env_tab = ttk.Frame(control_notebook)
        self.create_environment_controls(env_tab)
        control_notebook.add(env_tab, text="环境参数")
        
        # 仿真控制
        self.create_simulation_controls(parent)
        
    def create_seeker_controls(self, parent):
        """创建导引头参数控制"""
        # 滚动区域
        canvas = tk.Canvas(parent, highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 参数框架
        frame = ttk.LabelFrame(scrollable_frame, text="导引头参数", padding=10)
        frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        row = 0
        
        # 频率参数
        ttk.Label(frame, text="工作频率 (GHz):").grid(row=row, column=0, 
                                                     sticky=tk.W, pady=5)
        self.freq_var = tk.DoubleVar(value=10.0)
        ttk.Entry(frame, textvariable=self.freq_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 带宽
        ttk.Label(frame, text="带宽 (MHz):").grid(row=row, column=0, 
                                                 sticky=tk.W, pady=5)
        self.bw_var = tk.DoubleVar(value=1.0)
        ttk.Entry(frame, textvariable=self.bw_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 脉冲宽度
        ttk.Label(frame, text="脉冲宽度 (μs):").grid(row=row, column=0, 
                                                    sticky=tk.W, pady=5)
        self.pw_var = tk.DoubleVar(value=1.0)
        ttk.Entry(frame, textvariable=self.pw_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 波束宽度
        ttk.Label(frame, text="波束宽度 (°):").grid(row=row, column=0, 
                                                   sticky=tk.W, pady=5)
        self.beamwidth_var = tk.DoubleVar(value=3.0)
        ttk.Entry(frame, textvariable=self.beamwidth_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 跟踪带宽
        ttk.Label(frame, text="跟踪带宽 (Hz):").grid(row=row, column=0, 
                                                    sticky=tk.W, pady=5)
        self.tracking_bw_var = tk.DoubleVar(value=10.0)
        ttk.Entry(frame, textvariable=self.tracking_bw_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 通道不平衡
        ttk.Label(frame, text="通道不平衡:").grid(row=row, column=0, 
                                                sticky=tk.W, pady=5)
        self.imbalance_var = tk.DoubleVar(value=0.1)
        ttk.Entry(frame, textvariable=self.imbalance_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 校准误差
        ttk.Label(frame, text="校准误差:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.cal_error_var = tk.DoubleVar(value=0.05)
        ttk.Entry(frame, textvariable=self.cal_error_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 布局滚动区域
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_jammer_controls(self, parent):
        """创建干扰机参数控制"""
        canvas = tk.Canvas(parent, highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        frame = ttk.LabelFrame(scrollable_frame, text="干扰机参数", padding=10)
        frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        row = 0
        
        # 干扰机间距
        ttk.Label(frame, text="干扰机间距 (m):").grid(row=row, column=0, 
                                                     sticky=tk.W, pady=5)
        self.jammer_spacing_var = tk.DoubleVar(value=200.0)
        ttk.Entry(frame, textvariable=self.jammer_spacing_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 干扰功率
        ttk.Label(frame, text="干扰功率 (W):").grid(row=row, column=0, 
                                                   sticky=tk.W, pady=5)
        self.jammer_power_var = tk.DoubleVar(value=1000.0)
        ttk.Entry(frame, textvariable=self.jammer_power_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 相位差
        ttk.Label(frame, text="相位差 (°):").grid(row=row, column=0, 
                                                 sticky=tk.W, pady=5)
        self.phase_diff_var = tk.DoubleVar(value=180.0)
        ttk.Entry(frame, textvariable=self.phase_diff_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 幅度不平衡
        ttk.Label(frame, text="幅度不平衡:").grid(row=row, column=0, 
                                                sticky=tk.W, pady=5)
        self.amp_imbalance_var = tk.DoubleVar(value=0.1)
        ttk.Entry(frame, textvariable=self.amp_imbalance_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 调制类型
        ttk.Label(frame, text="调制类型:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.mod_type_var = tk.StringVar(value="cw")
        mod_combo = ttk.Combobox(frame, textvariable=self.mod_type_var,
                                values=["cw", "am", "fm", "pm"], width=13)
        mod_combo.grid(row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 调制深度
        ttk.Label(frame, text="调制深度:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.mod_depth_var = tk.DoubleVar(value=0.5)
        ttk.Entry(frame, textvariable=self.mod_depth_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 干扰开关
        ttk.Label(frame, text="干扰开关:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.jammer_enabled_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(frame, variable=self.jammer_enabled_var).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_target_controls(self, parent):
        """创建目标参数控制"""
        canvas = tk.Canvas(parent, highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        frame = ttk.LabelFrame(scrollable_frame, text="目标参数", padding=10)
        frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        row = 0
        
        # 初始距离
        ttk.Label(frame, text="初始距离 (km):").grid(row=row, column=0, 
                                                    sticky=tk.W, pady=5)
        self.target_range_var = tk.DoubleVar(value=10.0)
        ttk.Entry(frame, textvariable=self.target_range_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 初始方位角
        ttk.Label(frame, text="初始方位角 (°):").grid(row=row, column=0, 
                                                     sticky=tk.W, pady=5)
        self.target_az_var = tk.DoubleVar(value=1.0)
        ttk.Entry(frame, textvariable=self.target_az_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 初始俯仰角
        ttk.Label(frame, text="初始俯仰角 (°):").grid(row=row, column=0, 
                                                     sticky=tk.W, pady=5)
        self.target_el_var = tk.DoubleVar(value=0.5)
        ttk.Entry(frame, textvariable=self.target_el_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 目标RCS
        ttk.Label(frame, text="目标RCS (m²):").grid(row=row, column=0, 
                                                   sticky=tk.W, pady=5)
        self.target_rcs_var = tk.DoubleVar(value=5.0)
        ttk.Entry(frame, textvariable=self.target_rcs_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 目标速度
        ttk.Label(frame, text="目标速度 (m/s):").grid(row=row, column=0, 
                                                     sticky=tk.W, pady=5)
        self.target_speed_var = tk.DoubleVar(value=300.0)
        ttk.Entry(frame, textvariable=self.target_speed_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 机动模式
        ttk.Label(frame, text="机动模式:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.maneuver_mode_var = tk.StringVar(value="直线")
        maneuver_combo = ttk.Combobox(frame, textvariable=self.maneuver_mode_var,
                                     values=["直线", "蛇形", "圆周", "随机"], width=13)
        maneuver_combo.grid(row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 机动幅度
        ttk.Label(frame, text="机动幅度:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.maneuver_amp_var = tk.DoubleVar(value=0.5)
        ttk.Entry(frame, textvariable=self.maneuver_amp_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_environment_controls(self, parent):
        """创建环境参数控制"""
        canvas = tk.Canvas(parent, highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        frame = ttk.LabelFrame(scrollable_frame, text="环境参数", padding=10)
        frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        row = 0
        
        # 杂波强度
        ttk.Label(frame, text="杂波强度:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.clutter_var = tk.DoubleVar(value=0.5)
        ttk.Scale(frame, from_=0.0, to=1.0, variable=self.clutter_var,
                 orient=tk.HORIZONTAL, length=150).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 大气衰减
        ttk.Label(frame, text="大气衰减 (dB/km):").grid(row=row, column=0, 
                                                       sticky=tk.W, pady=5)
        self.atmosphere_var = tk.DoubleVar(value=0.2)
        ttk.Entry(frame, textvariable=self.atmosphere_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 天气条件
        ttk.Label(frame, text="天气条件:").grid(row=row, column=0, 
                                              sticky=tk.W, pady=5)
        self.weather_var = tk.StringVar(value="晴朗")
        weather_combo = ttk.Combobox(frame, textvariable=self.weather_var,
                                    values=["晴朗", "多云", "小雨", "大雨", "雾天"], width=13)
        weather_combo.grid(row=row, column=1, sticky=tk.W, pady=5)
        row += 1
        
        # 系统噪声
        ttk.Label(frame, text="系统噪声 (dB):").grid(row=row, column=0, 
                                                    sticky=tk.W, pady=5)
        self.noise_var = tk.DoubleVar(value=3.0)
        ttk.Entry(frame, textvariable=self.noise_var, width=15).grid(
            row=row, column=1, sticky=tk.W, pady=5)
        
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_simulation_controls(self, parent):
        """创建仿真控制"""
        control_frame = ttk.LabelFrame(parent, text="仿真控制", padding=10)
        control_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 仿真时间
        ttk.Label(control_frame, text="仿真时间 (s):").pack(anchor=tk.W, pady=2)
        self.sim_time_var = tk.DoubleVar(value=10.0)
        ttk.Entry(control_frame, textvariable=self.sim_time_var, width=15).pack(pady=2)
        
        # 更新速率
        ttk.Label(control_frame, text="更新速率 (Hz):").pack(anchor=tk.W, pady=2)
        self.update_rate_var = tk.DoubleVar(value=50.0)
        ttk.Entry(control_frame, textvariable=self.update_rate_var, width=15).pack(pady=2)
        
        # 控制按钮
        button_frame = ttk.Frame(control_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        ttk.Button(button_frame, text="启动仿真", 
                  command=self.start_simulation).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=2)
        ttk.Button(button_frame, text="暂停仿真", 
                  command=self.pause_simulation).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=2)
        ttk.Button(button_frame, text="停止仿真", 
                  command=self.stop_simulation).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=2)
        
        # 进度条
        self.progress_var = tk.DoubleVar(value=0.0)
        self.progress_bar = ttk.Progressbar(control_frame, 
                                           variable=self.progress_var,
                                           mode='determinate')
        self.progress_bar.pack(fill=tk.X, pady=10)
        
    def create_display_panel(self, parent):
        """创建显示面板"""
        # 使用Notebook组织显示
        display_notebook = ttk.Notebook(parent)
        display_notebook.pack(fill=tk.BOTH, expand=True)
        
        # 雷达显示标签页
        radar_tab = ttk.Frame(display_notebook)
        self.create_radar_display(radar_tab)
        display_notebook.add(radar_tab, text="雷达显示")
        
        # 信号分析标签页
        signal_tab = ttk.Frame(display_notebook)
        self.create_signal_display(signal_tab)
        display_notebook.add(signal_tab, text="信号分析")
        
        # 性能分析标签页
        performance_tab = ttk.Frame(display_notebook)
        self.create_performance_display(performance_tab)
        display_notebook.add(performance_tab, text="性能分析")
        
    def create_radar_display(self, parent):
        """创建雷达显示"""
        # 创建matplotlib图形
        self.radar_fig = Figure(figsize=(8, 6), dpi=100)
        self.radar_canvas = FigureCanvasTkAgg(self.radar_fig, parent)
        self.radar_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 创建子图
        self.ax_radar = self.radar_fig.add_subplot(111, projection='polar')
        self.ax_radar.set_theta_zero_location('N')
        self.ax_radar.set_theta_direction(-1)
        self.ax_radar.set_title("雷达显示")
        
        # 初始化显示
        self.update_radar_display()
        
    def create_signal_display(self, parent):
        """创建信号显示"""
        self.signal_fig = Figure(figsize=(8, 6), dpi=100)
        self.signal_canvas = FigureCanvasTkAgg(self.signal_fig, parent)
        self.signal_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 创建多个子图
        self.ax_signal = self.signal_fig.add_subplot(221)
        self.ax_spectrum = self.signal_fig.add_subplot(222)
        self.ax_error = self.signal_fig.add_subplot(223)
        self.ax_jsr = self.signal_fig.add_subplot(224)
        
        self.ax_signal.set_title("时域信号")
        self.ax_spectrum.set_title("频谱")
        self.ax_error.set_title("角误差")
        self.ax_jsr.set_title("干信比")
        
        self.signal_fig.tight_layout()
        
    def create_performance_display(self, parent):
        """创建性能显示"""
        self.perf_fig = Figure(figsize=(8, 6), dpi=100)
        self.perf_canvas = FigureCanvasTkAgg(self.perf_fig, parent)
        self.perf_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 创建性能指标子图
        self.ax_tracking = self.perf_fig.add_subplot(221)
        self.ax_jamming = self.perf_fig.add_subplot(222)
        self.ax_metrics = self.perf_fig.add_subplot(223)
        self.ax_analysis = self.perf_fig.add_subplot(224)
        
        self.ax_tracking.set_title("跟踪性能")
        self.ax_jamming.set_title("干扰效果")
        self.ax_metrics.set_title("性能指标")
        self.ax_analysis.set_title("综合分析")
        
        self.perf_fig.tight_layout()
        
    def create_status_panel(self, parent):
        """创建状态面板"""
        # 系统状态
        status_frame = ttk.LabelFrame(parent, text="系统状态", padding=10)
        status_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 状态变量
        self.status_vars = {
            'sim_time': tk.StringVar(value="0.0 s"),
            'target_range': tk.StringVar(value="0.0 km"),
            'target_az': tk.StringVar(value="0.0°"),
            'target_el': tk.StringVar(value="0.0°"),
            'seeker_az': tk.StringVar(value="0.0°"),
            'seeker_el': tk.StringVar(value="0.0°"),
            'az_error': tk.StringVar(value="0.0°"),
            'el_error': tk.StringVar(value="0.0°"),
            'snr': tk.StringVar(value="0.0 dB"),
            'jsr': tk.StringVar(value="0.0 dB"),
            'tracking_lock': tk.StringVar(value="否"),
            'jamming_effect': tk.StringVar(value="无")
        }
        
        # 创建状态显示
        row = 0
        for label, var in self.status_vars.items():
            ttk.Label(status_frame, text=f"{label.replace('_', ' ').title()}:").grid(
                row=row, column=0, sticky=tk.W, pady=2)
            ttk.Label(status_frame, textvariable=var, font=("Consolas", 9)).grid(
                row=row, column=1, sticky=tk.E, pady=2)
            row += 1
            
        # 报警指示
        alarm_frame = ttk.LabelFrame(parent, text="报警指示", padding=10)
        alarm_frame.pack(fill=tk.X, padx=5, pady=5)
        
        self.alarm_vars = {
            'tracking_lost': tk.BooleanVar(value=False),
            'low_snr': tk.BooleanVar(value=False),
            'high_jsr': tk.BooleanVar(value=False),
            'system_error': tk.BooleanVar(value=False)
        }
        
        for alarm, var in self.alarm_vars.items():
            frame = ttk.Frame(alarm_frame)
            frame.pack(fill=tk.X, pady=2)
            
            ttk.Label(frame, text=alarm.replace('_', ' ').title()).pack(side=tk.LEFT)
            canvas = tk.Canvas(frame, width=20, height=20, highlightthickness=0)
            canvas.pack(side=tk.RIGHT)
            canvas.create_oval(2, 2, 18, 18, fill="gray", tags="indicator")
            
            # 存储canvas引用
            setattr(self, f"{alarm}_indicator", canvas)
            
    def create_status_bar(self, parent):
        """创建状态栏"""
        status_bar = ttk.Frame(parent, relief=tk.SUNKEN, borderwidth=1)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 左侧状态
        self.status_text = tk.StringVar(value="就绪")
        ttk.Label(status_bar, textvariable=self.status_text).pack(side=tk.LEFT, padx=10)
        
        # 右侧信息
        import datetime
        time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ttk.Label(status_bar, text=f"系统时间: {time_str}").pack(side=tk.RIGHT, padx=10)
        
        # 内存使用
        import psutil
        memory = psutil.virtual_memory()
        memory_text = f"内存: {memory.percent}%"
        ttk.Label(status_bar, text=memory_text).pack(side=tk.RIGHT, padx=10)
        
    def initialize_system(self):
        """初始化系统"""
        # 初始化模型
        self.seeker = MonopulseSeekerModel()
        self.jammer = CrossEyeJammer()
        
        # 初始化目标
        self.target = TargetState(
            range=self.target_range_var.get() * 1000,
            azimuth=self.target_az_var.get(),
            elevation=self.target_el_var.get(),
            range_rate=-self.target_speed_var.get(),
            azimuth_rate=0.0,
            elevation_rate=0.0,
            rcs=self.target_rcs_var.get(),
            snr=20.0
        )
        
        self.system_status_var.set("系统就绪")
        
    def start_simulation(self):
        """启动仿真"""
        if self.simulation_running:
            return
            
        self.simulation_running = True
        self.simulation_paused = False
        self.simulation_time = 0.0
        self.simulation_step = 0
        
        # 重置性能历史
        for key in self.performance_history:
            self.performance_history[key].clear()
            
        # 启动仿真线程
        self.sim_thread = threading.Thread(target=self.run_simulation_loop, daemon=True)
        self.sim_thread.start()
        
        self.system_status_var.set("仿真运行中")
        
    def pause_simulation(self):
        """暂停仿真"""
        self.simulation_paused = not self.simulation_paused
        status = "仿真已暂停" if self.simulation_paused else "仿真运行中"
        self.system_status_var.set(status)
        
    def stop_simulation(self):
        """停止仿真"""
        self.simulation_running = False
        self.system_status_var.set("仿真已停止")
        
    def run_simulation_loop(self):
        """运行仿真循环"""
        total_time = self.sim_time_var.get()
        update_rate = self.update_rate_var.get()
        dt = 1.0 / update_rate
        
        while self.simulation_running and self.simulation_time < total_time:
            if self.simulation_paused:
                time.sleep(0.1)
                continue
                
            # 更新目标位置
            self.update_target_position()
            
            # 更新导引头状态
            seeker_state = self.seeker.get_current_state()
            
            # 计算干扰信号
            jamming_signal = self.jammer.calculate_jamming_signal(
                self.target, seeker_state, self.simulation_time
            ) if self.jammer_enabled_var.get() else None
            
            # 更新导引头跟踪
            az_error, el_error = self.seeker.update_target(self.target, jamming_signal)
            
            # 更新性能数据
            self.update_performance_data(seeker_state)
            
            # 更新UI
            self.update_ui()
            
            # 更新进度
            progress = self.simulation_time / total_time * 100
            self.progress_var.set(progress)
            

            # 更新时间
            self.simulation_time += dt
            self.simulation_step += 1
            
            # 控制更新速率
            time.sleep(dt)
            
        # 仿真结束
        self.simulation_running = False
        self.system_status_var.set("仿真完成")
        
        # 更新最终状态
        self.root.after(0, self.finalize_simulation)
        
    def update_target_position(self):
        """更新目标位置"""
        if not self.target:
            return
            
        # 根据机动模式更新目标位置
        mode = self.maneuver_mode_var.get()
        amplitude = self.maneuver_amp_var.get()
        t = self.simulation_time
        
        if mode == "直线":
            # 直线运动
            self.target.azimuth = self.target_az_var.get() + 0.1 * t
            self.target.elevation = self.target_el_var.get() + 0.05 * t
            
        elif mode == "蛇形":
            # 蛇形机动
            self.target.azimuth = self.target_az_var.get() + amplitude * np.sin(0.5 * t)
            self.target.elevation = self.target_el_var.get() + amplitude * np.cos(0.3 * t)
            
        elif mode == "圆周":
            # 圆周机动
            radius = amplitude
            angular_speed = 0.2
            self.target.azimuth = self.target_az_var.get() + radius * np.cos(angular_speed * t)
            self.target.elevation = self.target_el_var.get() + radius * np.sin(angular_speed * t)
            
        elif mode == "随机":
            # 随机机动
            if self.simulation_step % 10 == 0:  # 每10步改变一次
                self.target.azimuth += np.random.uniform(-0.2, 0.2)
                self.target.elevation += np.random.uniform(-0.1, 0.1)
                
        # 更新距离
        self.target.range += self.target.range_rate * (1.0 / self.update_rate_var.get())
        
    def update_performance_data(self, seeker_state: Dict[str, Any]):
        """更新性能数据"""
        # 获取导引头性能指标
        seeker_metrics = self.seeker.get_performance_metrics()
        jammer_metrics = self.jammer.get_performance_metrics() if self.jammer else {}
        
        # 记录数据
        self.performance_history['time'].append(self.simulation_time)
        self.performance_history['az_error'].append(seeker_state.get('angle_error_azimuth', 0))
        self.performance_history['el_error'].append(seeker_state.get('angle_error_elevation', 0))
        self.performance_history['snr'].append(seeker_state.get('snr', 0))
        
        if jammer_metrics and 'mean_jsr' in jammer_metrics:
            self.performance_history['jsr'].append(jammer_metrics['mean_jsr'])
        else:
            self.performance_history['jsr'].append(0.0)
            
        if jammer_metrics and 'mean_enhancement' in jammer_metrics:
            self.performance_history['enhancement'].append(jammer_metrics['mean_enhancement'])
        else:
            self.performance_history['enhancement'].append(1.0)
            
        self.performance_history['lock_status'].append(1 if seeker_state.get('tracking_lock', False) else 0)
        
    def update_ui(self):
        """更新UI显示"""
        # 获取当前状态
        seeker_state = self.seeker.get_current_state()
        jammer_state = self.jammer.get_performance_metrics() if self.jammer else {}
        
        # 更新状态变量
        self.status_vars['sim_time'].set(f"{self.simulation_time:.2f} s")
        self.status_vars['target_range'].set(f"{self.target.range/1000:.2f} km")
        self.status_vars['target_az'].set(f"{self.target.azimuth:.2f}°")
        self.status_vars['target_el'].set(f"{self.target.elevation:.2f}°")
        self.status_vars['seeker_az'].set(f"{seeker_state.get('azimuth', 0):.2f}°")
        self.status_vars['seeker_el'].set(f"{seeker_state.get('elevation', 0):.2f}°")
        self.status_vars['az_error'].set(f"{seeker_state.get('angle_error_azimuth', 0):.3f}°")
        self.status_vars['el_error'].set(f"{seeker_state.get('angle_error_elevation', 0):.3f}°")
        self.status_vars['snr'].set(f"{seeker_state.get('snr', 0):.1f} dB")
        
        if jammer_state and 'mean_jsr' in jammer_state:
            self.status_vars['jsr'].set(f"{jammer_state['mean_jsr']:.1f} dB")
        else:
            self.status_vars['jsr'].set("0.0 dB")
            
        self.status_vars['tracking_lock'].set("是" if seeker_state.get('tracking_lock', False) else "否")
        
        # 计算干扰效果
        if jammer_state and 'mean_enhancement' in jammer_state:
            enhancement = jammer_state['mean_enhancement']
            if enhancement > 5:
                effect = "强"
            elif enhancement > 2:
                effect = "中"
            else:
                effect = "弱"
            self.status_vars['jamming_effect'].set(effect)
        else:
            self.status_vars['jamming_effect'].set("无")
            
        # 更新报警指示
        self.update_alarm_indicators(seeker_state, jammer_state)
        
        # 更新图形显示
        self.update_plots()
        
    def update_alarm_indicators(self, seeker_state: Dict[str, Any], jammer_state: Dict[str, Any]):
        """更新报警指示器"""
        # 跟踪丢失报警
        tracking_lost = not seeker_state.get('tracking_lock', False)
        self.alarm_vars['tracking_lost'].set(tracking_lost)
        
        # 低信噪比报警
        low_snr = seeker_state.get('snr', 0) < 10
        self.alarm_vars['low_snr'].set(low_snr)
        
        # 高干信比报警
        if jammer_state and 'mean_jsr' in jammer_state:
            high_jsr = jammer_state['mean_jsr'] > 20
        else:
            high_jsr = False
        self.alarm_vars['high_jsr'].set(high_jsr)
        
        # 系统错误报警(暂时不实现)
        
        # 更新指示器颜色
        for alarm, var in self.alarm_vars.items():
            canvas = getattr(self, f"{alarm}_indicator", None)
            if canvas:
                color = "red" if var.get() else "green"
                canvas.itemconfig("indicator", fill=color)
                
    def update_plots(self):
        """更新图形显示"""
        if not self.performance_history['time']:
            return
            
        # 更新雷达显示
        self.update_radar_display()
        
        # 更新信号显示
        self.update_signal_display()
        
        # 更新性能显示
        self.update_performance_display()
        
    def update_radar_display(self):
        """更新雷达显示"""
        self.ax_radar.clear()
        
        # 设置极坐标
        self.ax_radar.set_theta_zero_location('N')
        self.ax_radar.set_theta_direction(-1)
        self.ax_radar.set_title("雷达显示")
        
        # 获取当前目标位置
        target_az = np.deg2rad(self.target.azimuth)
        target_el = self.target.elevation
        
        # 获取导引头指向
        seeker_state = self.seeker.get_current_state()
        seeker_az = np.deg2rad(seeker_state.get('azimuth', 0))
        seeker_el = seeker_state.get('elevation', 0)
        
        # 绘制扫描线
        scan_angle = np.deg2rad(seeker_az * 180 / np.pi)  # 简化扫描角度
        ranges = np.linspace(0, 1, 10)
        
        # 绘制扫描线
        self.ax_radar.plot([scan_angle, scan_angle], [0, 1], 'r-', alpha=0.5, linewidth=2)
        
        # 绘制目标
        self.ax_radar.scatter([target_az], [target_el/90], c='red', s=100, 
                             label='目标', edgecolors='black')
        
        # 绘制导引头指向
        self.ax_radar.scatter([seeker_az], [seeker_el/90], c='blue', s=80, 
                             marker='^', label='导引头', edgecolors='black')
        
        # 绘制距离环
        for r in [0.2, 0.4, 0.6, 0.8, 1.0]:
            theta = np.linspace(0, 2*np.pi, 100)
            self.ax_radar.plot(theta, [r]*100, 'gray', alpha=0.3, linewidth=0.5)
            
        # 设置范围
        self.ax_radar.set_ylim(0, 1)
        self.ax_radar.set_yticklabels([])
        self.ax_radar.legend(loc='upper right')
        
        # 添加距离标签
        max_range = self.target_range_var.get()
        for i, r in enumerate([0.2, 0.4, 0.6, 0.8, 1.0]):
            label_range = r * max_range
            self.ax_radar.text(0, r, f'{label_range:.0f}km', 
                              horizontalalignment='center',
                              verticalalignment='bottom',
                              fontsize=8)
        
        self.radar_canvas.draw_idle()
        
    def update_signal_display(self):
        """更新信号显示"""
        if len(self.performance_history['time']) < 2:
            return
            
        # 时域信号
        self.ax_signal.clear()
        time_data = self.performance_history['time'][-100:]  # 最后100个点
        az_error = self.performance_history['az_error'][-100:]
        el_error = self.performance_history['el_error'][-100:]
        
        self.ax_signal.plot(time_data, az_error, 'b-', label='方位误差')
        self.ax_signal.plot(time_data, el_error, 'r-', label='俯仰误差')
        self.ax_signal.set_xlabel('时间 (s)')
        self.ax_signal.set_ylabel('角误差 (°)')
        self.ax_signal.set_title('时域角误差')
        self.ax_signal.legend()
        self.ax_signal.grid(True, alpha=0.3)
        
        # 频谱
        self.ax_spectrum.clear()
        if len(az_error) > 10:
            # 计算FFT
            n = len(az_error)
            yf = np.fft.fft(az_error)
            xf = np.fft.fftfreq(n, 1/self.update_rate_var.get())
            
            # 只取正频率
            idx = np.where(xf >= 0)
            self.ax_spectrum.plot(xf[idx], np.abs(yf[idx])/n, 'b-')
            self.ax_spectrum.set_xlabel('频率 (Hz)')
            self.ax_spectrum.set_ylabel('幅度')
            self.ax_spectrum.set_title('角误差频谱')
            self.ax_spectrum.grid(True, alpha=0.3)
            
        # 角误差统计
        self.ax_error.clear()
        if len(az_error) > 0:
            errors = [az_error, el_error]
            positions = [1, 2]
            bp = self.ax_error.boxplot(errors, positions=positions, widths=0.6)
            self.ax_error.set_xticks([1, 2])
            self.ax_error.set_xticklabels(['方位', '俯仰'])
            self.ax_error.set_ylabel('角误差 (°)')
            self.ax_error.set_title('角误差统计')
            self.ax_error.grid(True, alpha=0.3)
            
        # 干信比
        self.ax_jsr.clear()
        if len(self.performance_history['jsr']) > 0:
            jsr_data = self.performance_history['jsr'][-100:]
            time_data = self.performance_history['time'][-100:]
            
            self.ax_jsr.plot(time_data, jsr_data, 'g-')
            self.ax_jsr.axhline(y=20, color='r', linestyle='--', alpha=0.5, label='干扰阈值')
            self.ax_jsr.set_xlabel('时间 (s)')
            self.ax_jsr.set_ylabel('干信比 (dB)')
            self.ax_jsr.set_title('干信比变化')
            self.ax_jsr.legend()
            self.ax_jsr.grid(True, alpha=0.3)
            
        self.signal_canvas.draw_idle()
        
    def update_performance_display(self):
        """更新性能显示"""
        if len(self.performance_history['time']) < 2:
            return
            
        # 跟踪性能
        self.ax_tracking.clear()
        time_data = self.performance_history['time'][-100:]
        lock_data = self.performance_history['lock_status'][-100:]
        snr_data = self.performance_history['snr'][-100:]
        
        # 绘制锁定状态
        ax2 = self.ax_tracking.twinx()
        
        # 锁定状态面积图
        self.ax_tracking.fill_between(time_data, 0, lock_data, 
                                     alpha=0.3, color='blue', label='锁定状态')
        self.ax_tracking.set_ylabel('锁定状态', color='blue')
        self.ax_tracking.tick_params(axis='y', labelcolor='blue')
        self.ax_tracking.set_ylim(-0.1, 1.1)
        
        # 信噪比曲线
        ax2.plot(time_data, snr_data, 'r-', label='信噪比')
        ax2.set_ylabel('信噪比 (dB)', color='red')
        ax2.tick_params(axis='y', labelcolor='red')
        ax2.axhline(y=10, color='orange', linestyle='--', alpha=0.5, label='锁定阈值')
        
        self.ax_tracking.set_xlabel('时间 (s)')
        self.ax_tracking.set_title('跟踪性能')
        
        # 合并图例
        lines1, labels1 = self.ax_tracking.get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        self.ax_tracking.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
        
        # 干扰效果
        self.ax_jamming.clear()
        if len(self.performance_history['enhancement']) > 0:
            enhancement_data = self.performance_history['enhancement'][-100:]
            time_data = self.performance_history['time'][-100:]
            
            self.ax_jamming.plot(time_data, enhancement_data, 'purple')
            self.ax_jamming.axhline(y=2, color='orange', linestyle='--', alpha=0.5, label='有效阈值')
            self.ax_jamming.axhline(y=5, color='red', linestyle='--', alpha=0.5, label='强干扰')
            self.ax_jamming.set_xlabel('时间 (s)')
            self.ax_jamming.set_ylabel('角误差增强因子')
            self.ax_jamming.set_title('干扰效果')
            self.ax_jamming.legend()
            self.ax_jamming.grid(True, alpha=0.3)
            
        # 性能指标
        self.ax_metrics.clear()
        if len(self.performance_history['az_error']) > 0:
            # 计算统计指标
            az_errors = self.performance_history['az_error'][-100:]
            el_errors = self.performance_history['el_error'][-100:]
            
            metrics = {
                'RMS方位误差': np.sqrt(np.mean(np.array(az_errors)**2)),
                'RMS俯仰误差': np.sqrt(np.mean(np.array(el_errors)**2)),
                '最大方位误差': np.max(np.abs(az_errors)),
                '最大俯仰误差': np.max(np.abs(el_errors)),
                '平均信噪比': np.mean(self.performance_history['snr'][-100:]),
                '平均干信比': np.mean(self.performance_history['jsr'][-100:]) if self.performance_history['jsr'] else 0
            }
            
            # 创建条形图
            names = list(metrics.keys())
            values = list(metrics.values())
            
            bars = self.ax_metrics.bar(names, values, color=['blue', 'red', 'green', 'orange', 'purple', 'brown'])
            self.ax_metrics.set_ylabel('数值')
            self.ax_metrics.set_title('性能指标')
            
            # 添加数值标签
            for bar, value in zip(bars, values):
                height = bar.get_height()
                self.ax_metrics.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                                    f'{value:.3f}', ha='center', va='bottom', fontsize=8)
            
            self.ax_metrics.set_xticklabels(names, rotation=45, ha='right')
            
        # 综合分析
        self.ax_analysis.clear()
        if len(self.performance_history['az_error']) > 0 and len(self.performance_history['el_error']) > 0:
            # 绘制误差散布图
            az_errors = self.performance_history['az_error'][-100:]
            el_errors = self.performance_history['el_error'][-100:]
            
            # 计算误差椭圆
            if len(az_errors) > 2:
                from matplotlib.patches import Ellipse
                import matplotlib.transforms as transforms
                
                # 计算协方差矩阵
                cov = np.cov(az_errors, el_errors)
                
                # 计算特征值和特征向量
                eigvals, eigvecs = np.linalg.eigh(cov)
                
                # 计算椭圆参数
                order = eigvals.argsort()[::-1]
                eigvals, eigvecs = eigvals[order], eigvecs[:, order]
                
                # 椭圆角度
                vx, vy = eigvecs[:,0][0], eigvecs[:,0][1]
                theta = np.arctan2(vy, vx)
                
                # 绘制散布点
                self.ax_analysis.scatter(az_errors, el_errors, alpha=0.5, s=20)
                
                # 绘制误差椭圆
                for n_std in [1, 2, 3]:
                    width = 2 * n_std * np.sqrt(eigvals[0])
                    height = 2 * n_std * np.sqrt(eigvals[1])
                    ellipse = Ellipse(xy=(np.mean(az_errors), np.mean(el_errors)),
                                     width=width, height=height,
                                     angle=np.degrees(theta),
                                     alpha=0.2/n_std, color='red')
                    self.ax_analysis.add_patch(ellipse)
                    
            self.ax_analysis.set_xlabel('方位误差 (°)')
            self.ax_analysis.set_ylabel('俯仰误差 (°)')
            self.ax_analysis.set_title('误差散布分析')
            self.ax_analysis.grid(True, alpha=0.3)
            
        self.perf_canvas.draw_idle()
        
    def finalize_simulation(self):
        """完成仿真后的处理"""
        # 更新进度条
        self.progress_var.set(100.0)
        
        # 计算最终性能指标
        seeker_metrics = self.seeker.get_performance_metrics()
        jammer_metrics = self.jammer.get_performance_metrics() if self.jammer else {}
        
        # 显示性能报告
        report = "仿真完成!\n\n"
        report += "性能指标:\n"
        
        if seeker_metrics:
            report += f"RMS方位误差: {seeker_metrics.get('rms_azimuth_error', 0):.3f}°\n"
            report += f"RMS俯仰误差: {seeker_metrics.get('rms_elevation_error', 0):.3f}°\n"
            report += f"最大方位误差: {seeker_metrics.get('max_azimuth_error', 0):.3f}°\n"
            report += f"最大俯仰误差: {seeker_metrics.get('max_elevation_error', 0):.3f}°\n"
            report += f"平均信噪比: {seeker_metrics.get('mean_snr', 0):.1f} dB\n"
            report += f"跟踪锁定比例: {seeker_metrics.get('tracking_lock_ratio', 0)*100:.1f}%\n"
            
        if jammer_metrics:
            report += f"平均干信比: {jammer_metrics.get('mean_jsr', 0):.1f} dB\n"
            report += f"平均角误差增强: {jammer_metrics.get('mean_enhancement', 0):.2f}x\n"
            report += f"干扰效率: {jammer_metrics.get('jamming_efficiency', 0):.3f}\n"
            
        # 显示报告
        messagebox.showinfo("仿真完成", report)
        
    def reset_simulation(self):
        """重置仿真"""
        self.stop_simulation()
        
        # 重置模型
        if self.seeker:
            self.seeker.reset()
        if self.jammer:
            self.jammer.reset()
            
        # 重置目标
        self.target = TargetState(
            range=self.target_range_var.get() * 1000,
            azimuth=self.target_az_var.get(),
            elevation=self.target_el_var.get(),
            range_rate=-self.target_speed_var.get(),
            azimuth_rate=0.0,
            elevation_rate=0.0,
            rcs=self.target_rcs_var.get(),
            snr=20.0
        )
        
        # 重置性能历史
        for key in self.performance_history:
            self.performance_history[key].clear()
            
        # 重置UI
        self.progress_var.set(0.0)
        self.system_status_var.set("就绪")
        
        # 更新状态显示
        for var in self.status_vars.values():
            var.set("0.0")
            
        # 重置图形
        self.update_radar_display()
        self.update_signal_display()
        self.update_performance_display()
        
    def new_simulation(self):
        """新建仿真"""
        if self.simulation_running:
            response = messagebox.askyesno("确认", "仿真正在运行,是否停止并新建?")
            if not response:
                return
                
        self.reset_simulation()
        
    def load_config(self):
        """加载配置"""
        filename = filedialog.askopenfilename(
            title="选择配置文件",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                config = json.load(f)
                
            # 加载导引头参数
            if 'seeker' in config:
                self.freq_var.set(config['seeker'].get('frequency', 10.0))
                self.bw_var.set(config['seeker'].get('bandwidth', 1.0))
                self.pw_var.set(config['seeker'].get('pulse_width', 1.0))
                self.beamwidth_var.set(config['seeker'].get('beamwidth', 3.0))
                self.tracking_bw_var.set(config['seeker'].get('tracking_bandwidth', 10.0))
                self.imbalance_var.set(config['seeker'].get('imbalance', 0.1))
                self.cal_error_var.set(config['seeker'].get('calibration_error', 0.05))
                
            # 加载干扰机参数
            if 'jammer' in config:
                self.jammer_spacing_var.set(config['jammer'].get('spacing', 200.0))
                self.jammer_power_var.set(config['jammer'].get('power', 1000.0))
                self.phase_diff_var.set(config['jammer'].get('phase_difference', 180.0))
                self.amp_imbalance_var.set(config['jammer'].get('amplitude_imbalance', 0.1))
                self.mod_type_var.set(config['jammer'].get('modulation_type', 'cw'))
                self.mod_depth_var.set(config['jammer'].get('modulation_depth', 0.5))
                self.jammer_enabled_var.set(config['jammer'].get('enabled', True))
                
            # 加载目标参数
            if 'target' in config:
                self.target_range_var.set(config['target'].get('range', 10.0))
                self.target_az_var.set(config['target'].get('azimuth', 1.0))
                self.target_el_var.set(config['target'].get('elevation', 0.5))
                self.target_rcs_var.set(config['target'].get('rcs', 5.0))
                self.target_speed_var.set(config['target'].get('speed', 300.0))
                self.maneuver_mode_var.set(config['target'].get('maneuver_mode', '直线'))
                self.maneuver_amp_var.set(config['target'].get('maneuver_amplitude', 0.5))
                
            # 加载环境参数
            if 'environment' in config:
                self.clutter_var.set(config['environment'].get('clutter', 0.5))
                self.atmosphere_var.set(config['environment'].get('atmosphere', 0.2))
                self.weather_var.set(config['environment'].get('weather', '晴朗'))
                self.noise_var.set(config['environment'].get('noise', 3.0))
                
            # 加载仿真参数
            if 'simulation' in config:
                self.sim_time_var.set(config['simulation'].get('time', 10.0))
                self.update_rate_var.set(config['simulation'].get('update_rate', 50.0))
                
            messagebox.showinfo("成功", "配置加载成功!")
            
        except Exception as e:
            messagebox.showerror("错误", f"加载配置失败:{str(e)}")
            
    def save_config(self):
        """保存配置"""
        config = {
            'seeker': {
                'frequency': self.freq_var.get(),
                'bandwidth': self.bw_var.get(),
                'pulse_width': self.pw_var.get(),
                'beamwidth': self.beamwidth_var.get(),
                'tracking_bandwidth': self.tracking_bw_var.get(),
                'imbalance': self.imbalance_var.get(),
                'calibration_error': self.cal_error_var.get()
            },
            'jammer': {
                'spacing': self.jammer_spacing_var.get(),
                'power': self.jammer_power_var.get(),
                'phase_difference': self.phase_diff_var.get(),
                'amplitude_imbalance': self.amp_imbalance_var.get(),
                'modulation_type': self.mod_type_var.get(),
                'modulation_depth': self.mod_depth_var.get(),
                'enabled': self.jammer_enabled_var.get()
            },
            'target': {
                'range': self.target_range_var.get(),
                'azimuth': self.target_az_var.get(),
                'elevation': self.target_el_var.get(),
                'rcs': self.target_rcs_var.get(),
                'speed': self.target_speed_var.get(),
                'maneuver_mode': self.maneuver_mode_var.get(),
                'maneuver_amplitude': self.maneuver_amp_var.get()
            },
            'environment': {
                'clutter': self.clutter_var.get(),
                'atmosphere': self.atmosphere_var.get(),
                'weather': self.weather_var.get(),
                'noise': self.noise_var.get()
            },
            'simulation': {
                'time': self.sim_time_var.get(),
                'update_rate': self.update_rate_var.get()
            }
        }
        
        filename = filedialog.asksaveasfilename(
            title="保存配置文件",
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
                
            messagebox.showinfo("成功", "配置保存成功!")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败:{str(e)}")
            
    def export_data(self):
        """导出数据"""
        if not self.performance_history['time']:
            messagebox.showwarning("警告", "没有数据可导出!")
            return
            
        data = {
            'performance': self.performance_history,
            'seeker_metrics': self.seeker.get_performance_metrics() if self.seeker else {},
            'jammer_metrics': self.jammer.get_performance_metrics() if self.jammer else {},
            'timestamp': datetime.now().isoformat(),
            'parameters': {
                'seeker': {
                    'frequency': self.freq_var.get(),
                    'bandwidth': self.bw_var.get(),
                    'pulse_width': self.pw_var.get(),
                    'beamwidth': self.beamwidth_var.get()
                },
                'jammer': {
                    'spacing': self.jammer_spacing_var.get(),
                    'power': self.jammer_power_var.get(),
                    'phase_difference': self.phase_diff_var.get()
                }
            }
        }
        
        filename = filedialog.asksaveasfilename(
            title="导出数据",
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("CSV文件", "*.csv"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            if filename.endswith('.csv'):
                # 导出为CSV
                import pandas as pd
                df = pd.DataFrame(data['performance'])
                df.to_csv(filename, index=False, encoding='utf-8-sig')
            else:
                # 导出为JSON
                with open(filename, 'w', encoding='utf-8') as f:
                    json.dump(data, f, indent=2, ensure_ascii=False)
                    
            messagebox.showinfo("成功", "数据导出成功!")
            
        except Exception as e:
            messagebox.showerror("错误", f"导出数据失败:{str(e)}")
            
    def save_plot(self):
        """保存图像"""
        if not hasattr(self, 'radar_fig'):
            messagebox.showwarning("警告", "没有图像可保存!")
            return
            
        filename = filedialog.asksaveasfilename(
            title="保存图像",
            defaultextension=".png",
            filetypes=[("PNG图像", "*.png"), ("PDF文档", "*.pdf"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            # 保存当前激活的图形
            if hasattr(self, 'current_figure'):
                self.current_figure.savefig(filename, dpi=300, bbox_inches='tight')
            else:
                self.radar_fig.savefig(filename, dpi=300, bbox_inches='tight')
                
            messagebox.showinfo("成功", "图像保存成功!")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存图像失败:{str(e)}")
            
    def set_theme(self, theme_name: str):
        """设置主题"""
        if theme_name == 'light':
            # 浅色主题
            plt.style.use('default')
        elif theme_name == 'dark':
            # 深色主题
            plt.style.use('dark_background')
            
        # 更新图形
        self.update_plots()
        
    def show_help(self):
        """显示帮助"""
        help_text = """雷达电子对抗仿真系统 - 使用说明

1. 参数设置:
   - 在左侧面板设置导引头、干扰机、目标和环境参数
   - 可以加载/保存配置文件

2. 仿真控制:
   - 设置仿真时间和更新速率
   - 点击"启动仿真"开始运行
   - 可随时暂停或停止仿真

3. 结果显示:
   - 雷达显示:实时显示目标位置和导引头指向
   - 信号分析:显示角误差、频谱、干信比等信息
   - 性能分析:显示跟踪性能、干扰效果等指标

4. 数据操作:
   - 可导出仿真数据为JSON或CSV格式
   - 可保存当前图形为图片或PDF
   
5. 快捷键:
   - F1: 显示帮助
   - Ctrl+S: 保存配置
   - Ctrl+O: 加载配置
   - Space: 暂停/继续仿真
   - Esc: 停止仿真
        """
        
        messagebox.showinfo("帮助", help_text)
        
    def show_about(self):
        """显示关于信息"""
        about_text = """雷达电子对抗仿真系统
版本: 2.0.0
        
功能:
- 单脉冲导引头跟踪仿真
- 交叉眼干扰效果模拟
- 实时数据可视化
- 性能分析评估
        
技术:
- 基于Python tkinter/ttk
- 使用matplotlib进行科学绘图
- MVC架构设计
- 多线程实时仿真
        
作者: Python GUI研究团队
日期: 2024年
        """
        
        messagebox.showinfo("关于", about_text)

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    
    # 设置窗口图标
    try:
        root.iconbitmap("radar_icon.ico")
    except:
        pass
    
    app = RadarSimulationUI(root)
    
    # 窗口居中
    root.update_idletasks()
    width = root.winfo_width()
    height = root.winfo_height()
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    root.geometry(f'{width}x{height}+{x}+{y}')
    
    # 绑定快捷键
    root.bind('<F1>', lambda e: app.show_help())
    root.bind('<Control-s>', lambda e: app.save_config())
    root.bind('<Control-o>', lambda e: app.load_config())
    root.bind('<space>', lambda e: app.pause_simulation())
    root.bind('<Escape>', lambda e: app.stop_simulation())
    
    # 启动主循环
    root.mainloop()

6. 实时数据可视化

6.1 多视图协同显示系统

python 复制代码
"""
multi_view_system.py

多视图协同显示系统
"""
import tkinter as tk
from tkinter import ttk
import threading
import queue
import numpy as np
from datetime import datetime
from typing import Dict, List, Any, Optional
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
from matplotlib.gridspec import GridSpec
import matplotlib.animation as animation

class MultiViewSystem:
    """多视图协同显示系统"""
    
    def __init__(self, parent):
        self.parent = parent
        
        # 数据缓冲区
        self.data_buffer_size = 1000
        self.radar_data = []
        self.signal_data = []
        self.performance_data = []
        
        # 视图状态
        self.views = {}
        self.view_layout = 'grid'
        
        # 创建UI
        self.create_ui()
        
    def create_ui(self):
        """创建UI界面"""
        # 主容器
        self.main_frame = ttk.Frame(self.parent)
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 工具栏
        self.create_toolbar()
        
        # 视图容器
        self.view_container = ttk.Frame(self.main_frame)
        self.view_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 初始视图布局
        self.set_view_layout('grid')
        
    def create_toolbar(self):
        """创建工具栏"""
        toolbar_frame = ttk.Frame(self.main_frame)
        toolbar_frame.pack(fill=tk.X, padx=5, pady=2)
        
        # 布局选择
        ttk.Label(toolbar_frame, text="视图布局:").pack(side=tk.LEFT, padx=5)
        
        self.layout_var = tk.StringVar(value='grid')
        layouts = ['grid', 'vertical', 'horizontal', 'custom']
        
        for layout in layouts:
            rb = ttk.Radiobutton(toolbar_frame, text=layout, 
                               variable=self.layout_var, 
                               value=layout,
                               command=lambda l=layout: self.set_view_layout(l))
            rb.pack(side=tk.LEFT, padx=2)
            
        # 视图控制
        ttk.Button(toolbar_frame, text="重置视图", 
                  command=self.reset_views).pack(side=tk.LEFT, padx=5)
        
        ttk.Button(toolbar_frame, text="保存布局", 
                  command=self.save_layout).pack(side=tk.LEFT, padx=5)
                  
        # 自动刷新
        self.auto_refresh_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(toolbar_frame, text="自动刷新", 
                       variable=self.auto_refresh_var).pack(side=tk.LEFT, padx=5)
        
    def set_view_layout(self, layout: str):
        """设置视图布局"""
        self.view_layout = layout
        
        # 清除现有视图
        for widget in self.view_container.winfo_children():
            widget.destroy()
            
        # 创建新布局
        if layout == 'grid':
            self.create_grid_layout()
        elif layout == 'vertical':
            self.create_vertical_layout()
        elif layout == 'horizontal':
            self.create_horizontal_layout()
        elif layout == 'custom':
            self.create_custom_layout()
            
    def create_grid_layout(self):
        """创建网格布局"""
        # 2x2网格
        for i in range(2):
            self.view_container.rowconfigure(i, weight=1)
            for j in range(2):
                self.view_container.columnconfigure(j, weight=1)
                
        # 创建视图
        view_types = ['radar', 'signal', 'spectrum', 'performance']
        
        for idx, view_type in enumerate(view_types):
            row = idx // 2
            col = idx % 2
            
            view_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
            view_frame.grid(row=row, column=col, sticky='nsew', padx=2, pady=2)
            
            self.create_view(view_frame, view_type, idx)
            
    def create_vertical_layout(self):
        """创建垂直布局"""
        for i in range(4):
            self.view_container.rowconfigure(i, weight=1)
        self.view_container.columnconfigure(0, weight=1)
        
        view_types = ['radar', 'signal', 'spectrum', 'performance']
        
        for i, view_type in enumerate(view_types):
            view_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
            view_frame.grid(row=i, column=0, sticky='nsew', padx=2, pady=2)
            
            self.create_view(view_frame, view_type, i)
            
    def create_horizontal_layout(self):
        """创建水平布局"""
        for i in range(4):
            self.view_container.columnconfigure(i, weight=1)
        self.view_container.rowconfigure(0, weight=1)
        
        view_types = ['radar', 'signal', 'spectrum', 'performance']
        
        for i, view_type in enumerate(view_types):
            view_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
            view_frame.grid(row=0, column=i, sticky='nsew', padx=2, pady=2)
            
            self.create_view(view_frame, view_type, i)
            
    def create_custom_layout(self):
        """创建自定义布局"""
        # 左侧大图,右侧三个小图
        self.view_container.columnconfigure(0, weight=3)
        self.view_container.columnconfigure(1, weight=1)
        self.view_container.rowconfigure(0, weight=3)
        self.view_container.rowconfigure(1, weight=1)
        self.view_container.rowconfigure(2, weight=1)
        
        # 雷达大图
        radar_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
        radar_frame.grid(row=0, column=0, rowspan=3, sticky='nsew', padx=2, pady=2)
        self.create_view(radar_frame, 'radar', 0)
        
        # 信号图
        signal_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
        signal_frame.grid(row=0, column=1, sticky='nsew', padx=2, pady=2)
        self.create_view(signal_frame, 'signal', 1)
        
        # 频谱图
        spectrum_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
        spectrum_frame.grid(row=1, column=1, sticky='nsew', padx=2, pady=2)
        self.create_view(spectrum_frame, 'spectrum', 2)
        
        # 性能图
        perf_frame = ttk.Frame(self.view_container, relief=tk.RAISED, borderwidth=1)
        perf_frame.grid(row=2, column=1, sticky='nsew', padx=2, pady=2)
        self.create_view(perf_frame, 'performance', 3)
        
    def create_view(self, parent, view_type: str, view_id: int):
        """创建单个视图"""
        # 视图标题
        title_frame = ttk.Frame(parent)
        title_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(title_frame, text=self.get_view_title(view_type), 
                 font=('微软雅黑', 10, 'bold')).pack(side=tk.LEFT)
        
        # 视图控制
        control_frame = ttk.Frame(title_frame)
        control_frame.pack(side=tk.RIGHT)
        
        ttk.Button(control_frame, text="最大化", 
                  command=lambda: self.maximize_view(view_id)).pack(side=tk.LEFT, padx=2)
        
        # 图形区域
        fig = Figure(figsize=(5, 4), dpi=100)
        canvas = FigureCanvasTkAgg(fig, parent)
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 工具栏
        toolbar = NavigationToolbar2Tk(canvas, parent)
        toolbar.update()
        
        # 存储视图
        self.views[view_id] = {
            'type': view_type,
            'frame': parent,
            'fig': fig,
            'canvas': canvas,
            'toolbar': toolbar,
            'ax': None
        }
        
        # 初始化图形
        self.init_view_plot(view_id)
        
    def get_view_title(self, view_type: str) -> str:
        """获取视图标题"""
        titles = {
            'radar': '雷达显示',
            'signal': '时域信号',
            'spectrum': '频谱分析',
            'performance': '性能指标',
            'error': '误差分析',
            'jamming': '干扰效果',
            'tracking': '跟踪轨迹'
        }
        return titles.get(view_type, view_type)
        
    def init_view_plot(self, view_id: int):
        """初始化视图图形"""
        view = self.views[view_id]
        fig = view['fig']
        view_type = view['type']
        
        fig.clf()  # 清除图形
        
        if view_type == 'radar':
            # 雷达显示
            ax = fig.add_subplot(111, projection='polar')
            ax.set_theta_zero_location('N')
            ax.set_theta_direction(-1)
            ax.set_title('雷达显示')
            view['ax'] = ax
            
        elif view_type == 'signal':
            # 时域信号
            ax = fig.add_subplot(111)
            ax.set_title('时域信号')
            ax.set_xlabel('时间 (s)')
            ax.set_ylabel('幅度')
            ax.grid(True, alpha=0.3)
            view['ax'] = ax
            
        elif view_type == 'spectrum':
            # 频谱分析
            ax = fig.add_subplot(111)
            ax.set_title('频谱分析')
            ax.set_xlabel('频率 (Hz)')
            ax.set_ylabel('幅度 (dB)')
            ax.grid(True, alpha=0.3)
            view['ax'] = ax
            
        elif view_type == 'performance':
            # 性能指标
            ax = fig.add_subplot(111)
            ax.set_title('性能指标')
            ax.set_ylabel('数值')
            ax.grid(True, alpha=0.3)
            view['ax'] = ax
            
        fig.tight_layout()
        
    def update_view(self, view_id: int, data: Dict[str, Any]):
        """更新视图数据"""
        if view_id not in self.views:
            return
            
        view = self.views[view_id]
        view_type = view['type']
        
        if not self.auto_refresh_var.get():
            return
            
        try:
            if view_type == 'radar':
                self.update_radar_view(view, data)
            elif view_type == 'signal':
                self.update_signal_view(view, data)
            elif view_type == 'spectrum':
                self.update_spectrum_view(view, data)
            elif view_type == 'performance':
                self.update_performance_view(view, data)
                
            view['canvas'].draw_idle()
            
        except Exception as e:
            print(f"更新视图 {view_id} 失败: {e}")
            
    def update_radar_view(self, view: Dict, data: Dict):
        """更新雷达视图"""
        ax = view['ax']
        ax.clear()
        
        if 'target_azimuth' in data and 'target_elevation' in data:
            az = np.deg2rad(data['target_azimuth'])
            el = data['target_elevation'] / 90.0  # 归一化到0-1
            
            ax.scatter([az], [el], c='red', s=100, label='目标')
            
        if 'seeker_azimuth' in data and 'seeker_elevation' in data:
            az = np.deg2rad(data['seeker_azimuth'])
            el = data['seeker_elevation'] / 90.0
            
            ax.scatter([az], [el], c='blue', s=80, marker='^', label='导引头')
            
        ax.set_theta_zero_location('N')
        ax.set_theta_direction(-1)
        ax.set_title('雷达显示')
        ax.legend()
        
        # 绘制距离环
        for r in [0.2, 0.4, 0.6, 0.8, 1.0]:
            theta = np.linspace(0, 2*np.pi, 100)
            ax.plot(theta, [r]*100, 'gray', alpha=0.3, linewidth=0.5)
            
        ax.set_ylim(0, 1)
        
    def update_signal_view(self, view: Dict, data: Dict):
        """更新信号视图"""
        ax = view['ax']
        ax.clear()
        
        if 'time' in data and 'signal' in data:
            time_data = data['time'][-100:]  # 最后100个点
            signal_data = data['signal'][-100:]
            
            ax.plot(time_data, signal_data, 'b-', linewidth=1)
            
        ax.set_title('时域信号')
        ax.set_xlabel('时间 (s)')
        ax.set_ylabel('幅度')
        ax.grid(True, alpha=0.3)
        
    def update_spectrum_view(self, view: Dict, data: Dict):
        """更新频谱视图"""
        ax = view['ax']
        ax.clear()
        
        if 'signal' in data and len(data['signal']) > 10:
            signal = data['signal']
            
            # 计算FFT
            n = len(signal)
            yf = np.fft.fft(signal)
            xf = np.fft.fftfreq(n, 1/100)  # 假设采样率100Hz
            
            # 只取正频率
            idx = np.where(xf >= 0)
            magnitude = np.abs(yf[idx]) / n
            
            ax.plot(xf[idx], 20*np.log10(magnitude + 1e-10), 'r-', linewidth=1)
            
        ax.set_title('频谱分析')
        ax.set_xlabel('频率 (Hz)')
        ax.set_ylabel('幅度 (dB)')
        ax.grid(True, alpha=0.3)
        
    def update_performance_view(self, view: Dict, data: Dict):
        """更新性能视图"""
        ax = view['ax']
        ax.clear()
        
        if 'metrics' in data:
            metrics = data['metrics']
            names = list(metrics.keys())
            values = list(metrics.values())
            
            bars = ax.bar(names, values, color='steelblue')
            ax.set_title('性能指标')
            ax.set_ylabel('数值')
            ax.grid(True, alpha=0.3, axis='y')
            
            # 添加数值标签
            for bar, value in zip(bars, values):
                height = bar.get_height()
                ax.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                       f'{value:.2f}', ha='center', va='bottom', fontsize=8)
                
            ax.set_xticklabels(names, rotation=45, ha='right')
            
    def maximize_view(self, view_id: int):
        """最大化视图"""
        if view_id not in self.views:
            return
            
        # 创建新窗口
        top = tk.Toplevel(self.parent)
        top.title(f"最大化视图 - {self.views[view_id]['type']}")
        top.geometry("800x600")
        
        # 复制视图
        view = self.views[view_id]
        
        # 创建新图形
        new_fig = Figure(figsize=(8, 6), dpi=100)
        new_canvas = FigureCanvasTkAgg(new_fig, top)
        new_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 复制原图形内容
        # 这里需要根据实际需求实现图形的复制
        
    def reset_views(self):
        """重置所有视图"""
        for view_id in self.views:
            self.init_view_plot(view_id)
            self.views[view_id]['canvas'].draw_idle()
            
    def save_layout(self):
        """保存布局"""
        # 保存当前布局配置
        layout_config = {
            'layout': self.view_layout,
            'views': list(self.views.keys()),
            'timestamp': datetime.now().isoformat()
        }
        
        print("布局已保存:", layout_config)
        
    def update_all_views(self, data: Dict[str, Any]):
        """更新所有视图"""
        for view_id, view in self.views.items():
            self.update_view(view_id, data)

# 测试函数
def test_multi_view():
    """测试多视图系统"""
    root = tk.Tk()
    root.title("多视图协同显示系统测试")
    root.geometry("1200x800")
    
    multi_view = MultiViewSystem(root)
    
    # 模拟数据更新
    def simulate_data():
        import random
        import time
        
        while True:
            data = {
                'target_azimuth': random.uniform(-30, 30),
                'target_elevation': random.uniform(0, 30),
                'seeker_azimuth': random.uniform(-30, 30),
                'seeker_elevation': random.uniform(0, 30),
                'time': [i*0.1 for i in range(100)],
                'signal': [np.sin(i*0.1) + random.gauss(0, 0.1) for i in range(100)],
                'metrics': {
                    'RMS误差': random.uniform(0, 1),
                    '信噪比': random.uniform(10, 30),
                    '干信比': random.uniform(0, 20),
                    '锁定概率': random.uniform(0.5, 1.0)
                }
            }
            
            multi_view.update_all_views(data)
            time.sleep(0.1)
            
    # 启动数据模拟线程
    thread = threading.Thread(target=simulate_data, daemon=True)
    thread.start()
    
    root.mainloop()

if __name__ == "__main__":
    test_multi_view()

7. 多线程与性能优化

7.1 高性能数据处理架构

python 复制代码
"""
high_performance_processor.py

高性能数据处理架构
"""
import tkinter as tk
from tkinter import ttk
import threading
import queue
import time
import numpy as np
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass
from enum import Enum
import multiprocessing as mp
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import psutil
import gc

@dataclass
class PerformanceMetrics:
    """性能指标"""
    fps: float = 0.0
    cpu_usage: float = 0.0
    memory_usage: float = 0.0
    processing_latency: float = 0.0
    render_latency: float = 0.0
    data_queue_size: int = 0
    
class ProcessingMode(Enum):
    """处理模式"""
    SINGLE_THREAD = "single_thread"
    MULTI_THREAD = "multi_thread"
    MULTI_PROCESS = "multi_process"
    GPU_ACCELERATED = "gpu_accelerated"

class HighPerformanceProcessor:
    """高性能处理器"""
    
    def __init__(self, ui_update_callback: Optional[Callable] = None):
        self.ui_update_callback = ui_update_callback
        
        # 处理模式
        self.processing_mode = ProcessingMode.MULTI_THREAD
        
        # 数据队列
        self.input_queue = queue.Queue(maxsize=1000)
        self.output_queue = queue.Queue(maxsize=1000)
        
        # 线程/进程
        self.worker_threads = []
        self.worker_processes = []
        self.running = False
        
        # 性能监控
        self.performance_metrics = PerformanceMetrics()
        self.frame_times = []
        self.max_frame_history = 100
        
        # 线程池
        self.thread_pool = ThreadPoolExecutor(max_workers=4)
        
        # 初始化处理模块
        self.init_processing_modules()
        
    def init_processing_modules(self):
        """初始化处理模块"""
        self.processing_modules = {
            'signal_processing': SignalProcessingModule(),
            'data_filtering': DataFilteringModule(),
            'feature_extraction': FeatureExtractionModule(),
            'visualization': VisualizationModule()
        }
        
    def start(self):
        """启动处理器"""
        if self.running:
            return
            
        self.running = True
        
        # 启动工作线程
        if self.processing_mode == ProcessingMode.MULTI_THREAD:
            self.start_multi_thread_workers()
        elif self.processing_mode == ProcessingMode.MULTI_PROCESS:
            self.start_multi_process_workers()
        else:
            self.start_single_thread_worker()
            
        # 启动性能监控
        self.start_performance_monitor()
        
    def stop(self):
        """停止处理器"""
        self.running = False
        
        # 停止工作线程
        for thread in self.worker_threads:
            if thread.is_alive():
                thread.join(timeout=1.0)
                
        # 停止进程
        for process in self.worker_processes:
            if process.is_alive():
                process.terminate()
                
        # 关闭线程池
        self.thread_pool.shutdown(wait=False)
        
    def start_single_thread_worker(self):
        """启动单线程工作器"""
        thread = threading.Thread(target=self.single_thread_worker, daemon=True)
        thread.start()
        self.worker_threads.append(thread)
        
    def start_multi_thread_workers(self):
        """启动多线程工作器"""
        # 启动多个工作线程
        for i in range(4):  # 4个工作线程
            thread = threading.Thread(
                target=self.multi_thread_worker, 
                args=(i,),
                daemon=True
            )
            thread.start()
            self.worker_threads.append(thread)
            
    def start_multi_process_workers(self):
        """启动多进程工作器"""
        # 启动多个工作进程
        for i in range(2):  # 2个工作进程
            process = mp.Process(
                target=self.multi_process_worker,
                args=(i,),
                daemon=True
            )
            process.start()
            self.worker_processes.append(process)
            
    def single_thread_worker(self):
        """单线程工作器"""
        while self.running:
            try:
                # 从输入队列获取数据
                data = self.input_queue.get(timeout=0.1)
                
                # 开始计时
                start_time = time.perf_counter()
                
                # 顺序处理数据
                processed_data = self.process_data_sequentially(data)
                
                # 计算处理延迟
                processing_time = time.perf_counter() - start_time
                
                # 放入输出队列
                if processed_data:
                    self.output_queue.put({
                        'data': processed_data,
                        'processing_time': processing_time
                    })
                    
            except queue.Empty:
                continue
            except Exception as e:
                print(f"处理错误: {e}")
                
    def multi_thread_worker(self, worker_id: int):
        """多线程工作器"""
        while self.running:
            try:
                # 从输入队列获取数据
                data = self.input_queue.get(timeout=0.1)
                
                # 使用线程池并行处理
                futures = []
                for module_name, module in self.processing_modules.items():
                    future = self.thread_pool.submit(
                        module.process,
                        data,
                        worker_id
                    )
                    futures.append((module_name, future))
                    
                # 收集结果
                processed_data = {}
                for module_name, future in futures:
                    try:
                        result = future.result(timeout=0.5)
                        processed_data[module_name] = result
                    except Exception as e:
                        print(f"模块 {module_name} 处理失败: {e}")
                        
                # 合并结果
                if processed_data:
                    self.output_queue.put({
                        'worker_id': worker_id,
                        'data': processed_data,
                        'timestamp': time.time()
                    })
                    
            except queue.Empty:
                continue
            except Exception as e:
                print(f"工作器 {worker_id} 错误: {e}")
                
    def multi_process_worker(self, worker_id: int):
        """多进程工作器"""
        # 在多进程中需要重新初始化模块
        import pickle
        import sys
        
        while self.running:
            try:
                # 多进程间通信需要序列化
                data_bytes = self.input_queue.get(timeout=0.1)
                data = pickle.loads(data_bytes)
                
                # 处理数据
                processed_data = self.process_data_sequentially(data)
                
                # 序列化结果
                result_bytes = pickle.dumps({
                    'worker_id': worker_id,
                    'data': processed_data
                })
                
                # 通过队列返回结果
                self.output_queue.put(result_bytes)
                
            except queue.Empty:
                continue
            except Exception as e:
                print(f"进程 {worker_id} 错误: {e}")
                
    def process_data_sequentially(self, data: Dict) -> Dict:
        """顺序处理数据"""
        processed_data = data.copy()
        
        # 信号处理
        if 'signal_data' in data:
            signal_result = self.processing_modules['signal_processing'].process(
                data['signal_data']
            )
            processed_data['signal_processed'] = signal_result
            
        # 数据滤波
        if 'raw_data' in data:
            filtered_result = self.processing_modules['data_filtering'].process(
                data['raw_data']
            )
            processed_data['filtered_data'] = filtered_result
            
        # 特征提取
        if 'filtered_data' in processed_data:
            features = self.processing_modules['feature_extraction'].process(
                processed_data['filtered_data']
            )
            processed_data['features'] = features
            
        return processed_data
    
    def start_performance_monitor(self):
        """启动性能监控"""
        monitor_thread = threading.Thread(target=self.performance_monitor, daemon=True)
        monitor_thread.start()
        
    def performance_monitor(self):
        """性能监控"""
        frame_count = 0
        last_time = time.time()
        
        while self.running:
            current_time = time.time()
            frame_count += 1
            
            # 每秒更新一次性能指标
            if current_time - last_time >= 1.0:
                # 计算FPS
                self.performance_metrics.fps = frame_count
                frame_count = 0
                
                # 获取CPU和内存使用率
                self.performance_metrics.cpu_usage = psutil.cpu_percent()
                self.performance_metrics.memory_usage = psutil.virtual_memory().percent
                
                # 获取队列大小
                self.performance_metrics.data_queue_size = self.input_queue.qsize()
                
                # 回调UI更新
                if self.ui_update_callback:
                    self.ui_update_callback(self.performance_metrics)
                    
                last_time = current_time
                
            time.sleep(0.1)
            
    def optimize_memory_usage(self):
        """优化内存使用"""
        # 清除缓存
        gc.collect()
        
        # 限制历史数据大小
        if len(self.frame_times) > self.max_frame_history:
            self.frame_times = self.frame_times[-self.max_frame_history:]
            
    def set_processing_mode(self, mode: ProcessingMode):
        """设置处理模式"""
        if mode == self.processing_mode:
            return
            
        # 停止当前模式
        self.stop()
        
        # 设置新模式
        self.processing_mode = mode
        
        # 重新启动
        self.start()
        
    def get_performance_report(self) -> Dict:
        """获取性能报告"""
        return {
            'fps': self.performance_metrics.fps,
            'cpu_usage': f"{self.performance_metrics.cpu_usage:.1f}%",
            'memory_usage': f"{self.performance_metrics.memory_usage:.1f}%",
            'queue_size': self.performance_metrics.data_queue_size,
            'processing_mode': self.processing_mode.value,
            'worker_count': len(self.worker_threads) + len(self.worker_processes)
        }

class SignalProcessingModule:
    """信号处理模块"""
    
    def __init__(self):
        self.filter_coeffs = None
        self.init_filters()
        
    def init_filters(self):
        """初始化滤波器"""
        # 创建低通滤波器系数
        from scipy import signal
        self.filter_coeffs = signal.butter(
            4, 0.1, btype='low', analog=False, output='sos'
        )
        
    def process(self, data: np.ndarray, worker_id: int = 0) -> Dict:
        """处理信号数据"""
        start_time = time.perf_counter()
        
        try:
            # 应用滤波器
            if self.filter_coeffs is not None and len(data) > 10:
                filtered = signal.sosfilt(self.filter_coeffs, data)
            else:
                filtered = data
                
            # 计算统计量
            stats = {
                'mean': np.mean(filtered),
                'std': np.std(filtered),
                'max': np.max(filtered),
                'min': np.min(filtered),
                'rms': np.sqrt(np.mean(filtered**2))
            }
            
            # 计算频谱
            if len(filtered) > 10:
                spectrum = np.abs(np.fft.fft(filtered))
                freq = np.fft.fftfreq(len(filtered))
                
                # 找到主频
                idx = np.argmax(spectrum[:len(spectrum)//2])
                main_freq = abs(freq[idx])
                
                stats['main_frequency'] = main_freq
                
            processing_time = time.perf_counter() - start_time
            
            return {
                'filtered_signal': filtered,
                'statistics': stats,
                'processing_time': processing_time,
                'worker_id': worker_id
            }
            
        except Exception as e:
            print(f"信号处理错误: {e}")
            return {'error': str(e)}
            
class DataFilteringModule:
    """数据滤波模块"""
    
    def process(self, data: np.ndarray, worker_id: int = 0) -> Dict:
        """滤波数据"""
        start_time = time.perf_counter()
        
        try:
            # 中值滤波
            if len(data) > 3:
                filtered = self.median_filter(data, window_size=3)
            else:
                filtered = data
                
            # 卡尔曼滤波
            if len(filtered) > 5:
                filtered = self.kalman_filter(filtered)
                
            processing_time = time.perf_counter() - start_time
            
            return {
                'filtered': filtered,
                'processing_time': processing_time
            }
            
        except Exception as e:
            print(f"数据滤波错误: {e}")
            return {'error': str(e)}
            
    def median_filter(self, data: np.ndarray, window_size: int = 3) -> np.ndarray:
        """中值滤波"""
        from scipy import ndimage
        return ndimage.median_filter(data, size=window_size)
        
    def kalman_filter(self, data: np.ndarray) -> np.ndarray:
        """卡尔曼滤波"""
        # 简化实现
        n = len(data)
        filtered = np.zeros_like(data)
        
        # 初始值
        x = data[0]
        p = 1.0
        
        # 过程噪声和观测噪声
        q = 0.1
        r = 0.1
        
        for i in range(n):
            # 预测
            x = x
            p = p + q
            
            # 更新
            k = p / (p + r)
            x = x + k * (data[i] - x)
            p = (1 - k) * p
            
            filtered[i] = x
            
        return filtered
        
class FeatureExtractionModule:
    """特征提取模块"""
    
    def process(self, data: np.ndarray, worker_id: int = 0) -> Dict:
        """提取特征"""
        start_time = time.perf_counter()
        
        try:
            features = {}
            
            if len(data) > 10:
                # 时域特征
                features['time_domain'] = self.extract_time_domain_features(data)
                
                # 频域特征
                features['frequency_domain'] = self.extract_frequency_domain_features(data)
                
                # 统计特征
                features['statistical'] = self.extract_statistical_features(data)
                
            processing_time = time.perf_counter() - start_time
            
            return {
                'features': features,
                'processing_time': processing_time
            }
            
        except Exception as e:
            print(f"特征提取错误: {e}")
            return {'error': str(e)}
            
    def extract_time_domain_features(self, data: np.ndarray) -> Dict:
        """提取时域特征"""
        return {
            'mean': np.mean(data),
            'rms': np.sqrt(np.mean(data**2)),
            'peak': np.max(np.abs(data)),
            'peak_to_peak': np.max(data) - np.min(data),
            'form_factor': np.sqrt(np.mean(data**2)) / np.mean(np.abs(data)),
            'crest_factor': np.max(np.abs(data)) / np.sqrt(np.mean(data**2))
        }
        
    def extract_frequency_domain_features(self, data: np.ndarray) -> Dict:
        """提取频域特征"""
        n = len(data)
        
        # 计算FFT
        spectrum = np.abs(np.fft.fft(data))
        freq = np.fft.fftfreq(n)
        
        # 只取正频率
        positive_idx = np.where(freq >= 0)
        spectrum = spectrum[positive_idx]
        freq = freq[positive_idx]
        
        if len(spectrum) > 0:
            # 找到主频
            main_freq_idx = np.argmax(spectrum)
            main_freq = abs(freq[main_freq_idx])
            
            # 计算频带能量
            total_energy = np.sum(spectrum**2)
            
            # 低频能量比例
            low_freq_idx = np.where(freq <= 0.1)
            low_freq_energy = np.sum(spectrum[low_freq_idx]**2)
            
            return {
                'main_frequency': main_freq,
                'total_energy': total_energy,
                'low_freq_energy_ratio': low_freq_energy / total_energy if total_energy > 0 else 0,
                'spectrum_centroid': np.sum(freq * spectrum) / np.sum(spectrum) if np.sum(spectrum) > 0 else 0
            }
        else:
            return {}
            
    def extract_statistical_features(self, data: np.ndarray) -> Dict:
        """提取统计特征"""
        from scipy import stats
        
        return {
            'skewness': stats.skew(data) if len(data) > 1 else 0,
            'kurtosis': stats.kurtosis(data) if len(data) > 1 else 0,
            'variance': np.var(data),
            'std': np.std(data)
        }
        
class VisualizationModule:
    """可视化模块"""
    
    def process(self, data: Dict, worker_id: int = 0) -> Dict:
        """准备可视化数据"""
        start_time = time.perf_counter()
        
        try:
            visualization_data = {}
            
            # 准备图表数据
            if 'signal_data' in data:
                visualization_data['time_series'] = {
                    'x': list(range(len(data['signal_data']))),
                    'y': data['signal_data'].tolist()
                }
                
            if 'features' in data and 'frequency_domain' in data['features']:
                visualization_data['spectrum'] = data['features']['frequency_domain']
                
            processing_time = time.perf_counter() - start_time
            
            return {
                'visualization_data': visualization_data,
                'processing_time': processing_time
            }
            
        except Exception as e:
            print(f"可视化处理错误: {e}")
            return {'error': str(e)}

# 性能优化演示界面
class PerformanceOptimizationDemo:
    """性能优化演示"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("高性能处理演示")
        self.root.geometry("1200x700")
        

        # 创建处理器
        self.processor = HighPerformanceProcessor(self.update_performance_display)
        
        # 构建UI
        self.create_ui()
        
        # 启动处理器
        self.processor.start()
        
        # 启动数据生成线程
        self.data_generation_running = True
        self.data_thread = threading.Thread(target=self.generate_data, daemon=True)
        self.data_thread.start()
        
    def create_ui(self):
        """创建UI界面"""
        # 主容器
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title_label = ttk.Label(main_frame, 
                               text="高性能数据处理架构演示",
                               font=("微软雅黑", 16, "bold"),
                               foreground="#2C3E50")
        title_label.pack(pady=(0, 10))
        
        # 控制面板
        control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.create_control_panel(control_frame)
        
        # 性能显示面板
        performance_frame = ttk.LabelFrame(main_frame, text="性能监控", padding=10)
        performance_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.create_performance_panel(performance_frame)
        
        # 数据显示面板
        display_frame = ttk.LabelFrame(main_frame, text="数据处理结果", padding=10)
        display_frame.pack(fill=tk.BOTH, expand=True)
        
        self.create_display_panel(display_frame)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        # 处理模式选择
        mode_frame = ttk.Frame(parent)
        mode_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(mode_frame, text="处理模式:").pack(side=tk.LEFT, padx=5)
        
        self.mode_var = tk.StringVar(value=ProcessingMode.MULTI_THREAD.value)
        modes = [
            ("单线程", ProcessingMode.SINGLE_THREAD),
            ("多线程", ProcessingMode.MULTI_THREAD),
            ("多进程", ProcessingMode.MULTI_PROCESS)
        ]
        
        for text, mode in modes:
            rb = ttk.Radiobutton(mode_frame, text=text, 
                                variable=self.mode_var,
                                value=mode.value,
                                command=self.change_processing_mode)
            rb.pack(side=tk.LEFT, padx=5)
            
        # 数据生成控制
        data_frame = ttk.Frame(parent)
        data_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(data_frame, text="数据生成速率 (Hz):").pack(side=tk.LEFT, padx=5)
        self.data_rate_var = tk.DoubleVar(value=100.0)
        data_rate_scale = ttk.Scale(data_frame, from_=10, to=1000,
                                   variable=self.data_rate_var,
                                   orient=tk.HORIZONTAL, length=200)
        data_rate_scale.pack(side=tk.LEFT, padx=5)
        
        ttk.Label(data_frame, text="数据大小:").pack(side=tk.LEFT, padx=5)
        self.data_size_var = tk.IntVar(value=1000)
        ttk.Entry(data_frame, textvariable=self.data_size_var, width=10).pack(side=tk.LEFT, padx=5)
        
        # 控制按钮
        button_frame = ttk.Frame(parent)
        button_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(button_frame, text="开始处理", 
                  command=self.start_processing).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="停止处理", 
                  command=self.stop_processing).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="性能报告", 
                  command=self.show_performance_report).pack(side=tk.LEFT, padx=5)
                  
    def create_performance_panel(self, parent):
        """创建性能监控面板"""
        # 性能指标显示
        metrics_frame = ttk.Frame(parent)
        metrics_frame.pack(fill=tk.X, pady=5)
        
        self.metric_vars = {}
        metrics = [
            ("FPS", "fps", "0.0"),
            ("CPU使用率", "cpu_usage", "0.0%"),
            ("内存使用率", "memory_usage", "0.0%"),
            ("队列大小", "queue_size", "0"),
            ("处理延迟", "processing_latency", "0.0ms"),
            ("渲染延迟", "render_latency", "0.0ms")
        ]
        
        for i, (label, key, default) in enumerate(metrics):
            frame = ttk.Frame(metrics_frame)
            frame.grid(row=i//3, column=i%3, sticky=tk.W, padx=10, pady=5)
            
            ttk.Label(frame, text=label + ":").pack(side=tk.LEFT)
            var = tk.StringVar(value=default)
            ttk.Label(frame, textvariable=var, font=("Consolas", 10, "bold"),
                     foreground="#2C3E50").pack(side=tk.LEFT, padx=5)
            self.metric_vars[key] = var
            
        # 实时图表
        self.create_performance_chart(parent)
        
    def create_performance_chart(self, parent):
        """创建性能图表"""
        # 使用matplotlib创建实时图表
        self.perf_fig = Figure(figsize=(10, 4), dpi=80)
        self.perf_canvas = FigureCanvasTkAgg(self.perf_fig, parent)
        self.perf_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, pady=10)
        
        # 创建子图
        self.ax_fps = self.perf_fig.add_subplot(221)
        self.ax_cpu = self.perf_fig.add_subplot(222)
        self.ax_memory = self.perf_fig.add_subplot(223)
        self.ax_queue = self.perf_fig.add_subplot(224)
        
        # 设置图表
        self.setup_chart(self.ax_fps, "FPS", "帧率", "green")
        self.setup_chart(self.ax_cpu, "CPU使用率", "百分比%", "blue")
        self.setup_chart(self.ax_memory, "内存使用率", "百分比%", "red")
        self.setup_chart(self.ax_queue, "队列大小", "数据量", "purple")
        
        # 数据存储
        self.chart_data = {
            'fps': [],
            'cpu': [],
            'memory': [],
            'queue': [],
            'time': []
        }
        
        # 启动图表更新
        self.update_chart()
        
    def setup_chart(self, ax, title, ylabel, color):
        """设置图表"""
        ax.set_title(title)
        ax.set_xlabel("时间 (s)")
        ax.set_ylabel(ylabel)
        ax.grid(True, alpha=0.3)
        ax.set_facecolor('#F8F9FA')
        ax.line, = ax.plot([], [], color=color, linewidth=2)
        
    def create_display_panel(self, parent):
        """创建数据显示面板"""
        # 使用Notebook组织显示
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True)
        
        # 原始数据标签页
        raw_tab = ttk.Frame(notebook)
        self.create_raw_data_display(raw_tab)
        notebook.add(raw_tab, text="原始数据")
        
        # 处理结果标签页
        processed_tab = ttk.Frame(notebook)
        self.create_processed_data_display(processed_tab)
        notebook.add(processed_tab, text="处理结果")
        
        # 特征数据标签页
        feature_tab = ttk.Frame(notebook)
        self.create_feature_display(feature_tab)
        notebook.add(feature_tab, text="特征提取")
        
    def create_raw_data_display(self, parent):
        """创建原始数据显示"""
        # 文本显示区域
        text_frame = ttk.Frame(parent)
        text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        ttk.Label(text_frame, text="原始数据预览:").pack(anchor=tk.W)
        
        self.raw_text = tk.Text(text_frame, height=15, width=40,
                               font=("Consolas", 9))
        scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, 
                                 command=self.raw_text.yview)
        self.raw_text.configure(yscrollcommand=scrollbar.set)
        
        self.raw_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 图表显示
        chart_frame = ttk.Frame(parent)
        chart_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.raw_fig = Figure(figsize=(6, 4), dpi=80)
        self.raw_canvas = FigureCanvasTkAgg(self.raw_fig, chart_frame)
        self.raw_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        self.raw_ax = self.raw_fig.add_subplot(111)
        self.raw_ax.set_title("原始数据波形")
        self.raw_ax.set_xlabel("采样点")
        self.raw_ax.set_ylabel("幅度")
        self.raw_ax.grid(True, alpha=0.3)
        
    def create_processed_data_display(self, parent):
        """创建处理结果显示"""
        # 创建多个图表
        self.processed_fig = Figure(figsize=(10, 6), dpi=80)
        self.processed_canvas = FigureCanvasTkAgg(self.processed_fig, parent)
        self.processed_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, 
                                                  padx=5, pady=5)
        
        # 创建子图
        self.ax_filtered = self.processed_fig.add_subplot(221)
        self.ax_spectrum = self.processed_fig.add_subplot(222)
        self.ax_histogram = self.processed_fig.add_subplot(223)
        self.ax_scatter = self.processed_fig.add_subplot(224)
        
        # 设置子图
        self.ax_filtered.set_title("滤波后信号")
        self.ax_filtered.set_xlabel("采样点")
        self.ax_filtered.set_ylabel("幅度")
        self.ax_filtered.grid(True, alpha=0.3)
        
        self.ax_spectrum.set_title("频谱")
        self.ax_spectrum.set_xlabel("频率")
        self.ax_spectrum.set_ylabel("幅度")
        self.ax_spectrum.grid(True, alpha=0.3)
        
        self.ax_histogram.set_title("数据分布")
        self.ax_histogram.set_xlabel("值")
        self.ax_histogram.set_ylabel("频数")
        self.ax_histogram.grid(True, alpha=0.3)
        
        self.ax_scatter.set_title("相关分析")
        self.ax_scatter.set_xlabel("X")
        self.ax_scatter.set_ylabel("Y")
        self.ax_scatter.grid(True, alpha=0.3)
        
        self.processed_fig.tight_layout()
        
    def create_feature_display(self, parent):
        """创建特征显示"""
        # 特征表格
        tree_frame = ttk.Frame(parent)
        tree_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        ttk.Label(tree_frame, text="特征统计:").pack(anchor=tk.W)
        
        # 创建Treeview
        columns = ("特征", "数值", "单位")
        self.feature_tree = ttk.Treeview(tree_frame, columns=columns, 
                                        show="headings", height=15)
        
        for col in columns:
            self.feature_tree.heading(col, text=col)
            self.feature_tree.column(col, width=100)
            
        scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL,
                                 command=self.feature_tree.yview)
        self.feature_tree.configure(yscrollcommand=scrollbar.set)
        
        self.feature_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 特征图表
        chart_frame = ttk.Frame(parent)
        chart_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.feature_fig = Figure(figsize=(6, 4), dpi=80)
        self.feature_canvas = FigureCanvasTkAgg(self.feature_fig, chart_frame)
        self.feature_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        self.feature_ax = self.feature_fig.add_subplot(111)
        self.feature_ax.set_title("特征雷达图")
        self.feature_ax.grid(True, alpha=0.3)
        
    def change_processing_mode(self):
        """改变处理模式"""
        mode = ProcessingMode(self.mode_var.get())
        self.processor.set_processing_mode(mode)
        
    def start_processing(self):
        """开始处理"""
        self.processor.start()
        
    def stop_processing(self):
        """停止处理"""
        self.processor.stop()
        
    def show_performance_report(self):
        """显示性能报告"""
        report = self.processor.get_performance_report()
        
        report_text = "性能报告:\n\n"
        for key, value in report.items():
            report_text += f"{key}: {value}\n"
            
        messagebox.showinfo("性能报告", report_text)
        
    def generate_data(self):
        """生成测试数据"""
        import random
        import math
        
        while self.data_generation_running:
            try:
                # 生成模拟雷达数据
                data_rate = self.data_rate_var.get()
                data_size = self.data_size_var.get()
                
                if data_rate <= 0 or data_size <= 0:
                    time.sleep(0.1)
                    continue
                    
                # 生成正弦波加噪声
                t = np.linspace(0, 2*np.pi, data_size)
                frequency = random.uniform(1, 10)
                signal = np.sin(2*np.pi*frequency*t) + 0.1*np.random.randn(data_size)
                
                # 添加脉冲
                if random.random() > 0.7:
                    pulse_pos = random.randint(0, data_size-1)
                    signal[pulse_pos] += random.uniform(0.5, 2.0)
                    
                # 创建数据包
                data_packet = {
                    'timestamp': time.time(),
                    'signal_data': signal,
                    'raw_data': signal.copy(),
                    'metadata': {
                        'frequency': frequency,
                        'data_size': data_size,
                        'sample_rate': data_rate
                    }
                }
                
                # 放入输入队列
                self.processor.input_queue.put(data_packet)
                
                # 控制生成速率
                time.sleep(1.0 / data_rate)
                
            except Exception as e:
                print(f"数据生成错误: {e}")
                time.sleep(0.1)
                
    def update_performance_display(self, metrics: PerformanceMetrics):
        """更新性能显示"""
        # 更新指标变量
        self.metric_vars['fps'].set(f"{metrics.fps:.1f}")
        self.metric_vars['cpu_usage'].set(f"{metrics.cpu_usage:.1f}%")
        self.metric_vars['memory_usage'].set(f"{metrics.memory_usage:.1f}%")
        self.metric_vars['queue_size'].set(f"{metrics.data_queue_size}")
        self.metric_vars['processing_latency'].set(f"{metrics.processing_latency:.1f}ms")
        self.metric_vars['render_latency'].set(f"{metrics.render_latency:.1f}ms")
        
        # 更新图表数据
        current_time = time.time()
        if not hasattr(self, 'start_time'):
            self.start_time = current_time
            
        elapsed = current_time - self.start_time
        
        self.chart_data['time'].append(elapsed)
        self.chart_data['fps'].append(metrics.fps)
        self.chart_data['cpu'].append(metrics.cpu_usage)
        self.chart_data['memory'].append(metrics.memory_usage)
        self.chart_data['queue'].append(metrics.data_queue_size)
        
        # 保持最近100个数据点
        max_points = 100
        for key in self.chart_data:
            if len(self.chart_data[key]) > max_points:
                self.chart_data[key] = self.chart_data[key][-max_points:]
                
        # 处理输出队列中的数据
        self.process_output_data()
        
    def update_chart(self):
        """更新图表"""
        if hasattr(self, 'chart_data') and self.chart_data['time']:
            # 更新FPS图表
            self.ax_fps.line.set_data(self.chart_data['time'], self.chart_data['fps'])
            self.ax_fps.relim()
            self.ax_fps.autoscale_view()
            
            # 更新CPU图表
            self.ax_cpu.line.set_data(self.chart_data['time'], self.chart_data['cpu'])
            self.ax_cpu.relim()
            self.ax_cpu.autoscale_view()
            
            # 更新内存图表
            self.ax_memory.line.set_data(self.chart_data['time'], self.chart_data['memory'])
            self.ax_memory.relim()
            self.ax_memory.autoscale_view()
            
            # 更新队列图表
            self.ax_queue.line.set_data(self.chart_data['time'], self.chart_data['queue'])
            self.ax_queue.relim()
            self.ax_queue.autoscale_view()
            
            self.perf_canvas.draw_idle()
            
        # 每隔100ms更新一次
        self.root.after(100, self.update_chart)
        
    def process_output_data(self):
        """处理输出数据"""
        try:
            # 获取所有可用的处理结果
            while not self.processor.output_queue.empty():
                result = self.processor.output_queue.get_nowait()
                
                # 更新原始数据显示
                if 'data' in result and 'signal_data' in result['data']:
                    self.update_raw_display(result['data'])
                    
                # 更新处理结果显示
                if 'data' in result and 'signal_processed' in result['data']:
                    self.update_processed_display(result['data'])
                    
                # 更新特征显示
                if 'data' in result and 'features' in result['data']:
                    self.update_feature_display(result['data']['features'])
                    
        except queue.Empty:
            pass
        except Exception as e:
            print(f"处理输出数据错误: {e}")
            
    def update_raw_display(self, data):
        """更新原始数据显示"""
        # 更新文本显示
        if 'signal_data' in data:
            signal = data['signal_data']
            signal_preview = signal[:20]  # 只显示前20个点
            
            self.raw_text.delete(1.0, tk.END)
            self.raw_text.insert(1.0, "原始信号数据:\n")
            self.raw_text.insert(2.0, f"长度: {len(signal)}\n")
            self.raw_text.insert(3.0, f"预览: {signal_preview}\n")
            
            # 更新图表
            self.raw_ax.clear()
            self.raw_ax.plot(signal[:100], 'b-', linewidth=1)  # 只显示前100个点
            self.raw_ax.set_title("原始数据波形")
            self.raw_ax.set_xlabel("采样点")
            self.raw_ax.set_ylabel("幅度")
            self.raw_ax.grid(True, alpha=0.3)
            self.raw_canvas.draw_idle()
            
    def update_processed_display(self, data):
        """更新处理结果显示"""
        if 'signal_processed' in data and 'filtered_signal' in data['signal_processed']:
            filtered = data['signal_processed']['filtered_signal']
            
            # 更新滤波后信号
            self.ax_filtered.clear()
            self.ax_filtered.plot(filtered[:100], 'g-', linewidth=1)
            self.ax_filtered.set_title("滤波后信号")
            self.ax_filtered.set_xlabel("采样点")
            self.ax_filtered.set_ylabel("幅度")
            self.ax_filtered.grid(True, alpha=0.3)
            
            # 更新频谱
            if len(filtered) > 10:
                spectrum = np.abs(np.fft.fft(filtered))
                freq = np.fft.fftfreq(len(filtered))
                
                self.ax_spectrum.clear()
                self.ax_spectrum.plot(freq[:len(freq)//2], spectrum[:len(spectrum)//2], 'r-', linewidth=1)
                self.ax_spectrum.set_title("频谱")
                self.ax_spectrum.set_xlabel("频率")
                self.ax_spectrum.set_ylabel("幅度")
                self.ax_spectrum.grid(True, alpha=0.3)
                
            # 更新直方图
            self.ax_histogram.clear()
            self.ax_histogram.hist(filtered, bins=20, alpha=0.7, color='blue')
            self.ax_histogram.set_title("数据分布")
            self.ax_histogram.set_xlabel("值")
            self.ax_histogram.set_ylabel("频数")
            self.ax_histogram.grid(True, alpha=0.3)
            
            # 更新散点图
            if len(filtered) > 2:
                x = filtered[:-1]
                y = filtered[1:]
                
                self.ax_scatter.clear()
                self.ax_scatter.scatter(x, y, s=1, alpha=0.5)
                self.ax_scatter.set_title("相关分析")
                self.ax_scatter.set_xlabel("X")
                self.ax_scatter.set_ylabel("Y")
                self.ax_scatter.grid(True, alpha=0.3)
                
            self.processed_canvas.draw_idle()
            
    def update_feature_display(self, features):
        """更新特征显示"""
        # 更新表格
        for item in self.feature_tree.get_children():
            self.feature_tree.delete(item)
            
        if 'time_domain' in features:
            for key, value in features['time_domain'].items():
                self.feature_tree.insert("", tk.END, values=(key, f"{value:.4f}", ""))
                
        if 'statistical' in features:
            for key, value in features['statistical'].items():
                self.feature_tree.insert("", tk.END, values=(key, f"{value:.4f}", ""))
                
        # 更新雷达图
        if 'time_domain' in features:
            self.update_radar_chart(features['time_domain'])
            
    def update_radar_chart(self, features):
        """更新雷达图"""
        self.feature_ax.clear()
        
        # 选择几个特征绘制雷达图
        selected_features = ['mean', 'rms', 'peak', 'peak_to_peak', 'crest_factor']
        values = []
        labels = []
        
        for feature in selected_features:
            if feature in features:
                values.append(features[feature])
                labels.append(feature)
                
        if len(values) >= 3:
            # 创建雷达图
            angles = np.linspace(0, 2*np.pi, len(values), endpoint=False).tolist()
            values += values[:1]  # 闭合图形
            angles += angles[:1]
            labels += labels[:1]
            
            self.feature_ax = self.feature_fig.add_subplot(111, projection='polar')
            self.feature_ax.plot(angles, values, 'o-', linewidth=2)
            self.feature_ax.fill(angles, values, alpha=0.25)
            self.feature_ax.set_xticks(angles[:-1])
            self.feature_ax.set_xticklabels(labels[:-1])
            self.feature_ax.set_title("特征雷达图")
            self.feature_ax.grid(True)
            
            self.feature_canvas.draw_idle()
            
    def on_closing(self):
        """窗口关闭处理"""
        self.data_generation_running = False
        self.processor.stop()
        self.root.destroy()

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = PerformanceOptimizationDemo(root)
    
    # 窗口关闭事件
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    
    # 窗口居中
    root.update_idletasks()
    width = root.winfo_width()
    height = root.winfo_height()
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    root.geometry(f'{width}x{height}+{x}+{y}')
    
    root.mainloop()

8. 仿真结果分析与展示

8.1 完整的仿真分析系统

python 复制代码
"""
simulation_analysis_system.py

仿真结果分析与展示系统
"""
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import numpy as np
import pandas as pd
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple
import json
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from scipy import stats, signal
import seaborn as sns
from dataclasses import dataclass
from enum import Enum
import warnings
warnings.filterwarnings('ignore')

@dataclass
class AnalysisResult:
    """分析结果数据类"""
    metrics: Dict[str, float]
    statistical_tests: Dict[str, Any]
    correlation_matrix: np.ndarray
    time_series_features: Dict[str, Any]
    frequency_features: Dict[str, Any]
    classification: str
    
class AnalysisMode(Enum):
    """分析模式"""
    BASIC = "basic"           # 基础分析
    ADVANCED = "advanced"     # 高级分析
    COMPARATIVE = "comparative"  # 对比分析
    TREND = "trend"           # 趋势分析

class SimulationAnalysisSystem:
    """仿真分析系统"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("仿真结果分析与展示系统")
        self.root.geometry("1400x900")
        
        # 分析数据
        self.analysis_data = {}
        self.analysis_results = {}
        self.current_analysis = None
        
        # 构建UI
        self.create_ui()
        
    def create_ui(self):
        """创建UI界面"""
        # 主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title_label = ttk.Label(main_container,
                               text="仿真结果分析与展示系统",
                               font=("微软雅黑", 18, "bold"),
                               foreground="#2C3E50")
        title_label.pack(pady=(0, 10))
        
        # 控制面板
        control_frame = ttk.LabelFrame(main_container, text="控制面板", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.create_control_panel(control_frame)
        
        # 分析结果显示区域
        display_frame = ttk.LabelFrame(main_container, text="分析结果", padding=10)
        display_frame.pack(fill=tk.BOTH, expand=True)
        
        self.create_display_panel(display_frame)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        # 文件操作
        file_frame = ttk.Frame(parent)
        file_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(file_frame, text="加载数据", 
                  command=self.load_data).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_frame, text="保存结果", 
                  command=self.save_results).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_frame, text="导出报告", 
                  command=self.export_report).pack(side=tk.LEFT, padx=5)
                  
        # 分析控制
        analysis_frame = ttk.Frame(parent)
        analysis_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(analysis_frame, text="分析模式:").pack(side=tk.LEFT, padx=5)
        
        self.analysis_mode_var = tk.StringVar(value=AnalysisMode.BASIC.value)
        modes = [
            ("基础分析", AnalysisMode.BASIC),
            ("高级分析", AnalysisMode.ADVANCED),
            ("对比分析", AnalysisMode.COMPARATIVE),
            ("趋势分析", AnalysisMode.TREND)
        ]
        
        for text, mode in modes:
            rb = ttk.Radiobutton(analysis_frame, text=text,
                                variable=self.analysis_mode_var,
                                value=mode.value)
            rb.pack(side=tk.LEFT, padx=5)
            
        ttk.Button(analysis_frame, text="执行分析",
                  command=self.perform_analysis).pack(side=tk.LEFT, padx=20)
                  
        # 数据选择
        data_frame = ttk.Frame(parent)
        data_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(data_frame, text="选择数据集:").pack(side=tk.LEFT, padx=5)
        
        self.dataset_var = tk.StringVar()
        self.dataset_combo = ttk.Combobox(data_frame, 
                                         textvariable=self.dataset_var,
                                         state="readonly", width=30)
        self.dataset_combo.pack(side=tk.LEFT, padx=5)
        self.dataset_combo.bind("<<ComboboxSelected>>", self.on_dataset_selected)
        
    def create_display_panel(self, parent):
        """创建显示面板"""
        # 使用Notebook组织显示
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True)
        
        # 概览标签页
        overview_tab = ttk.Frame(notebook)
        self.create_overview_tab(overview_tab)
        notebook.add(overview_tab, text="概览")
        
        # 统计分析标签页
        stats_tab = ttk.Frame(notebook)
        self.create_stats_tab(stats_tab)
        notebook.add(stats_tab, text="统计分析")
        
        # 可视化标签页
        viz_tab = ttk.Frame(notebook)
        self.create_viz_tab(viz_tab)
        notebook.add(viz_tab, text="可视化")
        
        # 报告标签页
        report_tab = ttk.Frame(notebook)
        self.create_report_tab(report_tab)
        notebook.add(report_tab, text="报告")
        
    def create_overview_tab(self, parent):
        """创建概览标签页"""
        # 使用文本和简单图表显示概览
        overview_frame = ttk.Frame(parent)
        overview_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 左侧文本信息
        left_frame = ttk.Frame(overview_frame)
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.overview_text = tk.Text(left_frame, height=20, width=40,
                                    font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(left_frame, orient=tk.VERTICAL,
                                 command=self.overview_text.yview)
        self.overview_text.configure(yscrollcommand=scrollbar.set)
        
        self.overview_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 右侧关键指标
        right_frame = ttk.Frame(overview_frame)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.metrics_frame = ttk.LabelFrame(right_frame, text="关键指标", padding=10)
        self.metrics_frame.pack(fill=tk.BOTH, expand=True)
        
    def create_stats_tab(self, parent):
        """创建统计分析标签页"""
        # 创建多个统计图表
        self.stats_fig = Figure(figsize=(10, 8), dpi=100)
        self.stats_canvas = FigureCanvasTkAgg(self.stats_fig, parent)
        self.stats_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, 
                                              padx=5, pady=5)
        
        # 创建子图网格
        self.stats_axes = []
        gs = self.stats_fig.add_gridspec(3, 3)
        
        self.ax_hist = self.stats_fig.add_subplot(gs[0, 0])
        self.ax_box = self.stats_fig.add_subplot(gs[0, 1])
        self.ax_qq = self.stats_fig.add_subplot(gs[0, 2])
        self.ax_corr = self.stats_fig.add_subplot(gs[1, :])
        self.ax_time = self.stats_fig.add_subplot(gs[2, 0])
        self.ax_freq = self.stats_fig.add_subplot(gs[2, 1])
        self.ax_acf = self.stats_fig.add_subplot(gs[2, 2])
        
        self.stats_fig.tight_layout()
        
    def create_viz_tab(self, parent):
        """创建可视化标签页"""
        # 高级可视化图表
        self.viz_fig = Figure(figsize=(10, 8), dpi=100)
        self.viz_canvas = FigureCanvasTkAgg(self.viz_fig, parent)
        self.viz_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, 
                                           padx=5, pady=5)
        
        # 创建子图
        self.viz_axes = []
        gs = self.viz_fig.add_gridspec(2, 2)
        
        self.ax_heatmap = self.viz_fig.add_subplot(gs[0, 0])
        self.ax_radar = self.viz_fig.add_subplot(gs[0, 1], projection='polar')
        self.ax_3d = self.viz_fig.add_subplot(gs[1, 0], projection='3d')
        self.ax_parallel = self.viz_fig.add_subplot(gs[1, 1])
        
    def create_report_tab(self, parent):
        """创建报告标签页"""
        # 报告文本区域
        report_frame = ttk.Frame(parent)
        report_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.report_text = tk.Text(report_frame, height=25, width=80,
                                  font=("微软雅黑", 10))
        scrollbar = ttk.Scrollbar(report_frame, orient=tk.VERTICAL,
                                 command=self.report_text.yview)
        self.report_text.configure(yscrollcommand=scrollbar.set)
        
        self.report_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def load_data(self):
        """加载数据"""
        filename = filedialog.askopenfilename(
            title="选择数据文件",
            filetypes=[
                ("JSON文件", "*.json"),
                ("CSV文件", "*.csv"),
                ("Excel文件", "*.xlsx"),
                ("所有文件", "*.*")
            ]
        )
        
        if not filename:
            return
            
        try:
            if filename.endswith('.json'):
                with open(filename, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    
            elif filename.endswith('.csv'):
                data = pd.read_csv(filename).to_dict(orient='list')
                
            elif filename.endswith('.xlsx'):
                data = pd.read_excel(filename).to_dict(orient='list')
                
            else:
                messagebox.showerror("错误", "不支持的文件格式")
                return
                
            # 处理数据
            dataset_name = filename.split('/')[-1]
            self.analysis_data[dataset_name] = data
            
            # 更新数据集选择
            self.dataset_combo['values'] = list(self.analysis_data.keys())
            
            if dataset_name not in self.dataset_combo['values']:
                self.dataset_combo['values'] = (*self.dataset_combo['values'], dataset_name)
                
            self.dataset_combo.set(dataset_name)
            
            messagebox.showinfo("成功", f"数据加载成功: {dataset_name}")
            
        except Exception as e:
            messagebox.showerror("错误", f"加载数据失败: {str(e)}")
            
    def on_dataset_selected(self, event=None):
        """数据集选择事件"""
        dataset_name = self.dataset_var.get()
        if dataset_name in self.analysis_data:
            self.current_analysis = None
            self.update_overview(self.analysis_data[dataset_name])
            
    def update_overview(self, data):
        """更新概览"""
        self.overview_text.delete(1.0, tk.END)
        
        # 显示数据基本信息
        self.overview_text.insert(1.0, "数据集概览\n")
        self.overview_text.insert(2.0, "="*50 + "\n\n")
        
        # 数据形状信息
        for key, value in data.items():
            if isinstance(value, list):
                self.overview_text.insert(tk.END, f"{key}: 长度={len(value)}\n")
                
        # 清除旧的指标显示
        for widget in self.metrics_frame.winfo_children():
            widget.destroy()
            
        # 计算并显示基本指标
        if 'performance' in data and 'az_error' in data['performance']:
            errors = data['performance']['az_error']
            
            if errors:
                metrics = {
                    '样本数': len(errors),
                    '平均值': np.mean(errors),
                    '标准差': np.std(errors),
                    '最大值': np.max(errors),
                    '最小值': np.min(errors),
                    '中位数': np.median(errors)
                }
                
                row = 0
                for name, value in metrics.items():
                    frame = ttk.Frame(self.metrics_frame)
                    frame.grid(row=row, column=0, sticky=tk.W, pady=2)
                    
                    ttk.Label(frame, text=f"{name}:").pack(side=tk.LEFT)
                    ttk.Label(frame, text=f"{value:.4f}", 
                             font=("Consolas", 9, "bold")).pack(side=tk.LEFT, padx=5)
                    
                    row += 1
                    
    def perform_analysis(self):
        """执行分析"""
        dataset_name = self.dataset_var.get()
        if dataset_name not in self.analysis_data:
            messagebox.showwarning("警告", "请先选择数据集")
            return
            
        data = self.analysis_data[dataset_name]
        mode = AnalysisMode(self.analysis_mode_var.get())
        
        try:
            if mode == AnalysisMode.BASIC:
                result = self.basic_analysis(data)
            elif mode == AnalysisMode.ADVANCED:
                result = self.advanced_analysis(data)
            elif mode == AnalysisMode.COMPARATIVE:
                result = self.comparative_analysis(data)
            elif mode == AnalysisMode.TREND:
                result = self.trend_analysis(data)
            else:
                result = self.basic_analysis(data)
                
            self.analysis_results[dataset_name] = result
            self.current_analysis = result
            
            # 更新显示
            self.update_stats_display(result, data)
            self.update_viz_display(result, data)
            self.update_report(result)
            
            messagebox.showinfo("成功", "分析完成")
            
        except Exception as e:
            messagebox.showerror("错误", f"分析失败: {str(e)}")
            
    def basic_analysis(self, data: Dict) -> AnalysisResult:
        """基础分析"""
        # 提取误差数据
        az_errors = data.get('performance', {}).get('az_error', [])
        el_errors = data.get('performance', {}).get('el_error', [])
        
        if not az_errors or not el_errors:
            raise ValueError("没有足够的数据进行分析")
            
        # 计算基本指标
        metrics = {
            'RMS方位误差': np.sqrt(np.mean(np.array(az_errors)**2)),
            'RMS俯仰误差': np.sqrt(np.mean(np.array(el_errors)**2)),
            '平均方位误差': np.mean(np.abs(az_errors)),
            '平均俯仰误差': np.mean(np.abs(el_errors)),
            '最大方位误差': np.max(np.abs(az_errors)),
            '最大俯仰误差': np.max(np.abs(el_errors)),
            '方位误差标准差': np.std(az_errors),
            '俯仰误差标准差': np.std(el_errors)
        }
        
        # 统计检验
        statistical_tests = {
            '正态性检验(方位)': stats.shapiro(az_errors) if len(az_errors) > 3 else None,
            '正态性检验(俯仰)': stats.shapiro(el_errors) if len(el_errors) > 3 else None,
            't检验(均值是否为0)': stats.ttest_1samp(az_errors, 0) if len(az_errors) > 1 else None
        }
        
        # 相关性分析
        if len(az_errors) == len(el_errors):
            correlation = np.corrcoef(az_errors, el_errors)[0, 1]
        else:
            correlation = 0
            
        correlation_matrix = np.array([[1.0, correlation], [correlation, 1.0]])
        
        # 时间序列特征
        time_series_features = {
            '自相关': self.calculate_autocorrelation(az_errors),
            '趋势': self.detect_trend(az_errors),
            '周期性': self.detect_periodicity(az_errors)
        }
        
        # 频域特征
        frequency_features = self.analyze_frequency(az_errors)
        
        # 分类
        classification = self.classify_performance(metrics)
        
        return AnalysisResult(
            metrics=metrics,
            statistical_tests=statistical_tests,
            correlation_matrix=correlation_matrix,
            time_series_features=time_series_features,
            frequency_features=frequency_features,
            classification=classification
        )
        
    def advanced_analysis(self, data: Dict) -> AnalysisResult:
        """高级分析"""
        basic_result = self.basic_analysis(data)
        
        # 添加高级分析
        az_errors = data.get('performance', {}).get('az_error', [])
        
        if len(az_errors) > 10:
            # 非线性分析
            basic_result.metrics.update({
                '近似熵': self.calculate_approximate_entropy(az_errors),
                '李雅普诺夫指数': self.estimate_lyapunov_exponent(az_errors),
                '分形维数': self.calculate_fractal_dimension(az_errors)
            })
            
            # 时频分析
            basic_result.frequency_features.update(
                self.time_frequency_analysis(az_errors)
            )
            
        return basic_result
        
    def comparative_analysis(self, data: Dict) -> AnalysisResult:
        """对比分析"""
        # 这里可以扩展为多数据集对比
        return self.basic_analysis(data)
        
    def trend_analysis(self, data: Dict) -> AnalysisResult:
        """趋势分析"""
        basic_result = self.basic_analysis(data)
        
        # 添加趋势分析
        az_errors = data.get('performance', {}).get('az_error', [])
        
        if len(az_errors) > 10:
            # 趋势检测
            trend_result = self.analyze_trend(az_errors)
            basic_result.time_series_features.update(trend_result)
            
        return basic_result
        
    def calculate_autocorrelation(self, data: List[float], max_lag: int = 20) -> List[float]:
        """计算自相关"""
        n = len(data)
        if n < 2:
            return []
            
        autocorr = []
        data_array = np.array(data)
        mean = np.mean(data_array)
        var = np.var(data_array)
        
        for lag in range(1, min(max_lag, n//2)):
            if var > 0:
                corr = np.sum((data_array[:n-lag] - mean) * (data_array[lag:] - mean)) / (n * var)
                autocorr.append(corr)
            else:
                autocorr.append(0)
                
        return autocorr
        
    def detect_trend(self, data: List[float]) -> Dict[str, Any]:
        """检测趋势"""
        if len(data) < 2:
            return {'trend': '无', 'slope': 0, 'r_squared': 0}
            
        x = np.arange(len(data))
        y = np.array(data)
        
        # 线性回归
        slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
        
        trend = '上升' if slope > 0.01 else '下降' if slope < -0.01 else '平稳'
        
        return {
            'trend': trend,
            'slope': slope,
            'intercept': intercept,
            'r_squared': r_value**2,
            'p_value': p_value
        }
        
    def detect_periodicity(self, data: List[float]) -> Dict[str, Any]:
        """检测周期性"""
        if len(data) < 10:
            return {'periodic': False, 'period': 0, 'strength': 0}
            
        # 使用FFT检测周期
        n = len(data)
        spectrum = np.abs(np.fft.fft(data))
        freq = np.fft.fftfreq(n)
        
        # 忽略直流分量
        spectrum[0] = 0
        
        # 找到主频
        idx = np.argmax(spectrum[1:n//2])
        main_freq = abs(freq[idx + 1])
        
        if main_freq > 0:
            period = 1 / main_freq
            strength = spectrum[idx + 1] / np.sum(spectrum)
            
            return {
                'periodic': strength > 0.3,
                'period': period,
                'frequency': main_freq,
                'strength': strength
            }
        else:
            return {'periodic': False, 'period': 0, 'strength': 0}
            
    def analyze_frequency(self, data: List[float]) -> Dict[str, Any]:
        """频域分析"""
        if len(data) < 10:
            return {}
            
        n = len(data)
        spectrum = np.abs(np.fft.fft(data))
        freq = np.fft.fftfreq(n)
        
        # 只取正频率
        positive_idx = np.where(freq >= 0)
        spectrum = spectrum[positive_idx]
        freq = freq[positive_idx]
        
        if len(spectrum) > 0:
            # 找到主频
            main_freq_idx = np.argmax(spectrum)
            main_freq = abs(freq[main_freq_idx])
            main_amp = spectrum[main_freq_idx]
            
            # 计算频带能量
            total_energy = np.sum(spectrum**2)
            
            # 低频能量比例
            low_freq_idx = np.where(freq <= 0.1)
            low_freq_energy = np.sum(spectrum[low_freq_idx]**2) if len(low_freq_idx[0]) > 0 else 0
            
            # 高频能量比例
            high_freq_idx = np.where(freq > 0.1)
            high_freq_energy = np.sum(spectrum[high_freq_idx]**2) if len(high_freq_idx[0]) > 0 else 0
            
            return {
                'main_frequency': main_freq,
                'main_amplitude': main_amp,
                'total_energy': total_energy,
                'low_freq_energy_ratio': low_freq_energy / total_energy if total_energy > 0 else 0,
                'high_freq_energy_ratio': high_freq_energy / total_energy if total_energy > 0 else 0,
                'spectrum_centroid': np.sum(freq * spectrum) / np.sum(spectrum) if np.sum(spectrum) > 0 else 0
            }
        else:
            return {}
            
    def classify_performance(self, metrics: Dict[str, float]) -> str:
        """性能分类"""
        rms_az = metrics.get('RMS方位误差', 0)
        
        if rms_az < 0.1:
            return "优秀"
        elif rms_az < 0.5:
            return "良好"
        elif rms_az < 1.0:
            return "一般"
        else:
            return "较差"
            
    def calculate_approximate_entropy(self, data: List[float], m: int = 2, r: float = 0.2) -> float:
        """计算近似熵"""
        # 简化实现
        n = len(data)
        if n < m + 1:
            return 0.0
            
        data_array = np.array(data)
        std = np.std(data_array)
        if std == 0:
            return 0.0
            
        r_scaled = r * std
        
        def phi(m_val):
            patterns = []
            for i in range(n - m_val + 1):
                pattern = data_array[i:i + m_val]
                patterns.append(pattern)
                
            patterns = np.array(patterns)
            count = 0
            
            for i in range(len(patterns)):
                for j in range(len(patterns)):
                    if np.max(np.abs(patterns[i] - patterns[j])) <= r_scaled:
                        count += 1
                        
            return np.log(count / len(patterns))
            
        return phi(m) - phi(m + 1)
        
    def estimate_lyapunov_exponent(self, data: List[float]) -> float:
        """估计李雅普诺夫指数"""
        # 简化实现
        n = len(data)
        if n < 10:
            return 0.0
            
        data_array = np.array(data)
        diffs = np.diff(data_array)
        
        if np.mean(np.abs(diffs)) == 0:
            return 0.0
            
        return np.log(np.mean(np.abs(diffs)) / np.mean(np.abs(data_array[:-1])))
        
    def calculate_fractal_dimension(self, data: List[float]) -> float:
        """计算分形维数"""
        # 使用盒计数法
        n = len(data)
        if n < 10:
            return 1.0
            
        data_array = np.array(data)
        data_min, data_max = np.min(data_array), np.max(data_array)
        
        if data_max == data_min:
            return 1.0
            
        # 归一化
        data_norm = (data_array - data_min) / (data_max - data_min)
        
        sizes = [2, 4, 8, 16, 32]
        counts = []
        
        for size in sizes:
            if size > n:
                break
                
            # 计算盒子数
            box_size = n / size
            grid = np.zeros((size, size))
            
            for i in range(n):
                x = int(i / box_size)
                y = int(data_norm[i] * (size - 1))
                grid[x, y] = 1
                
            counts.append(np.sum(grid > 0))
            
        if len(counts) < 2:
            return 1.0
            
        # 线性拟合
        x = np.log(sizes[:len(counts)])
        y = np.log(counts)
        
        slope, _, _, _, _ = stats.linregress(x, y)
        
        return -slope
        
    def time_frequency_analysis(self, data: List[float]) -> Dict[str, Any]:
        """时频分析"""
        if len(data) < 32:
            return {}
            
        # 短时傅里叶变换
        f, t, Zxx = signal.stft(data, fs=1.0, nperseg=min(32, len(data)//4))
        
        return {
            'stft_frequencies': f.tolist(),
            'stft_times': t.tolist(),
            'stft_magnitude': np.abs(Zxx).tolist()
        }
        
    def analyze_trend(self, data: List[float]) -> Dict[str, Any]:
        """趋势分析"""
        n = len(data)
        if n < 10:
            return {}
            
        data_array = np.array(data)
        x = np.arange(n)
        
        # 线性趋势
        linear_slope, intercept, r_value, p_value, _ = stats.linregress(x, data_array)
        
        # 移动平均趋势
        window = min(5, n//4)
        ma = np.convolve(data_array, np.ones(window)/window, mode='valid')
        
        # 趋势转折点
        turning_points = self.find_turning_points(data_array)
        
        return {
            'linear_slope': linear_slope,
            'linear_r_squared': r_value**2,
            'linear_p_value': p_value,
            'moving_average': ma.tolist(),
            'turning_points': turning_points
        }
        
    def find_turning_points(self, data: np.ndarray) -> List[int]:
        """找到转折点"""
        turning_points = []
        
        for i in range(1, len(data)-1):
            if (data[i] > data[i-1] and data[i] > data[i+1]) or \
               (data[i] < data[i-1] and data[i] < data[i+1]):
                turning_points.append(i)
                
        return turning_points
        
    def update_stats_display(self, result: AnalysisResult, data: Dict):
        """更新统计显示"""
        # 清除所有子图
        for ax in [self.ax_hist, self.ax_box, self.ax_qq, 
                  self.ax_corr, self.ax_time, self.ax_freq, self.ax_acf]:
            ax.clear()
            
        # 提取数据
        az_errors = data.get('performance', {}).get('az_error', [])
        el_errors = data.get('performance', {}).get('el_error', [])
        
        if not az_errors or not el_errors:
            return
            
        # 1. 直方图
        self.ax_hist.hist(az_errors, bins=20, alpha=0.7, color='blue', edgecolor='black')
        self.ax_hist.set_title('方位误差分布')
        self.ax_hist.set_xlabel('误差 (°)')
        self.ax_hist.set_ylabel('频数')
        self.ax_hist.grid(True, alpha=0.3)
        
        # 添加正态分布曲线
        mu, std = np.mean(az_errors), np.std(az_errors)
        x = np.linspace(min(az_errors), max(az_errors), 100)
        p = (1/(std*np.sqrt(2*np.pi))) * np.exp(-0.5*((x-mu)/std)**2)
        p = p * len(az_errors) * (max(az_errors)-min(az_errors))/20
        self.ax_hist.plot(x, p, 'r-', linewidth=2)
        
        # 2. 箱线图
        error_data = [az_errors, el_errors]
        bp = self.ax_box.boxplot(error_data, labels=['方位', '俯仰'])
        self.ax_box.set_title('误差箱线图')
        self.ax_box.set_ylabel('误差 (°)')
        self.ax_box.grid(True, alpha=0.3)
        
        # 3. Q-Q图
        stats.probplot(az_errors, dist="norm", plot=self.ax_qq)
        self.ax_qq.set_title('Q-Q图')
        self.ax_qq.grid(True, alpha=0.3)
        
        # 4. 相关性矩阵
        corr_matrix = result.correlation_matrix
        im = self.ax_corr.matshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1)
        self.ax_corr.set_title('相关性矩阵')
        self.ax_corr.set_xticks([0, 1])
        self.ax_corr.set_yticks([0, 1])
        self.ax_corr.set_xticklabels(['方位', '俯仰'])
        self.ax_corr.set_yticklabels(['方位', '俯仰'])
        
        # 添加数值标签
        for i in range(corr_matrix.shape[0]):
            for j in range(corr_matrix.shape[1]):
                self.ax_corr.text(j, i, f'{corr_matrix[i, j]:.2f}', 
                                 ha='center', va='center', color='white')
        
        # 5. 时间序列
        time_data = data.get('performance', {}).get('time', list(range(len(az_errors))))
        self.ax_time.plot(time_data[:100], az_errors[:100], 'b-', linewidth=1)
        self.ax_time.set_title('时间序列')
        self.ax_time.set_xlabel('时间')
        self.ax_time.set_ylabel('方位误差 (°)')
        self.ax_time.grid(True, alpha=0.3)
        
        # 6. 频域分析
        if len(az_errors) > 10:
            spectrum = np.abs(np.fft.fft(az_errors))
            freq = np.fft.fftfreq(len(az_errors))
            
            self.ax_freq.plot(freq[:len(freq)//2], spectrum[:len(spectrum)//2], 'g-')
            self.ax_freq.set_title('频谱')
            self.ax_freq.set_xlabel('频率')
            self.ax_freq.set_ylabel('幅度')
            self.ax_freq.grid(True, alpha=0.3)
            
        # 7. 自相关函数
        autocorr = result.time_series_features.get('自相关', [])
        if autocorr:
            self.ax_acf.stem(range(1, len(autocorr)+1), autocorr, basefmt=" ")
            self.ax_acf.set_title('自相关函数')
            self.ax_acf.set_xlabel('滞后')
            self.ax_acf.set_ylabel('自相关')
            self.ax_acf.grid(True, alpha=0.3)
            
        self.stats_fig.tight_layout()
        self.stats_canvas.draw_idle()
        
    def update_viz_display(self, result: AnalysisResult, data: Dict):
        """更新可视化显示"""
        # 清除所有子图
        for ax in [self.ax_heatmap, self.ax_radar, self.ax_3d, self.ax_parallel]:
            ax.clear()
            
        # 提取数据
        az_errors = data.get('performance', {}).get('az_error', [])
        el_errors = data.get('performance', {}).get('el_error', [])
        
        if not az_errors or not el_errors:
            return
            
        # 1. 热力图 (误差散布)
        if len(az_errors) > 10 and len(el_errors) > 10:
            heatmap, xedges, yedges = np.histogram2d(az_errors[:100], el_errors[:100], bins=20)
            extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
            
            im = self.ax_heatmap.imshow(heatmap.T, extent=extent, origin='lower',
                                       aspect='auto', cmap='hot')
            self.ax_heatmap.set_title('误差散布热力图')
            self.ax_heatmap.set_xlabel('方位误差 (°)')
            self.ax_heatmap.set_ylabel('俯仰误差 (°)')
            self.ax_heatmap.figure.colorbar(im, ax=self.ax_heatmap)
            
        # 2. 雷达图 (性能指标)
        if result.metrics:
            # 选择几个关键指标
            selected_metrics = ['RMS方位误差', 'RMS俯仰误差', 
                               '平均方位误差', '平均俯仰误差',
                               '最大方位误差', '最大俯仰误差']
            
            values = []
            labels = []
            
            for metric in selected_metrics:
                if metric in result.metrics:
                    # 归一化
                    value = result.metrics[metric]
                    values.append(min(value / 5.0, 1.0))  # 假设最大值为5
                    labels.append(metric)
                    
            if len(values) >= 3:
                # 创建雷达图
                angles = np.linspace(0, 2*np.pi, len(values), endpoint=False).tolist()
                values += values[:1]  # 闭合图形
                angles += angles[:1]
                
                self.ax_radar.clear()
                self.ax_radar = self.viz_fig.add_subplot(2, 2, 2, projection='polar')
                self.ax_radar.plot(angles, values, 'o-', linewidth=2)
                self.ax_radar.fill(angles, values, alpha=0.25)
                self.ax_radar.set_xticks(angles[:-1])
                self.ax_radar.set_xticklabels(labels[:-1], fontsize=8)
                self.ax_radar.set_title('性能指标雷达图')
                self.ax_radar.grid(True)
                
        # 3. 3D图 (误差轨迹)
        if len(az_errors) > 10 and len(el_errors) > 10:
            time_data = data.get('performance', {}).get('time', list(range(len(az_errors))))
            
            # 只取前100个点
            n_points = min(100, len(az_errors))
            x = az_errors[:n_points]
            y = el_errors[:n_points]
            z = time_data[:n_points]
            
            self.ax_3d.clear()
            self.ax_3d = self.viz_fig.add_subplot(2, 2, 3, projection='3d')
            self.ax_3d.plot(x, y, z, 'b-', linewidth=1)
            self.ax_3d.scatter(x, y, z, c=z, cmap='viridis', s=20)
            self.ax_3d.set_xlabel('方位误差')
            self.ax_3d.set_ylabel('俯仰误差')
            self.ax_3d.set_zlabel('时间')
            self.ax_3d.set_title('误差轨迹3D图')
            
        # 4. 平行坐标图
        if len(az_errors) > 10 and len(el_errors) > 10:
            # 使用多个指标
            metrics_data = []
            for i in range(min(20, len(az_errors))):
                point_metrics = {
                    'az_error': az_errors[i],
                    'el_error': el_errors[i],
                    'total_error': np.sqrt(az_errors[i]**2 + el_errors[i]**2)
                }
                metrics_data.append(point_metrics)
                
            if metrics_data:
                df = pd.DataFrame(metrics_data)
                
                # 标准化
                df_normalized = (df - df.min()) / (df.max() - df.min())
                
                # 绘制平行坐标
                for i in range(len(df_normalized)):
                    self.ax_parallel.plot(df_normalized.columns, 
                                         df_normalized.iloc[i].values, 
                                         color='blue', alpha=0.3, linewidth=0.5)
                    
                self.ax_parallel.set_title('平行坐标图')
                self.ax_parallel.set_xlabel('指标')
                self.ax_parallel.set_ylabel('归一化值')
                self.ax_parallel.set_xticklabels(df.columns, rotation=45)
                self.ax_parallel.grid(True, alpha=0.3)
                
        self.viz_fig.tight_layout()
        self.viz_canvas.draw_idle()
        
    def update_report(self, result: AnalysisResult):
        """更新报告"""
        self.report_text.delete(1.0, tk.END)
        
        # 生成报告
        report = "仿真结果分析报告\n"
        report += "="*50 + "\n\n"
        
        report += f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
        
        report += "1. 性能指标\n"
        report += "-"*30 + "\n"
        for name, value in result.metrics.items():
            report += f"{name}: {value:.4f}\n"
        report += f"\n性能分类: {result.classification}\n\n"
        
        report += "2. 统计检验\n"
        report += "-"*30 + "\n"
        for name, test_result in result.statistical_tests.items():
            if test_result:
                if hasattr(test_result, 'pvalue'):
                    report += f"{name}: p值 = {test_result.pvalue:.4f}\n"
                else:
                    report += f"{name}: {test_result}\n"
            else:
                report += f"{name}: 数据不足\n"
        report += "\n"
        
        report += "3. 时间序列特征\n"
        report += "-"*30 + "\n"
        for name, value in result.time_series_features.items():
            if isinstance(value, dict):
                report += f"{name}:\n"
                for sub_name, sub_value in value.items():
                    if isinstance(sub_value, float):
                        report += f"  {sub_name}: {sub_value:.4f}\n"
                    else:
                        report += f"  {sub_name}: {sub_value}\n"
            else:
                report += f"{name}: {value}\n"
        report += "\n"
        
        report += "4. 频域特征\n"
        report += "-"*30 + "\n"
        for name, value in result.frequency_features.items():
            if isinstance(value, float):
                report += f"{name}: {value:.4f}\n"
            else:
                report += f"{name}: {value}\n"
                
        self.report_text.insert(1.0, report)
        
    def save_results(self):
        """保存分析结果"""
        if not self.current_analysis:
            messagebox.showwarning("警告", "没有可保存的分析结果")
            return
            
        filename = filedialog.asksaveasfilename(
            title="保存分析结果",
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            # 转换结果为可序列化格式
            result_dict = {
                'metrics': self.current_analysis.metrics,
                'classification': self.current_analysis.classification,
                'correlation_matrix': self.current_analysis.correlation_matrix.tolist(),
                'timestamp': datetime.now().isoformat()
            }
            
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(result_dict, f, indent=2, ensure_ascii=False)
                
            messagebox.showinfo("成功", "分析结果保存成功")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存失败: {str(e)}")
            
    def export_report(self):
        """导出报告"""
        if not self.report_text.get(1.0, tk.END).strip():
            messagebox.showwarning("警告", "没有可导出的报告")
            return
            
        filename = filedialog.asksaveasfilename(
            title="导出报告",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        
        if not filename:
            return
            
        try:
            report_content = self.report_text.get(1.0, tk.END)
            
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(report_content)
                
            messagebox.showinfo("成功", "报告导出成功")
            
        except Exception as e:
            messagebox.showerror("错误", f"导出失败: {str(e)}")

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = SimulationAnalysisSystem(root)
    
    # 窗口居中
    root.update_idletasks()
    width = root.winfo_width()
    height = root.winfo_height()
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    root.geometry(f'{width}x{height}+{x}+{y}')
    
    root.mainloop()

9. 系统测试与验证

9.1 综合测试框架

python 复制代码
"""
system_test_framework.py

系统测试与验证框架
"""
import tkinter as tk
from tkinter import ttk, messagebox
import threading
import time
import numpy as np
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass, field
from enum import Enum
import json
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class TestStatus(Enum):
    """测试状态"""
    PENDING = "pending"      # 等待
    RUNNING = "running"      # 运行中
    PASSED = "passed"        # 通过
    FAILED = "failed"        # 失败
    SKIPPED = "skipped"      # 跳过

@dataclass
class TestCase:
    """测试用例"""
    name: str
    description: str
    test_function: Callable
    timeout: float = 10.0
    enabled: bool = True
    expected_result: Any = None
    
@dataclass
class TestResult:
    """测试结果"""
    test_case: TestCase
    status: TestStatus
    execution_time: float
    error_message: str = ""
    actual_result: Any = None
    metrics: Dict[str, Any] = field(default_factory=dict)
    
class SystemTestFramework:
    """系统测试框架"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("系统测试与验证框架")
        self.root.geometry("1200x800")
        
        # 测试用例
        self.test_cases: List[TestCase] = []
        self.test_results: List[TestResult] = []
        
        # 测试状态
        self.testing = False
        self.current_test_index = 0
        
        # 构建UI
        self.create_ui()
        
        # 注册默认测试用例
        self.register_default_tests()
        
    def create_ui(self):
        """创建UI界面"""
        # 主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title_label = ttk.Label(main_container,
                               text="雷达电子对抗仿真系统测试框架",
                               font=("微软雅黑", 18, "bold"),
                               foreground="#2C3E50")
        title_label.pack(pady=(0, 10))
        
        # 控制面板
        control_frame = ttk.LabelFrame(main_container, text="控制面板", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.create_control_panel(control_frame)
        
        # 测试用例面板
        test_case_frame = ttk.LabelFrame(main_container, text="测试用例", padding=10)
        test_case_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        self.create_test_case_panel(test_case_frame)
        
        # 结果面板
        result_frame = ttk.LabelFrame(main_container, text="测试结果", padding=10)
        result_frame.pack(fill=tk.BOTH, expand=True)
        
        self.create_result_panel(result_frame)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        # 按钮框架
        button_frame = ttk.Frame(parent)
        button_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(button_frame, text="运行所有测试", 
                  command=self.run_all_tests).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="运行选中测试", 
                  command=self.run_selected_tests).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="停止测试", 
                  command=self.stop_tests).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="生成报告", 
                  command=self.generate_report).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清空结果", 
                  command=self.clear_results).pack(side=tk.LEFT, padx=5)
                  
        # 进度条
        self.progress_var = tk.DoubleVar(value=0.0)
        self.progress_bar = ttk.Progressbar(parent, variable=self.progress_var,
                                           mode='determinate')
        self.progress_bar.pack(fill=tk.X, pady=5)
        
        # 状态标签
        self.status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(parent, textvariable=self.status_var,
                                font=("微软雅黑", 10), foreground="#2C3E50")
        status_label.pack(pady=5)
        
    def create_test_case_panel(self, parent):
        """创建测试用例面板"""
        # 使用Treeview显示测试用例
        columns = ("选择", "名称", "描述", "状态", "时间")
        self.test_tree = ttk.Treeview(parent, columns=columns, show="headings", height=10)
        
        # 设置列标题
        for col in columns:
            self.test_tree.heading(col, text=col)
            if col == "选择":
                self.test_tree.column(col, width=50, anchor=tk.CENTER)
            elif col == "状态":
                self.test_tree.column(col, width=80, anchor=tk.CENTER)
            elif col == "时间":
                self.test_tree.column(col, width=100, anchor=tk.CENTER)
            else:
                self.test_tree.column(col, width=200)
                
        # 添加滚动条
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.test_tree.yview)
        self.test_tree.configure(yscrollcommand=scrollbar.set)
        
        self.test_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 绑定选择事件
        self.test_tree.bind("<Button-1>", self.on_tree_click)
        
    def create_result_panel(self, parent):
        """创建结果面板"""
        # 使用Notebook组织结果
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True)
        
        # 详细结果标签页
        detail_tab = ttk.Frame(notebook)
        self.create_detail_result_tab(detail_tab)
        notebook.add(detail_tab, text="详细结果")
        
        # 统计标签页
        stats_tab = ttk.Frame(notebook)
        self.create_stats_tab(stats_tab)
        notebook.add(stats_tab, text="统计")
        
        # 图表标签页
        chart_tab = ttk.Frame(notebook)
        self.create_chart_tab(chart_tab)
        notebook.add(chart_tab, text="图表")
        
    def create_detail_result_tab(self, parent):
        """创建详细结果标签页"""
        # 文本显示区域
        self.result_text = tk.Text(parent, height=15, width=80,
                                  font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL,
                                 command=self.result_text.yview)
        self.result_text.configure(yscrollcommand=scrollbar.set)
        
        self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_stats_tab(self, parent):
        """创建统计标签页"""
        # 统计信息框架
        stats_frame = ttk.Frame(parent)
        stats_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 统计指标
        self.stats_vars = {
            'total': tk.StringVar(value="0"),
            'passed': tk.StringVar(value="0"),
            'failed': tk.StringVar(value="0"),
            'skipped': tk.StringVar(value="0"),
            'success_rate': tk.StringVar(value="0%"),
            'total_time': tk.StringVar(value="0.0s")
        }
        
        row = 0
        for label, var in self.stats_vars.items():
            frame = ttk.Frame(stats_frame)
            frame.grid(row=row, column=0, sticky=tk.W, pady=5)
            
            ttk.Label(frame, text=f"{label.replace('_', ' ').title()}:").pack(side=tk.LEFT)
            ttk.Label(frame, textvariable=var, font=("Consolas", 10, "bold")).pack(side=tk.LEFT, padx=5)
            row += 1
            
    def create_chart_tab(self, parent):
        """创建图表标签页"""
        # 创建matplotlib图表
        self.chart_fig = Figure(figsize=(8, 6), dpi=100)
        self.chart_canvas = FigureCanvasTkAgg(self.chart_fig, parent)
        self.chart_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 创建子图
        self.ax_pie = self.chart_fig.add_subplot(221)
        self.ax_bar = self.chart_fig.add_subplot(222)
        self.ax_time = self.chart_fig.add_subplot(212)
        
        self.chart_fig.tight_layout()
        
    def register_default_tests(self):
        """注册默认测试用例"""
        # 功能测试
        self.add_test_case(TestCase(
            name="系统初始化测试",
            description="测试系统能否正常初始化",
            test_function=self.test_system_initialization,
            timeout=5.0
        ))
        
        self.add_test_case(TestCase(
            name="单脉冲导引头模型测试",
            description="测试单脉冲导引头模型的正确性",
            test_function=self.test_monopulse_model,
            timeout=10.0
        ))
        
        self.add_test_case(TestCase(
            name="交叉眼干扰模型测试",
            description="测试交叉眼干扰模型的正确性",
            test_function=self.test_cross_eye_model,
            timeout=10.0
        ))
        
        self.add_test_case(TestCase(
            name="UI界面测试",
            description="测试UI界面能否正常创建和响应",
            test_function=self.test_ui_interface,
            timeout=8.0
        ))
        
        self.add_test_case(TestCase(
            name="数据可视化测试",
            description="测试数据可视化功能",
            test_function=self.test_data_visualization,
            timeout=8.0
        ))
        
        self.add_test_case(TestCase(
            name="性能测试",
            description="测试系统性能指标",
            test_function=self.test_performance,
            timeout=15.0
        ))
        
        self.add_test_case(TestCase(
            name="稳定性测试",
            description="测试系统长时间运行的稳定性",
            test_function=self.test_stability,
            timeout=20.0
        ))
        
        # 边界测试
        self.add_test_case(TestCase(
            name="边界条件测试",
            description="测试系统在边界条件下的行为",
            test_function=self.test_boundary_conditions,
            timeout=5.0
        ))
        
        # 错误处理测试
        self.add_test_case(TestCase(
            name="错误处理测试",
            description="测试系统的错误处理能力",
            test_function=self.test_error_handling,
            timeout=5.0
        ))
        
    def add_test_case(self, test_case: TestCase):
        """添加测试用例"""
        self.test_cases.append(test_case)
        self.update_test_tree()
        
    def update_test_tree(self):
        """更新测试用例树"""
        # 清除现有项
        for item in self.test_tree.get_children():
            self.test_tree.delete(item)
            
        # 添加测试用例
        for i, test_case in enumerate(self.test_cases):
            # 查找对应的结果
            result = self.find_test_result(test_case)
            status = result.status if result else TestStatus.PENDING
            exec_time = f"{result.execution_time:.2f}s" if result else ""
            
            # 插入项
            item_id = self.test_tree.insert("", tk.END, values=(
                "✓" if test_case.enabled else "✗",
                test_case.name,
                test_case.description,
                status.value,
                exec_time
            ))
            
            # 设置颜色
            self.update_tree_item_color(item_id, status)
            
    def find_test_result(self, test_case: TestCase) -> Optional[TestResult]:
        """查找测试结果"""
        for result in self.test_results:
            if result.test_case.name == test_case.name:
                return result
        return None
        
    def update_tree_item_color(self, item_id, status: TestStatus):
        """更新树项颜色"""
        colors = {
            TestStatus.PENDING: "#FFFFFF",  # 白色
            TestStatus.RUNNING: "#3498DB",  # 蓝色
            TestStatus.PASSED: "#2ECC71",   # 绿色
            TestStatus.FAILED: "#E74C3C",   # 红色
            TestStatus.SKIPPED: "#95A5A6"   # 灰色
        }
        
        color = colors.get(status, "#FFFFFF")
        
        # 设置行颜色
        self.test_tree.tag_configure(status.value, background=color)
        self.test_tree.item(item_id, tags=(status.value,))
        
    def on_tree_click(self, event):
        """树控件点击事件"""
        region = self.test_tree.identify_region(event.x, event.y)
        if region == "cell":
            column = self.test_tree.identify_column(event.x)
            item = self.test_tree.identify_row(event.y)
            
            if column == "#1":  # 选择列
                # 切换选择状态
                values = self.test_tree.item(item, "values")
                test_name = values[1]
                
                # 找到对应的测试用例
                for test_case in self.test_cases:
                    if test_case.name == test_name:
                        test_case.enabled = not test_case.enabled
                        new_values = list(values)
                        new_values[0] = "✓" if test_case.enabled else "✗"
                        self.test_tree.item(item, values=tuple(new_values))
                        break
                        
    def run_all_tests(self):
        """运行所有测试"""
        enabled_tests = [tc for tc in self.test_cases if tc.enabled]
        if not enabled_tests:
            messagebox.showwarning("警告", "没有启用的测试用例")
            return
            
        self.run_tests(enabled_tests)
        
    def run_selected_tests(self):
        """运行选中的测试"""
        selected_items = self.test_tree.selection()
        if not selected_items:
            messagebox.showwarning("警告", "请先选择测试用例")
            return
            
        selected_tests = []
        for item in selected_items:
            values = self.test_tree.item(item, "values")
            test_name = values[1]
            
            for test_case in self.test_cases:
                if test_case.name == test_name:
                    selected_tests.append(test_case)
                    break
                    
        if selected_tests:
            self.run_tests(selected_tests)
            
    def run_tests(self, tests: List[TestCase]):
        """运行测试用例列表"""
        if self.testing:
            return
            
        self.testing = True
        self.current_test_index = 0
        self.status_var.set("测试运行中...")
        
        # 重置进度条
        self.progress_var.set(0.0)
        
        # 在后台线程中运行测试
        self.test_thread = threading.Thread(target=self.run_tests_thread, args=(tests,), daemon=True)
        self.test_thread.start()
        
    def run_tests_thread(self, tests: List[TestCase]):
        """在后台线程中运行测试"""
        total_tests = len(tests)
        
        for i, test_case in enumerate(tests):
            if not self.testing:
                break
                
            self.current_test_index = i
            
            # 更新状态
            self.root.after(0, lambda tc=test_case: self.status_var.set(f"正在运行: {tc.name}"))
            
            # 运行测试
            result = self.run_single_test(test_case)
            
            # 存储结果
            self.test_results.append(result)
            
            # 更新UI
            self.root.after(0, self.update_test_result, result)
            
            # 更新进度
            progress = (i + 1) / total_tests * 100
            self.root.after(0, self.progress_var.set, progress)
            
        # 测试完成
        self.testing = False
        self.root.after(0, lambda: self.status_var.set("测试完成"))
        
        # 更新统计和图表
        self.root.after(0, self.update_stats)
        self.root.after(0, self.update_charts)
        
    def run_single_test(self, test_case: TestCase) -> TestResult:
        """运行单个测试用例"""
        start_time = time.time()
        error_message = ""
        actual_result = None
        metrics = {}
        
        try:
            # 设置超时
            import signal
            
            class TimeoutException(Exception):
                pass
                
            def timeout_handler(signum, frame):
                raise TimeoutException("测试超时")
                
            # 设置信号处理
            signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(int(test_case.timeout))
            
            try:
                # 执行测试
                actual_result = test_case.test_function()
                
                # 验证结果
                if test_case.expected_result is not None:
                    if actual_result != test_case.expected_result:
                        raise AssertionError(f"期望结果: {test_case.expected_result}, 实际结果: {actual_result}")
                        
                status = TestStatus.PASSED
                
            except TimeoutException as e:
                error_message = str(e)
                status = TestStatus.FAILED
            except Exception as e:
                error_message = str(e)
                status = TestStatus.FAILED
            finally:
                signal.alarm(0)  # 取消超时
                
        except Exception as e:
            error_message = f"测试框架错误: {str(e)}"
            status = TestStatus.FAILED
            
        execution_time = time.time() - start_time
        
        return TestResult(
            test_case=test_case,
            status=status,
            execution_time=execution_time,
            error_message=error_message,
            actual_result=actual_result,
            metrics=metrics
        )
        
    def update_test_result(self, result: TestResult):
        """更新测试结果"""
        # 更新树控件
        for item in self.test_tree.get_children():
            values = self.test_tree.item(item, "values")
            if values[1] == result.test_case.name:
                new_values = list(values)
                new_values[3] = result.status.value
                new_values[4] = f"{result.execution_time:.2f}s"
                self.test_tree.item(item, values=tuple(new_values))
                
                # 更新颜色
                self.update_tree_item_color(item, result.status)
                break
                
        # 更新详细结果
        self.update_detail_result(result)
        
    def update_detail_result(self, result: TestResult):
        """更新详细结果"""
        detail = f"测试用例: {result.test_case.name}\n"
        detail += f"描述: {result.test_case.description}\n"
        detail += f"状态: {result.status.value}\n"
        detail += f"执行时间: {result.execution_time:.2f}s\n"
        
        if result.error_message:
            detail += f"错误信息: {result.error_message}\n"
            
        if result.actual_result is not None:
            detail += f"实际结果: {result.actual_result}\n"
            
        detail += "-" * 50 + "\n"
        
        self.result_text.insert(tk.END, detail)
        self.result_text.see(tk.END)  # 滚动到最后
        
    def update_stats(self):
        """更新统计信息"""
        if not self.test_results:
            return
            
        total = len(self.test_results)
        passed = len([r for r in self.test_results if r.status == TestStatus.PASSED])
        failed = len([r for r in self.test_results if r.status == TestStatus.FAILED])
        skipped = len([r for r in self.test_results if r.status == TestStatus.SKIPPED])
        success_rate = (passed / total * 100) if total > 0 else 0
        total_time = sum(r.execution_time for r in self.test_results)
        
        self.stats_vars['total'].set(str(total))
        self.stats_vars['passed'].set(str(passed))
        self.stats_vars['failed'].set(str(failed))
        self.stats_vars['skipped'].set(str(skipped))
        self.stats_vars['success_rate'].set(f"{success_rate:.1f}%")
        self.stats_vars['total_time'].set(f"{total_time:.2f}s")
        
    def update_charts(self):
        """更新图表"""
        if not self.test_results:
            return
            
        # 清除现有图表
        self.ax_pie.clear()
        self.ax_bar.clear()
        self.ax_time.clear()
        
        # 统计测试状态
        status_counts = {}
        for result in self.test_results:
            status = result.status.value
            status_counts[status] = status_counts.get(status, 0) + 1
            
        # 1. 饼图
        if status_counts:
            labels = list(status_counts.keys())
            sizes = list(status_counts.values())
            colors = ['#2ECC71', '#E74C3C', '#95A5A6', '#3498DB']
            
            self.ax_pie.pie(sizes, labels=labels, colors=colors[:len(labels)], 
                           autopct='%1.1f%%', startangle=90)
            self.ax_pie.set_title('测试状态分布')
            self.ax_pie.axis('equal')
            
        # 2. 柱状图
        test_names = [r.test_case.name for r in self.test_results]
        exec_times = [r.execution_time for r in self.test_results]
        status_colors = []
        
        for result in self.test_results:
            if result.status == TestStatus.PASSED:
                status_colors.append('#2ECC71')
            elif result.status == TestStatus.FAILED:
                status_colors.append('#E74C3C')
            elif result.status == TestStatus.SKIPPED:
                status_colors.append('#95A5A6')
            else:
                status_colors.append('#3498DB')
                
        bars = self.ax_bar.bar(range(len(test_names)), exec_times, color=status_colors)
        self.ax_bar.set_xlabel('测试用例')
        self.ax_bar.set_ylabel('执行时间 (s)')
        self.ax_bar.set_title('测试执行时间')
        self.ax_bar.set_xticks(range(len(test_names)))
        self.ax_bar.set_xticklabels(test_names, rotation=45, ha='right')
        
        # 3. 时间序列图
        if len(self.test_results) > 1:
            cumulative_time = np.cumsum(exec_times)
            test_indices = range(1, len(self.test_results) + 1)
            
            self.ax_time.plot(test_indices, cumulative_time, 'b-', marker='o')
            self.ax_time.set_xlabel('测试序号')
            self.ax_time.set_ylabel('累计时间 (s)')
            self.ax_time.set_title('累计执行时间')
            self.ax_time.grid(True, alpha=0.3)
            
        self.chart_fig.tight_layout()
        self.chart_canvas.draw_idle()
        
    def stop_tests(self):
        """停止测试"""
        self.testing = False
        self.status_var.set("测试已停止")
        
    def generate_report(self):
        """生成测试报告"""
        if not self.test_results:
            messagebox.showwarning("警告", "没有测试结果")
            return
            
        import datetime
        
        report = "雷达电子对抗仿真系统测试报告\n"
        report += "=" * 50 + "\n\n"
        report += f"生成时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
        
        # 统计信息
        total = len(self.test_results)
        passed = len([r for r in self.test_results if r.status == TestStatus.PASSED])
        failed = len([r for r in self.test_results if r.status == TestStatus.FAILED])
        skipped = len([r for r in self.test_results if r.status == TestStatus.SKIPPED])
        success_rate = (passed / total * 100) if total > 0 else 0
        total_time = sum(r.execution_time for r in self.test_results)
        
        report += "统计信息:\n"
        report += f"  总测试数: {total}\n"
        report += f"  通过: {passed}\n"
        report += f"  失败: {failed}\n"
        report += f"  跳过: {skipped}\n"
        report += f"  成功率: {success_rate:.1f}%\n"
        report += f"  总执行时间: {total_time:.2f}s\n\n"
        
        # 详细结果
        report += "详细结果:\n"
        report += "-" * 50 + "\n"
        
        for result in self.test_results:
            report += f"测试用例: {result.test_case.name}\n"
            report += f"状态: {result.status.value}\n"
            report += f"执行时间: {result.execution_time:.2f}s\n"
            
            if result.error_message:
                report += f"错误信息: {result.error_message}\n"
                
            report += "\n"
            
        # 显示报告
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(1.0, report)
        
        # 询问是否保存
        if messagebox.askyesno("保存报告", "是否保存测试报告到文件?"):
            self.save_report_to_file(report)
            
    def save_report_to_file(self, report: str):
        """保存报告到文件"""
        import os
        from tkinter import filedialog
        
        filename = filedialog.asksaveasfilename(
            title="保存测试报告",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        
        if filename:
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(report)
                messagebox.showinfo("成功", f"报告已保存到: {filename}")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败: {str(e)}")
                
    def clear_results(self):
        """清空结果"""
        if self.testing:
            messagebox.showwarning("警告", "测试运行中,无法清空结果")
            return
            
        if messagebox.askyesno("确认", "确定要清空所有测试结果吗?"):
            self.test_results.clear()
            self.result_text.delete(1.0, tk.END)
            self.update_test_tree()
            self.update_stats()
            
            # 清除图表
            self.ax_pie.clear()
            self.ax_bar.clear()
            self.ax_time.clear()
            self.chart_canvas.draw_idle()
            
    # 以下是具体的测试用例实现
    def test_system_initialization(self):
        """测试系统初始化"""
        # 模拟系统初始化
        time.sleep(0.5)  # 模拟初始化时间
        
        # 检查关键组件
        components = ['seeker', 'jammer', 'target', 'environment']
        
        for component in components:
            if not hasattr(self, f'{component}_model'):
                return False
                
        return True
        
    def test_monopulse_model(self):
        """测试单脉冲导引头模型"""
        from monopulse_seeker_model import MonopulseSeekerModel, SeekerParameters
        
        try:
            # 创建模型
            params = SeekerParameters()
            seeker = MonopulseSeekerModel(params)
            
            # 测试基本功能
            test_cases = [
                (0.0, 0.0, 5.0),   # 正前方目标
                (1.0, 0.5, 5.0),   # 有角度目标
                (-0.5, 0.3, 3.0),  # 另一角度目标
            ]
            
            for az, el, rcs in test_cases:
                # 测试更新功能
                from cross_eye_jamming import TargetState
                target = TargetState(
                    range=10000, azimuth=az, elevation=el,
                    range_rate=-100, azimuth_rate=0, elevation_rate=0,
                    rcs=rcs, snr=20.0
                )
                
                error_az, error_el = seeker.update_target(target)
                
                # 检查返回值
                if not isinstance(error_az, (int, float)):
                    return False
                if not isinstance(error_el, (int, float)):
                    return False
                    
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_cross_eye_model(self):
        """测试交叉眼干扰模型"""
        from cross_eye_jamming import CrossEyeJammer, JammerParameters
        
        try:
            # 创建模型
            params = JammerParameters()
            jammer = CrossEyeJammer(params)
            
            # 测试基本功能
            from monopulse_seeker_model import TargetState
            
            target = TargetState(
                range=10000, azimuth=1.0, elevation=0.5,
                range_rate=-100, azimuth_rate=0, elevation_rate=0,
                rcs=5.0, snr=20.0
            )
            
            seeker_state = {
                'azimuth': 0.0,
                'elevation': 0.0,
                'tracking_lock': True
            }
            
            # 测试干扰信号计算
            sigma_j, delta_az_j, delta_el_j = jammer.calculate_jamming_signal(
                target, seeker_state, 0.0
            )
            
            # 检查返回值
            if not isinstance(sigma_j, complex):
                return False
            if not isinstance(delta_az_j, complex):
                return False
            if not isinstance(delta_el_j, complex):
                return False
                
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_ui_interface(self):
        """测试UI界面"""
        try:
            # 检查主要UI组件是否存在
            required_widgets = [
                'test_tree', 'result_text', 'progress_bar',
                'status_var', 'progress_var'
            ]
            
            for widget_name in required_widgets:
                if not hasattr(self, widget_name):
                    return False
                    
            # 测试UI响应
            self.root.update()
            
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_data_visualization(self):
        """测试数据可视化"""
        try:
            # 生成测试数据
            import numpy as np
            
            # 测试matplotlib集成
            fig = Figure(figsize=(6, 4), dpi=100)
            ax = fig.add_subplot(111)
            
            x = np.linspace(0, 10, 100)
            y = np.sin(x)
            
            ax.plot(x, y, 'b-')
            ax.set_title("测试图表")
            ax.set_xlabel("X")
            ax.set_ylabel("Y")
            ax.grid(True)
            
            # 测试Canvas集成
            from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
            test_frame = ttk.Frame(self.root)
            canvas = FigureCanvasTkAgg(fig, test_frame)
            canvas.draw()
            
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_performance(self):
        """测试性能"""
        import time
        import numpy as np
        
        try:
            # 测试数据处理性能
            data_size = 10000
            test_data = np.random.randn(data_size)
            
            start_time = time.time()
            
            # 执行一些计算密集型操作
            result = np.fft.fft(test_data)
            filtered = np.convolve(test_data, np.ones(10)/10, mode='same')
            stats = {
                'mean': np.mean(test_data),
                'std': np.std(test_data),
                'max': np.max(test_data),
                'min': np.min(test_data)
            }
            
            execution_time = time.time() - start_time
            
            # 性能要求:在1秒内完成
            if execution_time < 1.0:
                return True
            else:
                return f"性能不足: {execution_time:.2f}s > 1.0s"
                
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_stability(self):
        """测试稳定性"""
        import time
        import random
        
        try:
            # 模拟长时间运行
            test_duration = 5.0  # 缩短测试时间
            start_time = time.time()
            
            while time.time() - start_time < test_duration:
                # 执行一些操作
                data = [random.random() for _ in range(1000)]
                _ = sum(data) / len(data)
                
                # 模拟内存使用
                test_list = [i for i in range(10000)]
                del test_list
                
                time.sleep(0.01)
                
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_boundary_conditions(self):
        """测试边界条件"""
        from monopulse_seeker_model import MonopulseSeekerModel, SeekerParameters
        
        try:
            params = SeekerParameters()
            seeker = MonopulseSeekerModel(params)
            
            # 测试边界值
            boundary_cases = [
                (0.0, 0.0, 0.1),      # 最小RCS
                (0.0, 0.0, 100.0),    # 最大RCS
                (-180.0, 0.0, 5.0),   # 最小方位角
                (180.0, 0.0, 5.0),    # 最大方位角
                (0.0, -90.0, 5.0),    # 最小俯仰角
                (0.0, 90.0, 5.0),     # 最大俯仰角
            ]
            
            for az, el, rcs in boundary_cases:
                from cross_eye_jamming import TargetState
                
                target = TargetState(
                    range=10000, azimuth=az, elevation=el,
                    range_rate=-100, azimuth_rate=0, elevation_rate=0,
                    rcs=rcs, snr=20.0
                )
                
                try:
                    error_az, error_el = seeker.update_target(target)
                except Exception as e:
                    return f"边界条件失败: az={az}, el={el}, rcs={rcs}, 错误: {e}"
                    
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False
            
    def test_error_handling(self):
        """测试错误处理"""
        from monopulse_seeker_model import MonopulseSeekerModel, SeekerParameters
        
        try:
            params = SeekerParameters()
            seeker = MonopulseSeekerModel(params)
            
            # 测试无效输入
            invalid_cases = [
                None,           # None输入
                "invalid",      # 字符串输入
                [],             # 空列表
                {},             # 空字典
            ]
            
            for invalid_input in invalid_cases:
                try:
                    # 尝试用无效输入调用方法
                    seeker.update_target(invalid_input)
                    return f"应该抛出异常但接受了无效输入: {invalid_input}"
                except (TypeError, ValueError, AttributeError):
                    # 预期中的异常
                    continue
                except Exception as e:
                    # 其他异常
                    return f"意外的异常类型: {type(e).__name__}: {e}"
                    
            return True
            
        except Exception as e:
            print(f"测试失败: {e}")
            return False

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = SystemTestFramework(root)
    
    # 窗口居中
    root.update_idletasks()
    width = root.winfo_width()
    height = root.winfo_height()
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    root.geometry(f'{width}x{height}+{x}+{y}')
    
    root.mainloop()

10. 总结与展望

10.1 本博客的技术成果总结

通过本博客,我们实现了一个完整的雷达电子对抗仿真系统,展示了tkinter/ttk在复杂专业系统开发中的强大能力:

10.2 技术亮点回顾

  1. 高级布局系统

    • 实现了响应式布局,支持多种屏幕尺寸

    • 使用MVC架构分离界面逻辑和业务逻辑

    • 复杂控件的嵌套和组合

  2. 专业算法实现

    • 单脉冲导引头的完整数学模型

    • 交叉眼干扰的详细算法

    • 实时信号处理和特征提取

  3. 高性能架构

    • 多线程数据处理

    • 异步UI更新

    • 内存优化和性能监控

  4. 完善的工具链

    • 参数配置和保存

    • 数据导入导出

    • 测试验证框架

    • 报告生成系统

10.3 未来改进方向

10.4 实际应用价值

  1. 教学培训

    • 雷达原理教学演示

    • 电子对抗技术培训

    • 算法验证平台

  2. 科研开发

    • 新算法快速原型验证

    • 性能对比分析

    • 系统仿真研究

  3. 工程应用

    • 系统需求验证

    • 性能评估工具

    • 测试基准平台

10.5 结语

本博客通过构建一个完整的雷达电子对抗仿真系统,全面展示了tkinter/ttk在专业领域的应用潜力。我们不仅实现了复杂的数学模型和算法,还构建了美观、易用、高性能的用户界面。

关键技术突破

  • 证明了Python标准库能够胜任专业级仿真系统的开发

  • 实现了复杂系统的模块化设计和可扩展架构

  • 展示了实时数据处理和可视化的有效方法

  • 提供了完整的测试验证和质量保证框架

相关推荐
快乐小土豆~~2 小时前
上传视频时截取正脸照片
前端·音视频·vladmandic
财经资讯数据_灵砚智能2 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年4月12日
人工智能·python·信息可视化·自然语言处理·ai编程
27669582922 小时前
token1005 算法分析
java·前端·javascript·token·token1005·携程酒店·token算法分析
乆夨(jiuze)2 小时前
记录一个css,实现下划线内容显示,支持文本多行显示
前端·css
GISer_Jing2 小时前
前端视频多模态:编解码、传输、渲染全链路详解
前端·人工智能·音视频
kuankeTech3 小时前
汇信云·盘古发布 开启外贸AI新时代
大数据·人工智能·自动化·数据可视化·软件开发
测试秃头怪3 小时前
python&selenium自动化测试实战项目详解
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
恋猫de小郭3 小时前
Flutter PC 多窗口最新进展,底层原生窗口句柄支持已合并
android·前端·flutter
踏着七彩祥云的小丑3 小时前
Python——字符串常用操作
开发语言·python