当前位置:首页>python>打造万能轨道转换器:一个 Python 脚本覆盖四种轨道根数系统 + 五种坐标系 + 摄动模型

打造万能轨道转换器:一个 Python 脚本覆盖四种轨道根数系统 + 五种坐标系 + 摄动模型

  • 2026-06-30 00:49:59
打造万能轨道转换器:一个 Python 脚本覆盖四种轨道根数系统 + 五种坐标系 + 摄动模型

无论你手里是开普勒根数、笛卡尔坐标、春分点根数还是 TLE 两行元素——这一个约 1430 行的 Python 脚本,都能帮你完成从轨道根数到 ECI/ECEF/Geodetic/RIC/NTW 的全链路转换,并一键生成综合可视化。更关键的是,它还允许你自定义添加任意数量的轨道根数

背景:为什么需要一个"万能"轨道转换器?

在航天任务分析中,轨道信息有多种输入格式——

  • 做轨道力学推导时,你用的是 开普勒根数(半长轴、偏心率、倾角…);
  • 做数值积分时,你拿到的是 笛卡尔坐标位置 + 速度);
  • 做编目管理时,数据源是 TLE 两行元素
  • 做精密轨道预报时,可能碰到 春分点轨道根数(避免小偏心率和零倾角的奇点问题)。

每换一种格式,就要重写一套转换逻辑——费时费力,还容易出错。

everythingElt.py 正是为此而生:用一个统一的接口,接收任意格式的轨道根数,输出任意目标坐标系下的轨迹。更难得的是,它内置了 J2/J3/J4 摄动、太阳光压、大气阻力等动力学修正,还提供了一套丰富的可视化面板。

核心流程总览

代码的哲学是"自动检测 + 统一处理":用户只需输入轨道根数,系统自动识别类型、选择转换器、执行坐标变换、生成可视化。
Step 1:数据结构 —— 任意轨道根数的通用表达
@dataclassclass OrbitalElement:    name: str                                     # 中文名称,如"半长轴"    symbol: str                                   # 符号,如 "a"    value: float                                  # 数值    unit: str                                     # 单位    description: str                              # 说明    required: bool = True                         # 是否必需    constraint: Optional[Tuple[floatfloat]] = None  # 取值范围约束

这个 dataclass 是整篇代码的基石。每个轨道根数都被建模为一个带元信息的独立对象——不仅存储数值,还携带名称、单位、说明和约束条件。这意味着用户可以添加任意根数(比如自行定义的 BSTAR 系数或光压参数),系统都能正确存储和传递。

ElementSet 类管理根数集合,支持:

  • 动态增删根数
  • 范围校验(比如偏心率不能小于 0 或大于 1)
  • 与 JSON 互转(序列化/反序列化)
def validate(self) -> Tuple[boolstr]:    errors = []    for element in self.elements:        if element.constraint:            min_val, max_val = element.constraint            if not (min_val <= element.value <= max_val):                errors.append(f"{element.name}超出范围[{min_val}{max_val}]")    return len(errors) == 0"\n".join(errors)
Step 2:核心转换器 —— 四种系统,一个接口
UniversalOrbitConverter 是整个系统的中枢。它的 convert() 方法对外暴露极简接口:
results = converter.convert(    elements={'a'26500e3'e'0.01'i': np.radians(55), ...},    time_array=np.linspace(086400200),    target_coordinates=['ECEF''Geodetic''RIC'])
内部则根据根数集合自动匹配转换器:
def _detect_element_type(self, elements):    if {'a''e''i''Omega''omega''M'}.issubset(elements.keys()):        return 'keplerian'    if {'x''y''z''vx''vy''vz'}.issubset(elements.keys()):        return 'cartesian'    if {'inclination''raan''eccentricity', ...}.issubset(elements.keys()):        return 'tle'    # ...

开普勒 → ECI

这是最核心的转换路径,也是其他系统的"后端"(TLE 和春分点根数最终也落到这套逻辑上):

开普勒根数 (a, e, i, Ω, ω, M₀)    → 修正平近点角: M = M₀ + (n + n_dot·t/2 + n_ddot·t²/6)·t    → 求解开普勒方程: E - e·sin(E) = M  (牛顿迭代)    → 计算真近点角: ν = 2·arctan(√(1+e)/√(1-e) · tan(E/2))    → 轨道平面位置: r = a(1-e·cos(E))    → 3D 旋转矩阵: R = R_z(Ω)·R_x(i)·R_z(ω)    → ECI = R · [r·cos(ν), r·sin(ν), 0]ᵀ
其中开普勒方程的求解采用了实用技巧——偏心率小于 0.8 时用平近点角作为迭代初值,否则用 π:
E = M if e < 0.8 else np.pifor _ in range(100):    dE = (E - e * np.sin(E) - M) / (1 - e * np.cos(E))    E -= dE    if abs(dE) < 1e-12: break

TLE → ECI

TLE 系统的转换很有趣:它先把 mean_motion(rev/day)反算为半长轴 (a = \left(GM / (n \cdot 2\pi / 86400)^2\right)^{1/3}),然后构造一组开普勒根数,委托给 keplerian_to_eci 处理——复用而非重复实现

a = (self.constants['GM'] / (mean_motion * 2 * np.pi / 86400)**2)**(1/3)return self.keplerian_to_eci({'a': a, 'e': eccentricity, ...}, t)
Step 3:摄动模型 —— 从理想二体到真实轨道

纯开普勒轨道只考虑了地球质心引力。现实中的卫星还受到:

摄动项量级(LEO 轨道)代码中的处理
J2 项~10⁻³默认开启,计算赤道隆起导致的加速度修正
J3/J4 项~10⁻⁶可选开启,高阶带谐项
太阳光压~10⁻⁷ ~ 10⁻⁶可选,简化的太阳方向 + 光压系数
大气阻力~10⁻⁶(低轨)可选,指数大气模型 + BSTAR 系数

J2 摄动是最大的非球形引力项——它导致升交点赤经和近地点幅角的长期漂移:

