精密GNSS数据处理中主要涉及三种时间类型:以地球自转为基础建立的世界时系统;基于物质内部的原子运动特性的原子时系统;基于天体动力学理论的动力学时系统。
概念介绍
世界时(UT)
世界时是指通过观测恒星的视运动表达的时间系统,如恒星时(ST)指以春分点为参考连续两次经过地方子午圈的时间间隔。格林尼治平恒星时(GMST)消去了章动影响。 同理,以太阳为参考称为太阳时。以真太阳时的平均角速度在天球赤道上作周年视运动的 平太阳作为参考的为平太阳时。若平太阳时起点为平子夜,称为世界时(UT0)。UT0 进行 极移改正后的世界时记为 UT1,在 UT1 上进行地球自转周期性变化(如潮汐)改正后的世 界时记为UT2。
儒略日(JD)
儒略日(Julian Day)是在儒略周期内以连续的日数计算时间的计时法,主要是天文学家在使用。
儒略日数(Julian Day Number,JDN)的计算是从格林威治标准时间的中午开始,包含一个整天的时间,起点的时间(0日)回溯至儒略历的公元前4713年1月1日中午12点(在格里历是公元前4714年11月24日),这个日期是三种多年周期的共同起点,且是历史上最接近现代的一个起点。例如,2000年1月1日的UT12:00是儒略日2,451,545。
儒略日期(Julian date,JD)是以格林威治标准时中午12:00的儒略日加上那一天的瞬时时间的分数。儒略日期是儒略日添加小数部分所表示的儒略日数。例如,2013年1月1日00:30:00(UT)是儒略日期2,456,293.520833。
儒略周期(Julian Period)是开始于公元前4713年,长达7980年的纪年法,被用于历史上各种不同历法的日期转换。公元2018年是儒略周期的6731年,下一个儒略周期将开始于公元3268年。
简化儒略日(MJD)
简化儒略日(Modified Julian Day,MJD),是将儒略日(Julian Day,MJD)进行简化后得到的新计时法。1957年,简化儒略日由史密松天体物理台(Smithsonian Astrophysical Observatory)引入。
儒略日2400000是1858年11月16日,因为JD从中午开始计算,所以简化儒略日的定义中引入偏移量0.5,这意味着MJD 0相当于1858年11月17日的凌晨。并且每一个简化儒略日都在世界时午夜开始和结束。
简化儒略日有两个目的:
-
日期从午夜而不是中午开始。
-
儒略日的数值由7位数减为5位数,节省计算机储存空间。
动力学时(DT)
动力学时指以天体动力学理论为基础,建立运动方程并进行编算,采用独立变量时间 参数定义的时间系统。以太阳系质心为坐标原点的 DT称为太阳质心动力学时(TDB),以 地球质心为原点的 DT 称为地球动力学时(TDT,1992 年后称为地球时 TT)。DT 是一种 连续均匀的时间系统。TT 的起始时刻为 1977 年 1 月 1 日 0 时。
原子时(TAI)
国际原子时(Temps Atomique International, TAI)指以世界时 1958 年 1 月 1 日 0 时为起点,以铯原子基态两级间跃迁辐射的 9192631770 周所需的时间作为 1 秒秒长定义的一 种连续均匀的时间系统。TT 与 TAI 的转换关系
T
T
=
T
A
I
+
32.184
TT=TAI+32.184
TT=TAI+32.184
协调世界时(UTC)也属于 TAI,但是 UTC 通过跳秒保持与 UT1 在时刻上相近(差异小于 0.9s),从而有了实际的物理意义。跳秒的发生时间通常在一年的 6 月 30 日或 12 月 31 日最后一分钟变为 61s 或 59s。截止 2020 年 1 月,UTC 和 TAI 之间总的跳秒数为 37s, 近期的一次跳秒在 2016 年 12 月 31 日。UTC 与 TAI 的转换公式为
T
A
I
=
U
T
C
+
l
e
a
p
s
e
c
o
n
d
TAI=UTC+leap_second
TAI=UTC+leapsecond
leap_second为跳秒,其数值由国际地球自转和参考系统服务(International Earth Rotation and Reference System Service, IERS)机构维持和发布。 各GNSS 的时间系统也是基于原子时,只是定义的 UTC 时间起点存在差异。
代码实现
声明
#ifndef _TIME_H
#define _TIME_H
#include <math.h>
#include <stdio.h>
/* 通用时间定义; */
struct COMMONTIME
{
unsigned short Year;
unsigned short Month;
unsigned short Day;
unsigned short Hour;
unsigned short Minute;
double Second;
};
/* 简化儒略日; */
struct MJDTIME
{
int Days;
double FracDay;
MJDTIME()
{
Days = 0;
FracDay = 0.0;
}
};
/* 儒略日; */
struct JDTIME
{
int Days;
double FracDay;
JDTIME()
{
Days = 0;
FracDay = 0.0;
}
};
/* GPS时间定义 */
struct GPSTIME
{
unsigned short Week;
double SecOfWeek;
GPSTIME()
{
Week = 0;
SecOfWeek = 0.0;
}
};
/*通用时与简化儒略日;*/
bool CommonTime2MJDTime(COMMONTIME*Common, MJDTIME*MJD);
bool MJDTime2CommTime(MJDTIME*MJD,COMMONTIME*Common);
/*儒略日与简化儒略日;*/
bool JDTime2MJDTime(JDTIME*JD,MJDTIME*MJD);
bool MJDTime2JDTime(MJDTIME*MJD,JDTIME*JD);
/*儒略日与通用时;*/
bool JDTime2CommonTime(JDTIME*JD,COMMONTIME*Common);
bool CommonTime2JDTime(COMMONTIME*Common,JDTIME*JD);
/*GPST与通用时;*/
bool GPSTime2CommonTime(GPSTIME*GPS,COMMONTIME*Common);
bool CommonTime2GPSTime(COMMONTIME*Common,GPSTIME*GPS);
/*GPST与简化儒略日;*/
bool GPSTime2MJDTime(GPSTIME*GPS,MJDTIME*MJD);
bool MJDTime2GPSTime(MJDTIME*MJD,GPSTIME*GPS);
/*GPST与儒略日;*/
bool GPSTime2JDTime(GPSTIME*GPS,JDTIME*JD);
bool JDTime2GPSTime(JDTIME*JD,GPSTIME*GPS);
/*输出各种时间的函数;*/
bool PrintfCommon(COMMONTIME Common);
bool PrintfJD(JDTIME JD);
bool PrintfMJD(MJDTIME MJD);
bool PrintfGPST(GPSTIME GPS);
#endif
实现
/*--------------时间系统转换模板;---------------------
功能:提供儒略日,简化儒略日,GPST,通用时四个时间系统的任意两个间的相互转换功能;
包括;
//通用时与简化儒略日;
bool CommonTime2MJDTime;
bool MJDTime2CommTime;
//儒略日与简化儒略日;
bool JDTime2MJDTime;
bool MJDTime2JDTime;
//儒略日与通用时;
bool JDTime2CommonTime;
bool CommonTime2JDTime;
//GPST与通用时;
bool GPSTime2CommonTime;
bool CommonTime2GPSTime;
//GPST与简化儒略日;
bool GPSTime2MJDTime;
bool MJDTime2GPSTime;
//GPST与儒略日;
bool GPSTime2JDTime;
bool JDTime2GPSTime;
//输出各种时间的函数;
bool PrintfCommon;
bool PrintfJD;
bool PrintfMJD;
bool PrintfGPST;
-----------------------------------------------------*/
/*----------取小数部分;-------------------------
函数名称:FRAC
函数功能:输入一个浮点型变量,输出该变量的小数部分;
输入变量:;
input 要取小数部分的浮点型变量;
输出变量:;
return 浮点型变量的小数部分;
-------------------------------------------------*/
double FRAC(double input)
{
return (input - (int)(input));
}
/*-----------------通用时与简化儒略日的相互转换;----------------------
函数名称:;
bool CommonTime2MJDTime(COMMONTIME*Common, MJDTIME*MJD)
bool MJDTime2CommTime(MJDTIME*MJD, COMMONTIME*Common)
函数功能:;
实现通用时与简化儒略日之间的相互转换;
输入变量:;
*Common 通用时结构体地址;*MJD 简化儒略日结构体地址;
输出变量:;
*Common 通用时结构体地址;*MJD 简化儒略日结构体地址;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool CommonTime2MJDTime(const COMMONTIME Common, MJDTIME*MJD)
{
int y, m = 0;
double JD, UT = 0;
JDTIME jd;
if (Common.Month<=2)
{
y = Common.Year - 1;
m = Common.Month + 12;
}
if (Common.Month>2)
{
y = Common.Year;
m = Common.Month;
}
UT = Common.Hour + Common.Minute / 60.0 + Common.Second / 3600.0;
JD = (int)(365.25*y) + (int)(30.6001*(m + 1)) + Common.Day + UT / 24.0 + 1720981.5;
MJD->Days = (int)(365.25*y) + (int)(30.6001*(m + 1)) + Common.Day + UT / 24.0 + 1720981.5-2400000.5;
MJD->FracDay = (UT / 24.0 ) - (int)(UT / 24.0 );
return true;
}
bool MJDTime2CommTime(const MJDTIME MJD, COMMONTIME*Common)
{
int a, b, c, d, e = 0;
double UTDay = 0;
double UT = 0;
a = (int)(MJD.Days+MJD.FracDay + 2400000.5+0.5);
b = a + 1537;
c = (int)((1.0*b - 122.1) / (365.25));
d = (int)(365.25*c);
e = (int)((b - d)*1.0 / 30.6001);
UTDay = b - d - (int)(30.6001*e) + FRAC(MJD.Days + MJD.FracDay + 2400000.5 + 0.5);
Common->Day = (int)(UTDay);
Common->Month = e - 1 - 12 * (int)(e*1.0 / 14);
Common->Year = c - 4715 - (int)((7 + Common->Month)*1.0 / 10.0);
UT = (FRAC(UTDay) * 24.0);
/*Common->Hour = (int)(UT);
Common->Minute = (int)(FRAC(UT)*60.0);
Common->Second = FRAC(UT)*60.0*60.0-Common->Minute*60.0;*/
Common->Hour = int(MJD.FracDay * 24);
Common->Minute = int((MJD.FracDay * 24 - Common->Hour) * 60);
Common->Second = MJD.FracDay * 24 * 3600 - Common->Hour * 3600 - Common->Minute * 60;
return true;
}
/*-----------------简化儒略日与儒略日的相互转换;----------------------
函数名称:;
bool JDTime2MJDTime(JDTIME*JD, MJDTIME*MJD)
bool MJDTime2JDTime(MJDTIME*MJD, JDTIME*JD)
函数功能:;
实现简化儒略日与儒略日的相互转换;
输入变量:;
*JD 通用时结构体地址;*MJD 简化儒略日结构体地址;
输出变量:;
*JD 通用时结构体地址;*MJD 简化儒略日结构体地址;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool JDTime2MJDTime(const JDTIME JD, MJDTIME*MJD)
{
MJD->Days = JD.Days - 2400000 - (int)(JD.FracDay - 0.5-1);
MJD->FracDay = FRAC(JD.FracDay + 1 - 0.5);
return true;
}
bool MJDTime2JDTime(const MJDTIME MJD, JDTIME*JD)
{
JD->Days = MJD.Days + 2400000 + (int)(MJD.FracDay + 0.5);
JD->FracDay = FRAC(MJD.FracDay+0.5);
return true;
}
/*-----------------通用时与儒略日的相互转换;----------------------
函数名称:;
bool CommonTime2JDTime(COMMONTIME*Common, JDTIME*JD)
bool JDTime2CommTime(JDTIME*MJD, COMMONTIME*Common)
函数功能:;
实现通用时与儒略日之间的相互转换;
输入变量:;
*Common 通用时结构体地址;*JD 儒略日结构体地址;
输出变量:;
*Common 通用时结构体地址;*JD 儒略日结构体地址;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool JDTime2CommonTime(const JDTIME JD, COMMONTIME*Common)
{
MJDTIME MJD;
MJD.Days = JD.Days - 2400000 - (int)(JD.FracDay - 0.5 - 1);
MJD.FracDay = FRAC(JD.FracDay + 1 - 0.5);
int a, b, c, d, e = 0;
double UTDay = 0;
double UT = 0;
a = (int)(MJD.Days + MJD.FracDay + 2400000.5 + 0.5);
b = a + 1537;
c = (int)((1.0*b - 122.1) / (365.25));
d = (int)(365.25*c);
e = (int)((b - d)*1.0 / 30.6001);
UTDay = b - d - (int)(30.6001*e) + FRAC(MJD.Days + MJD.FracDay + 2400000.5 + 0.5);
Common->Day = (int)(UTDay);
Common->Month = e - 1 - 12 * (int)(e*1.0 / 14);
Common->Year = c - 4715 - (int)((7 + Common->Month)*1.0 / 10.0);
UT = (FRAC(UTDay) * 24.0);
Common->Hour = int(MJD.FracDay * 24);
Common->Minute = int((MJD.FracDay * 24 - Common->Hour) * 60);
Common->Second = MJD.FracDay * 24 * 3600 - Common->Hour * 3600 - Common->Minute * 60;
return true;
}
bool CommonTime2JDTime(const COMMONTIME Common, JDTIME*JD)
{
int y, m = 0;
double TemptJD, UT = 0;
if (Common.Month <= 2)
{
y = Common.Year - 1;
m = Common.Month + 12;
}
if (Common.Month > 2)
{
y = Common.Year;
m = Common.Month;
}
UT = Common.Hour + Common.Minute / 60.0 + Common.Second / 3600.0;
TemptJD = (int)(365.25*y) + (int)(30.6001*(m + 1)) + Common.Day + UT / 24.0 + 1720981.5;
JD->Days = (int)(TemptJD);
JD->FracDay = (TemptJD)-JD->Days;
return true;
}
/*-----------------通用时与GPST的相互转换;----------------------
函数名称:;
bool GPSTime2CommonTime(GPSTIME*GPS, COMMONTIME*Common)
bool CommonTime2GPSTime(COMMONTIME*Common, GPSTIME*GPS)
函数功能:;
实现通用时与GPST的相互转换;
输入变量:;
*GPS,*Common;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool GPSTime2CommonTime(const GPSTIME GPS, COMMONTIME*Common)
{
MJDTIME MJD;
MJD.Days = 44244 + GPS.Week * 7 + (int)(GPS.SecOfWeek / 86400.0);
MJD.FracDay = FRAC(GPS.SecOfWeek / 86400.0);
int a, b, c, d, e = 0;
double UTDay = 0;
double UT = 0;
a = (int)(MJD.Days + MJD.FracDay + 2400000.5 + 0.5);
b = a + 1537;
c = (int)((1.0*b - 122.1) / (365.25));
d = (int)(365.25*c);
e = (int)((b - d)*1.0 / 30.6001);
UTDay = b - d - (int)(30.6001*e) + FRAC(MJD.Days + MJD.FracDay + 2400000.5 + 0.5);
Common->Day = (int)(UTDay);
Common->Month = e - 1 - 12 * (int)(e*1.0 / 14);
Common->Year = c - 4715 - (int)((7 + Common->Month)*1.0 / 10.0);
UT = (FRAC(UTDay) * 24.0);
Common->Hour = int(MJD.FracDay * 24);
Common->Minute = int((MJD.FracDay * 24 - Common->Hour) * 60);
Common->Second = MJD.FracDay * 24 * 3600 - Common->Hour * 3600 - Common->Minute * 60;
return true;
}
bool CommonTime2GPSTime(const COMMONTIME Common, GPSTIME*GPS)
{
MJDTIME MJD;
int y, m = 0;
double UT = 0;
if (Common.Month <= 2)
{
y = Common.Year - 1;
m = Common.Month + 12;
}
if (Common.Month>2)
{
y = Common.Year;
m = Common.Month;
}
UT = Common.Hour + Common.Minute / 60.0 + Common.Second / 3600.0;
MJD.Days = (int)(365.25*y) + (int)(30.6001*(m + 1)) + Common.Day + UT / 24.0 + 1720981.5 - 2400000.5;
MJD.FracDay = (UT / 24.0) - (int)(UT / 24.0);
GPS->Week = (int)((MJD.Days - 44244) / 7.0);
GPS->SecOfWeek = MJD.Days*86400.0 - 44244 * 86400.0 - GPS->Week * 7*86400.0 + MJD.FracDay * 86400;
return true;
}
/*-----------------简化儒略日与GPST的相互转换;----------------------
函数名称:;
bool GPSTime2MJDTime(GPSTIME*GPS, MJDTIME*MJD)
bool MJDTime2GPSTime(MJDTIME*MJD, GPSTIME*GPS)
函数功能:;
简化儒略日与GPST的相互转换;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool GPSTime2MJDTime(const GPSTIME GPS, MJDTIME*MJD)
{
double temptMJD;
temptMJD = 44244 + GPS.Week * 7 + GPS.SecOfWeek / 86400;
MJD->Days = (int)(temptMJD);
MJD->FracDay = FRAC(temptMJD);
return true;
}
bool MJDTime2GPSTime(const MJDTIME MJD, GPSTIME*GPS)
{
GPS->Week = (int)((MJD.Days + MJD.FracDay - 44244) / 7.0);
GPS->SecOfWeek = (MJD.Days + MJD.FracDay - 44244 - GPS->Week * 7) * 86400;
return true;
}
/*-----------------儒略日与GPST的相互转换;----------------------
函数名称:;
bool GPSTime2JDTime(GPSTIME*GPS, JDTIME*JD)
bool JDTime2GPSTime(JDTIME*JD, GPSTIME*GPS)
函数功能:;
儒略日与GPST的相互转换;
公式来源:;
卫星导航算法与程序设计PPT
-------------------------------------------------------------------*/
bool GPSTime2JDTime(const GPSTIME GPS, JDTIME*JD)
{
double temptJD;
temptJD = 44244 + GPS.Week * 7 + GPS.SecOfWeek / 86400 + 2400000.5;
JD->Days = (int)(temptJD);
JD->FracDay = FRAC(temptJD);
return true;
}
bool JDTime2GPSTime(const JDTIME JD, GPSTIME*GPS)
{
GPS->Week = (int)((JD.Days + JD.FracDay - 2400000.5 - 44244) / 7.0);
GPS->SecOfWeek = (JD.Days + JD.FracDay - 2400000.5 - 44244 - GPS->Week * 7) * 86400;
return true;
}
/*------------------输出各种时间系统;--------------------
函数功能:输出各种时间系统的值,一个只能输出一个结构体的变量;
函数名称:;
bool PrintfCommon(COMMONTIME Common) 输出通用时;
bool PrintfJD(JDTIME JD) 输出儒略日;
bool PrintfMJD(MJDTIME MJD) 输出简化儒略日;
bool PrintfGPST(GPSTIME GPS) 输出GPST;
-----------------------------------------------------*/
bool PrintfCommon(COMMONTIME Common)
{
if (Common.Day>31)
{
printf("number of day was wrong!\n");
return false;
}
if (Common.Hour>24||Common.Hour<0)
{
printf("number of hour was wrong!\n");
return false;
}
if (Common.Minute>60||Common.Minute<0)
{
printf("number of minute was wrong!\n");
return false;
}
if (Common.Second>60||Common.Second<0)
{
printf("number of second was wrong!\n");
return false;
}
printf("%d.%d.%d %d:%d:%lf;\n", Common.Year, Common.Month, Common.Day, Common.Hour, Common.Minute, Common.Second);
return true;
}
bool PrintfJD(JDTIME JD)
{
printf("%lf;\n", JD.FracDay + JD.Days);
return true;
}
bool PrintfMJD(MJDTIME MJD)
{
printf("%lf;\n", MJD.FracDay + MJD.Days);
return true;
}
bool PrintfGPST(GPSTIME GPS)
{
if (GPS.SecOfWeek<0||GPS.SecOfWeek>604800)
{
printf("number of time of week was wrong!\n");
return false;
}
printf("%d %d;\n", GPS.Week, GPS.SecOfWeek);
return true;
}