@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN 
			
		
	
		
		
			
				
					
					from  laika . downloader  import  DownloadFailed from  laika . downloader  import  DownloadFailed  
			
		
	
		
		
			
				
					
					from  laika . ephemeris  import  EphemerisType ,  GPSEphemeris ,  GLONASSEphemeris ,  ephemeris_structs ,  parse_qcom_ephem from  laika . ephemeris  import  EphemerisType ,  GPSEphemeris ,  GLONASSEphemeris ,  ephemeris_structs ,  parse_qcom_ephem  
			
		
	
		
		
			
				
					
					from  laika . gps_time  import  GPSTime from  laika . gps_time  import  GPSTime  
			
		
	
		
		
			
				
					
					from  laika . helpers  import  ConstellationId from  laika . helpers  import  ConstellationId ,  get_sv_id  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					from  laika . raw_gnss  import  GNSSMeasurement ,  correct_measurements ,  process_measurements ,  read_raw_ublox ,  read_raw_qcom from  laika . raw_gnss  import  GNSSMeasurement ,  correct_measurements ,  process_measurements ,  read_raw_ublox ,  read_raw_qcom  
			
		
	
		
		
			
				
					
					from  laika . opt  import  calc_pos_fix ,  get_posfix_sympy_fun ,  calc_vel_fix ,  get_velfix_sympy_func from  laika . opt  import  calc_pos_fix ,  get_posfix_sympy_fun ,  calc_vel_fix ,  get_velfix_sympy_func  
			
		
	
		
		
			
				
					
					from  selfdrive . locationd . models . constants  import  GENERATED_DIR ,  ObservationKind from  selfdrive . locationd . models . constants  import  GENERATED_DIR ,  ObservationKind  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -33,6 +33,44 @@ CACHE_VERSION = 0.2 
			
		
	
		
		
			
				
					
					POS_FIX_RESIDUAL_THRESHOLD  =  100.0 POS_FIX_RESIDUAL_THRESHOLD  =  100.0  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					class  LogEphemerisType ( IntEnum ) :  
			
		
	
		
		
			
				
					
					  nav  =  0   
			
		
	
		
		
			
				
					
					  nasaUltraRapid  =  1   
			
		
	
		
		
			
				
					
					  glonassIacUltraRapid  =  2   
			
		
	
		
		
			
				
					
					  qcom  =  3   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					class  EphemerisSource ( IntEnum ) :  
			
		
	
		
		
			
				
					
					  gnssChip  =  0   
			
		
	
		
		
			
				
					
					  internet  =  1   
			
		
	
		
		
			
				
					
					  cache  =  2   
			
		
	
		
		
			
				
					
					  unknown  =  3   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  get_log_eph_type ( ephem ) :  
			
		
	
		
		
			
				
					
					  if  ephem . eph_type  ==  EphemerisType . NAV :   
			
		
	
		
		
			
				
					
					    source_type  =  LogEphemerisType . nav   
			
		
	
		
		
			
				
					
					  elif  ephem . eph_type  ==  EphemerisType . QCOM_POLY :   
			
		
	
		
		
			
				
					
					    source_type  =  LogEphemerisType . qcom   
			
		
	
		
		
			
				
					
					  else :   
			
		
	
		
		
			
				
					
					    assert  ephem . file_epoch  is  not  None   
			
		
	
		
		
			
				
					
					    file_src  =  ephem . file_source   
			
		
	
		
		
			
				
					
					    if  file_src  ==  ' igu ' :   # example nasa: '2214/igu22144_00.sp3.Z'   
			
		
	
		
		
			
				
					
					      source_type  =  LogEphemerisType . nasaUltraRapid   
			
		
	
		
		
			
				
					
					    elif  file_src  ==  ' Sta ' :   # example nasa: '22166/ultra/Stark_1D_22061518.sp3'   
			
		
	
		
		
			
				
					
					      source_type  =  LogEphemerisType . glonassIacUltraRapid   
			
		
	
		
		
			
				
					
					    else :   
			
		
	
		
		
			
				
					
					      raise  Exception ( f " Didn ' t expect file source  { file_src } " )   
			
		
	
		
		
			
				
					
					  return  source_type   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  get_log_eph_source ( ephem ) :  
			
		
	
		
		
			
				
					
					  if  ephem . file_name  ==  ' qcom '  or  ephem . file_name  ==  ' ublox ' :   
			
		
	
		
		
			
				
					
					    source  =  EphemerisSource . gnssChip   
			
		
	
		
		
			
				
					
					  elif  ephem . file_name  ==  EPHEMERIS_CACHE :   
			
		
	
		
		
			
				
					
					    source  =  EphemerisSource . cache   
			
		
	
		
		
			
				
					
					  else :   
			
		
	
		
		
			
				
					
					    source  =  EphemerisSource . internet   
			
		
	
		
		
			
				
					
					  return  source   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					class  Laikad : class  Laikad :  
			
		
	
		
		
			
				
					
					  def  __init__ ( self ,  valid_const = ( " GPS " ,  " GLONASS " ) ,  auto_fetch_navs = True ,  auto_update = False ,    def  __init__ ( self ,  valid_const = ( " GPS " ,  " GLONASS " ) ,  auto_fetch_navs = True ,  auto_update = False ,   
			
		
	
		
		
			
				
					
					               valid_ephem_types = ( EphemerisType . NAV ,  EphemerisType . QCOM_POLY ) ,                 valid_ephem_types = ( EphemerisType . NAV ,  EphemerisType . QCOM_POLY ) ,   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -64,6 +102,8 @@ class Laikad: 
			
		
	
		
		
			
				
					
					    self . last_fix_t  =  None      self . last_fix_t  =  None   
			
		
	
		
		
			
				
					
					    self . gps_week  =  None      self . gps_week  =  None   
			
		
	
		
		
			
				
					
					    self . use_qcom  =  use_qcom      self . use_qcom  =  use_qcom   
			
		
	
		
		
			
				
					
					    self . first_log_time  =  None   
			
		
	
		
		
			
				
					
					    self . ttff  =  - 1   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  def  load_cache ( self ) :    def  load_cache ( self ) :   
			
		
	
		
		
			
				
					
					    if  not  self . save_ephemeris :      if  not  self . save_ephemeris :   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -76,8 +116,8 @@ class Laikad: 
			
		
	
		
		
			
				
					
					    nav_dict  =  { }      nav_dict  =  { }   
			
		
	
		
		
			
				
					
					    try :      try :   
			
		
	
		
		
			
				
					
					      ephem_cache  =  ephemeris_structs . EphemerisCache . from_bytes ( cache_bytes )        ephem_cache  =  ephemeris_structs . EphemerisCache . from_bytes ( cache_bytes )   
			
		
	
		
		
			
				
					
					      glonass_navs  =  [ GLONASSEphemeris ( data_struct )  for  data_struct  in  ephem_cache . glonassEphemerides ]         glonass_navs  =  [ GLONASSEphemeris ( data_struct ,  file_name = EPHEMERIS_CACHE )  for  data_struct  in  ephem_cache . glonassEphemerides ]    
			
				
				
			
		
	
		
		
			
				
					
					      gps_navs  =  [ GPSEphemeris ( data_struct )  for  data_struct  in  ephem_cache . gpsEphemerides ]        gps_navs  =  [ GPSEphemeris ( data_struct ,  file_name = EPHEMERIS_CACHE )  for  data_struct  in  ephem_cache . gpsEphemerides ]   
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					      for  e  in  sum ( [ glonass_navs ,  gps_navs ] ,  [ ] ) :        for  e  in  sum ( [ glonass_navs ,  gps_navs ] ,  [ ] ) :   
			
		
	
		
		
			
				
					
					        if  e . prn  not  in  nav_dict :          if  e . prn  not  in  nav_dict :   
			
		
	
		
		
			
				
					
					          nav_dict [ e . prn ]  =  [ ]            nav_dict [ e . prn ]  =  [ ]   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -99,6 +139,22 @@ class Laikad: 
			
		
	
		
		
			
				
					
					      cloudlog . debug ( " Cache saved " )        cloudlog . debug ( " Cache saved " )   
			
		
	
		
		
			
				
					
					      self . last_cached_t  =  self . last_report_time        self . last_cached_t  =  self . last_report_time   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  def  create_ephem_statuses ( self ) :   
			
		
	
		
		
			
				
					
					    ephemeris_statuses  =  [ ]   
			
		
	
		
		
			
				
					
					    prns_to_check  =  list ( self . astro_dog . get_all_ephem_prns ( ) )   
			
		
	
		
		
			
				
					
					    prns_to_check . sort ( )   
			
		
	
		
		
			
				
					
					    for  prn  in  prns_to_check :   
			
		
	
		
		
			
				
					
					      eph  =  self . astro_dog . get_eph ( prn ,  self . last_report_time )   
			
		
	
		
		
			
				
					
					      if  eph  is  not  None :   
			
		
	
		
		
			
				
					
					        status  =  log . GnssMeasurements . EphemerisStatus . new_message ( )   
			
		
	
		
		
			
				
					
					        status . constellationId  =  ConstellationId . from_rinex_char ( prn [ 0 ] ) . value   
			
		
	
		
		
			
				
					
					        status . svId  =  get_sv_id ( prn )   
			
		
	
		
		
			
				
					
					        status . type  =  get_log_eph_type ( eph ) . value   
			
		
	
		
		
			
				
					
					        status . source  =  get_log_eph_source ( eph ) . value   
			
		
	
		
		
			
				
					
					        ephemeris_statuses . append ( status )   
			
		
	
		
		
			
				
					
					    return  ephemeris_statuses   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					      
			
		
	
		
		
			
				
					
					  def  get_lsq_fix ( self ,  t ,  measurements ) :    def  get_lsq_fix ( self ,  t ,  measurements ) :   
			
		
	
		
		
			
				
					
					    if  self . last_fix_t  is  None  or  abs ( self . last_fix_t  -  t )  >  0 :      if  self . last_fix_t  is  None  or  abs ( self . last_fix_t  -  t )  >  0 :   
			
		
	
		
		
			
				
					
					      min_measurements  =  5  if  any ( p . constellation_id  ==  ConstellationId . GLONASS  for  p  in  measurements )  else  4        min_measurements  =  5  if  any ( p . constellation_id  ==  ConstellationId . GLONASS  for  p  in  measurements )  else  4   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -170,10 +226,10 @@ class Laikad: 
			
		
	
		
		
			
				
					
					    else :      else :   
			
		
	
		
		
			
				
					
					      if  gnss_msg . which ( )  ==  ' ephemeris ' :        if  gnss_msg . which ( )  ==  ' ephemeris ' :   
			
		
	
		
		
			
				
					
					        data_struct  =  ephemeris_structs . Ephemeris . new_message ( * * gnss_msg . ephemeris . to_dict ( ) )          data_struct  =  ephemeris_structs . Ephemeris . new_message ( * * gnss_msg . ephemeris . to_dict ( ) )   
			
		
	
		
		
			
				
					
					        ephem  =  GPSEphemeris ( data_struct )          ephem  =  GPSEphemeris ( data_struct ,  file_name = ' ublox ' )   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					      elif  gnss_msg . which ( )  ==  ' glonassEphemeris ' :        elif  gnss_msg . which ( )  ==  ' glonassEphemeris ' :   
			
		
	
		
		
			
				
					
					        data_struct  =  ephemeris_structs . GlonassEphemeris . new_message ( * * gnss_msg . glonassEphemeris . to_dict ( ) )          data_struct  =  ephemeris_structs . GlonassEphemeris . new_message ( * * gnss_msg . glonassEphemeris . to_dict ( ) )   
			
		
	
		
		
			
				
					
					        ephem  =  GLONASSEphemeris ( data_struct )          ephem  =  GLONASSEphemeris ( data_struct ,  file_name = ' ublox ' )   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					      else :        else :   
			
		
	
		
		
			
				
					
					        cloudlog . error ( f " Unsupported ephemeris type:  { gnss_msg . which ( ) } " )          cloudlog . error ( f " Unsupported ephemeris type:  { gnss_msg . which ( ) } " )   
			
		
	
		
		
			
				
					
					        return          return   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -204,6 +260,12 @@ class Laikad: 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  def  process_gnss_msg ( self ,  gnss_msg ,  gnss_mono_time :  int ,  block = False ) :    def  process_gnss_msg ( self ,  gnss_msg ,  gnss_mono_time :  int ,  block = False ) :   
			
		
	
		
		
			
				
					
					    out_msg  =  messaging . new_message ( " gnssMeasurements " )      out_msg  =  messaging . new_message ( " gnssMeasurements " )   
			
		
	
		
		
			
				
					
					    out_msg . gnssMeasurements  =  {   
			
		
	
		
		
			
				
					
					        " timeToFirstFix " :  self . ttff ,   
			
		
	
		
		
			
				
					
					        " ephemerisStatuses "  :  self . create_ephem_statuses ( ) ,   
			
		
	
		
		
			
				
					
					    }   
			
		
	
		
		
			
				
					
					    if  self . first_log_time  is  None :   
			
		
	
		
		
			
				
					
					      self . first_log_time  =  1e-9  *  gnss_mono_time   
			
		
	
		
		
			
				
					
					    if  self . is_ephemeris ( gnss_msg ) :      if  self . is_ephemeris ( gnss_msg ) :   
			
		
	
		
		
			
				
					
					      self . read_ephemeris ( gnss_msg )        self . read_ephemeris ( gnss_msg )   
			
		
	
		
		
			
				
					
					      return  out_msg        return  out_msg   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -223,6 +285,8 @@ class Laikad: 
			
		
	
		
		
			
				
					
					      output  =  self . process_report ( new_meas ,  t )        output  =  self . process_report ( new_meas ,  t )   
			
		
	
		
		
			
				
					
					      if  output  is  None :        if  output  is  None :   
			
		
	
		
		
			
				
					
					        return  out_msg          return  out_msg   
			
		
	
		
		
			
				
					
					      if  self . ttff  < =  0 :   
			
		
	
		
		
			
				
					
					        self . ttff  =  max ( 1e-3 ,  t  -  self . first_log_time )   
			
		
	
		
		
			
				
					
					      position_estimate ,  position_std ,  velocity_estimate ,  velocity_std ,  corrected_measurements ,  _  =  output        position_estimate ,  position_std ,  velocity_estimate ,  velocity_std ,  corrected_measurements ,  _  =  output   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					      self . update_localizer ( position_estimate ,  t ,  corrected_measurements )        self . update_localizer ( position_estimate ,  t ,  corrected_measurements )   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -244,14 +308,12 @@ class Laikad: 
			
		
	
		
		
			
				
					
					        " velocityECEF " :  measurement_msg ( value = velocity_estimate ,  std = velocity_std . tolist ( ) ,  valid = bool ( self . last_fix_t  ==  t ) ) ,          " velocityECEF " :  measurement_msg ( value = velocity_estimate ,  std = velocity_std . tolist ( ) ,  valid = bool ( self . last_fix_t  ==  t ) ) ,   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        " measTime " :  gnss_mono_time ,          " measTime " :  gnss_mono_time ,   
			
		
	
		
		
			
				
					
					        " correctedMeasurements " :  meas_msgs          " correctedMeasurements " :  meas_msgs ,   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					        " timeToFirstFix " :  self . ttff ,   
			
		
	
		
		
			
				
					
					        " ephemerisStatuses "  :  self . create_ephem_statuses ( ) ,   
			
		
	
		
		
			
				
					
					      }        }   
			
		
	
		
		
			
				
					
					    return  out_msg      return  out_msg   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    #elif gnss_msg.which() == 'ionoData':   
			
		
	
		
		
			
				
					
					    # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them.   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  def  update_localizer ( self ,  est_pos ,  t :  float ,  measurements :  List [ GNSSMeasurement ] ) :    def  update_localizer ( self ,  est_pos ,  t :  float ,  measurements :  List [ GNSSMeasurement ] ) :   
			
		
	
		
		
			
				
					
					    # Check time and outputs are valid      # Check time and outputs are valid   
			
		
	
		
		
			
				
					
					    valid  =  self . kf_valid ( t )      valid  =  self . kf_valid ( t )   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -335,31 +397,8 @@ def create_measurement_msg(meas: GNSSMeasurement): 
			
		
	
		
		
			
				
					
					  c . satPos  =  meas . sat_pos_final . tolist ( )    c . satPos  =  meas . sat_pos_final . tolist ( )   
			
		
	
		
		
			
				
					
					  c . satVel  =  meas . sat_vel . tolist ( )    c . satVel  =  meas . sat_vel . tolist ( )   
			
		
	
		
		
			
				
					
					  c . satVel  =  meas . sat_vel . tolist ( )    c . satVel  =  meas . sat_vel . tolist ( )   
			
		
	
		
		
			
				
					
					  ephem  =  meas . sat_ephemeris   
			
		
	
		
		
			
				
					
					  assert  ephem  is  not  None   
			
		
	
		
		
			
				
					
					  week ,  time_of_week  =  - 1 ,  - 1   
			
		
	
		
		
			
				
					
					  if  ephem . eph_type  ==  EphemerisType . NAV :   
			
		
	
		
		
			
				
					
					    source_type  =  EphemerisSourceType . nav   
			
		
	
		
		
			
				
					
					  elif  ephem . eph_type  ==  EphemerisType . QCOM_POLY :   
			
		
	
		
		
			
				
					
					    source_type  =  EphemerisSourceType . qcom   
			
		
	
		
		
			
				
					
					  else :   
			
		
	
		
		
			
				
					
					    assert  ephem . file_epoch  is  not  None   
			
		
	
		
		
			
				
					
					    week  =  ephem . file_epoch . week   
			
		
	
		
		
			
				
					
					    time_of_week  =  ephem . file_epoch . tow   
			
		
	
		
		
			
				
					
					    file_src  =  ephem . file_source   
			
		
	
		
		
			
				
					
					    if  file_src  ==  ' igu ' :   # example nasa: '2214/igu22144_00.sp3.Z'   
			
		
	
		
		
			
				
					
					      source_type  =  EphemerisSourceType . nasaUltraRapid   
			
		
	
		
		
			
				
					
					    elif  file_src  ==  ' Sta ' :   # example nasa: '22166/ultra/Stark_1D_22061518.sp3'   
			
		
	
		
		
			
				
					
					      source_type  =  EphemerisSourceType . glonassIacUltraRapid   
			
		
	
		
		
			
				
					
					    else :   
			
		
	
		
		
			
				
					
					      raise  Exception ( f " Didn ' t expect file source  { file_src } " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  c . ephemerisSource . type  =  source_type . value   
			
		
	
		
		
			
				
					
					  c . ephemerisSource . gpsWeek  =  week   
			
		
	
		
		
			
				
					
					  c . ephemerisSource . gpsTimeOfWeek  =  int ( time_of_week )   
			
		
	
		
		
			
				
					
					  return  c    return  c   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  kf_add_observations ( gnss_kf :  GNSSKalman ,  t :  float ,  measurements :  List [ GNSSMeasurement ] ) : def  kf_add_observations ( gnss_kf :  GNSSKalman ,  t :  float ,  measurements :  List [ GNSSMeasurement ] ) :  
			
		
	
		
		
			
				
					
					  ekf_data  =  defaultdict ( list )    ekf_data  =  defaultdict ( list )   
			
		
	
		
		
			
				
					
					  for  m  in  measurements :    for  m  in  measurements :   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -375,18 +414,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe 
			
		
	
		
		
			
				
					
					      gnss_kf . predict_and_observe ( t ,  kind ,  data )        gnss_kf . predict_and_observe ( t ,  kind ,  data )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					class  EphemerisSourceType ( IntEnum ) :  
			
		
	
		
		
			
				
					
					  nav  =  0   
			
		
	
		
		
			
				
					
					  nasaUltraRapid  =  1   
			
		
	
		
		
			
				
					
					  glonassIacUltraRapid  =  2   
			
		
	
		
		
			
				
					
					  qcom  =  3   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  process_msg ( laikad ,  gnss_msg ,  mono_time ,  block = False ) :  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  return  laikad . process_gnss_msg ( gnss_msg ,  mono_time ,  block = block )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  clear_tmp_cache ( ) : def  clear_tmp_cache ( ) :  
			
		
	
		
		
			
				
					
					  if  os . path . exists ( DOWNLOADS_CACHE_FOLDER ) :    if  os . path . exists ( DOWNLOADS_CACHE_FOLDER ) :   
			
		
	
		
		
			
				
					
					    shutil . rmtree ( DOWNLOADS_CACHE_FOLDER )      shutil . rmtree ( DOWNLOADS_CACHE_FOLDER )