| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
=head1 NAME |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Time::TAI - International Atomic Time and realisations |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Time::TAI qw(tai_instant_to_mjd tai_mjd_to_instant); |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
$mjd = tai_instant_to_mjd($instant); |
|
10
|
|
|
|
|
|
|
$instant = tai_mjd_to_instant($mjd); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Time::TAI qw(tai_realisation); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
$rln = tai_realisation("npl"); |
|
15
|
|
|
|
|
|
|
$instant = $rln->to_tai($npl_instant); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
International Atomic Time (TAI) is a time scale produced by an ensemble |
|
20
|
|
|
|
|
|
|
of atomic clocks around Terra. It attempts to tick at the rate of proper |
|
21
|
|
|
|
|
|
|
time on the Terran geoid (i.e., at sea level), and thus is the principal |
|
22
|
|
|
|
|
|
|
realisation of Terrestrial Time (TT). It is the frequency standard |
|
23
|
|
|
|
|
|
|
underlying Coordinated Universal Time (UTC), and so is indirectly the |
|
24
|
|
|
|
|
|
|
basis for Terran civil timekeeping. |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
This module represents instants on the TAI time scale as a scalar number |
|
27
|
|
|
|
|
|
|
of TAI seconds since an epoch. This is an appropriate form for all manner |
|
28
|
|
|
|
|
|
|
of calculations. The TAI scale is defined with a well-known point at UT2 |
|
29
|
|
|
|
|
|
|
instant 1958-01-01T00:00:00.0 as calculated by the United States Naval |
|
30
|
|
|
|
|
|
|
Observatory. That instant is assigned the scalar value zero exactly, |
|
31
|
|
|
|
|
|
|
making it the epoch for this linear seconds count. This matches the |
|
32
|
|
|
|
|
|
|
convention used by C for instants on the TT scale. |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
There is also a conventional way to represent TAI instants using day-based |
|
35
|
|
|
|
|
|
|
notations associated with planetary rotation `time' scales. The `day' |
|
36
|
|
|
|
|
|
|
of TAI is a nominal period of exactly 86400 TAI seconds, which is |
|
37
|
|
|
|
|
|
|
slightly shorter than an actual Terran day. The well-known point at UT2 |
|
38
|
|
|
|
|
|
|
instant 1958-01-01T00:00:00.0 is assigned the label 1958-01-01T00:00:00.0 |
|
39
|
|
|
|
|
|
|
(MJD 36204.0). Because TAI is not connected to Terran rotation, and so |
|
40
|
|
|
|
|
|
|
has no inherent concept of a day, it is somewhat misleading to use such |
|
41
|
|
|
|
|
|
|
day-based notations. Conversion between this notation and the linear |
|
42
|
|
|
|
|
|
|
count of seconds is supported by this module. This notation does not |
|
43
|
|
|
|
|
|
|
match the similar day-based notation used for TT. |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Because TAI is canonically defined only in retrospect, real-time time |
|
46
|
|
|
|
|
|
|
signals can only approximate it. To achieve microsecond accuracy it |
|
47
|
|
|
|
|
|
|
is necessary to take account of this process. This module supports |
|
48
|
|
|
|
|
|
|
conversion of times between different realisations of TAI. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=cut |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
package Time::TAI; |
|
53
|
|
|
|
|
|
|
|
|
54
|
1
|
|
|
1
|
|
31579
|
{ use 5.006; } |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
38
|
|
|
55
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
51
|
|
|
56
|
1
|
|
|
1
|
|
11
|
use strict; |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
37
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
1
|
|
|
1
|
|
5
|
use Carp qw(croak); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
87
|
|
|
59
|
1
|
|
|
1
|
|
1450
|
use Math::BigRat 0.04; |
|
|
1
|
|
|
|
|
84643
|
|
|
|
1
|
|
|
|
|
8
|
|
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
our $VERSION = "0.003"; |
|
62
|
|
|
|
|
|
|
|
|
63
|
1
|
|
|
1
|
|
2635
|
use parent "Exporter"; |
|
|
1
|
|
|
|
|
404
|
|
|
|
1
|
|
|
|
|
4
|
|
|
64
|
|
|
|
|
|
|
our @EXPORT_OK = qw(tai_instant_to_mjd tai_mjd_to_instant tai_realisation); |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=over |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=item tai_instant_to_mjd(INSTANT) |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Converts from a count of seconds to a Modified Julian Date in the manner |
|
73
|
|
|
|
|
|
|
conventional for TAI. The MJD can be further converted to other forms of |
|
74
|
|
|
|
|
|
|
day-based date using other modules. The input must be a C |
|
75
|
|
|
|
|
|
|
object, and the result is the same type. |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=cut |
|
78
|
|
|
|
|
|
|
|
|
79
|
1
|
|
|
1
|
|
72
|
use constant TAI_EPOCH_MJD => Math::BigRat->new(36204); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
6
|
|
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub tai_instant_to_mjd($) { |
|
82
|
4
|
|
|
4
|
1
|
5455
|
my($tai) = @_; |
|
83
|
4
|
|
|
|
|
18
|
return TAI_EPOCH_MJD + ($tai / 86400); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=item tai_mjd_to_instant(MJD) |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Converts from a Modified Julian Date, interpreted in the manner |
|
89
|
|
|
|
|
|
|
conventional for TAI, to a count of seconds. The input must be a |
|
90
|
|
|
|
|
|
|
C object, and the result is the same type. |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=cut |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub tai_mjd_to_instant($) { |
|
95
|
4
|
|
|
4
|
1
|
4756
|
my($mjd) = @_; |
|
96
|
4
|
|
|
|
|
16
|
return ($mjd - TAI_EPOCH_MJD) * 86400; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item tai_realisation(NAME) |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Looks up and returns an object representing a named realisation of TAI. |
|
102
|
|
|
|
|
|
|
The object returned is of the class C; see the |
|
103
|
|
|
|
|
|
|
documentation of that class for its interface. |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
The name, recognised case-insensitively, may be of these forms: |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=over |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item "" (the empty string) |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
TAI itself, as defined retrospectively. |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item B |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
TAI(NPL), supplied in real time by the National Physical Laboratory in |
|
116
|
|
|
|
|
|
|
the UK. Other real-time estimates of TAI are named similarly using an |
|
117
|
|
|
|
|
|
|
abbreviation of the name of the supplying agency. The names recognised |
|
118
|
|
|
|
|
|
|
are: |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
aos cnm ftz inti lt nimb nrc pknm smu tug |
|
121
|
|
|
|
|
|
|
apl cnmp glo ipq lv nimt nrl pl snt ua |
|
122
|
|
|
|
|
|
|
asmw crl gps it mike nis nrlm psb so ume |
|
123
|
|
|
|
|
|
|
aus csao gum jatc mkeh nist ntsc ptb sp usno |
|
124
|
|
|
|
|
|
|
bev csir hko jv msl nmc omh rc sta vmi |
|
125
|
|
|
|
|
|
|
bim dlr ien kim nao nmij onba roa su vsl |
|
126
|
|
|
|
|
|
|
birm dmdm ifag kris naom nml onrj scl tao yuzm |
|
127
|
|
|
|
|
|
|
by dpt igma ksri naot nmls op sg tcc za |
|
128
|
|
|
|
|
|
|
cao dtag igna kz nict npl orb siq tl zipe |
|
129
|
|
|
|
|
|
|
ch eim inpl lds nim npli pel smd tp zmdm |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
See L for expansions of these abbreviations. |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Some pairs of these names refer to the same time scale, due to renaming |
|
134
|
|
|
|
|
|
|
of the underlying agency or transfer of responsibility for a time scale. |
|
135
|
|
|
|
|
|
|
It is possible that some names that should be aliases are treated |
|
136
|
|
|
|
|
|
|
as separate time scales, due to uncertainty of this module's author; |
|
137
|
|
|
|
|
|
|
see L. |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
The relationships between these scales and TAI are defined by isolated |
|
140
|
|
|
|
|
|
|
data points, so conversions in general involve interpolation. The process |
|
141
|
|
|
|
|
|
|
is by its nature inexact. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=back |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Other names may be recognised in the future, as more TAI(k) time scales |
|
146
|
|
|
|
|
|
|
are defined. |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=cut |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# |
|
151
|
|
|
|
|
|
|
# general |
|
152
|
|
|
|
|
|
|
# |
|
153
|
|
|
|
|
|
|
|
|
154
|
1
|
|
|
1
|
|
371
|
use constant MJD_1990_01 => 47892; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
50
|
|
|
155
|
1
|
|
|
1
|
|
10
|
use constant MJD_1991_01 => 48257; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
31
|
|
|
156
|
1
|
|
|
1
|
|
4
|
use constant MJD_1992_01 => 48622; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
38
|
|
|
157
|
1
|
|
|
1
|
|
3
|
use constant MJD_1993_01 => 48988; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
158
|
1
|
|
|
1
|
|
4
|
use constant MJD_1994_01 => 49353; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
45
|
|
|
159
|
1
|
|
|
1
|
|
4
|
use constant MJD_1995_01 => 49718; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
65
|
|
|
160
|
1
|
|
|
1
|
|
15
|
use constant MJD_1996_01 => 50083; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
46
|
|
|
161
|
1
|
|
|
1
|
|
5
|
use constant MJD_1997_01 => 50449; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
47
|
|
|
162
|
1
|
|
|
1
|
|
5
|
use constant MJD_1998_01 => 50814; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
41
|
|
|
163
|
1
|
|
|
1
|
|
4
|
use constant MJD_1999_01 => 51179; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
29
|
|
|
164
|
1
|
|
|
1
|
|
4
|
use constant MJD_2000_01 => 51544; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
165
|
1
|
|
|
1
|
|
4
|
use constant MJD_2001_01 => 51910; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
26
|
|
|
166
|
1
|
|
|
1
|
|
5
|
use constant MJD_2001_07 => 52091; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
167
|
1
|
|
|
1
|
|
10
|
use constant MJD_2002_01 => 52275; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
37
|
|
|
168
|
1
|
|
|
1
|
|
5
|
use constant MJD_2003_01 => 52640; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
27
|
|
|
169
|
1
|
|
|
1
|
|
4
|
use constant MJD_2003_04 => 52730; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
32
|
|
|
170
|
1
|
|
|
1
|
|
3
|
use constant MJD_2004_01 => 53005; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
26
|
|
|
171
|
1
|
|
|
1
|
|
4
|
use constant MJD_2005_01 => 53371; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
40
|
|
|
172
|
|
|
|
|
|
|
|
|
173
|
1
|
|
|
1
|
|
4
|
use constant UTC_1989_07 => Math::BigRat->new( 993945624); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
5
|
|
|
174
|
1
|
|
|
1
|
|
125
|
use constant UTC_1990_07 => Math::BigRat->new(1025481625); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
175
|
1
|
|
|
1
|
|
170
|
use constant UTC_1991_07 => Math::BigRat->new(1057017626); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
3
|
|
|
176
|
1
|
|
|
1
|
|
173
|
use constant UTC_1992_07 => Math::BigRat->new(1088640027); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6
|
|
|
177
|
1
|
|
|
1
|
|
180
|
use constant UTC_1993_07 => Math::BigRat->new(1120176028); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
4
|
|
|
178
|
1
|
|
|
1
|
|
168
|
use constant UTC_1994_07 => Math::BigRat->new(1151712029); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
3
|
|
|
179
|
1
|
|
|
1
|
|
184
|
use constant UTC_1995_07 => Math::BigRat->new(1183248029); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6
|
|
|
180
|
1
|
|
|
1
|
|
177
|
use constant UTC_1996_07 => Math::BigRat->new(1214870430); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
5
|
|
|
181
|
1
|
|
|
1
|
|
169
|
use constant UTC_1997_07 => Math::BigRat->new(1246406431); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
182
|
1
|
|
|
1
|
|
171
|
use constant UTC_1998_07 => Math::BigRat->new(1277942431); |
|
|
1
|
|
|
|
|
22
|
|
|
|
1
|
|
|
|
|
4
|
|
|
183
|
1
|
|
|
1
|
|
184
|
use constant UTC_1999_07 => Math::BigRat->new(1309478432); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4
|
|
|
184
|
1
|
|
|
1
|
|
199
|
use constant UTC_2000_07 => Math::BigRat->new(1341100832); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
185
|
1
|
|
|
1
|
|
145
|
use constant UTC_2001_07 => Math::BigRat->new(1372636832); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
9
|
|
|
186
|
1
|
|
|
1
|
|
133
|
use constant UTC_2002_07 => Math::BigRat->new(1404172832); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
3
|
|
|
187
|
1
|
|
|
1
|
|
152
|
use constant UTC_2003_02 => Math::BigRat->new(1422748832); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
188
|
1
|
|
|
1
|
|
179
|
use constant UTC_2003_07 => Math::BigRat->new(1435708832); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
4
|
|
|
189
|
1
|
|
|
1
|
|
168
|
use constant UTC_2004_07 => Math::BigRat->new(1467331232); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4
|
|
|
190
|
1
|
|
|
1
|
|
181
|
use constant UTC_2005_07 => Math::BigRat->new(1498867232); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4
|
|
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _get_bipm_file($) { |
|
193
|
0
|
|
|
0
|
|
|
my($fn) = @_; |
|
194
|
0
|
|
|
|
|
|
require LWP; |
|
195
|
0
|
|
|
|
|
|
LWP->VERSION(5.53_94); |
|
196
|
0
|
|
|
|
|
|
require LWP::UserAgent; |
|
197
|
0
|
|
|
|
|
|
my $response = LWP::UserAgent->new |
|
198
|
|
|
|
|
|
|
->get("ftp://ftp2.bipm.fr/pub/tai/$fn"); |
|
199
|
0
|
0
|
|
|
|
|
croak "can't download $fn: ".$response->message |
|
200
|
|
|
|
|
|
|
unless $response->code == 200; |
|
201
|
0
|
|
|
|
|
|
return $response->content; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
my $nl_rx = qr/\r?\n(?:\ *\r?\n)*/; |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# |
|
207
|
|
|
|
|
|
|
# UTC(k) data from utc-* files |
|
208
|
|
|
|
|
|
|
# |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _parse_utck_file($$$) { |
|
211
|
0
|
|
|
0
|
|
|
my($content, $min_mjd, $max_mjd) = @_; |
|
212
|
0
|
0
|
|
|
|
|
$content =~ /\A\ *MJD\ +\[UTC-UTC\([A-Z]+\ *\)\]\/ns |
|
213
|
|
|
|
|
|
|
(?:\ [^\n]*)?${nl_rx} |
|
214
|
|
|
|
|
|
|
(?>\ *[0-9]+\ +(?:-|-?[0-9]+(?:\.[0-9]+)?) |
|
215
|
|
|
|
|
|
|
(?:\ [^\n]*)?${nl_rx})* |
|
216
|
|
|
|
|
|
|
\x{1a}?\z/xo |
|
217
|
|
|
|
|
|
|
or die "doesn't look like a UTC-UTC(k) file\n"; |
|
218
|
0
|
|
|
|
|
|
require Time::TT::OffsetKnot; |
|
219
|
0
|
|
|
|
|
|
Time::TT::OffsetKnot->VERSION(0.004); |
|
220
|
0
|
|
|
|
|
|
my @data; |
|
221
|
0
|
|
|
|
|
|
my $last_mjd = 0; |
|
222
|
0
|
|
|
|
|
|
my $last_nonzero_mjd = 0; |
|
223
|
0
|
|
|
|
|
|
my $consecutive_zeroes = 0; |
|
224
|
0
|
|
|
|
|
|
while($content =~ /^\ *([0-9]+)\ +([-+]?[0-9]+(?:\.[0-9]+)?) |
|
225
|
|
|
|
|
|
|
[\ \r\n]/xmg) { |
|
226
|
0
|
|
|
|
|
|
my($mjd, $offset_ns) = ($1, $2); |
|
227
|
0
|
0
|
|
|
|
|
die "data out of order at mjd=$mjd" unless $mjd > $last_mjd; |
|
228
|
0
|
|
|
|
|
|
$last_mjd = $mjd; |
|
229
|
0
|
0
|
0
|
|
|
|
next unless $mjd >= $min_mjd && |
|
|
|
|
0
|
|
|
|
|
|
230
|
|
|
|
|
|
|
(!defined($max_mjd) || $mjd < $max_mjd); |
|
231
|
0
|
|
|
|
|
|
push @data, Time::TT::OffsetKnot->new($mjd, $offset_ns, 9); |
|
232
|
0
|
0
|
|
|
|
|
if($offset_ns =~ /\A-?0+(?:\.0+)?\z/) { |
|
233
|
0
|
|
|
|
|
|
$consecutive_zeroes++; |
|
234
|
|
|
|
|
|
|
} else { |
|
235
|
0
|
|
|
|
|
|
$consecutive_zeroes = 0; |
|
236
|
0
|
|
|
|
|
|
$last_nonzero_mjd = $last_mjd; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
# A couple of files have been seen with lots of bogus zero entries |
|
240
|
|
|
|
|
|
|
# at the end. |
|
241
|
0
|
0
|
|
|
|
|
splice @data, -$consecutive_zeroes if $consecutive_zeroes != 0; |
|
242
|
0
|
|
|
|
|
|
return (\@data, $last_nonzero_mjd); |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub _utck_file_source($$$;$); |
|
246
|
|
|
|
|
|
|
sub _utck_file_source($$$;$) { |
|
247
|
0
|
|
|
0
|
|
|
my($k, $rep_date, $min_mjd, $rpt) = @_; |
|
248
|
0
|
|
|
|
|
|
my $max_mjd; |
|
249
|
0
|
0
|
|
|
|
|
if(!defined($rpt)) { |
|
|
|
0
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
|
$rpt = { last_downloaded => 0, wait_until => 0 }; |
|
251
|
|
|
|
|
|
|
} elsif(ref($rpt) eq "") { |
|
252
|
0
|
|
|
|
|
|
$max_mjd = $rpt; |
|
253
|
0
|
|
|
|
|
|
$rpt = undef; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
0
|
|
|
|
|
|
require Math::Interpolator::Source; |
|
256
|
|
|
|
|
|
|
return Math::Interpolator::Source->new( |
|
257
|
|
|
|
|
|
|
sub () { |
|
258
|
0
|
0
|
|
0
|
|
|
if(defined $rpt) { |
|
259
|
0
|
|
|
|
|
|
my $time = time; |
|
260
|
0
|
0
|
0
|
|
|
|
croak "no more data for TT(TAI(".uc($k). |
|
261
|
|
|
|
|
|
|
")) available" |
|
262
|
|
|
|
|
|
|
unless $time >= $rpt->{wait_until} || |
|
263
|
|
|
|
|
|
|
$time < $rpt->{last_downloaded}; |
|
264
|
0
|
|
|
|
|
|
$rpt->{last_downloaded} = $time; |
|
265
|
0
|
|
|
|
|
|
$rpt->{wait_until} = |
|
266
|
|
|
|
|
|
|
$time + 86400 + rand(86400); |
|
267
|
|
|
|
|
|
|
} |
|
268
|
0
|
|
|
|
|
|
my($data, $last_mjd) = |
|
269
|
|
|
|
|
|
|
_parse_utck_file( |
|
270
|
|
|
|
|
|
|
_get_bipm_file("publication/utc-$k"), |
|
271
|
|
|
|
|
|
|
$min_mjd, $max_mjd); |
|
272
|
0
|
0
|
|
|
|
|
croak "no more data for TT(TAI(".uc($k).")) available" |
|
273
|
|
|
|
|
|
|
unless @$data; |
|
274
|
0
|
0
|
|
|
|
|
push @$data, _utck_file_source($k, |
|
275
|
|
|
|
|
|
|
$data->[-1]->x + 1000000, |
|
276
|
|
|
|
|
|
|
$last_mjd + 1, $rpt) |
|
277
|
|
|
|
|
|
|
if defined $rpt; |
|
278
|
0
|
|
|
|
|
|
return $data; |
|
279
|
|
|
|
|
|
|
}, |
|
280
|
0
|
|
|
|
|
|
$rep_date, $rep_date); |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# |
|
284
|
|
|
|
|
|
|
# UTC(k) data from utc.?? and utc??.ar files |
|
285
|
|
|
|
|
|
|
# |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub _parse_utcyr_file($$$) { |
|
288
|
0
|
|
|
0
|
|
|
my($content, $min_mjd, $max_mjd) = @_; |
|
289
|
0
|
0
|
|
|
|
|
$content =~ /\A\ *Values\ of\ UTC-UTC\(laboratory\)\ for |
|
290
|
|
|
|
|
|
|
(?>[^\n]+\n)+\n |
|
291
|
|
|
|
|
|
|
((?>(?>\ {5}(?:\ {4}[A-Z\ ]{4}){8}\n)+)) |
|
292
|
|
|
|
|
|
|
(?>[0-9]{5} |
|
293
|
|
|
|
|
|
|
(?:[\ \-\+][\ \-\+0-9]{3}\.(?:[0-9]{3}|0\ \ ) |
|
294
|
|
|
|
|
|
|
|\ {8}){8}\n)+ |
|
295
|
|
|
|
|
|
|
\z/x |
|
296
|
|
|
|
|
|
|
or die "doesn't look like a bulk UTC-UTC(k) file\n"; |
|
297
|
0
|
|
|
|
|
|
my @labs = map { [ map { lc } split ] } split(/\n/, $1); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
require Time::TT::OffsetKnot; |
|
299
|
0
|
|
|
|
|
|
Time::TT::OffsetKnot->VERSION(0.004); |
|
300
|
0
|
|
|
|
|
|
my %data; |
|
301
|
0
|
|
|
|
|
|
$content =~ /\n\n/g; |
|
302
|
0
|
|
|
|
|
|
my $last_mjd = 0; |
|
303
|
0
|
|
|
|
|
|
while($content =~ /^([0-9]{5})(.{64})\n/msg) { |
|
304
|
0
|
|
|
|
|
|
my($mjd, $numbers) = ($1, $2); |
|
305
|
0
|
0
|
|
|
|
|
die "data out of order at mjd=$mjd" unless $mjd > $last_mjd; |
|
306
|
0
|
|
|
|
|
|
$last_mjd = $mjd; |
|
307
|
0
|
|
|
|
|
|
for(my $line = 0; $line != @labs; $line++) { |
|
308
|
0
|
0
|
|
|
|
|
unless($line == 0) { |
|
309
|
0
|
0
|
|
|
|
|
$content =~ /^([0-9]{5})(.{64})\n/msg |
|
310
|
|
|
|
|
|
|
or die "incomplete data group\n"; |
|
311
|
0
|
|
|
|
|
|
($mjd, $numbers) = ($1, $2); |
|
312
|
0
|
0
|
|
|
|
|
die "inconsistent data group\n" |
|
313
|
|
|
|
|
|
|
unless $mjd eq $last_mjd; |
|
314
|
|
|
|
|
|
|
} |
|
315
|
0
|
0
|
0
|
|
|
|
next unless $mjd >= $min_mjd && $mjd < $max_mjd; |
|
316
|
0
|
|
|
|
|
|
for(my $i = 0; $i != 8; $i++) { |
|
317
|
0
|
|
|
|
|
|
my $num = substr($numbers, 8*$i, 8); |
|
318
|
0
|
|
|
|
|
|
my $lab = $labs[$line]->[$i]; |
|
319
|
0
|
0
|
|
|
|
|
if(!defined($lab)) { |
|
320
|
0
|
0
|
|
|
|
|
die "extraneous data\n" |
|
321
|
|
|
|
|
|
|
unless $num eq " "; |
|
322
|
0
|
|
|
|
|
|
next; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
0
|
0
|
|
|
|
|
next if $num eq " 0.0 "; |
|
325
|
0
|
0
|
|
|
|
|
die "malformed number\n" |
|
326
|
|
|
|
|
|
|
unless $num =~ /\A\ *([-+]?[0-9]+ |
|
327
|
|
|
|
|
|
|
\.[0-9]+)\z/x; |
|
328
|
0
|
|
|
|
|
|
push @{$data{$lab}}, |
|
|
0
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Time::TT::OffsetKnot |
|
330
|
|
|
|
|
|
|
->new($last_mjd, $1, 6); |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
} |
|
334
|
0
|
|
|
|
|
|
return \%data; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub _parse_utcyrar_file($$$) { |
|
338
|
0
|
|
|
0
|
|
|
my($content, $min_mjd, $max_mjd) = @_; |
|
339
|
0
|
0
|
|
|
|
|
$content =~ /\A[\ \t\n]*[^\n]*\ local\ representations\ of\ utc[\ :].* |
|
340
|
|
|
|
|
|
|
[\ \t\n]unit\ is\ one\ (micr|nan)osecond\./xsi |
|
341
|
|
|
|
|
|
|
or die "doesn't look like a bulk UTC-UTC(k) file\n"; |
|
342
|
0
|
0
|
|
|
|
|
my $unit = $1 =~ /\Amicr\z/i ? 6 : 9; |
|
343
|
0
|
|
|
|
|
|
require Time::TT::OffsetKnot; |
|
344
|
0
|
|
|
|
|
|
Time::TT::OffsetKnot->VERSION(0.004); |
|
345
|
0
|
|
|
|
|
|
my %data; |
|
346
|
|
|
|
|
|
|
my @labs; |
|
347
|
0
|
|
|
|
|
|
while($content =~ /^\ *0h\ UTC((?:\ +[A-Z]{1,4})+)\ *[\r\n] |
|
348
|
|
|
|
|
|
|
|^\ *[A-Z][a-z]{2}\ +[0-9]+\ +([0-9]+) |
|
349
|
|
|
|
|
|
|
((?:\ +(?:-|[-+]?[0-9]+(?:\.[0-9]+)?))+) |
|
350
|
|
|
|
|
|
|
\ *[\r\n]/xmg) { |
|
351
|
0
|
|
|
|
|
|
my($labs, $mjd, $offsets) = ($1, $2, $3); |
|
352
|
0
|
0
|
|
|
|
|
if(defined $labs) { |
|
353
|
0
|
|
|
|
|
|
@labs = map { lc } split(" ", $labs); |
|
|
0
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
foreach my $lab (@labs) { |
|
355
|
0
|
0
|
|
|
|
|
next if exists $data{$lab}; |
|
356
|
0
|
|
|
|
|
|
$data{$lab} = { |
|
357
|
|
|
|
|
|
|
last_mjd => 0, |
|
358
|
|
|
|
|
|
|
points => [], |
|
359
|
|
|
|
|
|
|
}; |
|
360
|
|
|
|
|
|
|
} |
|
361
|
0
|
|
|
|
|
|
next; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
0
|
0
|
|
|
|
|
die "data without heading\n" unless @labs; |
|
364
|
0
|
0
|
0
|
|
|
|
next unless $mjd >= $min_mjd && $mjd < $max_mjd; |
|
365
|
0
|
|
|
|
|
|
my @offsets = split(" ", $offsets); |
|
366
|
0
|
0
|
|
|
|
|
die "malformed table\n" unless @offsets == @labs; |
|
367
|
0
|
|
|
|
|
|
for(my $i = @labs; $i--; ) { |
|
368
|
0
|
|
|
|
|
|
my $lab = $labs[$i]; |
|
369
|
0
|
0
|
|
|
|
|
unless($mjd > $data{$lab}->{last_mjd}) { |
|
370
|
|
|
|
|
|
|
# there is a repeated table in utc98.ar |
|
371
|
0
|
0
|
|
|
|
|
next if $data{$lab}->{last_mjd} == 50994; |
|
372
|
0
|
|
|
|
|
|
die "data out of order at mjd=$mjd"; |
|
373
|
|
|
|
|
|
|
} |
|
374
|
0
|
|
|
|
|
|
$data{$lab}->{last_mjd} = $mjd; |
|
375
|
0
|
|
|
|
|
|
my $offset = $offsets[$i]; |
|
376
|
0
|
0
|
|
|
|
|
push @{$data{$lab}->{points}}, |
|
|
0
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Time::TT::OffsetKnot->new($mjd, $offset, $unit) |
|
378
|
|
|
|
|
|
|
unless $offset eq "-"; |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
} |
|
381
|
0
|
|
|
|
|
|
foreach my $lab (keys %data) { |
|
382
|
0
|
|
|
|
|
|
$data{$lab} = $data{$lab}->{points}; |
|
383
|
|
|
|
|
|
|
} |
|
384
|
0
|
|
|
|
|
|
return \%data; |
|
385
|
|
|
|
|
|
|
} |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# |
|
388
|
|
|
|
|
|
|
# UTC(GPS) & UTC(GLO) data from utcg(ps|lo)??.ar files |
|
389
|
|
|
|
|
|
|
# |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub _parse_gpsyr_file($$$) { |
|
392
|
0
|
|
|
0
|
|
|
my($content, $min_mjd, $max_mjd) = @_; |
|
393
|
0
|
0
|
|
|
|
|
$content =~ /\A[\ \t\n]*[^\n]* |
|
394
|
|
|
|
|
|
|
\[\ *(?:tai|utc)\ *-\ *(?:gps|glonass)\ time\]/xi |
|
395
|
|
|
|
|
|
|
or die "doesn't look like a GPS file\n"; |
|
396
|
0
|
0
|
|
|
|
|
my $unit = $content =~ /\(Unit is one microsecond\)/ ? 6 : 9; |
|
397
|
0
|
|
|
|
|
|
require Time::TT::OffsetKnot; |
|
398
|
0
|
|
|
|
|
|
Time::TT::OffsetKnot->VERSION(0.004); |
|
399
|
0
|
|
|
|
|
|
my @data; |
|
400
|
0
|
|
|
|
|
|
my $last_mjd = 0; |
|
401
|
|
|
|
|
|
|
# in some cases adjacent data lines are separated by a large number |
|
402
|
|
|
|
|
|
|
# of spaces instead of by a newline character |
|
403
|
0
|
|
|
|
|
|
while($content =~ /(?:^|\ {30})\ *[A-Z][a-z]{2}\ +[0-9]+\ +([0-9]+) |
|
404
|
|
|
|
|
|
|
\ +([-+]?[0-9]+(?:\.[0-9]+)?) |
|
405
|
|
|
|
|
|
|
(?:\ +(?:-|[-+]?[0-9]+(?:\.[0-9]+)?)){1,2} |
|
406
|
|
|
|
|
|
|
(?:\ *[\r\n]|\ {30})/xmg) { |
|
407
|
0
|
|
|
|
|
|
my($mjd, $offset) = ($1, $2); |
|
408
|
0
|
0
|
|
|
|
|
unless($mjd > $last_mjd) { |
|
409
|
|
|
|
|
|
|
# there are two data for one day in utcgps94.ar |
|
410
|
|
|
|
|
|
|
# (they give different C0 values, no idea which is |
|
411
|
|
|
|
|
|
|
# better) |
|
412
|
0
|
0
|
|
|
|
|
next if $mjd == 49709; |
|
413
|
0
|
|
|
|
|
|
die "data out of order at mjd=$mjd"; |
|
414
|
|
|
|
|
|
|
} |
|
415
|
0
|
|
|
|
|
|
$last_mjd = $mjd; |
|
416
|
0
|
0
|
0
|
|
|
|
next unless $mjd >= $min_mjd && $mjd < $max_mjd; |
|
417
|
0
|
|
|
|
|
|
push @data, Time::TT::OffsetKnot->new($mjd, $offset, $unit); |
|
418
|
|
|
|
|
|
|
} |
|
419
|
0
|
|
|
|
|
|
return \@data; |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
my %gpsyr_year = ( |
|
423
|
|
|
|
|
|
|
"93" => { |
|
424
|
|
|
|
|
|
|
min_mjd => MJD_1993_01, max_mjd => MJD_1994_01, |
|
425
|
|
|
|
|
|
|
rep_date => UTC_1993_07, |
|
426
|
|
|
|
|
|
|
}, |
|
427
|
|
|
|
|
|
|
"94" => { |
|
428
|
|
|
|
|
|
|
min_mjd => MJD_1994_01, max_mjd => MJD_1995_01, |
|
429
|
|
|
|
|
|
|
rep_date => UTC_1994_07, |
|
430
|
|
|
|
|
|
|
}, |
|
431
|
|
|
|
|
|
|
"95" => { |
|
432
|
|
|
|
|
|
|
min_mjd => MJD_1995_01, max_mjd => MJD_1996_01, |
|
433
|
|
|
|
|
|
|
rep_date => UTC_1995_07, |
|
434
|
|
|
|
|
|
|
}, |
|
435
|
|
|
|
|
|
|
"96" => { |
|
436
|
|
|
|
|
|
|
min_mjd => MJD_1996_01, max_mjd => MJD_1997_01, |
|
437
|
|
|
|
|
|
|
rep_date => UTC_1996_07, |
|
438
|
|
|
|
|
|
|
}, |
|
439
|
|
|
|
|
|
|
"97" => { |
|
440
|
|
|
|
|
|
|
min_mjd => MJD_1997_01, max_mjd => MJD_1998_01, |
|
441
|
|
|
|
|
|
|
rep_date => UTC_1997_07, |
|
442
|
|
|
|
|
|
|
}, |
|
443
|
|
|
|
|
|
|
"98" => { |
|
444
|
|
|
|
|
|
|
min_mjd => MJD_1998_01, max_mjd => MJD_1999_01, |
|
445
|
|
|
|
|
|
|
rep_date => UTC_1998_07, |
|
446
|
|
|
|
|
|
|
}, |
|
447
|
|
|
|
|
|
|
"99" => { |
|
448
|
|
|
|
|
|
|
min_mjd => MJD_1999_01, max_mjd => MJD_2000_01, |
|
449
|
|
|
|
|
|
|
rep_date => UTC_1999_07, |
|
450
|
|
|
|
|
|
|
}, |
|
451
|
|
|
|
|
|
|
"00" => { |
|
452
|
|
|
|
|
|
|
min_mjd => MJD_2000_01, max_mjd => MJD_2001_01, |
|
453
|
|
|
|
|
|
|
rep_date => UTC_2000_07, |
|
454
|
|
|
|
|
|
|
}, |
|
455
|
|
|
|
|
|
|
"01" => { |
|
456
|
|
|
|
|
|
|
min_mjd => MJD_2001_01, max_mjd => MJD_2002_01, |
|
457
|
|
|
|
|
|
|
rep_date => UTC_2001_07, |
|
458
|
|
|
|
|
|
|
}, |
|
459
|
|
|
|
|
|
|
"02" => { |
|
460
|
|
|
|
|
|
|
min_mjd => MJD_2002_01, max_mjd => MJD_2003_01, |
|
461
|
|
|
|
|
|
|
rep_date => UTC_2002_07, |
|
462
|
|
|
|
|
|
|
}, |
|
463
|
|
|
|
|
|
|
"03" => { |
|
464
|
|
|
|
|
|
|
min_mjd => MJD_2003_01, max_mjd => MJD_2003_04, |
|
465
|
|
|
|
|
|
|
rep_date => UTC_2003_02, |
|
466
|
|
|
|
|
|
|
}, |
|
467
|
|
|
|
|
|
|
); |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub _gpsyr_file_source($$) { |
|
470
|
0
|
|
|
0
|
|
|
my($k, $yr) = @_; |
|
471
|
0
|
|
|
|
|
|
my $year = $gpsyr_year{$yr}; |
|
472
|
0
|
0
|
|
|
|
|
die "GPS-style data requested for unknown year `$yr'" |
|
473
|
|
|
|
|
|
|
unless defined $year; |
|
474
|
0
|
|
|
|
|
|
require Math::Interpolator::Source; |
|
475
|
|
|
|
|
|
|
return Math::Interpolator::Source->new( |
|
476
|
|
|
|
|
|
|
sub () { |
|
477
|
0
|
|
|
0
|
|
|
return _parse_gpsyr_file( |
|
478
|
|
|
|
|
|
|
_get_bipm_file("scale/utc$k$yr.ar"), |
|
479
|
|
|
|
|
|
|
$year->{min_mjd}, $year->{max_mjd}); |
|
480
|
|
|
|
|
|
|
}, |
|
481
|
0
|
|
|
|
|
|
$year->{rep_date}, $year->{rep_date}); |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# |
|
485
|
|
|
|
|
|
|
# UTC(GPS) & UTC(GLO) data from utcgpsglo??.ar files |
|
486
|
|
|
|
|
|
|
# |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub _parse_gpsgloyr_file($$$) { |
|
489
|
0
|
|
|
0
|
|
|
my($content, $min_mjd, $max_mjd) = @_; |
|
490
|
0
|
0
|
|
|
|
|
$content =~ /\A[\ \t\n]*Relations\ of\ UTC\ and\ TAI\ with |
|
491
|
|
|
|
|
|
|
\ GPS\ time\ and\ GLONASS\ time[\ \t\n]/x |
|
492
|
|
|
|
|
|
|
or die "doesn't look like a GPS/GLONASS file\n"; |
|
493
|
0
|
|
|
|
|
|
require Time::TT::OffsetKnot; |
|
494
|
0
|
|
|
|
|
|
Time::TT::OffsetKnot->VERSION(0.004); |
|
495
|
0
|
|
|
|
|
|
my(@gps, @glo); |
|
496
|
0
|
|
|
|
|
|
my $last_mjd = 0; |
|
497
|
0
|
|
|
|
|
|
while($content =~ /^\ *[A-Z]{3}\ +[0-9]+\ +([0-9]+) |
|
498
|
|
|
|
|
|
|
\ +(-|[-+]?[0-9]+(?:\.[0-9]+)?)\ +[0-9]+ |
|
499
|
|
|
|
|
|
|
\ +(-|[-+]?[0-9]+(?:\.[0-9]+)?)\ +[0-9]+ |
|
500
|
|
|
|
|
|
|
\ *[\r\n]/xmg) { |
|
501
|
0
|
|
|
|
|
|
my($mjd, $gps_offset_ns, $glo_offset_ns) = ($1, $2, $3); |
|
502
|
0
|
0
|
|
|
|
|
die "data out of order at mjd=$mjd" unless $mjd > $last_mjd; |
|
503
|
0
|
|
|
|
|
|
$last_mjd = $mjd; |
|
504
|
0
|
0
|
0
|
|
|
|
next unless $mjd >= $min_mjd && $mjd < $max_mjd; |
|
505
|
0
|
0
|
|
|
|
|
push @gps, Time::TT::OffsetKnot->new($mjd, $gps_offset_ns, 9) |
|
506
|
|
|
|
|
|
|
unless $gps_offset_ns eq "-"; |
|
507
|
0
|
0
|
|
|
|
|
push @glo, Time::TT::OffsetKnot->new($mjd, $glo_offset_ns, 9) |
|
508
|
|
|
|
|
|
|
unless $glo_offset_ns eq "-"; |
|
509
|
|
|
|
|
|
|
} |
|
510
|
0
|
|
|
|
|
|
return { gps => \@gps, glo => \@glo }; |
|
511
|
|
|
|
|
|
|
} |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# |
|
514
|
|
|
|
|
|
|
# mechanism for multi-scale files |
|
515
|
|
|
|
|
|
|
# |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
my %multiscale = ( |
|
518
|
|
|
|
|
|
|
u90 => { |
|
519
|
|
|
|
|
|
|
filename => "scale/utc.90", |
|
520
|
|
|
|
|
|
|
parser => \&_parse_utcyr_file, |
|
521
|
|
|
|
|
|
|
min_mjd => MJD_1990_01, max_mjd => MJD_1991_01, |
|
522
|
|
|
|
|
|
|
rep_date => UTC_1990_07, |
|
523
|
|
|
|
|
|
|
}, |
|
524
|
|
|
|
|
|
|
u91 => { |
|
525
|
|
|
|
|
|
|
filename => "scale/utc.91", |
|
526
|
|
|
|
|
|
|
parser => \&_parse_utcyr_file, |
|
527
|
|
|
|
|
|
|
min_mjd => MJD_1991_01, max_mjd => MJD_1992_01, |
|
528
|
|
|
|
|
|
|
rep_date => UTC_1991_07, |
|
529
|
|
|
|
|
|
|
}, |
|
530
|
|
|
|
|
|
|
u92 => { |
|
531
|
|
|
|
|
|
|
filename => "scale/utc.92", |
|
532
|
|
|
|
|
|
|
parser => \&_parse_utcyr_file, |
|
533
|
|
|
|
|
|
|
min_mjd => MJD_1992_01, max_mjd => MJD_1993_01, |
|
534
|
|
|
|
|
|
|
rep_date => UTC_1992_07, |
|
535
|
|
|
|
|
|
|
}, |
|
536
|
|
|
|
|
|
|
u93 => { |
|
537
|
|
|
|
|
|
|
filename => "scale/utc93.ar", |
|
538
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
539
|
|
|
|
|
|
|
min_mjd => MJD_1993_01, max_mjd => MJD_1994_01, |
|
540
|
|
|
|
|
|
|
rep_date => UTC_1993_07, |
|
541
|
|
|
|
|
|
|
}, |
|
542
|
|
|
|
|
|
|
u94 => { |
|
543
|
|
|
|
|
|
|
filename => "scale/utc94.ar", |
|
544
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
545
|
|
|
|
|
|
|
min_mjd => MJD_1994_01, max_mjd => MJD_1995_01, |
|
546
|
|
|
|
|
|
|
rep_date => UTC_1994_07, |
|
547
|
|
|
|
|
|
|
}, |
|
548
|
|
|
|
|
|
|
u95 => { |
|
549
|
|
|
|
|
|
|
filename => "scale/utc95.ar", |
|
550
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
551
|
|
|
|
|
|
|
min_mjd => MJD_1995_01, max_mjd => MJD_1996_01, |
|
552
|
|
|
|
|
|
|
rep_date => UTC_1995_07, |
|
553
|
|
|
|
|
|
|
}, |
|
554
|
|
|
|
|
|
|
u96 => { |
|
555
|
|
|
|
|
|
|
filename => "scale/utc96.ar", |
|
556
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
557
|
|
|
|
|
|
|
min_mjd => MJD_1996_01, max_mjd => MJD_1997_01, |
|
558
|
|
|
|
|
|
|
rep_date => UTC_1996_07, |
|
559
|
|
|
|
|
|
|
}, |
|
560
|
|
|
|
|
|
|
u97 => { |
|
561
|
|
|
|
|
|
|
filename => "scale/utc97.ar", |
|
562
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
563
|
|
|
|
|
|
|
min_mjd => MJD_1997_01, max_mjd => MJD_1998_01, |
|
564
|
|
|
|
|
|
|
rep_date => UTC_1997_07, |
|
565
|
|
|
|
|
|
|
}, |
|
566
|
|
|
|
|
|
|
u98 => { |
|
567
|
|
|
|
|
|
|
filename => "scale/utc98.ar", |
|
568
|
|
|
|
|
|
|
parser => \&_parse_utcyrar_file, |
|
569
|
|
|
|
|
|
|
min_mjd => MJD_1998_01, max_mjd => MJD_1999_01, |
|
570
|
|
|
|
|
|
|
rep_date => UTC_1998_07, |
|
571
|
|
|
|
|
|
|
}, |
|
572
|
|
|
|
|
|
|
gg03 => { |
|
573
|
|
|
|
|
|
|
filename => "scale/utcgpsglo03.ar", |
|
574
|
|
|
|
|
|
|
parser => \&_parse_gpsgloyr_file, |
|
575
|
|
|
|
|
|
|
min_mjd => MJD_2003_04, max_mjd => MJD_2004_01, |
|
576
|
|
|
|
|
|
|
rep_date => UTC_2003_07, |
|
577
|
|
|
|
|
|
|
}, |
|
578
|
|
|
|
|
|
|
gg04 => { |
|
579
|
|
|
|
|
|
|
filename => "scale/utcgpsglo04.ar", |
|
580
|
|
|
|
|
|
|
parser => \&_parse_gpsgloyr_file, |
|
581
|
|
|
|
|
|
|
min_mjd => MJD_2004_01, max_mjd => MJD_2005_01, |
|
582
|
|
|
|
|
|
|
rep_date => UTC_2004_07, |
|
583
|
|
|
|
|
|
|
}, |
|
584
|
|
|
|
|
|
|
); |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
sub _multiscale_source($$) { |
|
587
|
0
|
|
|
0
|
|
|
my($k, $source) = @_; |
|
588
|
0
|
|
|
|
|
|
my $metadata = $multiscale{$source}; |
|
589
|
0
|
0
|
|
|
|
|
die "multi-scale data requsted from unknown source `$source'\n" |
|
590
|
|
|
|
|
|
|
unless defined $metadata; |
|
591
|
0
|
|
|
|
|
|
require Math::Interpolator::Source; |
|
592
|
|
|
|
|
|
|
return Math::Interpolator::Source->new( |
|
593
|
|
|
|
|
|
|
sub () { |
|
594
|
0
|
|
|
0
|
|
|
my $data = $metadata->{data}; |
|
595
|
0
|
0
|
|
|
|
|
unless(defined $data) { |
|
596
|
0
|
|
|
|
|
|
$data = $metadata->{parser}->( |
|
597
|
|
|
|
|
|
|
_get_bipm_file($metadata->{filename}), |
|
598
|
|
|
|
|
|
|
$metadata->{min_mjd}, |
|
599
|
|
|
|
|
|
|
$metadata->{max_mjd}); |
|
600
|
0
|
|
|
|
|
|
$metadata->{data} = $data; |
|
601
|
|
|
|
|
|
|
} |
|
602
|
0
|
|
0
|
|
|
|
return $data->{$k} || []; |
|
603
|
|
|
|
|
|
|
}, |
|
604
|
0
|
|
|
|
|
|
$metadata->{rep_date}, $metadata->{rep_date}); |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# |
|
608
|
|
|
|
|
|
|
# permanently-broken sources to represent missing data |
|
609
|
|
|
|
|
|
|
# |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
sub _bad_start_source($) { |
|
612
|
0
|
|
|
0
|
|
|
my($k) = @_; |
|
613
|
0
|
|
|
|
|
|
$k = uc($k); |
|
614
|
0
|
|
|
|
|
|
require Math::Interpolator::Source; |
|
615
|
|
|
|
|
|
|
return Math::Interpolator::Source->new( |
|
616
|
|
|
|
|
|
|
sub () { |
|
617
|
0
|
|
|
0
|
|
|
croak "earlier data for TT(TAI($k)) is missing"; |
|
618
|
|
|
|
|
|
|
}, |
|
619
|
0
|
|
|
|
|
|
UTC_1989_07, UTC_1989_07); |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub _bad_end_source($) { |
|
623
|
0
|
|
|
0
|
|
|
my($k) = @_; |
|
624
|
0
|
|
|
|
|
|
$k = uc($k); |
|
625
|
0
|
|
|
|
|
|
require Math::Interpolator::Source; |
|
626
|
|
|
|
|
|
|
return Math::Interpolator::Source->new( |
|
627
|
|
|
|
|
|
|
sub () { |
|
628
|
0
|
|
|
0
|
|
|
croak "later data for TT(TAI($k)) is missing"; |
|
629
|
|
|
|
|
|
|
}, |
|
630
|
0
|
|
|
|
|
|
UTC_2005_07, UTC_2005_07); |
|
631
|
|
|
|
|
|
|
} |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# |
|
634
|
|
|
|
|
|
|
# overall structure of realisations |
|
635
|
|
|
|
|
|
|
# |
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# |
|
638
|
|
|
|
|
|
|
# These recipes detail where to find data on each time scale. This is |
|
639
|
|
|
|
|
|
|
# necessary because the data are split up between several files, and |
|
640
|
|
|
|
|
|
|
# there are redundancies and renamings. The recipe string contains the |
|
641
|
|
|
|
|
|
|
# following items: |
|
642
|
|
|
|
|
|
|
# |
|
643
|
|
|
|
|
|
|
# "u90".."u98": utc.?? and utc??.ar files, which each contain data on |
|
644
|
|
|
|
|
|
|
# many UTC(k) time scales for a single year |
|
645
|
|
|
|
|
|
|
# "u": utc-* files, which each contain data on a single time scale |
|
646
|
|
|
|
|
|
|
# from 1998 onwards |
|
647
|
|
|
|
|
|
|
# "u*gum": special case: utc-gum has data only up to 2001-07 |
|
648
|
|
|
|
|
|
|
# "u*pl": special case: utc-pl has data from 2001-07 onwards |
|
649
|
|
|
|
|
|
|
# "g93".."g03": utcg(ps|lo)??.ar files, which each contain data on either |
|
650
|
|
|
|
|
|
|
# GPS or GLONASS for a single year |
|
651
|
|
|
|
|
|
|
# "gg03".."gg04": utcgpsglo??.ar files, which each contain GPS and GLONASS |
|
652
|
|
|
|
|
|
|
# data for a single year |
|
653
|
|
|
|
|
|
|
# "<": data missing at start |
|
654
|
|
|
|
|
|
|
# ">": data missing at end |
|
655
|
|
|
|
|
|
|
# ":dtag": change of name |
|
656
|
|
|
|
|
|
|
# "!": following data source has only blanks for this scale |
|
657
|
|
|
|
|
|
|
# "?": following data source has only redundant data for this scale |
|
658
|
|
|
|
|
|
|
# |
|
659
|
|
|
|
|
|
|
# or the recipe may consist entirely of: |
|
660
|
|
|
|
|
|
|
# |
|
661
|
|
|
|
|
|
|
# "=dtag": alias of referenced scale |
|
662
|
|
|
|
|
|
|
# "*tai": special case for TAI itself |
|
663
|
|
|
|
|
|
|
# |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
my %realisation = ( |
|
666
|
|
|
|
|
|
|
"" => "*tai", |
|
667
|
|
|
|
|
|
|
# not a real realisation: amc => "!u", |
|
668
|
|
|
|
|
|
|
aos => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
669
|
|
|
|
|
|
|
apl => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
670
|
|
|
|
|
|
|
asmw => "< u90 >", |
|
671
|
|
|
|
|
|
|
aus => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
672
|
|
|
|
|
|
|
bev => "< u90 u91 u92 u93 u94 u95 u96 !u97 ?u98 u", |
|
673
|
|
|
|
|
|
|
bim => "< :nmc u91 u92 u93 !u94 ?u :bim u", |
|
674
|
|
|
|
|
|
|
birm => "u95 u96 u97 ?u98 u", |
|
675
|
|
|
|
|
|
|
by => "u", |
|
676
|
|
|
|
|
|
|
cao => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
677
|
|
|
|
|
|
|
ch => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
678
|
|
|
|
|
|
|
cnm => "u96 u97 ?u98 u", |
|
679
|
|
|
|
|
|
|
cnmp => "u", |
|
680
|
|
|
|
|
|
|
crl => "=nict", |
|
681
|
|
|
|
|
|
|
csao => "=ntsc", |
|
682
|
|
|
|
|
|
|
csir => "=za", |
|
683
|
|
|
|
|
|
|
dlr => "u96 u97 ?u98 u", |
|
684
|
|
|
|
|
|
|
dmdm => "u", |
|
685
|
|
|
|
|
|
|
dpt => "=za", |
|
686
|
|
|
|
|
|
|
dtag => "< :ftz u90 u91 u92 u93 u94 u95 :dtag u96 u97 ?u98 u", |
|
687
|
|
|
|
|
|
|
eim => "u", |
|
688
|
|
|
|
|
|
|
ftz => "=dtag", |
|
689
|
|
|
|
|
|
|
glo => "< g93 g94 g95 g96 g97 g98 g99 g00 g01 g02 g03 gg03 gg04 >", |
|
690
|
|
|
|
|
|
|
gps => "< g93 g94 g95 g96 g97 g98 g99 g00 g01 g02 g03 gg03 gg04 >", |
|
691
|
|
|
|
|
|
|
gum => "=pl", |
|
692
|
|
|
|
|
|
|
hko => "u", |
|
693
|
|
|
|
|
|
|
ien => "=it", |
|
694
|
|
|
|
|
|
|
ifag => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
695
|
|
|
|
|
|
|
igma => "=igna", |
|
696
|
|
|
|
|
|
|
igna => "< :igma u90 u91 u92 u93 u94 u95 u96 u97 ?u98 :igna u", |
|
697
|
|
|
|
|
|
|
inpl => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
698
|
|
|
|
|
|
|
inti => "u", |
|
699
|
|
|
|
|
|
|
ipq => "u95 u96 u97 ?u98 u", |
|
700
|
|
|
|
|
|
|
it => "< :ien u90 u91 u92 u93 u94 u95 u96 u97 ?u98 ?u :it u", |
|
701
|
|
|
|
|
|
|
jatc => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
702
|
|
|
|
|
|
|
jv => "u", |
|
703
|
|
|
|
|
|
|
kim => "u", |
|
704
|
|
|
|
|
|
|
kris => "< :ksri u90 :kris u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
705
|
|
|
|
|
|
|
ksri => "=kris", |
|
706
|
|
|
|
|
|
|
kz => "u", |
|
707
|
|
|
|
|
|
|
lds => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
708
|
|
|
|
|
|
|
lt => "u", |
|
709
|
|
|
|
|
|
|
lv => "u", |
|
710
|
|
|
|
|
|
|
mike => "u", |
|
711
|
|
|
|
|
|
|
mkeh => "< :omh u90 u91 u92 u93 u94 u95 u96 u97 ?u98 ?u :mkeh u", |
|
712
|
|
|
|
|
|
|
msl => "< :pel u90 u91 :msl u92 u93 u94 u95 u96 u97 ?u98 u", |
|
713
|
|
|
|
|
|
|
nao => "< :naom u90 u91 u92 u93 u94 u95 u96 :nao u97 ?u98 u", |
|
714
|
|
|
|
|
|
|
naom => "=nao", |
|
715
|
|
|
|
|
|
|
naot => "< u92 u93 u94 u95 u96 >", |
|
716
|
|
|
|
|
|
|
nict => "< :crl u90 u91 u92 u93 u94 u95 u96 u97 ?u98 ?u :nict u", |
|
717
|
|
|
|
|
|
|
nim => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
718
|
|
|
|
|
|
|
nimb => "u", |
|
719
|
|
|
|
|
|
|
nimt => "u", |
|
720
|
|
|
|
|
|
|
nis => "u", |
|
721
|
|
|
|
|
|
|
nist => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
722
|
|
|
|
|
|
|
nmc => "=bim", |
|
723
|
|
|
|
|
|
|
nmij => "< :nrlm u90 u91 u92 u93 u94 u95 u96 u97 ?u98 ?u :nmij u", |
|
724
|
|
|
|
|
|
|
nml => "u97 u98", |
|
725
|
|
|
|
|
|
|
nmls => "u", |
|
726
|
|
|
|
|
|
|
npl => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
727
|
|
|
|
|
|
|
npli => "< u90 u91 u92 u93 u94 !u95 !u96 ?u98 u", |
|
728
|
|
|
|
|
|
|
nrc => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
729
|
|
|
|
|
|
|
nrl => "u", |
|
730
|
|
|
|
|
|
|
nrlm => "=nmij", |
|
731
|
|
|
|
|
|
|
ntsc => "< :csao u90 u91 u92 u93 u94 u95 u96 u97 ?u98 ?u :ntsc u", |
|
732
|
|
|
|
|
|
|
omh => "=mkeh", |
|
733
|
|
|
|
|
|
|
onba => "< u92 u93 u94 u95 u96 u97 ?u98 u", |
|
734
|
|
|
|
|
|
|
onrj => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
735
|
|
|
|
|
|
|
op => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
736
|
|
|
|
|
|
|
orb => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
737
|
|
|
|
|
|
|
pel => "=msl", |
|
738
|
|
|
|
|
|
|
pknm => "=pl", |
|
739
|
|
|
|
|
|
|
pl => "< :pknm u90 u91 u92 u93 :gum u94 u95 u96 u97 ?u98 u*gum :pl u*pl", |
|
740
|
|
|
|
|
|
|
psb => "=sg", |
|
741
|
|
|
|
|
|
|
ptb => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
742
|
|
|
|
|
|
|
rc => "< u90 u91 u92 u93 u94 u95 u96 >", |
|
743
|
|
|
|
|
|
|
roa => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
744
|
|
|
|
|
|
|
scl => "< u92 u93 u94 u95 u96 u97 ?u98 u", |
|
745
|
|
|
|
|
|
|
sg => ":psb u97 ?u98 ?u :sg u", |
|
746
|
|
|
|
|
|
|
siq => "u", |
|
747
|
|
|
|
|
|
|
smd => "u", |
|
748
|
|
|
|
|
|
|
smu => "?u98 u", |
|
749
|
|
|
|
|
|
|
snt => "< u91 u92 u93 u94 u95 >", |
|
750
|
|
|
|
|
|
|
so => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
751
|
|
|
|
|
|
|
sp => "u96 u97 ?u98 u", |
|
752
|
|
|
|
|
|
|
sta => "< u90 >", |
|
753
|
|
|
|
|
|
|
su => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
754
|
|
|
|
|
|
|
tao => "< u90 u91 >", |
|
755
|
|
|
|
|
|
|
tcc => "u", |
|
756
|
|
|
|
|
|
|
tl => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
757
|
|
|
|
|
|
|
tp => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
758
|
|
|
|
|
|
|
tug => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
759
|
|
|
|
|
|
|
ua => "u", |
|
760
|
|
|
|
|
|
|
ume => "u94 u95 u96 u97 ?u98 u", |
|
761
|
|
|
|
|
|
|
usno => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
762
|
|
|
|
|
|
|
vmi => "u", |
|
763
|
|
|
|
|
|
|
vsl => "< u90 u91 u92 u93 u94 u95 u96 u97 ?u98 u", |
|
764
|
|
|
|
|
|
|
yuzm => "< u90 u91 !u92 >", |
|
765
|
|
|
|
|
|
|
za => "< :dpt u90 u91 u92 :csir u93 u94 u95 u96 u97 ?u98 ?u :za u", |
|
766
|
|
|
|
|
|
|
zipe => "< u90 u91 >", |
|
767
|
|
|
|
|
|
|
zmdm => "=dmdm", |
|
768
|
|
|
|
|
|
|
); |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
sub tai_realisation($); |
|
771
|
|
|
|
|
|
|
sub tai_realisation($) { |
|
772
|
0
|
|
|
0
|
1
|
|
my($name) = @_; |
|
773
|
0
|
|
|
|
|
|
$name = lc($name); |
|
774
|
0
|
|
|
|
|
|
my $r = $realisation{$name}; |
|
775
|
0
|
0
|
|
|
|
|
croak "no realisation TT(TAI(".uc($name).")) known" unless defined $r; |
|
776
|
0
|
0
|
|
|
|
|
if(ref($r) eq "") { |
|
777
|
0
|
0
|
|
|
|
|
if($r =~ /\A=([a-z]+)\z/) { |
|
|
|
0
|
|
|
|
|
|
|
778
|
0
|
|
|
|
|
|
$r = tai_realisation($1); |
|
779
|
|
|
|
|
|
|
} elsif($r eq "*tai") { |
|
780
|
0
|
|
|
|
|
|
require Time::TAI::Realisation_TAI; |
|
781
|
0
|
|
|
|
|
|
$r = Time::TAI::Realisation_TAI->new; |
|
782
|
|
|
|
|
|
|
} else { |
|
783
|
0
|
|
|
|
|
|
my @parts; |
|
784
|
0
|
|
|
|
|
|
my $k = $name; |
|
785
|
0
|
|
|
|
|
|
foreach my $ingredient (split(/ /, $r)) { |
|
786
|
0
|
0
|
|
|
|
|
if($ingredient =~ /\A[!?]/) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
# ignore this data |
|
788
|
|
|
|
|
|
|
} elsif($ingredient =~ |
|
789
|
|
|
|
|
|
|
/\A(?:u|gg)[0-9][0-9]\z/) { |
|
790
|
0
|
|
|
|
|
|
push @parts, _multiscale_source($k, |
|
791
|
|
|
|
|
|
|
$ingredient); |
|
792
|
|
|
|
|
|
|
} elsif($ingredient eq "u") { |
|
793
|
0
|
|
|
|
|
|
push @parts, _utck_file_source($k, |
|
794
|
|
|
|
|
|
|
UTC_1998_07, MJD_1998_01); |
|
795
|
|
|
|
|
|
|
} elsif($ingredient eq "u*gum") { |
|
796
|
0
|
|
|
|
|
|
push @parts, _utck_file_source($k, |
|
797
|
|
|
|
|
|
|
UTC_1998_07, |
|
798
|
|
|
|
|
|
|
MJD_1998_01, MJD_2001_07), |
|
799
|
|
|
|
|
|
|
} elsif($ingredient eq "u*pl") { |
|
800
|
0
|
|
|
|
|
|
push @parts, _utck_file_source($k, |
|
801
|
|
|
|
|
|
|
UTC_2002_07, MJD_2001_07); |
|
802
|
|
|
|
|
|
|
} elsif($ingredient =~ /\Ag([0-9][0-9])\z/) { |
|
803
|
0
|
|
|
|
|
|
push @parts, |
|
804
|
|
|
|
|
|
|
_gpsyr_file_source($k, $1); |
|
805
|
|
|
|
|
|
|
} elsif($ingredient eq "<") { |
|
806
|
0
|
|
|
|
|
|
push @parts, _bad_start_source($k); |
|
807
|
|
|
|
|
|
|
} elsif($ingredient eq ">") { |
|
808
|
0
|
|
|
|
|
|
push @parts, _bad_end_source($k); |
|
809
|
|
|
|
|
|
|
} elsif($ingredient =~ /\A:([a-z]+)\z/) { |
|
810
|
0
|
|
|
|
|
|
$k = $1; |
|
811
|
|
|
|
|
|
|
} else { |
|
812
|
0
|
|
|
|
|
|
die "unrecognised ingredient ". |
|
813
|
|
|
|
|
|
|
"`$ingredient'"; |
|
814
|
|
|
|
|
|
|
} |
|
815
|
|
|
|
|
|
|
} |
|
816
|
0
|
|
|
|
|
|
require Math::Interpolator::Robust; |
|
817
|
0
|
|
|
|
|
|
$r = Math::Interpolator::Robust->new(@parts); |
|
818
|
0
|
|
|
|
|
|
require Time::TT::InterpolatingRealisation; |
|
819
|
0
|
|
|
|
|
|
$r = Time::TT::InterpolatingRealisation->new($r); |
|
820
|
|
|
|
|
|
|
} |
|
821
|
0
|
|
|
|
|
|
$realisation{$name} = $r; |
|
822
|
|
|
|
|
|
|
} |
|
823
|
0
|
|
|
|
|
|
return $r; |
|
824
|
|
|
|
|
|
|
} |
|
825
|
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
=back |
|
827
|
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=head1 BUGS |
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
For a few of the named realisations of TAI for which there is data, the |
|
831
|
|
|
|
|
|
|
author of this module was unable to determine conclusively whether they |
|
832
|
|
|
|
|
|
|
were renamed at some point. This affects particularly the names "naot", |
|
833
|
|
|
|
|
|
|
"snt", "sta", "tao". |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
Time scale data only goes back to the beginning of 1990. GPS and GLONASS |
|
836
|
|
|
|
|
|
|
data only goes back to the beginning of 1993, and forward to the end |
|
837
|
|
|
|
|
|
|
of 2004. |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
If you can supply more information about any of the time scales for |
|
840
|
|
|
|
|
|
|
which data is missing then please mail the author. |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
Time steps and frequency shifts are not noted in the time scale data |
|
843
|
|
|
|
|
|
|
available to this module. The smooth interpolation will therefore produce |
|
844
|
|
|
|
|
|
|
inaccurate results in the immediate vicinity of such discontinuities. |
|
845
|
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
847
|
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
L, |
|
849
|
|
|
|
|
|
|
L, |
|
850
|
|
|
|
|
|
|
L, |
|
851
|
|
|
|
|
|
|
L, |
|
852
|
|
|
|
|
|
|
L, |
|
853
|
|
|
|
|
|
|
L, |
|
854
|
|
|
|
|
|
|
L |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=head1 AUTHOR |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
Andrew Main (Zefram) |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
Copyright (C) 2006, 2007, 2010 Andrew Main (Zefram) |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
=head1 LICENSE |
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
|
867
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=cut |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
1; |