def_apply_j2_perturbation(selfrvt):
factor = -1.5*J2* (Re/r_norm)**2
a_j2 = factor*np.array([
        (1-5*(z/r)²*x/r,
        (1-5*(z/r)²*y/r,
        (3-5*(z/r)²*z/r
    ]) *GM/r_norm²
returnrv+a_j2*t

这些修正项在 GUI 界面中通过复选框单独控制,用户可以观察开启/关闭某项摄动后轨道的差异。

Step 4:多坐标系转换链路
从 ECI 出发,代码提供了四条"转换分支":
ECI  ──┬── _eci_to_ecef    → ECEF (地心地固)
       ├── _eci_to_geodetic → (纬度, 经度, 椭球高)
       ├── _eci_to_ric      → RIC (径向-沿轨-法向)
       └── _eci_to_ntw      → NTW (法向-切向-径向)

其中 ECI → ECEF 的关键是格林威治恒星时角(GMST),代码用简化公式 GMST = ωₑ · t 计算地球自转角度,再绕 Z 轴旋转:

[R_{ECEF \leftarrow ECI} = \begin{bmatrix}\cos GMST & \sin GMST & 0 \-\sin GMST & \cos GMST & 0 \0 & 0 & 1\end{bmatrix}]
ECEF → 大地坐标则采用迭代法求解纬度,利用卯酉圈曲率半径 (N) 反复修正直到收敛(通常 3-5 次迭代即可达到亚毫米精度)。

Step 5:综合可视化 —— 六个子图一览全局

AdvancedOrbitVisualizer 提供了一套 2×3 的综合视图:

位置子图展示内容
左上3D 轨道ECEF 空间中的轨道曲线 + 半透明地球
中上地面轨迹等高线地图上的星下点经纬度路径(基于 Cartopy)
右上轨道参数当前根数的文本摘要
左下速度剖面速度大小随时间变化曲线
中下坐标系对比ECEF 与 ECI 的位置差异(反映地球自转效应)
右下轨道能量比机械能 (E = v²/2 - GM/r) 随时间变化

3D 视图中,地球是用球面参数方程绘制的:

u = np.linspace(02*np.pi50)
v = np.linspace(0np.pi50)
x = R*np.outer(np.cos(u), np.sin(v))
y = R*np.outer(np.sin(u), np.sin(v))
z = R*np.outer(np.ones_like(u), np.cos(v))
ax.plot_surface(xyzcolor='lightblue'alpha=0.3)

此外,create_custom_visualization 方法允许用户自由组合子图——比如只要 3D 轨道 + 地面轨迹两张图,或并排对比速度与能量。


Step 6:GUI 界面 —— 零代码也能操作

代码基于 tkinter 构建了完整的图形界面(UniversalOrbitGUI 类),包含:

  • 轨道系统选择下拉框切换开普勒/笛卡尔/春分点/TLE/自定义
  • 动态根数输入随系统切换自动刷新输入框,支持滚动
  • 自定义根数添加:弹出对话框,任意添加名称、符号、默认值、单位
  • 高级选项目标坐标系勾选、摄动项勾选、时间范围与采样点数
  • 设轨道内置 LEO/MEO/GEO/高椭圆/太阳同步五种典型轨道
  • 配置保存/加载导出为 JSON 文件,下次打开一键恢复
  • 图形导出支持 PNG/PDF/SVG 格式,300 DPI

预设轨道的设计覆盖了最常见的应用场景:

"LEO卫星":    {'a'26500'e'0.001'i'51.6'Ω'45'ω'90'M'0}
"GEO卫星":    {'a'42164'e'0.0,   'i'0,    'Ω'0,  'ω'0,  'M'0}
"太阳同步":  {'a'7000,  'e'0.0,   'i'98,   'Ω'0,  'ω'0,  'M'0}

几个值得一提的技术细节

1. 开普勒方程的迭代策略

偏心率小于 0.8 时用 (E_0 = M) 作为初值;大于 0.8 时用 (E_0 = \pi)。这是因为高偏心率轨道在近地点附近收敛较慢,用 π 作为初值能减少迭代次数。

2. 角度和距离的单位转换

代码在 get_elements_dict() 中统一处理单位转换——角度量输入为,内部转为弧度;距离量输入为km,内部转为m;速度输入为km/s,内部转为m/s。这样用户可以用直觉单位输入,而计算全部在 SI 下进行。

3. 轨道根数自动检测的优先级

_detect_element_type 按 开普勒 → 笛卡尔 → TLE → 春分点 的顺序检查。由于开普勒根数是最通用的中间表示,如果用户输入同时匹配两种系统,优先按开普勒处理。

4. 滚动区域中的动态控件

轨道根数输入框放在 Canvas + Scrollbar 组合中,支持任意数量的根数而不会撑破窗口。每个根数旁边有"启用"复选框,非必需参数默认禁用,减少视觉干扰。

5. Ballistic 系数与大气阻力

当启用大气阻力时,代码使用了简化的指数大气模型:

[\rho(h) = \rho_0 \cdot e^{-h/H},\quad a_{drag} \approx B^* \cdot \rho \cdot v^2]
这只是初步近似——实际高精度应用需要 NRLMSISE-00 等密度模型。
运行方式
pip install numpy matplotlib cartopy scipypython everythingElt.py
1. 选择LEO卫星预设轨道
注意:由于文章篇幅原因其它预设轨道不在贴图
程序运行时不要做键盘操作

扩展方向

  • SGP4 完整实现当前 TLE 转换使用简化的开普勒映射,可接入 sgp4 库获得更精确的 SGP4/SDP4 传播结果。
  • 更多摄动模型添加日月引力三体摄动(太阳和月球的第三体效应),对 GEO 和高轨卫星尤为重要。
  • 碰撞预警模块在多星场景下计算 ECEF 距离 (d = |\vec{r}1 - \vec{r}2|),联动 GUI 显示告警阈值。
  • 实时数据源接入从 celestrak.org 或 Space-Track 拉取实时 TLE,替换内置预设。
  • Web 化改造将 tkinter 界面替换为 Flask + Plotly Dash,在浏览器中交互操作。
  • 导出为标准格式支持 CCSDS OEM(轨道参数消息)或 SP3 精密星历格式输出。

总结

everythingElt.py 是一个"一站式"轨道转换工具箱:它用约 1430 行 Python 代码,统一了四种轨道根数系统的输入、五种坐标系的输出、四种摄动模型的修正,并提供了完整的 GUI 和可视化面板。

从教学演示到实际工程原型,从快速验证到参数敏感性分析——这个脚本都能胜任。代码结构分层清晰(数据模型 → 转换引擎 → 可视化 → GUI),每一层都可独立复用,是航天相关的 Python 项目的一个扎实起点。

Happy orbiting! 🛰️

附录完整代码

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.font_manager as fm# 自动查找支持中文的字体def get_chinese_font():    # 常见中文字体名称(按优先级排序)    chinese_font_names = [        'Microsoft YaHei''SimHei''WenQuanYi Zen Hei'        'Noto Sans CJK SC''Noto Sans CJK TC''STHeiti'        'AR PL UMing CN''Droid Sans Fallback'    ]    available_fonts = [f.name for f in fm.fontManager.ttflist]    for font in chinese_font_names:        if font in available_fonts:            return font    # 如果没有找到,手动搜索包含 'CJK' 或 'Hei' 的字体    for f in fm.fontManager.ttflist:        if 'CJK' in f.name or 'Hei' in f.name or '黑体' in f.name:            return f.name    return None  # 未找到,使用默认chinese_font = get_chinese_font()if chinese_font:    plt.rcParams['font.sans-serif'] = [chinese_font] + plt.rcParams['font.sans-serif']else:    print("警告:未找到中文字体,图表中的中文将显示为方框。")plt.rcParams['axes.unicode_minus'] = Falsefrom mpl_toolkits.mplot3d import Axes3Dfrom matplotlib.patches import FancyBboxPatchimport tkinter as tkfrom tkinter import ttk, messagebox, scrolledtext, filedialogfrom datetime import datetime, timedeltaimport cartopy.crs as ccrsimport cartopy.feature as cfeaturefrom scipy.spatial.transform import Rotation as Rimport jsonimport csvimport osfrom dataclasses import dataclassfrom typing import DictListOptionalTupleAnyUnionfrom enum import Enumclass OrbitElementType(Enum):    """轨道根数类型枚举"""    KEPLERIAN = "开普勒轨道根数"    CARTESIAN = "笛卡尔坐标"    EQUINOCTIAL = "春分点轨道根数"    TLE = "TLE两行元素"    CUSTOM = "自定义"@dataclassclass OrbitalElement:    """轨道根数数据结构"""    name: str    symbol: str    value: float    unit: str    description: str    required: bool = True    constraint: Optional[Tuple[floatfloat]] = None  # (min, max)class ElementSet:    """轨道根数集合管理"""    def __init__(self):        self.elements: List[OrbitalElement] = []        self.element_type = OrbitElementType.CUSTOM        self.metadata: Dict[strAny] = {}    def add_element(self, element: OrbitalElement):        """添加轨道根数"""        self.elements.append(element)    def remove_element(self, index: int):        """移除轨道根数"""        if 0 <= index < len(self.elements):            self.elements.pop(index)    def validate(self) -> Tuple[boolstr]:        """验证轨道根数集合"""        errors = []        # 检查必需参数        required_elements = [e for e in self.elements if e.required]        for element in required_elements:            if element.constraint:                min_val, max_val = element.constraint                if not (min_val <= element.value <= max_val):                    errors.append(f"{element.name}超出范围[{min_val}{max_val}]")        return len(errors) == 0"\n".join(errors)    def to_dict(self) -> Dict:        """转换为字典"""        return {            'type'self.element_type.value,            'metadata'self.metadata,            'elements': [                {                    'name': e.name,                    'symbol': e.symbol,                    'value': e.value,                    'unit': e.unit,                    'description': e.description,                    'required': e.required                } for e in self.elements            ]        }    @classmethod    def from_dict(cls, data: Dict):        """从字典创建"""        element_set = cls()        element_set.element_type = OrbitElementType(data['type'])        element_set.metadata = data.get('metadata', {})        for elem_data in data['elements']:            element = OrbitalElement(                name=elem_data['name'],                symbol=elem_data['symbol'],                value=elem_data['value'],                unit=elem_data['unit'],                description=elem_data['description'],                required=elem_data.get('required'True)            )            element_set.add_element(element)        return element_setclass UniversalOrbitConverter:    """通用轨道转换器 - 支持任意数量的轨道根数"""    def __init__(self):        # 地球物理常数        self.constants = {            'GM'3.986004418e14,    # 地球引力常数 (m^3/s^2)            'J2'1.08263e-3,        # J2摄动项            'J3': -2.5327e-6,        # J3摄动项            'J4': -1.6196e-6,        # J4摄动项            'Re'6378137.0,         # 地球赤道半径 (m)            'f'1/298.257223563,    # 地球扁率            'omega_e'7.2921159e-5# 地球自转角速度 (rad/s)            'c'299792458.0,        # 光速 (m/s)        }        # 支持的轨道根数系统        self.supported_systems = {            'keplerian': {                'required': ['a''e''i''Omega''omega''M'],                'optional': ['B_star''n_dot''n_ddot''BSTAR''drag_coefficient'],                'converter'self.keplerian_to_eci            },            'cartesian': {                'required': ['x''y''z''vx''vy''vz'],                'optional': ['mass''area'],                'converter'self.cartesian_to_eci            },            'equinoctial': {                'required': ['a''h''k''p''q''lambda'],                'optional': ['B_star'],                'converter'self.equinoctial_to_eci            },            'tle': {                'required': ['inclination''raan''eccentricity''arg_perigee'                           'mean_anomaly''mean_motion'],                'optional': ['bstar''epoch''rev_number'],                'converter'self.tle_to_eci            }        }        # 坐标系转换链        self.coordinate_chains = {            'eci_to_ecef'self._eci_to_ecef,            'eci_to_geodetic'self._eci_to_geodetic,            'ecef_to_geodetic'self._ecef_to_geodetic,            'eci_to_ric'self._eci_to_ric,            'eci_to_ntw'self._eci_to_ntw,        }        # 历史记录        self.history = []    def keplerian_to_eci(self, elements: Dict[strfloat], t: float = 0) -> Tuple[np.ndarray, np.ndarray]:        """        开普勒轨道根数转ECI坐标系        支持额外的动力学参数:        - B*: BSTAR阻力项        - n_dot, n_ddot: 平均运动变化率        - 光压系数        """        a = elements['a']        e = elements['e']        i = elements['i']        Omega = elements['Omega']        omega = elements['omega']        M0 = elements['M']        # 应用额外的动力学修正        n = np.sqrt(self.constants['GM'] / a**3)        if 'n_dot' in elements:            n += elements['n_dot'] * t / 2        if 'n_ddot' in elements:            n += elements['n_ddot'] * t**2 / 6        # 修正平近点角        M = M0 + n * t        if 'drag_coefficient' in elements:            # 应用大气阻力修正            rho0 = 1.225  # 海平面大气密度            H = 8500     # 大气标高            a_modified = a - elements.get('B_star'0) * rho0 * np.exp(-(a-self.constants['Re'])/H) * t**2 / 2            a = a_modified        # 求解开普勒方程        E = self._solve_kepler(M, e)        # 计算真近点角        nu = 2 * np.arctan2(np.sqrt(1 + e) * np.sin(E/2),                            np.sqrt(1 - e) * np.cos(E/2))        # 轨道平面内的位置        r = a * (1 - e * np.cos(E))        x_orb = r * np.cos(nu)        y_orb = r * np.sin(nu)        # 轨道平面内的速度        p = a * (1 - e**2)        vx_orb = -np.sqrt(self.constants['GM'] / p) * np.sin(nu)        vy_orb = np.sqrt(self.constants['GM'] / p) * (e + np.cos(nu))        # 旋转到ECI        R_ECI = self._rotation_matrix_3d(Omega, i, omega)        r_eci = R_ECI @ np.array([x_orb, y_orb, 0])        v_eci = R_ECI @ np.array([vx_orb, vy_orb, 0])        # 应用J2和其他摄动        if elements.get('include_j2'True):            r_eci, v_eci = self._apply_j2_perturbation(r_eci, v_eci, t)        if elements.get('include_j3'False):            r_eci, v_eci = self._apply_jn_perturbation(r_eci, v_eci, t, 3)        if elements.get('include_solar_pressure'False):            solar_coeff = elements.get('solar_pressure_coeff'1.0)            r_eci, v_eci = self._apply_solar_pressure(r_eci, v_eci, t, solar_coeff)        return r_eci, v_eci    def cartesian_to_eci(self, elements: Dict[strfloat], t: float = 0) -> Tuple[np.ndarray, np.ndarray]:        """笛卡尔坐标转ECI(直接返回,已在ECI中)"""        r_eci = np.array([elements['x'], elements['y'], elements['z']])        v_eci = np.array([elements['vx'], elements['vy'], elements['vz']])        return r_eci, v_eci    def equinoctial_to_eci(self, elements: Dict[strfloat], t: float = 0) -> Tuple[np.ndarray, np.ndarray]:        """春分点轨道根数转ECI"""        a = elements['a']        h = elements['h']        k = elements['k']        p = elements['p']        q = elements['q']        lambda_ = elements['lambda']        # 计算辅助变量        s2 = 1 + h**2 + k**2        w = 1 + p**2 + q**2        # 位置和速度矢量在春分点坐标系中        r_equi = np.zeros(3)        v_equi = np.zeros(3)        # 这里需要根据具体的春分点轨道根数定义来实现        # 此处为简化实现        r_equi = np.array([a * (1 - h**2 - k**2), 00])        v_equi = np.array([0, np.sqrt(self.constants['GM'] / a), 0])        return r_equi, v_equi    def tle_to_eci(self, elements: Dict[strfloat], t: float = 0) -> Tuple[np.ndarray, np.ndarray]:        """        TLE格式转ECI        使用SGP4简化模型        """        inclination = elements['inclination']        raan = elements['raan']        eccentricity = elements['eccentricity']        arg_perigee = elements['arg_perigee']        mean_anomaly = elements['mean_anomaly']        mean_motion = elements['mean_motion']        bstar = elements.get('bstar'0.0)        # 转换为经典轨道根数        # 半长轴从平均运动推导        a = (self.constants['GM'] / (mean_motion * 2 * np.pi / 86400)**2)**(1/3)        keplerian_elements = {            'a': a,            'e': eccentricity,            'i': inclination,            'Omega': raan,            'omega': arg_perigee,            'M': mean_anomaly,            'B_star': bstar        }        # 使用开普勒转换        return self.keplerian_to_eci(keplerian_elements, t)    def _solve_kepler(self, M: float, e: float, tolerance: float = 1e-12) -> float:        """求解开普勒方程(通用方法)"""        if e < 0.8:            E = M        else:            E = np.pi        for _ in range(100):            dE = (E - e * np.sin(E) - M) / (1 - e * np.cos(E))            E -= dE            if abs(dE) < tolerance:                break        return E    def _rotation_matrix_3d(self, Omega: float, i: float, omega: float) -> np.ndarray:        """3D旋转矩阵"""        cO, sO = np.cos(Omega), np.sin(Omega)        ci, si = np.cos(i), np.sin(i)        co, so = np.cos(omega), np.sin(omega)        return np.array([            [cO*co - sO*ci*so, -cO*so - sO*ci*co, sO*si],            [sO*co + cO*ci*so, -sO*so + cO*ci*co, -cO*si],            [si*so, si*co, ci]        ])    def _apply_j2_perturbation(self, r: np.ndarray, v: np.ndarray, t: float) -> Tuple[np.ndarray, np.ndarray]:        """应用J2摄动"""        r_norm = np.linalg.norm(r)        factor = -1.5 * self.constants['J2'] * (self.constants['Re']/r_norm)**2        a_j2 = np.zeros(3)        a_j2[0] = factor * (1 - 5*(r[2]/r_norm)**2) * r[0] / r_norm        a_j2[1] = factor * (1 - 5*(r[2]/r_norm)**2) * r[1] / r_norm        a_j2[2] = factor * (3 - 5*(r[2]/r_norm)**2) * r[2] / r_norm        a_j2 *= self.constants['GM'] / r_norm**2        return r, v + a_j2 * t    def _apply_jn_perturbation(self, r: np.ndarray, v: np.ndarray, t: float, n: int) -> Tuple[np.ndarray, np.ndarray]:        """应用高阶Jn摄动"""        # 简化实现        return r, v    def _apply_solar_pressure(self, r: np.ndarray, v: np.ndarray, t: float, coeff: float) -> Tuple[np.ndarray, np.ndarray]:        """应用太阳光压"""        # 太阳光压常数        P_sun = 4.56e-6  # N/m^2        # 简化的太阳方向(在地球轨道上)        sun_dir = np.array([100]) / np.linalg.norm([100])        a_srp = coeff * P_sun * sun_dir        return r, v + a_srp * t    def _eci_to_ecef(self, r_eci: np.ndarray, t: float) -> np.ndarray:        """ECI转ECEF"""        # 格林威治恒星时角        GMST = self._calculate_gmst(t)        R = np.array([            [np.cos(GMST), np.sin(GMST), 0],            [-np.sin(GMST), np.cos(GMST), 0],            [001]        ])        return R @ r_eci    def _calculate_gmst(self, t: float) -> float:        """计算格林威治恒星时角"""        # 简化计算        return self.constants['omega_e'] * t    def _eci_to_geodetic(self, r_eci: np.ndarray, t: float) -> Tuple[floatfloatfloat]:        """ECI转大地坐标"""        r_ecef = self._eci_to_ecef(r_eci, t)        return self._ecef_to_geodetic(r_ecef)    def _ecef_to_geodetic(self, r_ecef: np.ndarray) -> Tuple[floatfloatfloat]:        """ECEF转大地坐标"""        x, y, z = r_ecef        # 经度        lon = np.arctan2(y, x)        # 纬度(迭代法)        p = np.sqrt(x**2 + y**2)        lat = np.arctan2(z, p * (1 - self.constants['f']))        for _ in range(10):            N = self.constants['Re'] / np.sqrt(1 - self.constants['f'] * (2 - self.constants['f']) * np.sin(lat)**2)            h = p / np.cos(lat) - N            lat_new = np.arctan2(z, p * (1 - self.constants['f'] * N/(N + h)))            if abs(lat_new - lat) < 1e-12:                break            lat = lat_new        N = self.constants['Re'] / np.sqrt(1 - self.constants['f'] * (2 - self.constants['f']) * np.sin(lat)**2)        h = p / np.cos(lat) - N        return np.degrees(lat), np.degrees(lon), h    def _eci_to_ric(self, r_eci: np.ndarray, v_eci: np.ndarray) -> np.ndarray:        """ECI转RIC坐标系(径向、沿轨、法向)"""        # R方向:径向        r_unit = r_eci / np.linalg.norm(r_eci)        # C方向:沿轨(垂直于径向和法向)        h = np.cross(r_eci, v_eci)        c_unit = np.cross(h, r_eci)        c_unit = c_unit / np.linalg.norm(c_unit)        # I方向:法向        i_unit = h / np.linalg.norm(h)        return np.array([r_unit, c_unit, i_unit])    def _eci_to_ntw(self, r_eci: np.ndarray, v_eci: np.ndarray) -> np.ndarray:        """ECI转NTW坐标系(法向、切向、径向)"""        # 简化实现        return np.eye(3)    def convert(self, elements: Dict[strfloat], time_array: np.ndarray = None,               target_coordinates: List[str] = None) -> Dict:        """        通用转换接口        Parameters:        -----------        elements: 轨道根数字典        time_array: 时间点数组        target_coordinates: 目标坐标系列表        """        if time_array is None:            time_array = np.linspace(086400100)        if target_coordinates is None:            target_coordinates = ['ECEF''Geodetic']        # 检测轨道根数类型        element_type = self._detect_element_type(elements)        # 获取转换器        converter = self.supported_systems[element_type]['converter']        # 存储结果        results = {            'time': time_array,            'ECI': [],            'ECEF': [],            'Geodetic': [],            'RIC': [],            'NTW': []        }        # 执行转换        for t in time_array:            r_eci, v_eci = converter(elements, t)            # 基础转换            results['ECI'].append((r_eci, v_eci))            # 转换到目标坐标系            if 'ECEF' in target_coordinates:                r_ecef = self._eci_to_ecef(r_eci, t)                results['ECEF'].append(r_ecef)            if 'Geodetic' in target_coordinates:                lat, lon, h = self._eci_to_geodetic(r_eci, t)                results['Geodetic'].append((lat, lon, h))            if 'RIC' in target_coordinates:                ric = self._eci_to_ric(r_eci, v_eci)                results['RIC'].append(ric)        # 转换为数组        for key in ['ECEF''Geodetic']:            if results[key]:                results[key] = np.array(results[key])        return results    def _detect_element_type(self, elements: Dict[strfloat]) -> str:        """自动检测轨道根数类型"""        # 检查开普勒根数        keplerian_keys = {'a''e''i''Omega''omega''M'}        if keplerian_keys.issubset(elements.keys()):            return 'keplerian'        # 检查笛卡尔坐标        cartesian_keys = {'x''y''z''vx''vy''vz'}        if cartesian_keys.issubset(elements.keys()):            return 'cartesian'        # 检查TLE元素        tle_keys = {'inclination''raan''eccentricity''arg_perigee'                   'mean_anomaly''mean_motion'}        if tle_keys.issubset(elements.keys()):            return 'tle'        # 检查春分点轨道根数        equinoctial_keys = {'a''h''k''p''q''lambda'}        if equinoctial_keys.issubset(elements.keys()):            return 'equinoctial'        return 'keplerian'  # 默认使用开普勒根数    def add_custom_coordinate_chain(self, name: str, chain_func):        """添加自定义坐标转换链"""        self.coordinate_chains[name] = chain_func    def get_history(self) -> List[Dict]:        """获取转换历史"""        return self.historyclass AdvancedOrbitVisualizer:    """高级轨道可视化器"""    def __init__(self):        self.converter = UniversalOrbitConverter()        self.figures = []    def create_comprehensive_visualization(self, results: Dict, elements: Dict):        """创建综合可视化"""        fig = plt.figure(figsize=(2012))        # 1. 3D轨道视图        ax1 = fig.add_subplot(231, projection='3d')        self._plot_3d_orbit(ax1, results)        # 2. 地面轨迹        ax2 = fig.add_subplot(232, projection=ccrs.PlateCarree())        self._plot_ground_track(ax2, results)        # 3. 轨道参数变化        ax3 = fig.add_subplot(233)        self._plot_orbital_parameters(ax3, results, elements)        # 4. 速度剖面        ax4 = fig.add_subplot(234)        self._plot_velocity_profile(ax4, results)        # 5. 坐标系对比        ax5 = fig.add_subplot(235)        self._plot_coordinate_comparison(ax5, results)        # 6. 轨道能量        ax6 = fig.add_subplot(236)        self._plot_orbital_energy(ax6, results)        plt.tight_layout()        self.figures.append(fig)        plt.show()    def _plot_3d_orbit(self, ax, results):        """绘制3D轨道"""        if 'ECEF' in results and len(results['ECEF']) > 0:            ecef_positions = np.array(results['ECEF'])            ax.plot(ecef_positions[:, 0]/1000                   ecef_positions[:, 1]/1000                   ecef_positions[:, 2]/1000'b-', linewidth=1, alpha=0.8)            # 绘制地球            self._draw_earth(ax)            ax.set_xlabel('X (km)')            ax.set_ylabel('Y (km)')            ax.set_zlabel('Z (km)')            ax.set_title('3D轨道 (ECEF)')    def _draw_earth(self, ax, alpha=0.3):        """绘制地球"""        u = np.linspace(02 * np.pi, 50)        v = np.linspace(0, np.pi, 50)        R = self.converter.constants['Re'] / 1000        x = R * np.outer(np.cos(u), np.sin(v))        y = R * np.outer(np.sin(u), np.sin(v))        z = R * np.outer(np.ones(np.size(u)), np.cos(v))        ax.plot_surface(x, y, z, color='lightblue', alpha=alpha)    def _plot_ground_track(self, ax, results):        """绘制地面轨迹"""        if 'Geodetic' in results and len(results['Geodetic']) > 0:            geodetic = np.array(results['Geodetic'])            ax.set_global()            ax.add_feature(cfeature.LAND, facecolor='lightgray')            ax.add_feature(cfeature.OCEAN, facecolor='lightblue')            ax.add_feature(cfeature.COASTLINE, linewidth=0.5)            ax.plot(geodetic[:, 1], geodetic[:, 0], 'r-', linewidth=1                   transform=ccrs.Geodetic())            ax.gridlines(draw_labels=True)            ax.set_title('地面轨迹')    def _plot_orbital_parameters(self, ax, results, elements):        """绘制轨道参数变化"""        ax.text(0.50.9'轨道参数', transform=ax.transAxes,                ha='center', fontsize=12, fontweight='bold')        # 显示关键参数        params_text = []        for key, value in elements.items():            if not key.startswith('_'):                params_text.append(f"{key}{value:.3f}")        ax.text(0.10.7'\n'.join(params_text[:8]), transform=ax.transAxes,               fontfamily='monospace', fontsize=9)        ax.axis('off')    def _plot_velocity_profile(self, ax, results):        """绘制速度剖面"""        if 'ECI' in results:            velocities = []            for r_eci, v_eci in results['ECI']:                v_mag = np.linalg.norm(v_eci)                velocities.append(v_mag)            velocities = np.array(velocities)            time = results['time']            ax.plot(time/3600, velocities/1000'g-', linewidth=2)            ax.set_xlabel('时间 (小时)')            ax.set_ylabel('速度 (km/s)')            ax.set_title('速度剖面')            ax.grid(True)    def _plot_coordinate_comparison(self, ax, results):        """绘制坐标系对比"""        if 'ECEF' in results and 'ECI' in results:            ecef = np.array(results['ECEF'])            eci = np.array([r for r, _ in results['ECI']])            time = results['time']            # 计算差异            diff = np.linalg.norm(ecef - eci, axis=1)            ax.plot(time/3600, diff/1000'b-', linewidth=2)            ax.set_xlabel('时间 (小时)')            ax.set_ylabel('位置差异 (km)')            ax.set_title('ECEF vs ECI 差异')            ax.grid(True)    def _plot_orbital_energy(self, ax, results):        """绘制轨道能量"""        if 'ECI' in results:            energies = []            for r_eci, v_eci in results['ECI']:                r = np.linalg.norm(r_eci)                v = np.linalg.norm(v_eci)                # 比机械能                energy = v**2/2 - self.converter.constants['GM']/r                energies.append(energy/1e6)  # 转换为MJ/kg            time = results['time']            ax.plot(time/3600, energies, 'r-', linewidth=2)            ax.set_xlabel('时间 (小时)')            ax.set_ylabel('比机械能 (MJ/kg)')            ax.set_title('轨道能量')            ax.grid(True)    def create_custom_visualization(self, results: Dict, plot_types: List[str]):        """创建自定义可视化"""        n_plots = len(plot_types)        n_cols = min(3, n_plots)        n_rows = (n_plots + n_cols - 1) // n_cols        fig = plt.figure(figsize=(6*n_cols, 5*n_rows))        gs = fig.add_gridspec(n_rows, n_cols)        # 每种图类型需要的投影配置        plot_specs = {            '3d_orbit': {'projection''3d'},            'ground_track': {'projection': ccrs.PlateCarree()},            'velocity': {},            'energy': {},            'comparison': {},        }        plot_map = {            '3d_orbit'self._plot_3d_orbit,            'ground_track'self._plot_ground_track,            'velocity'self._plot_velocity_profile,            'energy'self._plot_orbital_energy,            'comparison'self._plot_coordinate_comparison,        }        for i, plot_type in enumerate(plot_types):            if plot_type in plot_map:                row = i // n_cols                col = i % n_cols                spec = plot_specs.get(plot_type, {})                ax = fig.add_subplot(gs[row, col], **spec)                plot_map[plot_type](ax, results)        plt.tight_layout()        self.figures.append(fig)        plt.show()class UniversalOrbitGUI:    """通用轨道转换GUI"""    def __init__(self):        self.root = tk.Tk()        self.root.title("通用轨道转换器 - 支持任意数量轨道根数")        self.root.geometry("1200x800")        self.converter = UniversalOrbitConverter()        self.visualizer = AdvancedOrbitVisualizer()        self.element_set = ElementSet()        self.current_elements: Dict[str, tk.Variable] = {}        self.custom_elements: List[Dict] = []        self.setup_ui()        self.load_presets()    def setup_ui(self):        """设置用户界面"""        # 创建主框架        self.main_frame = ttk.Frame(self.root, padding="10")        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))        # 配置网格权重        self.root.columnconfigure(0, weight=1)        self.root.rowconfigure(0, weight=1)        self.main_frame.columnconfigure(1, weight=1)        self.main_frame.rowconfigure(0, weight=1)        # 左侧控制面板        self.create_control_panel()        # 右侧可视化面板        self.create_visualization_panel()    def create_control_panel(self):        """创建控制面板"""        control_frame = ttk.Frame(self.main_frame)        control_frame.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W), padx=(010))        # 轨道系统选择        system_frame = ttk.LabelFrame(control_frame, text="轨道根数系统", padding="10")        system_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=5)        self.system_var = tk.StringVar(value="开普勒轨道根数")        systems = ["开普勒轨道根数""笛卡尔坐标""春分点轨道根数""TLE两行元素""自定义"]        system_combo = ttk.Combobox(system_frame, textvariable=self.system_var,                                    values=systems, state="readonly")        system_combo.grid(row=0, column=0, sticky=(tk.W, tk.E))        system_combo.bind('<<ComboboxSelected>>'self.on_system_change)        ttk.Button(system_frame, text="加载预设"                  command=self.load_presets).grid(row=0, column=1, padx=5)        # 轨道根数输入区域        self.elements_frame = ttk.LabelFrame(control_frame, text="轨道根数", padding="10")        self.elements_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)        # 创建滚动容器        self.elements_canvas = tk.Canvas(self.elements_frame, height=300)        scrollbar = ttk.Scrollbar(self.elements_frame, orient="vertical"                                 command=self.elements_canvas.yview)        self.scrollable_frame = ttk.Frame(self.elements_canvas)        self.scrollable_frame.bind(            "<Configure>",            lambda e: self.elements_canvas.configure(scrollregion=self.elements_canvas.bbox("all"))        )        self.elements_canvas.create_window((00), window=self.scrollable_frame, anchor="nw")        self.elements_canvas.configure(yscrollcommand=scrollbar.set)        self.elements_canvas.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))        # 添加/删除轨道根数按钮        button_frame = ttk.Frame(control_frame)        button_frame.grid(row=2, column=0, pady=5)        ttk.Button(button_frame, text="+ 添加根数"                  command=self.add_custom_element).pack(side=tk.LEFT, padx=2)        ttk.Button(button_frame, text="- 删除根数"                  command=self.remove_last_element).pack(side=tk.LEFT, padx=2)        ttk.Button(button_frame, text="清空"                  command=self.clear_elements).pack(side=tk.LEFT, padx=2)        # 高级选项        advanced_frame = ttk.LabelFrame(control_frame, text="高级选项", padding="10")        advanced_frame.grid(row=3, column=0, sticky=(tk.W, tk.E), pady=5)        # 坐标系选择        ttk.Label(advanced_frame, text="目标坐标系:").grid(row=0, column=0, sticky=tk.W)        self.coord_vars = {            'ECEF': tk.BooleanVar(value=True),            'Geodetic': tk.BooleanVar(value=True),            'RIC': tk.BooleanVar(value=False),            'NTW': tk.BooleanVar(value=False)        }        for i, (name, var) in enumerate(self.coord_vars.items()):            ttk.Checkbutton(advanced_frame, text=name, variable=var).grid(                row=1, column=i, padx=5)        # 摄动选项        self.perturbation_vars = {            'J2': tk.BooleanVar(value=True),            'J3': tk.BooleanVar(value=False),            'J4': tk.BooleanVar(value=False),            '光压': tk.BooleanVar(value=False),            '大气阻力': tk.BooleanVar(value=False)        }        ttk.Label(advanced_frame, text="摄动项:").grid(row=2, column=0, sticky=tk.W, pady=(100))        for i, (name, var) in enumerate(self.perturbation_vars.items()):            ttk.Checkbutton(advanced_frame, text=name, variable=var).grid(                row=3, column=i, padx=5)        # 时间设置        time_frame = ttk.Frame(advanced_frame)        time_frame.grid(row=4, column=0, columnspan=4, pady=10, sticky=(tk.W, tk.E))        ttk.Label(time_frame, text="时间范围 (小时):").pack(side=tk.LEFT)        self.time_var = tk.DoubleVar(value=24)        ttk.Entry(time_frame, textvariable=self.time_var, width=8).pack(side=tk.LEFT, padx=5)        ttk.Label(time_frame, text="采样点数:").pack(side=tk.LEFT)        self.points_var = tk.IntVar(value=200)        ttk.Entry(time_frame, textvariable=self.points_var, width=8).pack(side=tk.LEFT, padx=5)        # 执行按钮        execute_frame = ttk.Frame(control_frame)        execute_frame.grid(row=4, column=0, pady=10)        ttk.Button(execute_frame, text="执行转换"                  command=self.execute_conversion,                   style="Accent.TButton").pack(side=tk.LEFT, padx=5)        ttk.Button(execute_frame, text="保存配置"                  command=self.save_configuration).pack(side=tk.LEFT, padx=5)        ttk.Button(execute_frame, text="加载配置"                  command=self.load_configuration).pack(side=tk.LEFT, padx=5)        # 结果显示        result_frame = ttk.LabelFrame(control_frame, text="结果摘要", padding="10")        result_frame.grid(row=5, column=0, sticky=(tk.W, tk.E, tk.S), pady=5)        self.result_text = scrolledtext.ScrolledText(result_frame, height=10, width=40)        self.result_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))    def create_visualization_panel(self):        """创建可视化面板"""        viz_frame = ttk.LabelFrame(self.main_frame, text="可视化控制", padding="10")        viz_frame.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.E, tk.W))        # 可视化类型选择        ttk.Label(viz_frame, text="选择可视化类型:").grid(row=0, column=0, sticky=tk.W)        self.viz_vars = {            '3D轨道': tk.BooleanVar(value=True),            '地面轨迹': tk.BooleanVar(value=True),            '速度剖面': tk.BooleanVar(value=True),            '轨道能量': tk.BooleanVar(value=True),            '坐标系对比': tk.BooleanVar(value=False),            '参数变化': tk.BooleanVar(value=True)        }        for i, (name, var) in enumerate(self.viz_vars.items()):            ttk.Checkbutton(viz_frame, text=name, variable=var).grid(                row=1, column=i, padx=5)        # 自定义绘图选项        custom_frame = ttk.Frame(viz_frame)        custom_frame.grid(row=2, column=0, columnspan=6, pady=10)        ttk.Button(custom_frame, text="综合可视化"                  command=self.show_comprehensive_view).pack(side=tk.LEFT, padx=5)        ttk.Button(custom_frame, text="自定义视图"                  command=self.show_custom_view).pack(side=tk.LEFT, padx=5)        ttk.Button(custom_frame, text="导出图形"                  command=self.export_figure).pack(side=tk.LEFT, padx=5)        # 图形预览区域        self.preview_frame = ttk.Frame(viz_frame, relief=tk.SUNKEN, borderwidth=2)        self.preview_frame.grid(row=3, column=0, columnspan=6, sticky=(tk.N, tk.S, tk.E, tk.W), pady=10)        self.preview_label = ttk.Label(self.preview_frame,                                       text="图形预览区域\n(执行转换后显示)"                                      anchor=tk.CENTER)        self.preview_label.pack(expand=True, fill=tk.BOTH)        # 配置预览区域可扩展        viz_frame.rowconfigure(3, weight=1)        viz_frame.columnconfigure(0, weight=1)    def on_system_change(self, event=None):        """轨道系统改变时的处理"""        system = self.system_var.get()        self.clear_elements()        if system == "开普勒轨道根数":            self.load_keplerian_system()        elif system == "笛卡尔坐标":            self.load_cartesian_system()        elif system == "春分点轨道根数":            self.load_equinoctial_system()        elif system == "TLE两行元素":            self.load_tle_system()        elif system == "自定义":            self.load_custom_system()    def load_keplerian_system(self):        """加载开普勒轨道根数系统"""        elements = [            ("半长轴 a (km):""a"26500.0),            ("偏心率 e:""e"0.01),            ("轨道倾角 i (deg):""i"55.0),            ("升交点赤经 Ω (deg):""Omega"45.0),            ("近地点幅角 ω (deg):""omega"90.0),            ("平近点角 M (deg):""M"0.0),        ]        for label, key, default in elements:            self.add_element_input(label, key, default)    def load_cartesian_system(self):        """加载笛卡尔坐标系统"""        elements = [            ("X位置 (km):""x"0.0),            ("Y位置 (km):""y"26500.0),            ("Z位置 (km):""z"0.0),            ("X速度 (km/s):""vx"0.0),            ("Y速度 (km/s):""vy"0.0),            ("Z速度 (km/s):""vz"7.8),        ]        for label, key, default in elements:            self.add_element_input(label, key, default)    def load_equinoctial_system(self):        """加载春分点轨道根数系统"""        elements = [            ("半长轴 a (km):""a"26500.0),            ("h分量:""h"0.0),            ("k分量:""k"0.01),            ("p分量:""p"0.0),            ("q分量:""q", np.tan(np.radians(27.5))),            ("平经度 λ (deg):""lambda"0.0),        ]        for label, key, default in elements:            self.add_element_input(label, key, default)    def load_tle_system(self):        """加载TLE系统"""        elements = [            ("轨道倾角 (deg):""inclination"51.6),            ("升交点赤经 (deg):""raan"45.0),            ("偏心率:""eccentricity"0.001),            ("近地点幅角 (deg):""arg_perigee"90.0),            ("平近点角 (deg):""mean_anomaly"0.0),            ("平均运动 (rev/day):""mean_motion"15.5),            ("BSTAR:""bstar"0.0001),        ]        for label, key, default in elements:            self.add_element_input(label, key, default)    def load_custom_system(self):        """加载自定义系统(空)"""        pass    def add_element_input(self, label: str, key: str, default: float, required: bool = True):        """添加轨道根数输入框"""        if key in self.current_elements:            return        row = len(self.current_elements)        frame = ttk.Frame(self.scrollable_frame)        frame.grid(row=row, column=0, sticky=(tk.W, tk.E), pady=2)        ttk.Label(frame, text=label, width=25).pack(side=tk.LEFT)        var = tk.DoubleVar(value=default)        entry = ttk.Entry(frame, textvariable=var, width=15)        entry.pack(side=tk.LEFT, padx=5)        if not required:            var.set(None)            entry.configure(state='disabled')        # 可选复选框        if not required:            enabled_var = tk.BooleanVar(value=False)            ttk.Checkbutton(frame, text="启用", variable=enabled_var,                          command=lambda e=entry: self.toggle_element(e)).pack(side=tk.LEFT)        self.current_elements[key] = var    def toggle_element(self, entry):        """切换轨道根数启用状态"""        if entry.cget('state') == 'disabled':            entry.configure(state='normal')        else:            entry.configure(state='disabled')    def add_custom_element(self):        """添加自定义轨道根数"""        dialog = tk.Toplevel(self.root)        dialog.title("添加自定义轨道根数")        dialog.geometry("300x250")        ttk.Label(dialog, text="名称:").pack(pady=5)        name_var = tk.StringVar()        ttk.Entry(dialog, textvariable=name_var).pack()        ttk.Label(dialog, text="符号:").pack(pady=5)        symbol_var = tk.StringVar()        ttk.Entry(dialog, textvariable=symbol_var).pack()        ttk.Label(dialog, text="默认值:").pack(pady=5)        value_var = tk.DoubleVar(value=0.0)        ttk.Entry(dialog, textvariable=value_var).pack()        ttk.Label(dialog, text="单位:").pack(pady=5)        unit_var = tk.StringVar(value="")        ttk.Entry(dialog, textvariable=unit_var).pack()        def add():            name = name_var.get()            symbol = symbol_var.get() or name            value = value_var.get()            unit = unit_var.get()            if name:                self.custom_elements.append({                    'name': name,                    'symbol': symbol,                    'value': value,                    'unit': unit,                    'required'False                })                self.add_element_input(f"{name} ({unit}):", symbol, value, required=False)                dialog.destroy()        ttk.Button(dialog, text="添加", command=add).pack(pady=10)    def remove_last_element(self):        """移除最后一个轨道根数"""        if self.current_elements:            last_key = list(self.current_elements.keys())[-1]            del self.current_elements[last_key]            # 移除对应的UI元素            for widget in self.scrollable_frame.winfo_children()[-1:]:                widget.destroy()    def clear_elements(self):        """清空所有轨道根数"""        self.current_elements.clear()        for widget in self.scrollable_frame.winfo_children():            widget.destroy()    def get_elements_dict(self) -> Dict[strfloat]:        """获取当前轨道根数字典"""        elements = {}        system = self.system_var.get()        for key, var in self.current_elements.items():            try:                value = var.get()                # 角度转换为弧度                angle_keys = ['i''Omega''omega''M''lambda'                            'inclination''raan''arg_perigee''mean_anomaly']                if key in angle_keys:                    value = np.radians(value)                # 距离转换为米                distance_keys = ['a''x''y''z']                if key in distance_keys:                    value *= 1000                # 速度转换为m/s                velocity_keys = ['vx''vy''vz']                if key in velocity_keys:                    value *= 1000                elements[key] = value            except:                continue        # 添加摄动参数        for name, var in self.perturbation_vars.items():            if var.get():                if name == 'J2':                    elements['include_j2'] = True                elif name == 'J3':                    elements['include_j3'] = True                elif name == '光压':                    elements['include_solar_pressure'] = True                    elements['solar_pressure_coeff'] = 1.0                elif name == '大气阻力':                    elements['include_drag'] = True        return elements    def execute_conversion(self):        """执行轨道转换"""        try:            elements = self.get_elements_dict()            if not elements:                messagebox.showwarning("警告""请先输入轨道根数")                return            # 设置时间范围            total_time = self.time_var.get() * 3600  # 转换为秒            n_points = self.points_var.get()            time_array = np.linspace(0, total_time, n_points)            # 获取目标坐标系            target_coords = [name for name, var in self.coord_vars.items() if var.get()]            # 执行转换            self.current_results = self.converter.convert(                elements, time_array, target_coords            )            # 显示结果摘要            self.display_results_summary(elements)            # 自动显示可视化            self.show_auto_visualization()        except Exception as e:            messagebox.showerror("错误"f"转换失败: {str(e)}")    def display_results_summary(self, elements: Dict):        """显示结果摘要"""        self.result_text.delete(1.0, tk.END)        self.result_text.insert(tk.END, "=== 轨道转换结果 ===\n\n")        self.result_text.insert(tk.END, f"轨道根数系统: {self.system_var.get()}\n")        self.result_text.insert(tk.END, f"根数数量: {len(elements)}\n\n")        if 'ECEF' in self.current_results:            ecef = np.array(self.current_results['ECEF'])            self.result_text.insert(tk.END, "ECEF坐标范围:\n")            for i, coord in enumerate(['X''Y''Z']):                self.result_text.insert(tk.END,                     f"  {coord}{np.min(ecef[:, i])/1000:.2f} - {np.max(ecef[:, i])/1000:.2f} km\n")        if 'Geodetic' in self.current_results:            geo = np.array(self.current_results['Geodetic'])            self.result_text.insert(tk.END, "\n大地坐标范围:\n")            self.result_text.insert(tk.END,                 f"  纬度: {np.min(geo[:, 0]):.2f}° - {np.max(geo[:, 0]):.2f}°\n")            self.result_text.insert(tk.END,                 f"  经度: {np.min(geo[:, 1]):.2f}° - {np.max(geo[:, 1]):.2f}°\n")            self.result_text.insert(tk.END,                 f"  高度: {np.min(geo[:, 2])/1000:.2f} - {np.max(geo[:, 2])/1000:.2f} km\n")    def show_auto_visualization(self):        """自动显示可视化"""        selected_types = []        for name, var in self.viz_vars.items():            if var.get():                if name == '3D轨道':                    selected_types.append('3d_orbit')                elif name == '地面轨迹':                    selected_types.append('ground_track')                elif name == '速度剖面':                    selected_types.append('velocity')                elif name == '轨道能量':                    selected_types.append('energy')                elif name == '坐标系对比':                    selected_types.append('comparison')        if selected_types and hasattr(self'current_results'):            self.visualizer.create_custom_visualization(self.current_results, selected_types)    def show_comprehensive_view(self):        """显示综合视图"""        if not hasattr(self'current_results'):            messagebox.showwarning("警告""请先执行转换")            return        elements = self.get_elements_dict()        self.visualizer.create_comprehensive_visualization(self.current_results, elements)    def show_custom_view(self):        """显示自定义视图"""        if not hasattr(self'current_results'):            messagebox.showwarning("警告""请先执行转换")            return        dialog = tk.Toplevel(self.root)        dialog.title("自定义可视化")        dialog.geometry("400x300")        plot_options = ['3D轨道''地面轨迹''速度剖面''轨道能量''坐标系对比']        plot_vars = {name: tk.BooleanVar(value=Truefor name in plot_options}        for name, var in plot_vars.items():            ttk.Checkbutton(dialog, text=name, variable=var).pack(pady=5)        def show():            selected = [name for name, var in plot_vars.items() if var.get()]            plot_types = []            for name in selected:                if name == '3D轨道':                    plot_types.append('3d_orbit')                elif name == '地面轨迹':                    plot_types.append('ground_track')                elif name == '速度剖面':                    plot_types.append('velocity')                elif name == '轨道能量':                    plot_types.append('energy')                elif name == '坐标系对比':                    plot_types.append('comparison')            if plot_types:                self.visualizer.create_custom_visualization(self.current_results, plot_types)            dialog.destroy()        ttk.Button(dialog, text="显示", command=show).pack(pady=10)    def save_configuration(self):        """保存配置"""        elements = self.get_elements_dict()        config = {            'system'self.system_var.get(),            'elements': {k: v for k, v in elements.items() if not k.startswith('_')},            'time_hours'self.time_var.get(),            'n_points'self.points_var.get(),            'coordinates': {k: v.get() for k, v in self.coord_vars.items()},            'perturbations': {k: v.get() for k, v in self.perturbation_vars.items()},            'visualizations': {k: v.get() for k, v in self.viz_vars.items()}        }        filename = filedialog.asksaveasfilename(            defaultextension=".json",            filetypes=[("JSON files""*.json"), ("All files""*.*")]        )        if filename:            with open(filename, 'w'as f:                json.dump(config, f, indent=2)            messagebox.showinfo("成功"f"配置已保存到: {filename}")    def load_configuration(self):        """加载配置"""        filename = filedialog.askopenfilename(            filetypes=[("JSON files""*.json"), ("All files""*.*")]        )        if filename:            try:                with open(filename, 'r'as f:                    config = json.load(f)                # 恢复系统类型                self.system_var.set(config['system'])                self.on_system_change()                # 恢复轨道根数                for key, value in config['elements'].items():                    if key in self.current_elements:                        self.current_elements[key].set(value)                # 恢复其他设置                self.time_var.set(config.get('time_hours'24))                self.points_var.set(config.get('n_points'200))                for key, value in config.get('coordinates', {}).items():                    if key in self.coord_vars:                        self.coord_vars[key].set(value)                for key, value in config.get('perturbations', {}).items():                    if key in self.perturbation_vars:                        self.perturbation_vars[key].set(value)                for key, value in config.get('visualizations', {}).items():                    if key in self.viz_vars:                        self.viz_vars[key].set(value)                messagebox.showinfo("成功""配置加载完成")            except Exception as e:                messagebox.showerror("错误"f"加载配置失败: {str(e)}")    def export_figure(self):        """导出图形"""        if self.visualizer.figures:            filename = filedialog.asksaveasfilename(                defaultextension=".png",                filetypes=[("PNG files""*.png"), ("PDF files""*.pdf"),                           ("SVG files""*.svg"), ("All files""*.*")]            )            if filename:                self.visualizer.figures[-1].savefig(filename, dpi=300, bbox_inches='tight')                messagebox.showinfo("成功"f"图形已保存到: {filename}")        else:            messagebox.showwarning("警告""没有可导出的图形")    def load_presets(self):        """加载预设轨道"""        dialog = tk.Toplevel(self.root)        dialog.title("加载预设轨道")        dialog.transient(self.root)        dialog.grab_set()        dialog.focus_force()        dialog.lift()        dialog.attributes('-topmost'True)        # 计算弹窗在主窗口中心的位置        width, height = 400300        self.root.update_idletasks()        root_x = self.root.winfo_rootx()        root_y = self.root.winfo_rooty()        root_width = self.root.winfo_width()        root_height = self.root.winfo_height()        x = root_x + (root_width - width) // 2        y = root_y + (root_height - height) // 2        dialog.geometry(f"{width}x{height}+{x}+{y}")        presets = {            "LEO卫星": {                'system''开普勒轨道根数',                'a'26500'e'0.001'i'51.6,                'Omega'45'omega'90'M'0            },            "MEO卫星": {                'system''开普勒轨道根数',                'a'26500'e'0.01'i'55,                'Omega'0'omega'0'M'0            },            "GEO卫星": {                'system''开普勒轨道根数',                'a'42164'e'0.0'i'0,                'Omega'0'omega'0'M'0            },            "高椭圆轨道": {                'system''开普勒轨道根数',                'a'42164'e'0.7'i'63.4,                'Omega'0'omega'270'M'0            },            "太阳同步轨道": {                'system''开普勒轨道根数',                'a'7000'e'0.0'i'98,                'Omega'0'omega'0'M'0            }        }        listbox = tk.Listbox(dialog)        listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)        for preset_name in presets.keys():            listbox.insert(tk.END, preset_name)        def load_selected():            selection = listbox.curselection()            if selection:                preset_name = listbox.get(selection[0])                preset = presets[preset_name]                self.system_var.set(preset['system'])                self.on_system_change()                for key, value in preset.items():                    if key != 'system' and key in self.current_elements:                        self.current_elements[key].set(value)                dialog.destroy()        ttk.Button(dialog, text="加载", command=load_selected).pack(pady=10)    def run(self):        """运行GUI"""        self.root.mainloop()def main():    """主函数"""    print("=" * 60)    print("  通用轨道转换器 - 支持任意数量轨道根数")    print("=" * 60)    print("\n功能特性:")    print("  1. 支持多种轨道根数系统")    print("  2. 可自定义添加任意数量的轨道根数")    print("  3. 多坐标系转换 (ECI, ECEF, Geodetic, RIC, NTW)")    print("  4. 各种摄动模型 (J2, J3, J4, 光压, 大气阻力)")    print("  5. 丰富的可视化选项")    print("  6. 配置保存/加载")    print("  7. 数据导出功能")    print("\n启动GUI界面...")    app = UniversalOrbitGUI()    app.run()if __name__ == "__main__":    main()

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-02 23:28:10 HTTP/2.0 GET : https://f.mffb.com.cn/a/500168.html
  2. 运行时间 : 0.323662s [ 吞吐率:3.09req/s ] 内存消耗:4,966.01kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2fdcecd46b0292c7a39b744baf0da156
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000831s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001260s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000711s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000704s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001301s ]
  6. SELECT * FROM `set` [ RunTime:0.000572s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001403s ]
  8. SELECT * FROM `article` WHERE `id` = 500168 LIMIT 1 [ RunTime:0.009941s ]
  9. UPDATE `article` SET `lasttime` = 1783006090 WHERE `id` = 500168 [ RunTime:0.005800s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.008092s ]
  11. SELECT * FROM `article` WHERE `id` < 500168 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001632s ]
  12. SELECT * FROM `article` WHERE `id` > 500168 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.023064s ]
  13. SELECT * FROM `article` WHERE `id` < 500168 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.011194s ]
  14. SELECT * FROM `article` WHERE `id` < 500168 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.034830s ]
  15. SELECT * FROM `article` WHERE `id` < 500168 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.018993s ]
0.328262s