【Cesium】使用TLE轨道两行数计算轨道信息,并生成CZML格式文件

news2024/11/19 7:27:59

TLE为轨道两行数,简单的说是用两行数字表示轨道的相关信息,本文即用轨道两行数来计算任一时刻卫星的位置信息和速度信息,并生成CZML文件能够读取的格式

1、satellite.js库简介

简而言之,satellite.js库可以根据TLE轨道两行数,使用SGP4/SDP4方法对任一时刻卫星的位置信息速度信息进行计算,也可以完成地惯坐标系和地固坐标系下位置信息的转换等其他功能,本篇文章主要使用到satellite.js库的轨道计算功能,感兴趣的读者可以看一下这个库中其他的功能,链接放在下面
satellite.js库介绍
中文翻译
举例:

// 示例TLE轨道两行数
var tleLine1 = '1 25544U 98067A   19156.50900463  .00003075  00000-0  59442-4 0  9992',
    tleLine2 = '2 25544  51.6433  59.2583 0008217  16.4489 347.6017 15.51174618173442';    

// 初始化卫星记录
var satrec = satellite.twoline2satrec(tleLine1, tleLine2);

//  获取卫星在某一时间点的位置与方向信息 **(注意时间是从TLE记录的初始时刻后的分钟数,可以为负)**
var positionAndVelocity = satellite.sgp4(satrec, timeSinceTleEpochMinutes);

//  或者使用JavaScript日期
var positionAndVelocity = satellite.propagate(satrec, new Date());

// 获得地惯坐标系下的当前时间点的位置信息和速度信息
var positionEci = positionAndVelocity.position,
    velocityEci = positionAndVelocity.velocity;

// 将观察者(固定区域)设为西经122.03度,北纬36.96度(degreesToRadians——角度转弧度)
var observerGd = {
    longitude: satellite.degreesToRadians(-122.0308),
    latitude: satellite.degreesToRadians(36.9613422),
    height: 0.370
};

// 将GMT中国时、Julindate时转成格林尼治恒星时
var gmst = satellite.gstime(new Date());

// 地惯坐标系下的位置信息转换成地固坐标系下的位置信息
var positionEcf   = satellite.eciToEcf(positionEci, gmst),
// 大地坐标系转地固坐标系
    observerEcf   = satellite.geodeticToEcf(observerGd),
//  地惯坐标系转大地坐标系
    positionGd    = satellite.eciToGeodetic(positionEci, gmst),
//  获得观测角度
    lookAngles    = satellite.ecfToLookAngles(observerGd, positionEcf),
// 获得笛卡尔坐标中的x,y,z
var satelliteX = positionEci.x,
    satelliteY = positionEci.y,
    satelliteZ = positionEci.z;

// 角度可以通过' azimuth ', ' elevation ', ' range_sat '属性访问。
var azimuth   = lookAngles.azimuth,
    elevation = lookAngles.elevation,
    rangeSat  = lookAngles.rangeSat;

// 通过'经度','纬度','高度'访问大地坐标。
var longitude = positionGd.longitude,
    latitude  = positionGd.latitude,
    height    = positionGd.height;

//  将弧度转换为度。
var longitudeDeg = satellite.degreesLong(longitude),
    latitudeDeg  = satellite.degreesLat(latitude);

2、生成CZML能够识别的格式

使用CZML文件表示卫星,不仅需要知道卫星的位置信息,还需要知道卫星在运行过程中每一圈轨道的运行时间,这样画出来的轨道才能够是一圈一圈独立的
在这里插入图片描述
不然会出现轨道交叉的现象
这里使用二维地图表示,现实的更清楚
其实根本在于要控制好卫星轨迹提前出现的时间,以及轨迹保留的时间,也即leadIntervalArray和trailIntervalArray这两个参数,具体的代码如下:

const satellite = require('satellite.js')
const moment = require('moment')
const julian = require('julian')

