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.

173 lines
6.3 KiB

function [xHat,z,svPos,H,Wpr,Wrr] = WlsPvt(prs,gpsEph,xo)
% [xHat,z,svPos,H,Wpr,Wrr] = WlsPvt(prs,gpsEph,xo)
% calculate a weighted least squares PVT solution, xHat
% given pseudoranges, pr rates, and initial state
%
% Inputs:
% prs: matrix of raw pseudoranges, and pr rates, each row of the form:
% [trxWeek,trxSeconds,sv,prMeters,prSigmaMeters,prrMps,prrSigmaMps]
% trxWeek, trxSeconds: Rx time of measurement
% where trxSeconds = seconds in the current GPS week
% sv: satellite id number
% prMeters, prSigmaMeters: pseudorange and standard deviation (meters)
% prrMps, prrSigmaMps: pseudorange rate and standard deviation (m/s)
% gpsEph: matching vector of GPS ephemeris struct, defined in ReadRinexNav
% xo: initial (previous) state, [x,y,z,bc,xDot,yDot,xDot,bcDot]'
% in ECEF coordinates(meters and m/s)
%
% Outputs: xHat: estimate of state update
% z = [zPr; zPrr] a-posteriori residuals (measured-calculated)
% svPos: matrix of calculated sv positions and sv clock error:
% [sv prn, x,y,z (ecef m), dtsv (s),xDot,yDot,zDot, dtsvDot]
% H: H observation matrix corresponding to svs in svPos(:,1)
% Wpr,Wrr Weights used in WlsPvt = 1/diag(sigma measurements)
% use these matrices to compute variances of xHat
%
% The PVT solution = xo + xHat, in ECEF coordinates
% For unweighted solution, set all sigmas = 1
%Author: Frank van Diggelen
%Open Source code for processing Android GNSS Measurements
jWk=1; jSec=2; jSv=3; jPr=4; jPrSig=5; jPrr=6; jPrrSig=7;%index of columns
[bOk,numVal] = checkInputs(prs, gpsEph, xo);
if ~bOk
error('inputs not right size, or not properly aligned with each other')
end
xHat=[]; z=[]; H=[]; svPos=[];
xyz0 = xo(1:3);
bc = xo(4);
if numVal<4
return
end
ttxWeek = prs(:,jWk); %week of tx. Note - we could get a rollover, when ttx_sv
%goes negative, and it is handled in GpsEph2Pvt, where we work with fct
ttxSeconds = prs(:,jSec) - prs(:,jPr)/GpsConstants.LIGHTSPEED; %ttx by sv clock
% this is accurate satellite time of tx, because we use actual pseudo-ranges
% here, not corrected ranges
% write the equation for pseudorange to see the rx clock error exactly cancel
% to get precise GPS time: we subtract the satellite clock error from sv time,
% as done next:
dtsv = GpsEph2Dtsv(gpsEph,ttxSeconds);
dtsv = dtsv(:); %make into a column for compatibility with other time vectors
ttx = ttxSeconds - dtsv; %subtract dtsv from sv time to get true gps time
%calculate satellite position at ttx
[svXyzTtx,dtsv,svXyzDot,dtsvDot]=GpsEph2Pvt(gpsEph,[ttxWeek,ttx]);
svXyzTrx = svXyzTtx; %initialize svXyz at time of reception
%Compute weights ---------------------------------------------------
Wpr = diag(1./prs(:,jPrSig));
Wrr = diag(1./prs(:,jPrrSig));
%iterate on this next part tilL change in pos & line of sight vectors converge
xHat=zeros(4,1);
dx=xHat+inf;
whileCount=0; maxWhileCount=100;
%we expect the while loop to converge in < 10 iterations, even with initial
%position on other side of the Earth (see Stanford course AA272C "Intro to GPS")
while norm(dx) > GnssThresholds.MAXDELPOSFORNAVM
whileCount=whileCount+1;
assert(whileCount < maxWhileCount,...
'while loop did not converge after %d iterations',whileCount);
for i=1:length(gpsEph)
% calculate tflight from, bc and dtsv
dtflight = (prs(i,jPr)-bc)/GpsConstants.LIGHTSPEED + dtsv(i);
% Use of bc: bc>0 <=> pr too big <=> tflight too big.
% i.e. trx = trxu - bc/GpsConstants.LIGHTSPEED
% Use of dtsv: dtsv>0 <=> pr too small <=> tflight too small.
% i.e ttx = ttxsv - dtsv
svXyzTrx(i,:) = FlightTimeCorrection(svXyzTtx(i,:), dtflight);
end
%calculate line of sight vectors and ranges from satellite to xo
v = xyz0(:)*ones(1,numVal,1) - svXyzTrx';%v(:,i) = vector from sv(i) to xyz0
range = sqrt( sum(v.^2) );
v = v./(ones(3,1)*range); % line of sight unit vectors from sv to xo
svPos=[prs(:,3),svXyzTrx,dtsv(:)];
%calculate the a-priori range residual
prHat = range(:) + bc -GpsConstants.LIGHTSPEED*dtsv;
% Use of bc: bc>0 <=> pr too big <=> rangehat too big
% Use of dtsv: dtsv>0 <=> pr too small
zPr = prs(:,jPr)-prHat;
H = [v', ones(numVal,1)]; % H matrix = [unit vector,1]
%z = Hx, premultiply by W: Wz = WHx, and solve for x:
dx = pinv(Wpr*H)*Wpr*zPr;
% update xo, xhat and bc
xHat=xHat+dx;
xyz0=xyz0(:)+dx(1:3);
bc=bc+dx(4);
%Now calculate the a-posteriori range residual
zPr = zPr-H*dx;
end
% Compute velocities ---------------------------------------------------------
rrMps = zeros(numVal,1);
for i=1:numVal
%range rate = [satellite velocity] dot product [los from xo to sv]
rrMps(i) = -svXyzDot(i,:)*v(:,i);
end
prrHat = rrMps + xo(8) - GpsConstants.LIGHTSPEED*dtsvDot;
zPrr = prs(:,jPrr)-prrHat;
%z = Hx, premultiply by W: Wz = WHx, and solve for x:
vHat = pinv(Wrr*H)*Wrr*zPrr;
xHat = [xHat;vHat];
z = [zPr;zPrr];
end %end of function WlsPvt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [bOk,numVal] = checkInputs(prs, gpsEph, xo)
%utility function for WlsPvt
jWk=1; jSec=2; jSv=3; jPr=4; jPrSig=5; jPrr=6; jPrrSig=7;%index of columns
bOk=false;
%check inputs
numVal=size(prs,1);
if (max(prs(:,jSec))-min(prs(:,jSec)))> eps
return
elseif length(gpsEph)~=numVal
return
elseif any(prs(:,jSv) ~= [gpsEph.PRN]')
return
elseif any(size(xo) ~= [8,1])
return
elseif size(prs,2)~=7
return
else
bOk = true;
end
%We insist that gpsEph and prs are aligned first.
%ClosestGpsEph.m does this, and passes back indices for prs - this is the way to
%do it right, so we don't have nested searches for svId
end %end of function checkInputs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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.