記錄一次獲取czml衛星軌道資料

友人A發表於2023-03-27

背景:
本次需求基於實現衛星模型掃描地球的業務。
技術棧採用:
cesium 1.103.0
html
czml

記錄:
1.衛星軌道資料獲取
地址:https://www.space-track.org/#catalog
我這裡選擇獲取fengyun的資料,可以得到一個TLE格式的兩行資料
image.png


image.png
2.衛星軌道資料通用轉換
因為有了tle資料,這裡也選擇去用sgp4來將資料轉換成czml格式檔案。

#!/usr/bin/python
# -*- coding:utf8 -*-

"""
本指令碼根據TLE檔案生成每顆衛星的CMZL檔案,用於前端js使用Cesium顯示衛星軌道
"""


# sgp4演算法根據二行星曆計算每個時間點衛星的位置
from sgp4.earth_gravity import wgs84
from sgp4.io import twoline2rv
import datetime
import json


# 按行讀取北斗兩行星曆檔案
# 每三行標識一個衛星,格式如下:
#   FENGYUN 1A
#   1 19467U 88080A   23086.12932362 -.00000103  00000-0 -36906-4 0  9992
#   2 19467  99.1890 121.7932 0014370  10.7878 349.3593 14.03214030768865
# 星曆下載地址:http://celestrak.com/
with open('fengyun.txt', 'r') as f:
    data_lines = f.read().split('\n')
#TLE每顆衛星資料必須三行:第一行名稱,後兩行資料"

# 使用字典的陣列(json檔案)儲存每顆衛星的軌道六根數
orbit_info = {}

