You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.4 KiB

function [utcTime] = Gps2Utc(gpsTime)
% [utcTime] = Gps2Utc(gpsTime)
% Convert GPS time (week & seconds) to UTC
%
% Input: gpsTime, [mx2] matrix [gpsWeek, gpsSeconds],
%
% Outputs: utcTime, [mx6] matrix = [year,month,day,hours,minutes,seconds]
%
% Valid range of inputs:
% gps times corresponding to 1980/6/1 <= time < 2100/1/1
% i.e. [0,0] <= gpsTime < [6260, 432000]
%
% See also: Utc2Gps
% Other functions needed: LeapSeconds.m
%Author: Frank van Diggelen
%Open Source code for processing Android GNSS Measurements
%Algorithm for handling leap seconds:
% When a leap second happens, utc time stands still for one second, so
% gps seconds get further ahead, so we subtract leapSecs to move from gps time
%
% 1) convert gpsTime to time = [yyyy,mm,dd,hh,mm,ss] (with no leap seconds)
% 2) look up leap seconds for time: ls = LeapSeconds(time);
% This is (usually) the correct leap second value. Unless:
% If (utcTime=time) and (utcTime=time+ls) straddle a leap second
% then we need to add 1 to ls
% So, after step 2) ...
% 3) convert gpsTime-ls to timeMLs
% 4) look up leap seconds: ls1 = LeapSeconds(timeMLs);
% 5) if ls1~=ls, convert (gpsTime-ls1) to UTC Time
%% Check inputs
if size(gpsTime,2)~=2
error('gpsTime must have two columns')
end
fctSeconds = gpsTime*[GpsConstants.WEEKSEC; 1];
%fct at 2100/1/1 00:00:00, not counting leap seconds:
fct2100 = [6260, 432000]*[GpsConstants.WEEKSEC; 1];
if any(fctSeconds<0) || any (fctSeconds >= fct2100)
error('gpsTime must be in this range: [0,0] <= gpsTime < [6260, 432000]');
end
%% Finished checks
%from now on work with fct
%% Apply algorithm for handling leaps seconds
% 1) convert gpsTime to time = [yyyy,mm,dd,hh,mm,ss] (with no leap seconds)
time = Fct2Ymdhms(fctSeconds);
% 2) look up leap seconds for time: ls = LeapSeconds(time);
ls = LeapSeconds(time);
% 3) convert gpsTime-ls to timeMLs
timeMLs = Fct2Ymdhms(fctSeconds-ls);
% 4) look up leap seconds: ls1 = LeapSeconds(timeMLs);
ls1 = LeapSeconds(timeMLs);
% 5) if ls1~=ls, convert (gpsTime-ls1) to UTC Time
if all(ls1==ls)
utcTime = timeMLs;
else
utcTime = Fct2Ymdhms(fctSeconds-ls1);
end
% NOTE:
% Gps2Utc.m doesn't produce 23:59:60, at a leap second.
% Instead, as the leap second occurs, the Gps2Utc.m sequence of
% UTC hh:mm:ss is 23:59:59, 00:00:00, 00:00:00
% and we keep it like that for code simplicity.
% Here are a sequence of UTC and GPS times around a leap second:
% formalUtcTimes = [1981 12 31 23 59 59; 1981 12 31 23 59 60; 1982 1 1 0 0 0];
% gpsTimes = [103 431999; 103 432000; 103 432001];
% >> Gps2Utc(gpsTimes)
% ans =
% 1981 12 31 23 59 59
% 1982 1 1 0 0 0
% 1982 1 1 0 0 0
% If you want to change this you could check LeapSeconds.m to see if you're
% exactly on the addition of a leap second, and then change the UTC format
% to include the '60' seconds
end %end of function Gps2Utc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function time = Fct2Ymdhms(fctSeconds)
%Utility function for Gps2Utc
%Convert GPS full cycle time to [yyyy,mm,dd,hh,mm,ss.s] format
HOURSEC = 3600; MINSEC = 60;
monthDays=[31,28,31,30,31,30,31,31,30,31,30,31];%days each month (not leap year)
m=length(fctSeconds);
days = floor(fctSeconds / GpsConstants.DAYSEC) + 6;%days since 1980/1/1
years=zeros(m,1)+1980;
%decrement days by a year at a time, until we have calculated the year:
leap=ones(m,1); %1980 was a leap year
while (any(days > (leap+365)))
I = find(days > (leap+365) );
days(I) = days(I) - (leap(I) + 365);
years(I)=years(I)+1;
leap(I) = (rem(years(I),4) == 0); % leap = 1 on a leap year, 0 otherwise
% This works from 1901 till 2099, 2100 isn't a leap year (2000 is).
% Calculate the year, ie time(1)
end,
time=zeros(m,6);%initialize matrix
time(:,1)=years;
%decrement days by a month at a time, until we have calculated the month
% Calculate the month, ie time(:,2)
% Loop through m:
for i=1:m
month = 1;
if (rem(years(i),4) == 0) %This works from 1901 till 2099
monthDays(2)=29; %Make February have 29 days in a leap year
else
monthDays(2)=28;
end
while (days(i) > monthDays(month))
days(i) = days(i)-monthDays(month);
month = month+1;
end
time(i,2)=month;
end
time(:,3) = days;
sinceMidnightSeconds = rem(fctSeconds, GpsConstants.DAYSEC);
time(:,4) = fix(sinceMidnightSeconds/HOURSEC);
lastHourSeconds = rem(sinceMidnightSeconds, HOURSEC);
time(:,5) = fix(lastHourSeconds/MINSEC);
time(:,6) = rem(lastHourSeconds,MINSEC);
end %end of function Fct2Ymdhms
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright 2016 Google Inc.
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
%     http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.