/*
根据卫星显示的起始时间,终止时间,tle轨道两行数得出czml文件,时间为js的Date对象,tles为对象数组,对象格式为
{
name:xx,
tle1:xx,
tle2:xx
}
*/
function tles2czml(startTime, endTime, tles) {
    // 计算起始时间和终止时间相隔的分钟数
    let minsInDuration = (endTime.getTime() - startTime.getTime()) / 60000;   //mins
	//设置为开始时间
    let initialTime = moment(startTime.toISOString()).toISOString();
    //设置为结束时间
    endTime = moment(endTime.toISOString()).toISOString(); 
    // 初始化czml数据,创建场景信息
    let tempCZML = [];
    tempCZML.push({
        "id": "document",
        "name": "CZML Point - Time Dynamic",
        "version": "1.0",
        "clock": {
            "interval": `${initialTime}/${endTime}`,
            "multiplier": 1,
            "range": "LOOP_STOP",
            "step": "SYSTEM_CLOCK"
        }
    },
    )

    // 处理每一个sat
    for (let no = 0; no < tles.length; no++) {
        if(!tles[no].name){
            console.log("请输入第" + no+1 + "个卫星的名称");
            return
        };
        if(!tles[no].tle1){
            console.log("请输入第" + no+1 + "个卫星的第一个两行数");
            return
        };
        if(!tles[no].tle2){
            console.log("请输入第" + no+1 + "个卫星的第二个两行数");
            return
        };
        let sat_name = tles[no].name;
        // 保存位置信息
        let res = []; 
        let satrec 
        satrec = satellite.twoline2satrec(tles[no].tle1, tles[no].tle2);
        //satrec.no:以弧度/分钟为单位的平均运动,一天有1440分钟,一弧度是0.159155圈
        // to go from RAD/DAY -> REV/DAY: rad * 1440 * 0.159155
        //to go from REV/PER DAY to MINS/REV -> 1440/RevPerDay
        let totalIntervalsInDay = satrec.no * 1440 * 0.159155; //1440 = min && 0.159155 = 1turn
        // 获得运行一圈的分钟数
        let minsPerInterval = 1440 / totalIntervalsInDay; // mins for 1 revolution around earth
        // intervalTime 取结束时间 格式为2008-09-20T12:25:40.104Z
        let intervalTime = endTime

        let leadIntervalArray = [];
        let trailIntervalArray = [];
        console.log("Setting intervals...");
        // 注意:这里之所以要倒过来求leadInterval和trailInterval是因为如果正着求,很有可能在终止时刻卫星并没有运行完一圈,导致轨道只显示一半
        for (let i = minsInDuration; i >= 0; i -= minsPerInterval) {
            if (i <= minsPerInterval) { // intial interval 
                let currentOrbitalInterval = {
                    "interval": `${initialTime}/${intervalTime}`,
                    "epoch": `${initialTime}`,
                    "number": [
                        0, minsPerInterval * 60,
                        minsPerInterval * 60, 0
                    ]
                }
                let currTrail = {
                    "interval": `${initialTime}/${intervalTime}`,
                    "epoch": `${initialTime}`,
                    "number": [
                        0, 0,
                        minsPerInterval * 60, minsPerInterval * 60
                    ]
                }
                leadIntervalArray.push(currentOrbitalInterval);
                trailIntervalArray.push(currTrail);
            }
            else {	//not initial so make intervals 
                let previousIntervalTime = moment(intervalTime).add(-minsPerInterval, 'm').toISOString();
                let currentOrbitalInterval = {
                    "interval": `${previousIntervalTime}/${intervalTime}`,
                    "epoch": `${previousIntervalTime}`,
                    "number": [
                        0, minsPerInterval * 60,
                        minsPerInterval * 60, 0
                    ]
                }
                let currTrail = {
                    "interval": `${previousIntervalTime}/${intervalTime}`,
                    "epoch": `${previousIntervalTime}`,
                    "number": [
                        0, 0,
                        minsPerInterval * 60, minsPerInterval * 60
                    ]
                }
                intervalTime = moment(intervalTime).add(-minsPerInterval, 'm').toISOString();
                leadIntervalArray.push(currentOrbitalInterval);
                trailIntervalArray.push(currTrail);
            }
        }
        // Seconds between current time and epoch time
        let sec = (startTime - julian.toDate(satrec.jdsatepoch)) / 1000;
        console.log(startTime, julian.toDate(satrec.jdsatepoch), sec);
        for (let i = sec; i <= sec + minsInDuration * 60; i++) { //每60秒计算一个位置信息,最后采用拉格朗日插值法处理数据
            // 根据当前时间距tle两行数历元时刻的分钟数,计算当前卫星位置和速度
            let positionAndVelocity = satellite.sgp4(satrec, i * 0.0166667); // 0.0166667min = 1sec
            // 地惯坐标系
            let positionEci = positionAndVelocity.position;
            positionEci.x = positionEci.x * 1000;
            positionEci.y = positionEci.y * 1000;
            positionEci.z = positionEci.z * 1000;
            // let velocityEci = positionAndVelocity.velocity;
            // velocityEci.x = velocityEci.x * 1000;
            // velocityEci.y = velocityEci.y * 1000;
            // velocityEci.z = velocityEci.z * 1000;

            res.push(i - sec, positionEci.x, positionEci.y, positionEci.z);
        }
        let initialCZMLProps =
        {
            "id": `${sat_name}`,
            "name": `${sat_name}`,
            "availability": `${initialTime}/${endTime}`,
            "label": {
                "fillColor": {
                    "rgba": [
                        255, 0, 255, 255
                    ]
                },
                "font": "11pt Lucida Console",
                "horizontalOrigin": "LEFT",
                "outlineColor": {
                    "rgba": [
                        0, 0, 0, 255
                    ]
                },
                "outlineWidth": 2,
                "pixelOffset": {
                    "cartesian2": [
                        12, 0
                    ]
                },
                "show": true,
                "style": "FILL_AND_OUTLINE",
                "text": `${sat_name}`,
                "verticalOrigin": "CENTER"
            },
            "path": {
                "show": [
                    {
                        "interval": `${initialTime}/${endTime}`,
                        "boolean": true
                    }
                ],
                "width": 3,
                "material": {
                    "solidColor": {
                        "color": {
                            "rgba": [
                                // 随机生成轨道颜色
                                Math.floor(255 * Math.random(0, 1)), Math.floor(255 * Math.random(0, 1)), Math.floor(255 * Math.random(0, 1)), 255
                            ]
                        }
                    }
                },
                "resolution": 120,
                // The time ahead of the animation time, in seconds, to show the path.
                "leadTime": leadIntervalArray,
                // The time behind the animation time, in seconds, to show the
                "trailTime": trailIntervalArray
            },
            "model": {
                "show": true,
                "gltf": "./111.gltf",
                "minimumPixelSize": 50,
            },
            "position": {
                // 采用拉格朗日插值法
                "interpolationAlgorithm": "LAGRANGE",
                // 1为线性插值,2为平方插值
                "interpolationDegree": 2,
                // 参考坐标系,地惯坐标系
                "referenceFrame": "INERTIAL",
                "epoch": `${initialTime}`,
                "cartesian": res
            }
        }
        tempCZML.push(initialCZMLProps);
    }
    return tempCZML;
}
export default tles2czml

