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.
 
 

134 lines
5.4 KiB

function gpsPvt = GpsWlsPvt(gnssMeas,allGpsEph,bRaw)
%gpsPvt = GpsWlsPvt(gnssMeas,allGpsEph,bRaw)
%compute PVT from gnssMeas
% Input: gnssMeas, structure of pseudoranges, etc. from ProcessGnssMeas
% allGpsEph, structure with all ephemeris
% [bRaw], default true, true => use raw pr, false => use smoothed
%
% Output:
% gpsPvt.FctSeconds Nx1 time vector, same as gnssMeas.FctSeconds
% .allLlaDegDegM Nx3 matrix, (i,:) = [lat (deg), lon (deg), alt (m)]
% .sigmaLlaM Nx3 standard deviation of [lat,lon,alt] (m)
% .allBcMeters Nx1 common bias computed with llaDegDegM
% .allVelMps Nx3 (i,:) = velocity in NED coords
% .sigmaVelMps Nx3 standard deviation of velocity (m/s)
% .allBcDotMps Nx1 common freq bias computed with velocity
% .numSvs Nx1 number of satellites used in corresponding llaDegDegM
% .hdop Nx1 hdop of corresponding fix
%
%Algorithm: Weighted Least Squares
%Author: Frank van Diggelen
%Open Source code for processing Android GNSS Measurements
if nargin<3
bRaw = true;
else
%check that smoothed pr fields exists in input
if any(~isfield(gnssMeas,{'PrSmM','PrSmSigmaM'}))
error('If bRaw is false, gnssMeas must have fields gnssMeas.PrSmM and gnssMeas.PrSmSigmaM')
end
end
xo =zeros(8,1);%initial state: [center of the Earth, bc=0, velocities = 0]'
weekNum = floor(gnssMeas.FctSeconds/GpsConstants.WEEKSEC);
%TBD check for week rollover here (it is checked in ProcessGnssMeas, but
%this function should stand alone, so we should check again, and adjust
%tRxSeconds by +- a week if necessary)
%btw, Q. why not just carry around fct and not worry about the hassle of
%weeknumber, and the associated week rollover problems?
% A. because you cannot get better than 1000ns (1 microsecond) precsision
% when you put fct into a double. And that would cause errors of ~800m/s * 1us
% (satellite range rate * time error) ~ 1mm in the range residual computation
% So what? well, if you start processing with carrier phase, these errors
% could accumulate.
N = length(gnssMeas.FctSeconds);
gpsPvt.FctSeconds = gnssMeas.FctSeconds;
gpsPvt.allLlaDegDegM = zeros(N,3)+NaN;
gpsPvt.sigmaLLaM = zeros(N,3)+NaN;
gpsPvt.allBcMeters = zeros(N,1)+NaN;
gpsPvt.allVelMps = zeros(N,3)+NaN;
gpsPvt.sigmaVelMps = zeros(N,3)+NaN;
gpsPvt.allBcDotMps = zeros(N,1)+NaN;
gpsPvt.numSvs = zeros(N,1);
gpsPvt.hdop = zeros(N,1)+inf;
for i=1:N
iValid = find(isfinite(gnssMeas.PrM(i,:))); %index into valid svid
svid = gnssMeas.Svid(iValid)';
[gpsEph,iSv] = ClosestGpsEph(allGpsEph,svid,gnssMeas.FctSeconds(i));
svid = svid(iSv); %svid for which we have ephemeris
numSvs = length(svid); %number of satellites this epoch
gpsPvt.numSvs(i) = numSvs;
if numSvs<4
continue;%skip to next epoch
end
%% WLS PVT -----------------------------------------------------------------
%for those svIds with valid ephemeris, pack prs matrix for WlsNav
prM = gnssMeas.PrM(i,iValid(iSv))';
prSigmaM= gnssMeas.PrSigmaM(i,iValid(iSv))';
prrMps = gnssMeas.PrrMps(i,iValid(iSv))';
prrSigmaMps = gnssMeas.PrrSigmaMps(i,iValid(iSv))';
tRx = [ones(numSvs,1)*weekNum(i),gnssMeas.tRxSeconds(i,iValid(iSv))'];
prs = [tRx, svid, prM, prSigmaM, prrMps, prrSigmaMps];
xo(5:7) = zeros(3,1); %initialize speed to zero
[xHat,~,~,H,Wpr,Wrr] = WlsPvt(prs,gpsEph,xo);%compute WLS solution
xo = xo + xHat;
%extract position states
llaDegDegM = Xyz2Lla(xo(1:3)');
gpsPvt.allLlaDegDegM(i,:) = llaDegDegM;
gpsPvt.allBcMeters(i) = xo(4);
%extract velocity states
RE2N = RotEcef2Ned(llaDegDegM(1),llaDegDegM(2));
%NOTE: in real-time code compute RE2N once until position changes
vNed = RE2N*xo(5:7); %velocity in NED
gpsPvt.allVelMps(i,:) = vNed;
gpsPvt.allBcDotMps(i) = xo(8);
%compute HDOP
H = [H(:,1:3)*RE2N', ones(numSvs,1)]; %observation matrix in NED
P = inv(H'*H);%unweighted covariance
gpsPvt.hdop(i) = sqrt(P(1,1)+P(2,2));
%compute variance of llaDegDegM
%inside LsPvt the weights are used like this:
% z = Hx, premultiply by W: Wz = WHx, and solve for x:
% x = pinv(Wpr*H)*Wpr*zPr;
% the point of the weights is to make sigma(Wz) = 1
% therefore, the variances of x come from diag(inv(H'Wpr'WprH))
P = inv(H'*(Wpr'*Wpr)*H); %weighted covariance
gpsPvt.sigmaLLaM(i,:) = sqrt(diag(P(1:3,1:3)));
%similarly, compute variance of velocity
P = inv(H'*(Wrr'*Wrr)*H); %weighted covariance
gpsPvt.sigmaVelMps(i,:) = sqrt(diag(P(1:3,1:3)));
%%end WLS PVT --------------------------------------------------------------
end
end %end of function GpsWlsPvt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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.