# 每三行一組,遍歷所有衛星
for j in range(len(data_lines) // 3):
    # 第一行名字,後兩行資料
    # 資料詳細說明:http://celestrak.com/columns/v04n03/
    name = data_lines[j * 3].strip()
    line1 = data_lines[1 + j * 3]
    line2 = data_lines[2 + j * 3]

    # 寫軌道六根數到json檔案
    # print("衛星軌道傾斜角", line2[8:16], "度")
    # print("升交點赤經", line2[17:25], "度")
    # print("偏心率", line2[26:33])
    # print("近地點角距", line2[34: 42], "度")
    # print("平近點角", line2[43:51], "度")
    # print("平均運動(每天繞地球圈數)", line2[52:63])
    orbit_info.update({
        name: {
            'Inclination': line2[8:16],
            'Right Ascension of the Ascending Node'.replace(' ', '_'): line2[17:25],
            'Eccentricity': line2[26:33],
            'Argument of Perigee'.replace(' ', '_'): line2[34: 42],
            'Mean Anomaly'.replace(' ', '_'): line2[43:51],
            'Mean Motion'.replace(' ', '_'): line2[52:63]
        }
    })

    # 衛星每轉1°所經歷的時間(單位:秒)
    gap = 1. / float(line2[52:63]) * 24 * 60 * 60 / 360

    # 呼叫sgp4演算法計算星曆每個時刻的位置
    satellite = twoline2rv(line1, line2, wgs84)
    assert satellite.error == 0

    # 記錄當前時間,並在迴圈中計算出一個週期後的時間
    # 用於在CZML檔案中指定interval
    now_time = datetime.datetime.now()
    next_time = datetime.datetime.now()

    # 儲存每1°變化後衛星的位置(x, y, z):表示具體地心的距離(單位:km)
    position_list = []

    # 迴圈一圈
    # 每次間隔gap秒
    nums = 361
    for i in range(nums):
        # next_time表示每個位置對應的時間點
        next_time = now_time + datetime.timedelta(seconds=gap * (i + 1))
        # 表示為字典,方便propagate函式的計算
        next_time_str = next_time.strftime('%Y %m %d %H %M %S').split(' ')
        next_time_str = [int(v) for v in next_time_str]
        time_key = ['year', 'month', 'day', 'hour', 'minute', 'second']
        time_map = dict(zip(time_key, next_time_str))

        # 呼叫sgp4庫的propagate函式計算對應時刻的位置
        position, velocity = satellite.propagate(
            year=time_map['year'],
            month=time_map['month'],
            day=time_map['day'],
            hour=time_map['hour'],
            minute=time_map['minute'],
            second=time_map['second']
        )
        # The position vector measures the satellite position in kilometers from the center of the earth.
        # CZML檔案中position的格式為:(time, x, y, z, time, x, y, z...)
        position_list.append(next_time.isoformat())
        position_list.append(position[0] * 1000)
        position_list.append(position[1] * 1000)
        position_list.append(position[2] * 1000)

    # 格式化為ISO時間標準格式
    begin = str(now_time.isoformat())
    end = str((next_time + datetime.timedelta(seconds=gap)).isoformat())

    # Write the CZML document to a file
    filename = "D:/test/{}.czml".format(name)

    # 初始化CZML
    # CZML實際上是JSON檔案,JSON檔案就是字典陣列
    # 所以使用字典資料結構表示每個衛星
    doc = []

    # 定義頭部
    header = {
        # id和version為固定格式
        'id': "document",
        "version": "1.0",
        'name': name,
        "clock": {
            # interval為有效時間,currentTime表示起始點,multiplier表示時鐘速度
            "interval": '{}/{}'.format(begin, end),
            "currentTime": begin,
            "multiplier": gap
        }
    }
    doc.append(header)

    # 定義主體
    body = {
        "id": "satellites/{}".format(name),
        "availability": '{}/{}'.format(begin, end),
        "label": {
            # 使用label顯示衛星名字
            "font": "11pt Lucida Console",
            "outlineWidth": 2,
            "outlineColor": {"rgba": [0, 0, 0, 255]},
            "horizontalOrigin": "LEFT",
            "pixelOffset": {"cartesian2": [12, 0]},
            "fillColor": {"rgba": [213, 255, 0, 255]},
            "text": name
        },
        "path": {
            # path定義軌道的樣式
            "material": {
                "polyline": {
                    "color": {
                        "rgba": [255, 0, 255, 255]
                    }
                }
            },
            "width": 1,
            "resolution": 120
        },
        "billboard": {
            # 衛星的圖示,使用base64編碼表示圖片
            "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADJSURBVDhPnZHRDcMgEEMZjVEYpaNklIzSEfLfD4qNnXAJSFWfhO7w2Zc0Tf9QG2rXrEzSUeZLOGm47WoH95x3Hl3jEgilvDgsOQUTqsNl68ezEwn1vae6lceSEEYvvWNT/Rxc4CXQNGadho1NXoJ+9iaqc2xi2xbt23PJCDIB6TQjOC6Bho/sDy3fBQT8PrVhibU7yBFcEPaRxOoeTwbwByCOYf9VGp1BYI1BA+EeHhmfzKbBoJEQwn1yzUZtyspIQUha85MpkNIXB7GizqDEECsAAAAASUVORK5CYII=",
            "scale": 1.5
        },
        "position": {
            # cartesian的格式:(time, x, y, z, time, x, y, z...)
            "referenceFrame": "FIXED",  # 可以取FIXED和INERTIAL表示固定和慣性參考系
            # 插值填補軌道
            "interpolationDegree": 5,
            "interpolationAlgorithm": "LAGRANGE",
            "epoch": begin,
            "cartesian": position_list
        }
    }

    # 在body中新增position
    doc.append(body)

    # 使用JSON寫CZML檔案
    with open(filename, 'w') as f:
        json.dump(doc, f)

原創作者地址:https://segmentfault.com/u/yourena_c
3.cesium載入衛星軌道資料

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Cesium CZML Example</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/cesium/1.103.0/Cesium.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/cesium/1.103.0/Widgets/widgets.css" rel="stylesheet">
    <style>
        html, body, #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="cesiumContainer"></div>
    <script>
        // 初始化Cesium Viewer
        var viewer = new Cesium.Viewer('cesiumContainer');

        // 建立CzmlDataSource
        var dataSource = new Cesium.CzmlDataSource();

        // 載入CZML資料
        dataSource.load('./fengyun.czml').then(function() {
            // 新增資料到Viewer
            viewer.dataSources.add(dataSource);
            // 調整視角以檢視資料
            viewer.zoomTo(dataSource);
        });
    </script>
</body>
</html>

image.png

後續新增gltf衛星模型和掃描效果

相關文章