上面的方法参考了tle2czml库的写法,但是有一点需要注意,如果直接调用tle2czml库的话,最后一圈的卫星轨道往往是不完整的,本文所写的方法是根据时间倒序求leadInterval和trailInterval,这样即便到了终止时间,卫星的轨道显示也是完整的一圈。
如果对CZML文件格式有疑问的可以看 这里
欢迎交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue 项目适配笔记本1920*1080 125%缩放

前言 在台式机上开发pc端项目时&#xff0c;由于是1920*1080的分辨路和100缩放&#xff0c;看起来是没有问题。在笔记本上有问题 因为现在很多14寸的笔记本&#xff0c;出厂默认就是125%或150%的显示。导致很多时候我们的项目&#xff0c;自己开发的时候都是按照100%比例来开发…

Vue使用Serial连接串口

本来只是随手记录一下&#xff0c;发现看的人多了&#xff0c;想着还是修复一下bug吧&#xff0c;供各位看官指正 2022-10-24本次更新: 1、修复在不支持Serial的情况下&#xff0c;控制台报错 2022-09-19本次更新: 1、修复了传输数据接收分隔的情况(增加数据缓存) 2、修复串口连…

【中兴】web训练营~一文带你走进前端 | 百图制作

&#x1f4e2;作者简介&#xff1a;物联网领域创作者&#xff0c;&#x1f3c5;阿里云专家博主&#x1f3c5; &#x1f3c5;华为云享专家&#x1f3c5; ✒️个人主页&#xff1a;Choice~ &#x1f310;格言&#xff1a;可正因为难&#xff0c;才有价值&#xff01;&#x1f536…

