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.
 
 

148 lines
5.6 KiB

function [adrResid]= GpsAdrResiduals(gnssMeas,allGpsEph,llaDegDegM)
% [adrResid]= GpsAdrResiduals(gnssMeas,allGpsEph,llaDegDegM)
% Compute residuals from GPS Accumulated Delta Ranges
%
% Inputs:
% gnssMeas.FctSeconds = Nx1 vector. Rx time tag of measurements.
% .ClkDCount = Nx1 vector. Hw clock discontinuity count
% .Svid = 1xM vector of all svIds found in gnssRaw.
% ...
% .tRxSeconds = NxM time of reception, seconds of gps week
% .tTxSeconds = NxM time of tranmission, seconds of gps week
% .AdrM = NxM accumulated delta range (= -k*carrier phase)
% ...
%
% allGpsEph, structure with all ephemeris
% llaDegDegM [1x3] true position
%
% Output:
% adrResid.FctSeconds = Nx1 time vector, same as gnssMeas.FctSeconds
% .Svid0 = reference satellite for single differences
% .Svid = 1xM vector of all svid
% .ResidM = [NxM] adr residuals
%
%Algorithm: compute single difference from sv to reference satellite svid0, then
% diff from reference time: tk - t0 (where t0 is the first common epoch for
% sv & svid0), then subtract expected values
%Author: Frank van Diggelen
%Open Source code for processing Android GNSS Measurements
adrResid = [];
if ~any(any(isfinite(gnssMeas.AdrM) & gnssMeas.AdrM~=0))
%Nothing in AdrM but NaNs and zeros
return
end
if nargin<3 || isempty(llaDegDegM)
fprintf('GpsAdrResiduals needs the true position: llaDegDegM\n')
return
end
xyz0M = Lla2Xyz(llaDegDegM);
M = length(gnssMeas.Svid);
N = length(gnssMeas.FctSeconds);
weekNum = floor(gnssMeas.FctSeconds/GpsConstants.WEEKSEC);
adrResid.FctSeconds = gnssMeas.FctSeconds;
adrResid.Svid0 = [];
adrResid.Svid = gnssMeas.Svid;
adrResid.ResidM = zeros(N,M)+NaN;
%From gps.h:
%/* However, it is expected that the data is only accurate when:
% * 'accumulated delta range state' == GPS_ADR_STATE_VALID.
%*/
% #define GPS_ADR_STATE_UNKNOWN 0
% #define GPS_ADR_STATE_VALID (1<<0)
% #define GPS_ADR_STATE_RESET (1<<1)
% #define GPS_ADR_STATE_CYCLE_SLIP (1<<2)
%choose Svid0 as the satellite that has most valid adr
numValidAdr = zeros(1,M);
for j=1:M
numValidAdr(j) = length(find(bitand(gnssMeas.AdrState(:,j),2^0)));
end
[~,j0] = max(numValidAdr);
adrResid.Svid0 = gnssMeas.Svid(j0);
svid = gnssMeas.Svid;
%% Compute expected pseudoranges
prHatM = zeros(N,M)+NaN; %to store expected pseudoranges
%"pseudo" here refers to the clock error in the satellite, not the receiver
%compute expected pr at each epoch
for i=1:N
for j=1:M
ttxSeconds = gnssMeas.tTxSeconds(i,j);
if isnan(ttxSeconds)
continue %skip to next
end
[gpsEph,iSv]= ClosestGpsEph(allGpsEph,svid(j),gnssMeas.FctSeconds(i));
if isempty(iSv)
continue; %skip to next
end
%compute pr for this sv
dtsv = GpsEph2Dtsv(gpsEph,ttxSeconds);
ttxSeconds = ttxSeconds - dtsv;%subtract dtsv from sv time to get true gps time
%calculate satellite position at ttx:
[svXyzTtxM,dtsv]=GpsEph2Xyz(gpsEph,[weekNum(i),ttxSeconds]);
%in ECEF coordinates at trx:
dtflightSeconds = norm(xyz0M - svXyzTtxM)/GpsConstants.LIGHTSPEED;
svXyzTrxM = FlightTimeCorrection(svXyzTtxM, dtflightSeconds);
prHatM(i,j) = norm(xyz0M - svXyzTrxM) - GpsConstants.LIGHTSPEED*dtsv;
% Use of dtsv: dtsv>0 <=> pr too small
end
end
%% Compute single difference, then delta from t0, then residuals
iT0 = zeros(1,M); %to store common start index for svid and svid0
for i=1:N %loop over time
if ~bitand(gnssMeas.AdrState(i,j0),2^0)
continue; %skip to next epoch
end
%now we have valid Adr for reference satellite, svid(j0) at this epoch
for j=1:M %loop over svid
if j==j0
continue; %skip over reference satellite
end
if ~bitand(gnssMeas.AdrState(i,j),2^0) %no valid adr for this svid
iT0(j) = 0;%reset common start index for this svid
continue %skip to next svid
elseif ~iT0(j) %we haven't yet set a common start,
if all(isfinite(prHatM(i,[j,j0]))) %we have valid prHat at this epoch
iT0(j) = i;%set common start index
end
end
%Now we have valid Adr for svid(j) and svid(j0)
i0 = iT0(j); %common start index for svid(j) and svid(j0)
if i>i0 && all(isfinite(prHatM(i,[j,j0])))%valid prHat at this epoch
delAdrM = (gnssMeas.AdrM(i,j) - gnssMeas.AdrM(i,j0)) - ...
(gnssMeas.AdrM(i0,j) - gnssMeas.AdrM(i0,j0));
delPrHatM = (prHatM(i,j) - prHatM(i,j0)) - ...
(prHatM(i0,j) - prHatM(i0,j0));
adrResid.ResidM(i,j) = delAdrM - delPrHatM;
%by all the above 'isfinite' checks, residM should not be NaN
assert(isfinite(adrResid.ResidM(i,j)),...
'Residual should be finite, check the above logic');
end
end
end
end %end of function GpsAdrResiduals
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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.