|
|
|
|
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.
|
|
|
|
|
|