Linux 使用Nginx部署web(vue、react)项目

前言 本文基于&#xff1a;操作系统 CentOS 7.6 使用的工具&#xff1a;Xshell7、Xftp7 1.安装所需依赖 安装gcc yum -y install gcc安装pcre、pcre-devel yum -y install pcre pcre-devel安装zlib、zlib-devel yum install -y zlib zlib-devel安装openssl、openssl-dev…

【uni-app】点击左上角返回按钮,弹出弹窗或者是携带参数返回上一页

目录 1、弹出弹窗 2、把这一页的数据带回到上一页&#xff08;获取下一页的数据 &#xff09; 3、跳转页面并携带参数&#xff0c;接受页获取参数 1、弹出弹窗 当我返回上一页的时候需要做一个判断是否需要保存 onBackPress 只支持APP和H5 但不支持小程序 &#xff0c;可以…

Java web—访问http://localhost:8080/xx/xx.jsp报404错误问题

由于我们在eclipse ee中把项目部署在web端经常会出现报404错误。 原因为&#xff1a; 404状态码是一种http状态码&#xff0c;其意思是&#xff1a; 所请求的页面不存在或已被删除。通俗的讲就是当用户输入了错误的链接时&#xff0c;返回的页面。 以下描述几种情况&#xff1a…

IDEA从零到精通(24)之lombok插件的安装与使用

文章目录作者简介引言导航概述安装插件使用小结导航热门专栏推荐作者简介 作者名&#xff1a;编程界明世隐 简介&#xff1a;CSDN博客专家&#xff0c;从事软件开发多年&#xff0c;精通Java、JavaScript&#xff0c;博主也是从零开始一步步把学习成长、深知学习和积累的重要性…

【Vue】 组件封装

目录1 组件封装1.1 全局注册1.2 局部注册1.2.1 命名1.2.2 引用组件1.2.2.1 传统写法1.2.2.2 setup1.2.2.3 easycom1.3 父子组件间的数据传递1.3.1 子组件 data() 中设置数据1.3.2 父组件通过 prop 将数据传递给子组件1.3.3 子组件不能直接修改 prop 中的值1.3.4 子组件通过 emi…

Pinia中action使用详解

actions的使用 动作相当于组件中的方法。它们可以使用actionsin 属性进行定义。 并且在pinia中的action既可以有同步函数也可以有异步函数。 在actions中可以通过this访问该仓库所有实例 export const useUsers defineStore(users,{state:()>{userData:null},actions:{a…

【SpringMVC】集成Web、MVC执行流程、数据响应、数据交互

文章目录前言一.Spring集成Web二.对于SpringMVC的理解三.MVC执行流程&#xff08;&#x1f3f3;️‍&#x1f308;&#xff09;1.组件解析2.RequestMapping四.SpringMVC数据响应页面跳转回写数据五.SpringMVC获得请求数据前言 SpringMVC确实很麻烦&#xff0c;零碎的点太多 一…

小程序自定义tabbar导航栏、动态控制tabbar功能实现(uniapp)

uniapp开发小程序&#xff0c;不同角色/已登录未登录&#xff0c;都有不一样的底部导航栏&#xff0c;这些情况下就需要自行定义tabbar&#xff0c;从而实现动态tabbar的实现。 1.首先我们需要在pages.json配置tabbar 我这里并没有开启custom(自定义)&#xff0c;不开启的话&a…

vue实现思维导图

介绍 前景&#xff1a; 仿幕布实现思维导图效果 技术实现&#xff1a;jsmind 完整代码&#xff1a;vue-jsmind 参考文章&#xff1a; 在vue中使用jsmind组织架构或思维导图 实现效果&#xff1a; 功能描述&#xff1a; 编辑、删除、插入、拖拽、展开/收起节点分布结构切换…

数字IC前端面试问题总结

本篇主要参考了 1、新芯设计(3条消息) 新芯设计的博客_CSDN博客-如何成为一名高级数字 IC 设计工程师,数字 IC 技能拓展,基于 SoC 的卷积神经网络车牌识别系统设计领域博主 2、小汪的IC自习室 (3条消息) 小汪的IC自习室的博客_CSDN博客-数字IC设计,SystemVerilog & I…

前端使用xlsx插件读取excel文件数据(保姆级教程)

本人属于一个实习菜鸟&#xff0c;大神请谨慎阅读............ 在开发过程中&#xff0c;难免会碰到用前端来处理excel文件的需求&#xff0c;我们需要解析出excel文件的内容然后在以对象的形式展示或者与后端对接 功能的实现思路&#xff1a; 文件选择 > FileReader对象…

微信小程序中使用vant框架,方法步骤清晰,简单适用

1.说到vant框架相信大家应该并不陌生了吧&#xff0c;做过移动端开发的小伙伴们应该都知道它吧。 2.Vant 是有赞前端团队开源的移动端组件库&#xff0c;于 2017 年开源&#xff0c;已持续维护 4 年时间。Vant 对内承载了有赞所有核心业务&#xff0c;对外服务十多万开发者&am…

Vue 权限菜单(动态路由)详解

今天记录一下Vue的权限菜单&#xff08;动态路由&#xff09;&#xff0c;在我们写后台的时候用的比较多&#xff0c;Vue的权限菜单分两种&#xff0c;一种是通过本地进行&#xff0c;根据账号的权限进行筛选出可用的权限&#xff0c;组合菜单并在页面上渲染显示&#xff0c;另…

Vue3 从入门到放弃 (第一篇.环境准备)

什么是 Vue&#xff1f;# Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的…

uniapp-路由uni-simple-router

背景 专为uniapp打造的路由器&#xff0c;和uniapp深度集成通配小程序、App和H5端H5能完全使用vue-router开发模块化、查询、通配符、路由参数使 uni-app实现嵌套路由&#xff08;仅H5端完全使用vue-router&#xff09;uniapp用到了很多vue的api&#xff0c;但在路由管理的功能…

vue 上传文件和下载文件

vue 上传文件和下载文件1. 上传文件2. 下载文件1. 上传文件 上传文件我所使用的组件是element ui 的 el-upload&#xff0c;我一共进行了如下两步&#xff0c;第一步&#xff1a;修改样式&#xff0c;因为el-upload的样式不是我所要的&#xff0c;我想要这种的 代码如下 <…

【Vue 项目】使用 vuedraggable 实现拖拽效果时遇到的问题及解决方案总结(允许 el-table 行拖拽、部分元素不允许拖拽、拖拽避免影响文字复制和输入框输入文字)

由于在自己的工作和学习过程中&#xff0c;只查看某个大佬的教程或文章无法满足自己的学习需求和解决遇到的问题&#xff0c;所以自己在追赶大佬们步伐的基础上&#xff0c;又自己总结、整理、汇总了一些资料&#xff0c;方便自己理解和后续回顾&#xff0c;同时也希望给大家带…