o
    4iS                    @   s  d dl mZ d dlmZ d dlT d dlmZmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlZd dlZd dlZd dlmZ d dlZd dlZd d	lmZ d d
lmZ d dl Z dd Z!g dZ"dddZ#dd Z$dd Z%dddZ&dd Z'dddZ(dddZ)d d! Z*G d"d# d#e+Z,G d$d% d%e-Z.dd&d'Z/d(d) Z0dd+d,Z1de+fd-d.Z2d/d0 Z3G d1d2 d2Z4G d3d4 d4e+Z5d5d6 Z6d7d8 Z7dd:d;Z8d<d= Z9G d>d? d?e+Z:dd@dAZ;dBdC Z<ddDdEZ=ddFdGZ>dHdI Z?ddKdLZ@dMdN ZAdOdP ZBdQdR ZCdSdT ZDdUdV ZEdWdX ZFdYdZ ZGdd[d\ZHdd]d^ZId_d` ZJddadbZKdcdd ZLdedf ZMdgdh ZNddjdkZOddldmZPdndo ZQdpdq ZRdrds ZSddtduZTddvdwZUG dxdy dye+ZVG dzd{ d{e+ZWd|d} ZXd~d ZYdd ZZdd Z[dd Z\dd Z]dddZ^dddZ_dddZ`dd Zadd Zbdd ZcdddZddd ZedddZfdddZgdd ZhdddZidddZjdddZkd ddZldddZmdddZndddZodd ZpG dd dejqZrdddZsdd Ztdd Zudd Zvdd ZwdddZxddĄ ZydddƄZzddȄ Z{dddʄZ|ddd̄Z}ddd΄Z~ddЄ Zdd҄ Z	9	dddԄZdddքZddd؄Zddڄ Zdd܄ Zdejfdd߄ZdddZ					 	9dddZdd Zdd ZdS (      )absolute_import)pylab)*)butterfiltfilt)print_)rangeN)Image)glob)
namedtuplec                 C   s   t | d S )Nr   )wherex r   B/home/russ/Documents/_GNSS_data/2026/SUMO-343_bench_test/mutils.pyfind      r   )2zAuto LSQzGNSS LSQzSBAS LSQz	RTK Floatz	RTK FixedzWA RTK FloatzWA RTK FixedOmniSTARzCDGPS - ObszAuto KFzDGNSS KFzSBAS KFzCDGPS KF - ObszSBAS+ KFzSBAS/CDPGS+ KF - ObsRTXz
XPS CoarsezXPS FinezINS Autoz	INS DGNSSzINS RTKzINS SBASzINS RTXzINS GVBSzINS OmnizINS DRGVBSzRTX FastxFillXzRTX LitezRTX Lite L1zRTX Field PointzRTX Fast RAM -??zAuto TNzGNSS TNzSBAS TNzQZSS SLAS LSQzQZSS SLAS KFz
INS xFillXCLASzINS CLASHASzINS HASSouthPANzINS SouthPANz
BEIDOU PPPzINS BEIDOU PPPzINS SLASBVRSzINS BVRSTc                    s  t j  |rtd    fdd}| d}|d}d|v rcddlm} | d}||}g }d}		 |	dkr=d
}
nd|	 }
|
|vrJ	 t	|S d|v rW|||
 j n|||
  |	d7 }	q6dd }| d}d}|
 D ]}|  }t|dkr||d r n|d7 }qrddl}ddlm} | d}z-|dd	d}||j|dkr|sd|d< n|sd|d< |j|fi |j|jddjW S  |jjy   tg  Y S w )a>  
    filename=text file or viewdat --mat output.
    [verbose=True - print status info when loading file?]
    [error_bad_lines=False - pass error_bad_lines to pandas read_csv?  Skips lines with errors.]
    Accepts gzip'd files ending in '.gz' and bzip'd files ending in '.bz2'
    Returns numpy array with data.
    zLoading %s...c                    sF     drdd l}| |S   drdd l}| |S t |S )N.gzr   .bz2)endswithgzipopenbz2BZ2File)fnamemoder   r    filenamer   r   myopenb   s   


zdoload.<locals>.myopenrb       r   )loadmatTdatazdata%ds	   C library   c                 S   s$   zt |  W dS  ty   Y dS w )NFTfloat
ValueError)sr   r   r   is_string_a_float   s   
z!doload.<locals>.is_string_a_floatrN)parse)skiprowsheaderdelim_whitespacez1.3.0skipon_bad_linesFerror_bad_linescoerceerrors)ospath
expanduserprintreadscipy.ior*   appendTconcatenate	readlinesstripsplitlenpandaspackaging.versionr3   __version__read_csvapply
to_numericvaluesr<   EmptyDataErrorarray)r%   verboser9   r&   fbytesr*   raw_dall_dcurr_ivar_namer1   nlwpdparse_versioncsv_argsr   r$   r   doloadV   sl   





r`   c                 c   s.    | D ]}||v r| ||}| V  qd S N)replacerH   )input_streampattern1pattern2linenew_liner   r   r   _substitute_lines   s   
rh   c                 C   s   ddl }ddl}ddl}ddl}ddl}| \}}}	}
td|  |
dr9|j||
d | |j	dd}|j
}n"|
drDt|d	}n|
d
rP||d	}n|
dr[||d	}t|||	}z||j|jddjW S    td Y S )zSee doload_sedr   Nzdoload_sed loading viewdat T)stdouttextcatrtzcatbzcatr:   r;   )shlex
subprocessrJ   r    r   r@   
startswithPopenrH   PIPErk   r   rh   	DataFramerN   rO   rP   zeros)infoseprq   spr]   r    r   r%   pat1pat2cmdrm   substituted_linesr   r   r   _doload_sed_help   s0   
 


r    \s+c                    s2  ddl }t| tu rtttj| }n	tdd | D }|du rM|d dr,d}n!|d dr6d}n|d 	 d	sH|d 	 d
rKd}nd}g }|D ]}	|
|	|||f qQd}
 fdd}t|dkr|r|j }|||}
W d   n1 sw   Y  nt||}
dd |
D }t|S )a  
    Used to run "sed" on a file before loading it.  This is useful for diagnostic data.
    filename=text file.  Accepts gzip'd files ending in '.gz' and bzip'd files ending in '.bz2'
    pat1 = String(sed pattern) to search for.  Only match lines with this pattern.
    pat2 = default "".  Replace 'pat1' with this string before importing data.
    cmd = default None.  Run "cmd filename" to get data from filename.  (e.g., "viewdat -d16 -mb")
    Returns numpy array with data.
    r   Nc                 S      g | ]}t j|qS r   r=   r>   abspath.0r   r   r   r   
<listcomp>       zdoload_sed.<locals>.<listcomp>r   ro   r   rp   z.t02.t04zviewdat -d99 -mbrm   c                    s   t |  dS )Nry   )r   r   r   r   r   <lambda>       zdoload_sed.<locals>.<lambda>r,   c                 S      g | ]
}t |d kr|qS r   rI   r   r   r   r   r          )multiprocessing.pooltypestrsortedr
   r=   r>   r   r   lowerrC   rI   pool
ThreadPoolmaprE   )r%   r{   r|   r}   parallelry   multiprocessingfilesall_inforT   ddoload_funcr   d2r   r   r   
doload_sed   s2   	$
r   c           
         s2  t j| sdS dd  dd }ti }tddg}d}g }tt| D ]f\}}|dkr_| dd	 }g }|D ]}	|	 }	|	|vrHt	|||	< |
||	  q8t	||jd kr^|||}q$| dd	 } |d r fd
d|D |||f< |d7 }||jd kr|||}q$|d|ddf }||fS )a9  
    Load a WinAstra .pos file
    Expects rtkPosOutputFormat = LLH and rtkOutputFileHeaders = yes in winastra.ini
    filename=text ".pos" file from WinAstra.exe
    Returns (header,data)
    header = dictionary of column names -> index of data column
    data = numpy array of data.  'nan' values are empty
    NNc                 S   $   zt |  W dS  ty   Y dS w NTFr-   r   r   r   r   
_is_number     zload_pos.<locals>._is_numberc                 S   s@   t | jd d t|gt}| |d | jd d | jd f< |S )Nr     r,   )fullshaperI   nan)all_dataall_hdrtmpr   r   r   _extend_data  s    zload_pos.<locals>._extend_datar   r,   Nc                    s    g | ]} |rt |ntqS r   )r.   r   r   r   r   r   r          zload_pos.<locals>.<listcomp>)r=   r>   isfiledotdictempty	enumerater   rH   rG   rI   rC   r   )
r%   r   r   r   poshdr_idxline_numr[   r\   r   r   r   r   load_pos   s:   	

r   r   c                 C   s  dd }i }g }d}d}t t| D ]f\}}|dkr ||kr  nY|ddd }	||	d rY|d7 }| D ]}
|
t q7t||	D ]\}}z
t||| d< W qD   Y qDq||d krx|}d	d
 |	D }|D ]}||vrwtg| ||< qjq| D ]
\}}t	|||< q}|S )aJ  
    Load a Titan .hud file
    filename=text ".hud" file from TitanPlayer.exe
    Returns 'data' dictionary
     keys = column names
     values = numpy array of data.  'nan' values are empty
    For example:
      plot( data['GPS_Sec'], data['Platf13_GnssRcv0_R02_D1C-R_Std'])
    (The files use RINEX encoding for signals)
    c                 S   r   r   r-   r   r   r   r   r   2  r   zload_hud.<locals>._is_numberr   i;Nr   r,   c                 S   s   g | ]}|  qS r   )rG   )r   w0r   r   r   r   P      zload_hud.<locals>.<listcomp>)
r   r   rH   rP   rC   r   zipr.   itemsrR   )r%   	max_linesr   r+   	curr_hdrsr   prev_hdr_liner   r[   r\   colhdrvalkeyr   r   r   load_hud'  s:   r   c                    s   |du rt | S dt|  t fdd|D r| t| S tdd |D rottt| | \}}d}d}| krK|d7 }|||d  7 }| ks;|||d  8 }| kri||d | }t|tt| S ||d  S dS )	z(Calculate the weighted median of a list.N      ?c                    s   g | ]}| kqS r   r   r   jmidpointr   r   r   _  r   z#weighted_median.<locals>.<listcomp>c                 S   s   g | ]}|d kqS r   r   r   r   r   r   r   a  r   r   r,      )mediansumanyargmaxr   r   r.   rI   )r+   weightssorted_datasorted_weightscumulative_weightbelow_midpoint_indexboundsr   r   r   weighted_medianZ  s&   r   c                 C   sl  ddl }t| d \}}|dd|d f }d|v rd}nd}|dd||d  f }|dd||d	  f }	|dd|d
 f }
tt|}td|d d dd\}}t|||
dd}
||jtt	||d|jtt	||dd|j
f dd}td|d |d|j
f |d |d|j
f f  d}tdd}td|d td|d d}| D ]s\}}|d }t|sq|d }|| }|| d k r||7 }t|s|dkrqt|}|||jf tjd   }t|rt|}|| |
|  }|	| }|}|}|}n
|||  }|d! }|d"krqtd#|| | |f |d qW d   dS 1 s/w   Y  dS )$zGenerates RefClock.txt for SNPC based on Titan's clock.  Titan
    usually provides a very good clock estimate.

    titan_dir = directory containing PKFEE_States_RcvClkBias.hud
    d,k = rec 35:2 from vd2arr()
    r   N/PKFEE_States_RcvClkBias.hudGPS_Sec(SatSysDepRcvClk_Platf00_GnssRcv0_G00_Val%SatSysDepRcvClk_Platf00_GnssRcv0_G00_#SatSysDepRcvClk_Platf00_GnssRcv0_G_ValStdz&CodeRcvBias_Platf00_GnssRcv0_C1C-G_Val   r   r   lowpassbtypegustmethod)index)clkr   z,Titan/d start_t = %.1f/%.1f, end_t %.1f/%.1fr        u"AzRefClock.txtr\   z% clk_types 1)filez% 0 0.0g      $r   r   g?    .Ar         Y@z%.3f %.1f %.3f %.1f)rJ   r   r   diffr   r   rv   Seriesr   rI   TIMEr   r   iterrowsisfiniteintCLKDRIFT	GnssConstLIGHT)	titan_dirr   kr]   hClkdClktclkkeyclk_bias	clk_sigma	code_biasdtbadfSECS_IN_WEEKoutfile
last_clk_tcurr_trowiposiclkmydriftmybiasmysigmalast_clk_biaslast_clk_sigmar   r   r   gen_titan_ref_clocko  s^   "0

$r  c                   @   s`   e Zd ZdZdddZdd Zdd Zd	d
 ZdddZdd Z	dd Z
dddZdddZdS )TitanHudPKFEEz?Load the (measurement) Titan PKFEE HUD files in given directory   c                 C   sl   t |d \| _| _t |d \| _| _t |d \| _| _t |d \| _| _d | _	i | _
i | _|| _d S )Nz/PKFEE_FilterRes_GNSS.hudz/PKFEE_States_Amb.hudz/PKFEE_States_RcvSatBias.hudr   )r   hResdReshAmbdAmbhMPdMPr   r   
amb_medianL1_reduced_ambL1_MP_plus_ambplatf)selfdirnamer  r   r   r   __init__  s   
zTitanHudPKFEE.__init__c                 C   s&   |D ]}t ||}|r|  S qdS )z)Get HUD header value that matches patternN)rematch)r  r   patternhmr   r   r   get_ID  s   zTitanHudPKFEE.get_IDc                 C   T   |t jkrd| j|f S |t jkrd| j|f S |t jkr$d| j|f S td| )NzPlatf%.2d_.*G%.2d_[PC]1C-G_zPlatf%.2d_.*R%.2d_[PC]1C-R_zPlatf%.2d_.*C%.2d_[PC]1I-C_unknown sat_type %dRTConstRT_SatType_GPSr  RT_SatType_GLONASSRT_SatType_BEIDOU_B1GEOPhsr/   r  sv_idsat_typer   r   r   get_cde_pat     


zTitanHudPKFEE.get_cde_patc                 C   r#  )NzPlatf%.2d_.*G%.2d_L1C-G_zPlatf%.2d_.*R%.2d_L1C-R_zPlatf%.2d_.*C%.2d_L1I-C_r$  r%  r*  r   r   r   get_phs_pat  r.  zTitanHudPKFEE.get_phs_patT      c                 C   s$  |  ||}|tjkrd}n|tjkrd}n|tjkrd}ntd| | | j|d }| | j|d }|du s>|du rCg g g fS | jdd| jd f }	| jdd| j| f }
| jdd| j| f }|r| | j	|}| j
dd| j	| f }tt|
|  }|	| }	|
| || t||   }
|| }ntt|
 }|	| }	|
| }
|| }|d	krtt|	}td
|d | dd\}}d	}tt|	|d kD ]%}||kr|
|| |
||< nt|||
|| dd|
||< |d }qt|	}t|||
|| dd|
||< |	|
|fS )a  Returns code residuals: t, cde_val [m], cde_std [m].
        If remove_clk==True (default), remove clock from residuals.
          Currently this is needed to look at code multipath values.
        If filt_Tc > 0, run low pass filter on cde_res with this time constant.
        z)CodeRcvBias_Platf00_GnssRcv0_[PC]1C-G_Valz)CodeRcvBias_Platf00_GnssRcv0_[PC]1C-R_Valz)CodeRcvBias_Platf00_GnssRcv0_[PC]1I-C_Valr$  r   r   Nr   r   r   r   r   r   MbP?r   r   r,   )r-  r&  r'  r(  r)  r/   r"  r  r  r   r   r   isnanr   minr   r   r   rI   )r  r+  r,  
remove_clkfilt_TcresPatbiasPatid1id2r   cde_valcde_stdtclkir   r   r   start_iend_ir   r   r   get_L1_cde_res  sL   





 
 
zTitanHudPKFEE.get_L1_cde_resc           	      C   s   |  ||}| | j|d }| | j|d }| jdd| jd f }| jdd| j| f }| jdd| j| f }|||fS )z4Returns phase residuals: t, phs_val [m], phs_std [m]r   r   Nr   )r/  r"  r  r  )	r  r+  r,  r6  r8  r9  r   phs_valphs_stdr   r   r   get_L1_phs_res   s   
zTitanHudPKFEE.get_L1_phs_resc                 C   s   g }| j D ]A}td|}|r|t|dtjf td|}|r1|t|dtjf td|}|rF|t|dtj	f qt
dd |D }tdd |D S )zRReturns list of all sv IDs (sv_id, RT_SatType) that have PKFEE_States_amb.hud dataz.*?_G([0-9][0-9])_[PL]1r,   z.*?_R([0-9][0-9])_[PL]1z.*?_C([0-9][0-9])_[PL]1c                 S   s   g | ]
\}}||d   qS   r   )r   svr,  r   r   r   r     r   z-TitanHudPKFEE.get_amb_svs.<locals>.<listcomp>c                 S   $   g | ]}t |d  t |d  fqS rD  r   r   r   r   r   r        $ )r  r  r  rC   r   groupr&  r'  r(  r)  uniquerR   )r  sv_listr   r!  svs_combinedr   r   r   get_amb_svs
  s   
zTitanHudPKFEE.get_amb_svsFc                 C   s   d|  || }| | j|d }| | j|d }| jdd| jd f }| jdd| j| f }| jdd| j| f }	|r]| ||\}
}}t||
t| \}}}t||< t|	|< |||	fS )a"  Get all L1 phase multipath: t [s], phs_val [m], phs_std [m].  Look
        at phs_res to see if data is used.  This doesn't include any drift
        found by the phase AMB states.
        If only_valid=False -> return all MP data.  If True -> set invalid MP data to nan (based on phs_res).PhaseMP_r   r   Nr   )r/  r"  r  r  rC  	intersectr2  r   )r  r+  r,  
only_validmpPatr8  r9  r   rA  rB  t2phs_res_i1i2r   r   r   get_L1_phs_MP  s   
zTitanHudPKFEE.get_L1_phs_MPc                 C   s   d|  || }| | j|d }| | j|d }| jdd| jd f }| jdd| j| f }| jdd| j| f }	| ||\}
}}|r]t||
t| \}}}t||< t|	|< |||	|fS )zGet all L1 code multipath: t [s], cde_val [m], cde_std [m], cde_res [m].
        If only_valid=False -> return all MP data.  If True -> set invalid MP data to nan (based on cde_res).CodeMP_r   r   Nr   )r-  r"  r  r  r@  rP  r2  r   )r  r+  r,  rQ  rR  r8  r9  t1r:  r;  rS  cde_resrU  rV  rW  r   r   r   get_L1_cde_MP-  s   zTitanHudPKFEE.get_L1_cde_MPN)r  )Tr0  F)__name__
__module____qualname____doc__r  r"  r-  r/  r@  rC  rN  rX  r\  r   r   r   r   r    s    

	
	1

r  c                       sH   e Zd Zi ZejZejZ fddZ	dd Z
dd Z fddZ  ZS )	r   c                    s>   t |tkst |tkrdd t|D }tt| | d S )Nc                 S   s   i | ]\}}||qS r   r   )r   rZ   r   r   r   r   
<dictcomp>L      z$dotdict.__init__.<locals>.<dictcomp>)r   listtupler   superr   r  )r  idict	__class__r   r   r  J  s   zdotdict.__init__c                 C   s   i S ra   r   r  r   r   r   __getstate__N     zdotdict.__getstate__c                 C   s   d S ra   r   )r  r   r   r   r   __setstate__P  rl  zdotdict.__setstate__c                    s*   t t| || j}|| ju rt||S ra   )rf  r   get
unique_valKeyError)r  nameobjrh  r   r   __getattr__R  s   
zdotdict.__getattr__)r^  r_  r`  ro  dict__setitem____setattr____delitem____delattr__r  rk  rm  rs  __classcell__r   r   rh  r   r   F  s    r   c           
      C   s|   dd l }| \}}}}}|rtd|  d| }|jdd| d|g| | |d g }	zt|d | d	d
}	W |	S    Y |	S )Nr   z  loading... %sz
temp%d.matri   z--mat=%s-h)cwd/FrS   )rr   r   callr`   )
	info_listrS   rz   rT   recoptmydirrZ   tmpfiler   r   r   r   _vd2arr_helpX  s   "r  c                 C   s   | \}}}}}d|vrd|vst |dkrtdtd|  d }dd l}t }t|d |  ||ddg |\}}	t| |	dkrStd	t	|	  td
t |
 dkr}|d }
t|
d}t|| W d    |
S 1 svw   Y  |
S |S )N-d35:2z-d35:19r   zcrec opt unacceptable. Current BoostPythonViewdat module only accepts -d35:2 or -d35:19 with no opt.zloading(by boostpython) ... %sr|  z	--mat_memrz  zerr_code = z%BoostPythonViewdat.get_vdata() failedi Hz/tmp.npywb)rI   	Exceptionr   BoostPythonViewdatr=   getcwdchdir	get_vdatar@   r   flattenr   npsave)r  rT   r  r  r  rZ   r   r  r>   err_codenp_fnamer   r   r   _vd2arr_help_boostpythong  s,   

r  r  c                    s  ddl }ddl}ddl}ddl}	||}|du rg }d|v r%|ddg7 }d|v r.|dg7 }ti }
ti }g }zt| tu rStj	
| } tj	| } tt| }n	tdd	 | D }t|dkrhtd
|  t|D ]\}}|jddd}||||||f qld}d}zztjd}|du}|std|dkrtdddlm} |rtt|nd}||}|t|}W d   n1 sw   Y  tt|D ](}t|| tkrt|| d}t|||< W d   n1 sw   Y  qdd	 |D }W nJ tyJ } z=t|dkr0|r0|	j  }|t!|}W d   n	1 s*w   Y  n	t fdd|}dd	 |D }W Y d}~nd}~ww t"|}|D ]t\}}}}}|d }tj	#|rt|dD ]R}t$%d|}|rt|& dkrt|'dd |
|'d< t$%d|}|rt|& dkr|rt|'d|
|'d< qht|'d||'d< qht|
dkr nqQW |D ]\}}}}}|(| qn|D ]\}}}}}|(| qw |r||
fS ||
|fS )a  
    Run viewdat with --mat option.
    filename=T0x file, or list of files, or glob filename pattern
    rec='-d27' or '-d29' or '-d35:2' (default -d35:2).
      Can also pass args here (e.g. '-d27 -s10000 -p1')
    extra flags: opt=['--return_rec27_fll_meas','--whatever'] (default [])
    Returns (d,key):
     d = raw data
     key = structure with values from any key info generated by '-h'
    r   N-d27--translate_rec35_sub9_to_rec27 --translate_rec35_sub19_to_rec27z-d29z--translate_rec35_sub2_to_rec29c                 S   r   r   r   r   r   r   r   r     r   zvd2arr.<locals>.<listcomp>z)Failed to find any input files of format z.tmp.)prefixdirr  zSkip using BoostPythonViewdat.Fz@Parallel = False, switch back to use default viewdat executable.)Poolr,   r'   c                 S   r   r   r   r   r   r   r   r     r   c                    s
   t |  S ra   )r  )rx   r}  r   r   r     s   
 zvd2arr.<locals>.<lambda>c                 S   r   r   r   r   r   r   r   r     r   z
/mat_key.mr2   z\s+key.([^ ]+)\s+=\s+(\d+)r   z\s+flag.([^ ]+)\s+=\s+(\d+)))tempfileshutilrq   r   rH   r   r   r   r=   r>   r?   r   r   r
   rI   r  r   mkdtemprC   	importlibutil	find_specr   r  r   r   r  r   r   r  loadr   r   r  rE   r   r  r  groupsrJ  rmtree)r%   r  r  r   combine_flagsrS   r  r  rq   r   r   flagsr  r   rZ   rT   r  r   r   BoostPythonViewdat_specfoundr  n_cpur   dierU  keyfiler[   r!  r   r}  r   vd2arr  s   



r  c                 C   s   ddl }ddl}|j|| |jd}g }	 |j }|dkr n|dur2||dk r,q||d}|	dd | D  qt
||d	S )
a  
    Run command "cmd" and return array with data.
    If 'prefix_str' is set, then strip from text before converting to an array.
    For example: cmd='viewdat -d29 -mb filename.T04'
    vd2arr is faster, but this doesn't need a temporary file and works for more types
    r   Nrk   T    r   c                 S      g | ]}t |qS r   r.   r   r   r   r   r     r   zcmd2arr.<locals>.<listcomp>dtype)rq   rr   rt   rH   ru   rk   readliner   rb   rC   rR   )r}   
prefix_strr  rq   rz   piper   r[   r   r   r   cmd2arr  s   

r  c                 C   s~   ddl }ddl}|j|| |jd}g }	 |j }|dkr#t|S |dkr(q|dkr-q|dkr2q|t|	 
d	 q)
z
    Run command "cmd" and return array with raw lines as UTF-8 encoding.
    For example: cmd='viewdat -d99 -mb filename.T04'
    r   Nr  Tr     
s   
s   
utf-8)rq   rr   rt   rH   ru   rk   r  rC   r   rstripdecoderR   )r}   rq   rz   r  r   r[   r   r   r   cmd2arr_raw  s   



r  c                   @   s6   e Zd ZdZdd Zdd Zdd ZG dd	 d	Zd
S )	BinStructa  Simplify naming struct.unpack/pack data.
    Example for a binary file with a byte and one array of 2 U16s:
      x = BinStruct('flag:<B scales:2H')
      x.decode(b' ')
      print(x.d.flag) # 1
      print(x.d.scales) # [512, 1027].  (array because '2H' starts with a number)
    c                 C   s   g }d}t  | _| D ]3}|d\}}t| j|d  td|}t|dkr5||t|d fg7 }n||dfg7 }||7 }q|| _	|| _
d S )Nr   :z^\d+r   r,   )r  Emptyr   rH   setattrr  findallrI   r   	data_descbin_desc)r  descr  r  elemrq  formr!  r   r   r   r    s   


zBinStruct.__init__c                 C   sb   t | j|}d}| jD ]"\}}|dkrt||||  }n|| }t| j|| ||7 }qd S Nr   r,   )structunpackr  r  rd  r  r   )r  bin_dataunpack_dr   	elem_nameelem_lenunpack_currr   r   r   r  ,  s   
zBinStruct.decodec                 C   sT   g }| j D ]\}}t| j|}z||7 }W q   ||g7 }Y qtj| jg|R  S ra   )r  getattrr   r  packr  )r  out_datar  rU  	curr_elemr   r   r   encode7  s   zBinStruct.encodec                   @   s   e Zd Zdd ZdS )zBinStruct.Emptyc                 C   s
   t | jS ra   )r   __dict__rj  r   r   r   __str__B  s   
zBinStruct.Empty.__str__N)r^  r_  r`  r  r   r   r   r   r  A  s    r  N)r^  r_  r`  ra  r  r  r  r  r   r   r   r   r    s    
r  c                   @   s2   e Zd ZdZdddZdd Zdd Zd	d
 ZdS )RunCmdByLinea	  Run a shell command and get results one line at a time
    without waiting for the entire command to complete.
    Example:
      data = RunCmdByLine("ls -l /")
      while True:
        line = data.readline()
        if line is None: break
        print(line)
    Tc                 C   s\   dd l }dd l}dd l}|| _|| _g }| dkrddg}|j||| |jd| _	d S )Nr   Linuxstdbuf-o0r  )
rr   rq   platformrG   r  systemrt   rH   ru   r  )r  cmd_strr  rG   rz   rq   r  r  r   r   r   r  P  s    zRunCmdByLine.__init__c                 C   sT   | j j }| j   |s| j jd ur| j   d S | jr!| }| jr(| }|S ra   )	r  rk   r  poll
returncodewaitr  rG   r  )r  r[   r   r   r   r  \  s   

zRunCmdByLine.readlinec                 C   s,   | j d ur| j   | j   d | _ d S d S ra   )r  killr  rj  r   r   r   closeh  s
   



zRunCmdByLine.closec                 C   s   |    d S ra   )r  rj  r   r   r   __del__n  r   zRunCmdByLine.__del__NTT)r^  r_  r`  ra  r  r  r  r  r   r   r   r   r  F  s    
	r  c                 C   s   dd l }dd l}dd l}t|d}g }| dkrddg}|j|||  |jd}	 |j	 }|
  |s<|jd ur<n||rM|  |  | S q+|  td| )	Nr   r  r  r  r  r  Tzcould not find search_str: %s)rr   rq   r  	bytearrayr  rt   rH   ru   rk   r  r  r  rs   r  r  r  r/   )r  
search_strrz   rq   r  r  r  r[   r   r   r   get_first_strq  s(   


	r  c                 C   s    d| }t d|  |dd S )z
    Get key-value data from viewdat.  Returns first occurance as a string.
    filename = T04 file name
    key = key to return (e.g., AntennaType or RefStationLLH)
    
  - %s => viewdat -d16     => r,   )r  rH   )r%   r   r  r   r   r   get_kv_info  s   r  Fc           	      C   s   ddl }ddl}|j|d|  |jd}g }td| d}	 |j }|dkr,t|S |durM||dk r8q|	 d	d
 d}|rMdd |D }|
| q)z
    Convert key-value data to an array.
    Options: key - if set, only return data with this key string
             convert_float - if set, convert data to float instead of returning strings
    r   Nr  r  r  r  Tr  r  r,       c                 S   r  r   r  r   r   r   r   r     r   zkv_info2arr.<locals>.<listcomp>)rq   rr   rt   rH   ru   r  rk   r  r   r  rC   rR   )	r%   r   convert_floatrq   rz   r  r   r  r[   r   r   r   kv_info2arr  s"   

r  c                 C   s~   ddl }dddd| g}|j||jd}g }tdD ]#}|j }|d	kr+td
  dS td|}|r<t	|
d  S qdS )zX
    Use viewdat to get the 1st week # present in measurements (rec27, 35:9, 35:19)
    r   Nri   r  r  r  r  d   r   z-Didn't fine week number near start of file...zWeek : ([0-9]+)r,   )rr   rt   ru   r   rk   r  r   r  searchr   rJ  )r%   rz   r}   r  r   r   r[   r!  r   r   r   get_meas_week  s   
r  c                   @   s(   e Zd ZdZdZdZdZdZdZdZ	dS )	
OrbitConstz
    Orbital constants
    -DT!	@g   @TXAgЗ?XAgak{?g<(?gP{?N)
r^  r_  r`  ra  PIA_WGS84B_WGS84E2_WGS84
ONE_MIN_E2SQRT_ONE_MIN_E2r   r   r   r   r    s    r  c                 C   s
  |d }|s
t |}tdtjt|d   }tj| }tjdtj  |d  }t| j}| dddf |t|  |dddf< | dddf | |dddf< | dddf |dddf< |st	|dddf |dddf< t	|dddf |dddf< || S )z
    add delta east/north/up to reference lat/lon/height to produce
    full lat/lon/height
    enu = delta east/north/up [m]
    ref_llh = lat[rad], lon[rad], height[m] (if_ref_rad=False, degrees instead of radians)
    r   r,   r   r   N)
radianssqrtr  r  sinr  r   r   cosdegrees)enuref_llh
is_ref_radref_latWNMdllhr   r   r   enu2llh  s   

(   r  c                 C   s   t |||\}}}tt|}	tt|}
tt|}tt|}t| }t|}| t| t| }|t| t| }|t| }|	| | |
 |  || |  | }|	|
 | ||  ||
 |  | }| | |	|  | }t|||gS )aO  
    Convert satellite az/el/range (viewed from observer) to ECEF position.
    azimuthDeg = satellite azimuth [deg]
    elevationDeg = satellite elevation [deg]
    slantRange = distance from observer to satellite [m]
    obs_lat = observer latitude [rad]
    obs_long = observer longitude [rad]
    obs_alt = observer height [m]
    )conv_lla_ecefr  r  r  rR   )
azimuthDegelevationDeg
slantRangeobs_latobs_longobs_altsitexsiteysitezslatslonclatclonazRadelRadsoutheastzenithr   yzr   r   r   aer2ecef  s   &$r  c                 C   s`  t t| dkr| dt | f} t t|dkr"|dt |f}tt| }tt|}t|dddf }|sK|ddddf  tjd 9  < |se|ddddf  tjd 9  < |tjd 9 }| | ||  }tdtjt	|d   }tj
| }	tj
dtj  |d  }
|dddf |	 t| }|dddf |
 }|dddf }|||fS )aO  
    Convert lat/lon/height to delta east/north/up.
    llh = array of lat/lon/height [lat/lon in degrees by default]
    ref_llh = point or array of lat/lon/height [lat/lon in degrees by default]
    is_rad = True -> "llh" lat/lon is radians, else in degrees
    is_ref_rad = True -> "ref_llh" lat/lon is radians, else in degrees
    r,   Nr   r      r   )rI   r   reshapeonescopyr  r  r  r  r  r  r  )llhr  is_radr  scale1scale2r  r  r  r   r  dEdNdUr   r   r   llh2enu   s(   	""

r%  c                 C   s0   t | |||\}}}t|d |d  |d  S )aG  
    Convert lat/lon/height to 3D distance.
    llh = array of lat/lon/height [lat/lon in degrees by default]
    ref_llh = point or array of lat/lon/height [lat/lon in degrees by default]
    is_rad = True -> "llh" lat/lon is radians, else in degrees
    is_ref_rad = True -> "ref_llh" lat/lon is radians, else in degrees
    r   )r%  r  )r  r  r  r  r"  r#  r$  r   r   r   comp_3d_dist'  s   r&  c                     s   ddl m} dd|v r|d dg d|v r|d |dd dd	 | D  r.t  rLt }t|d
d
 dkd } | t |  fdd gfdd| d | d fD  }|fdd| dd
 D 7 }|S )a  
    intersect( a, b, c, ..., make_unique=False )
    Find values that appear in both a and b, c, d, ...
    a = array
    b = array
    etc. [optional]
    ret[0] = common values in a,b,c, ... Will be sorted!
    ret[1] = index into a[] (not sorted)
    ret[2] = index into b[] (not sorted)
    etc. [optional]
    Note that any repeated input values will be in the output too
    unless you set make_unique=True.
    If any of c,d,etc. are None, then it won't be used for comparison
    and ret[3],ret[4],etc. will be [].
    r   )reduceFmake_uniquemake_quick_uniquec                 S   s   t | |dS NT)intersect1d)r[   r2   r   r   r   r   K  r   zintersect.<locals>.<lambda>c                 s   s    | ]	}|d ur|V  qd S ra   r   )r   r=  r   r   r   	<genexpr>K  s    zintersect.<locals>.<genexpr>Nc                    s   | d u rg S r$t | t} t| td}d|t| ddd < d | | < r@D ]}t| d d  |kd }d | |d d < q(t|  	 d }t
 t
|krUtd |S )Nr  T)return_indexr,   r   r   z;intersect length mismatch - perhaps there is repeated data?)rR   astypeobject
zeros_likeboolrK  r  r   in1dnonzerorI   r   )argr!  r   r   
common_arg)commonduplicted_valuesr)  r(  r   r   get_arg_idxT  s   
zintersect.<locals>.get_arg_idxc                       g | ]} |qS r   r   r   r4  r8  r   r   r   f  r   zintersect.<locals>.<listcomp>r,   c                    r9  r   r   r:  r;  r   r   r   h  r   r   )	functoolsr'  rK  r  ediff1dr   delete)argskwargsr'  rstr   retr   )r6  r7  r8  r)  r(  r   rP  2  s(   
$rP  皙?c                 C   s   |dkr|t | krtt| tg|t |   f}nt| }tt |d tt | }|rcddlm} || |d}tt	t |d }|dd| }	||	}
t
|
}|dkr]|
t
|
 }
|||	|
fS ||fS )a$  Compute CDF (and PDF?) for 'x'.
    if do_pdf is False:
      Returns (cx, cy)
        cx = is just 'x' sorted
        cy = value from 0 to 1.0 - shows the % of data below corresponding cx
    if do_pdf is True:
      Returns (cx, cy, px, py )
      cx/cy as above
      px = X values for PDF (correspond to input 'x' values)
      py = Y values for PDF (probability)
      (Modify 'pdf_sm' to get more or less smoothing.  Higher pdf_sm=more smoothing.)
    plot( cx, cy ) to show CDF plot.
    plot( cx, cy, px, py ) to show CDF and PDF plot.
    r   r,   )gaussian_kde)	bw_method     @@N      ?)rI   sortrE   Infaranger.   scipy.statsrD  r   ceilmax)r   do_pdfpdf_smpadcxcyrD  fit
decimate_npxpymax_pyr   r   r   docdfk  s    rX  c           
      C   s   | t  d |t  d }}tjtdtjt| t|   }|| t| }|t| }|t| }|tj | t| }	|||	fS )zy
    lat_deg - latitude in deg
    lon_deg - longitude in deg
    alt_m - height in m
    Returns (x,y,z) - ECEF [m]
    g     f@rG  )pir  r  r  r  r  r  r  )
lat_deglon_degalt_mlatlonRnr   r   r  r  r   r   r   r    s   $
r  c                 C   sR  d}t jt j }dt j }t j}t jt j }d}d}	d}
d}d}|dk r'd}nd}t| |  ||  }|dk rO|dkr@|d }n| d }d}	t|t j }
nd| }|t| }|| }|| }d| }d| }| | }|dkr}|| }|||  }n2|dkr|| }n)|| | }|| | ||  ||  | }|dkr|| }n
|| }|||  }	 |d
7 }|| }|| }||| | | |  d| d|  | |  }||7 }|dk rt|dksnq|| }d| }d| }t|d| | | }t|| }	d| | | t||  ||  t|| ||   }
|d t	 |	d t	 |
fS )zK
    x, y, z = ECEF [m]
    Returns (lat [deg], lon [deg], height [m])
    r  g      @r           r0  rG  {Gz?       @Tr,   g      @   gHz>r  )
r  r  r  r  r  absr  fabsarctan2rY  )r   r  r  r  cfoure2e_primeae_primer]  r^  hgtcountr   signOfZpp_invz_primez_prime_plus_cz_prime_minus_cuvt_mt_m3fmt_m2ptdelta_tone_plus_t2one_minus_t2r   r   r   conv_ecef_lla  sp   




 
0
"r}  c                  C   s  g }| ||   | ||  | ||  dt|d d |d d  |d d   }|d | }|d | }	|d | }
t| ||}|d tj d }|d tj d }|d }t|}t|}t|}t|}|}|}| }|}| | }|| }|| }| | }|| |	|  |
|  }t|}|| ||	  }|| ||	  ||
  }t||}|dk r|dtj 7 }||fS )NrG  r   r   r,   r  r`  rb  )	rC   mathr  r}  rY  r  r  asinatan2) xRXyRXzRXxSVySVzSVdposinv_rdcosxdcosydcoszllar]  r^  rk  sinlatcoslatsinloncoslonutzceet1et2nt1nt2utxutysin_eaelev	east_dcos
north_dcosazir   r   r   compute_elev_azi  s@   .






r  c                 C   s   | d| d ? d@ }| d| d ? d@ }| d| d ? d@ }| d| d ? d@ }d||A  d d|  dd||A  d d|    S )N   r   r,   r   r                 ?r   )u16r   ISIMQSQMr   r   r   _decode_2bsm.  s
   4r  c              	   C   s   t ddttt| dk t|  dtttt| dk t|  f  t ddttt| dk t|  dtttt| dk t|  f  d S )NzIS %%%.1f IM %%%.1fr   r   r   zQS %%%.1f QM %%%.1f)r   rI   r   realre  imag)cvalr   r   r   _print_stats6  s   """"r  c                 C   s   dd | D S )z@
    Convert a Maxwell 7/8 U16 logged sample to 4 I/Q pairs
    c                 S   s&   g | ]}t d dD ]}t||q	qS )r   r  )r   r  )r   r  r=  r   r   r   r   @  s   & z decode_2bu16.<locals>.<listcomp>r   )raw16r   r   r   decode_2bu16<  s   r  c                 C   s"   dd l }|d|d  | |S )Nr   z<%dHr   )r  r  rA   )rT   u8lenr  r   r   r   _unpack_u16sB  s   r  c                 C   sp   t | d}|dkr|d d@ }|| n|dk r'| d d@  }||d t||}t|}|r6t| |S )zB
    Read a raw 2-bit Ettus RF file (or raw Maxwell 6/7 data)
    r'   r   r,   r   )r   seekr  r  r  )r%   r  offsetrS   rT   r  r  r   r   r   
read_raw2bH  s   

r  c                 C   sj  ddl }t| d}|d|dd }|d|dd }|d|d	d }|d|dd }|d|d	d }	|d
|dd }
|| |d	@ }|d@ }|d@ }|d@ rftd|  t|ddkrstd td|
  |rtd |rtd |rtd t||}|s|rt	|ddd }t	|d	dd }||fS t	|ddd }|S )z
    Read a p16 file
    r   Nr'   Ir  Hr   Br,   r      i  z&Unknown bands : 0x%x - incorrect read?1z)Probably will not handle > 2 bands well..zSamp Hz %.1f.  Bands:z  L1z  L2z  G1)
r  r   r  rA   r  r   binrl  r  r  )r%   r  r  r  rT   hdr_lenhdr_srchdr_encoding	hdr_bandshdr_padhdr_samp_Hzhas_L1has_L2has_G1r  L1valL2valr   r   r   read_p16Y  s6   


r  c                 C   s   | d d| ? d@ }| d d| ? d@ }| d d| ? d@ }| d d| ? d@ }d| d||A   d dd| d||A   d   S )Nr      r,   r   r   r  r  r   )raw32r   r  r  r  r  r   r   r   _decode_u32z  s
   4r  c                    s  ddl }t| d}d}|d|dd }|d|dd }|d|d	d }|d|d	d }	|d
|dd }
td|
d   |d|dd }|d|dd }|rf|d	7 }|	rl|d	7 }d\}}|| kr|d|d	d }|d|dd }|d	7 }|dkrd	}n|dkrd	}ntd|  || ksvd| d	 }|| | @ }||| d |d }|d| ||td|||	||f  d| |d	  M }g }t|D ]  fddtd| D }|| q|S )z
    Read a p32 file
    u8len = # of bytes in file to read
    offset = # of bytes to skip at startup.  Rounded to multiple of 16.
    r   Nr'   r  r  r  r   r  r,   z<dr  zSample rate: %.3f MHzư>r   )r   r   r   zUnknown signal type %d   <%dIz%%d signals: L1 %d, L2 %d, G1 %d B1 %dc              	      sJ   g | ]!}t d dD ]}t| d   | d d    |q	qS )r       r  )r   r  )r   r=  r   rZ   r  ry   r   r   r     s   J zread_p32.<locals>.<listcomp>)	r  r   r  rA   r@   tellr  r   rC   )r%   r  r  r  rT   n_sigr  r  hdr_L1hdr_L2samp_HzL1_HzL2_Hzhdr_G1hdr_B1hdr_XX_Hzmasku32lenoutr   r   r  r   read_p32  sN   
 r  c                 C   sD   g d}| dd|  ? d@ }| dd|  ? d@ }|| d||   S )N)r,   r   r      r  r      r  r   )r  rZ   lookupInQnr   r   r   _decode_2bit_gss6450  s   r  c                 C   s   | dd|  ? d@ }|dkr|d d d }n|d d }| dd|  ? d@ }|dkr4|d d d }n|d d }|d	|  S )
Nr  r  rc     r  r   r,      r  r   r  rZ   r  r  r   r   r   _decode_4bit_gss6450     r  c                 C   s   | dd|  ? d@ }|dkr|d d d }n|d d }| dd|  ? d@ }|dkr4|d d d }n|d d }|d|  S )	Nr  r           r   r,   r  r   r  r   r   r   _decode_8bit_gss6450  r  r  r`  c           %      C   s  ddl }ddlm}m} t| d}d}d}	d}
g }tdD ]}|d }|dr- nv|r3t| |d	ra|d
d 	d}|
|d}||j|j|j}||| d d8 }||  }
td|}|rt|d}t|d}	t|d}|  dr|dkr|t|d q|dkr|t|d q|	dk s|dk rtd| }|d d@ }||d  |d|dd }|dkr|d|dd }|dkrtd dS |d|dd }|rtd||f  ||krd}nd}|rtd|  | |d k rF|d|dd }|dkr0|d|dd }|dkr=|r<td n	| |d k s|rQtd||f  |	d  d! }|d | | d" d# }t|| }|d d$@ }|rytd%| ||d t|| }t|d }|d }|rtd&| |d'| ||}|dkrt}d(}n|dkrt}d}n|d(krt }d}ntd) dS t!t|| t| |ft"d*}|dkrtt|d D ]/} t|D ]'}!||d|   |!|| | |! df< ||d|  d  |!|| | |! df< qqn!tt|D ]} t|D ]}!|||  |!|| | |! df< q"q|
| }"t#d+g d,}#|#|"|||}$|$|fS )-z
    Read a Sprint GSS6450 file
    n_secs = # of seconds in file to read
    offset_secs = # of seconds to skip at startup.
    Returns 2 things:
      Info: (utc seconds in week at start of samples, etc.)
      array: signal #1 [,signal #2?]
    r   Ndatetime	timedeltar'   r   r  x   s   <End of Header>s   <Start Time>r  r  z%H:%M:%S %d/%m/%yr  dayss[   <Signal Recorded> +([0-9]+), .*?, Bandwidth ([0-9]+) MHz, Freq ([.0-9]+) MHz, Bits ([0-9]+)r  r   r,   z.a.gnsr   zUnknown freq/bitsP   r  izError: unknown synczstart: %x %xz# of signals in file: %di   zFound end of syncz
end: %x %x
   g(\u$@r   g       @izFile offset {}z# of bytes to read {}r  r  zError: unknown # of bitsr  Info)start_t
f_samp_MHzn_bits	f_mid_MHz)$r  r  r  r   r   r  r  rs   r@   r  strptimeyearmonthday
isoweekdaytotal_secondsr  r  r   rJ  r   r   rC   r.   RuntimeErrorr  r  r  rA   formatr  r  r  r   complexr   )%r%   n_secsoffset_secsrS   r  r  r  rT   r  bandwidth_mhz	week_secs	f_mid_mhzrU  r0   date_str	utc_start
week_startr!  
signal_numsync_possync1sync2n_sigs
f_samp_mhzbytes_per_secr  r  r  r  decode_funcn_in_32bsigsr=  r   r  r  	samp_infor   r   r   read_gss6450  s   	








 
"*"r  c           	   	   C   s   t t| | }|dkrt||}t|}d}|rt|}d}td|D ]}|ttt| || |d |  | 7 }|d7 }q$|| S )z
    compute averaged FFT
    d = raw input data
    flen = # of points for each FFT
    max_avg = maximum # of averages to perform
    do_window = set to True if you want to apply a Hamming window
      (e.g., in case a jammer is present)
    r   rG  r,   )	r   rI   r3  rw   hammingr   fftshiftrd  fft)	r   flenmax_avg	do_windowi_maxdfftwindown_sumsr=  r   r   r   do_1d_avg_fftW  s   	
,
r!  c                 C   s8   d| | || ||   }|| | }|t |8 }|S )Nrb  )mean)r   FreqLxFreqLyPhaseLxPhaseLyetaatmr   r   r   	_calc_atmm  s   r)  c              	   C   s   |  }ttt| |d k}d}|D ]}|||d   t|||d  8  < |d }q||d   t||d  8  < |S )Nr1  r   r,   )r  r   rd  r   r"  )r   r   r   new_vali_jmpr0   r=  r   r   r   remove_seg_meanss  s   (
 r,  c
                 C   s   t j| }
t j| }|
 | | | }}t| ||||}|| | }tt| }t| ||}t|dkrB|| | }t| ||}ng }t| ||}|||fS )a  
    Compute iono-free stationary pseudorange (MPx)
    FreqLx = Lx frequency [Hz]
    PseudoLx = Lx pseudorange [m]
    PhaseLx = Lx carrier phase [cyc]
    SlipLx = Lx slip count
    FreqLy, PseudoLy, PhaseLy, SlipLy = same for Ly
    If you let PseudoLy == [] then MPLy will be empty too.
    Returns: (MPLx, atmLx, MPLy)
    Note: atmLx is twice the iono because it is a correction to "PR - phase"
    r   )r   r   r)  r   r   r,  rI   )r   r#  PseudoLxr%  SlipLxr$  PseudoLyr&  SlipLylp_knownWavelengthLxWavelengthLyatmLxMPLxr   MPLyr   r   r   iono_free_SR}  s   


r7  c           	      C   s   t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }t|dkrEtg tdS |S )a  
    Similar to get_L1L2_idx(), but for any signal type
    Inputs: d = rec27/35:19 data
            k = rec27/35:19 key (from vd2arr)
            sv_id = satellite ID
            sat_type = satellite type from T0x file
            Lx_freq = "x"/master frequency (e.g., dRec27L1Band)
            Lx_trk = "x"/master track type (e.g., dRec27Track_CA)
            elev_mask_deg = elevation mask [deg]
            min_seg = minimum # of points in each non-slip segment
    Returns: i_Lx
    Nr   r  )	r   SVSAT_TYPEELFREQTRACKrI   rR   r   )	r   r   r+  r,  Lx_freqLx_trkelev_mask_degmin_segi_Lxr   r   r   
get_Lx_idx  s   rB  c
                 C   sn  t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }
|dk rt | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }t|dkrt| ||jf }t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }n>tg }n9t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }t|
dkst|dkrtg t	dtg t	dfS t
| |
|jf | ||jf \}}}|
| }
|| }dd }|| ||
||	\}
}|
|fS )a  
    Similar to get_L1L2_idx(), but for any signal type
    Inputs: d = rec27/35:19 data
            k = rec27/35:19 key (from vd2arr)
            sv_id = satellite ID
            sat_type = satellite type from T0x file
            Lx_freq = "x"/master frequency (e.g., dRec27L1Band)
            Lx_trk = "x"/master track type (e.g., dRec27Track_CA)
            Ly_freq = "y"/slave frequency (e.g., dRec27L1Band)
            Ly_trk = "y"/slave track type (e.g., dRec27Track_CA)
            elev_mask_deg = elevation mask [deg]
            min_seg = minimum # of points in each non-slip segment
    Returns: i_Lx, i_Ly -> for input into get_MPx()
    Nr   r  c                 S   s   t t| ||jf dkt| ||jf dk@ d }|dkrgtdgt t|dkd t|gf}tj|dgt| d}tt|d D ]}|| ||d  }	}
|
|	 |k r_d|j|	|
< qE||j  j	}|| || }}||fS )zRemove any data with a slip on either frequency.
        If min_seg > 0, then make sure data segments are at least 'min_seg' points long.
        r   r,   F)r  T)
r   r   SLIP_CNTrE   rI   marR   r   r  r+   )r   r   iLxiLyr@  i_noslipi_jumpi_noslip_mar=  startendr   r   r   remove_slips  s   4&z"get_LxLy_idx.<locals>.remove_slips)r   r8  r9  r:  r;  r<  rI   rM  rR   r   rP  r   )r   r   r+  r,  r=  r>  Ly_freqLy_trkr?  r@  rA  i_LytrackrU  ixiyrL  r   r   r   get_LxLy_idx  s\   
$rS  c                   @   s|   e Zd ZdZejejdfejej	dfej
ejdfejejdfejejdfejejdfejejdfejejd	fiZd
d ZdS )get_sat_typez
  Return the SAT_TYPE_ for the supplied RT_SatType
  Also returns a system name string
  get_sat_type(RT_SatType_GPS).SAT_TYPE
  get_sat_type(RT_SatType_GALILEO).sysstr
  GPSSBASGALILEOQZSSBEIDOUGLONASSIRNSSXONAc                 C   s$   | j | d | _| j | d | _d S r  )sat_type_dictr9  sysstr)r  
RT_SatTyper   r   r   r    s   zget_sat_type.__init__N)r^  r_  r`  ra  r&  r'  	RcvrConstSAT_TYPE_GPSRT_SatType_SBASSAT_TYPE_SBASRT_SatType_GALILEOSAT_TYPE_GALILEORT_SatType_QZSSSAT_TYPE_QZSSr)  SAT_TYPE_BEIDOUr(  SAT_TYPE_GLONASSRT_SatType_IRNSSSAT_TYPE_IRNSSRT_SatType_XONASAT_TYPE_XONAr]  r  r   r   r   r   rT    s    
rT  c                   @   sL
  e Zd Zedg dZedg dZi eejejej	edde
jdeejejejedde
jd	eejejejed
de
jdeejejejed
de
jdeejejejed
de
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
jdeejejejedde
j deej!ejej	edde
jdeej!ejejedde
jd	i eej"ejejed de
j#deej"ejejed de
j#deej"ejejed de
j#deej"ejejed de
j#deej"ejejed de
j#deej"ejejed de
j#deej"ejej$ed!d"e
j%d	eej"ejej&ed!d#e
j%d	eej"ejej'ed!d$e
j%d	eej"ej(ej$ed%d"e
j)deej"ej(ej&ed%d#e
j)deej"ej(ej'ed%d$e
j)deej"ej*ej+ed&d"e
j,deej"ej*ej-ed&d#e
j,deej"ej*ej.ed&d$e
j,deej"ej*ej/ed&d'e
j,deej"ej0ej1ed(d"e
j2di eej"ej0ej3ed(d#e
j2deej"ej0ej4ed(d$e
j2deej5ejej	ed)de
jdeej5ejej6ed*de
j7deej5ejejed+de
jd	eej5ejejed+de
jd	eej5ejejed+de
jd	eej5ejejed+de
jd	eej5ejejed+de
jd	eej5ejejed+de
jd	eej5ejej8ed,de
j9deej5ejejed-de
jdeej5ejejed-de
jdeej5ejejed-de
jdeej5ejejed.de
jdeej5ejejed.de
jdeej5ejejed.de
jdi eej5ej0ej:ed/de
j;deej<ej=ej>ed0de
j?deej<ejejed1de
j@d	eej<ejejed1de
j@d	eej<ejejed1de
j@d	eej<ejejed1de
j@d	eej<ejejed1de
j@d	eej<ejejed1de
j@d	eej<ej(ejAed2de
jBdeej<ejejed3d"e
jCdeej<ejejed3d#e
jCdeej<ejejed3d$e
jCdeej<ej(ejed4d"e
jDdeej<ej(ejed4d#e
jDdeej<ej(ejed4d$e
jDdeej<ej*ej+ed5d"e
jEdeej<ej*ej-ed5d#e
jEdeej<ej*ej.ed5d$e
jEdeej<ejFejGed6de
jHd7eejIejej	ed8de
jJdeejIejejKed9de
jLd	eejIejej	ed:de
jMdeejIejejKed;de
jNdeejIejOejPed<d=e
jQdeejIejOejRed<d#e
jQdeejIejOejSed<d$e
jQdeejTejej	ed>de
jUdeejTejVej	ed?de
jWd	eejXejejYed@de
jZd	eejXejej[edAde
j\diZ]	 dBdC Z^dDS )Eget_sub_typeRTSat)SatTypebandrP  SatInfo)r  IQsubtypeorderzGPS L1CAr   r   zGPS L2Er,   zGPS L2CCMCLr   CMCLzGPS L5rs  r   r  QzGPS L1CzDP BOC11r  zD BOC11zP BOC11zDP MBOCzD MBOCzP MBOCzGPS L1E   zSBAS L1zSBAS L5zGAL E1zGAL E5ADPDPzGAL E5Bz	GAL E5AltFullzGAL E6z	QZSS L1CAz	QZSS L1CBzQZSS L1CzQZSS L1SAIFzQZSS L2CzQZSS L5zQZSS LEXzBDS B1zBDS B1CzBDS B2zBDS B2AzBDS B2Bz	BDS B2AcezBDS B3   zGLN G1CzGLN G1PzGLN G2CzGLN G2PzGLN G3PDzIRN L5zIRN S1zXON X1zXON X5c                 C   s   |||f| j v rR| j |||f d | _| j |||f d | _| j |||f d | _| j |||f d | _| j |||f d | _t| jrP|  jd| j 7  _d S d S d| _d| _d| _d	| _d
|||f | _d S )Nr   r   r,   r   -r   z
??? signalz	??? trackc   z??? (%d %d %d))sub_type_dictSUBTYPEsigstrtrkstrrJ  fullstrrI   )r  r_  
dRec27BanddRec27Trackr   r   r   r  }  s   
zget_sub_type.__init__N)_r^  r_  r`  r   ro  rr  r&  r'  dRec27L1BanddRec27Track_CAr`  SUBTYPE_L1CAdRec27L2BanddRec27Track_ESUBTYPE_L2EdRec27Track_CMCLSUBTYPE_L2CdRec27Track_CMdRec27Track_CLdRec27L5E5ABanddRec27Track_IQ
SUBTYPE_L5dRec27Track_IdRec27Track_QdRec27Track_BOC_1_1_DPSUBTYPE_L1CdRec27Track_BOC_1_1_DdRec27Track_BOC_1_1_PdRec27Track_BOC_1_1_DP_MBOCdRec27Track_BOC_1_1_D_MBOCdRec27Track_BOC_1_1_P_MBOCdRec27Track_L1ESUBTYPE_L1Erb  rd  
SUBTYPE_E1dRec27Track_BPSK10_PDSUBTYPE_E5AdRec27Track_BPSK10_DdRec27Track_BPSK10_PdRec27E5BBandSUBTYPE_E5BdRec27E5ABCentreBanddRec27Track_AltBOCCompPDSUBTYPE_E5AltBOCdRec27Track_AltBOCCompDdRec27Track_AltBOCCompPdRec27Track_AltBOCNonCompdRec27E6BanddRec27Track_E6_PD
SUBTYPE_E6dRec27Track_E6_DdRec27Track_E6_Prf  dRec27Track_L1CBSUBTYPE_L1CBdRec27Track_SAIFSUBTYPE_L1SAIFdRec27Track_LEXSUBTYPE_LEXr)  dRec27B1BanddRec27Track_B1
SUBTYPE_B1SUBTYPE_B1CdRec27Track_B2
SUBTYPE_B2SUBTYPE_B2ASUBTYPE_B2BSUBTYPE_B2AceBOCdRec27B3BanddRec27Track_B3
SUBTYPE_B3r(  SUBTYPE_G1CdRec27Track_PSUBTYPE_G1PSUBTYPE_G2CSUBTYPE_G2PdRec27G3BanddRec27Track_G3_PD
SUBTYPE_G3dRec27Track_G3_DdRec27Track_G3_Prj  SUBTYPE_L5CAdRec27S1BandSUBTYPE_S1CArl  dRec27Track_X1_PD
SUBTYPE_X1dRec27Track_X5_PD
SUBTYPE_X5r  r  r   r   r   r   rn    s8   	
 !"#$%&()*+,-./012345679:;<=>?@ABCDEFGHIZrn  c                 C   s   i ddddddddddddd	dd
ddddddddddddd	dd	dddddddddddddddd
ddd}| | dS )Nr   r   r     r  r,   rc  r  rz  r  r         r  r  r     r  	   r  r   )r                       r  r     !         rn  )rt  switchr   r   r   get_subtype_to_subband  sf   	
!r  c                 C   s   ddddddd}| | dS )	NLG1LG2LE5z E6z B1z S )r   r,   r  rz  r  r  zInvalid rt_band!!r  )rt_bandr  r   r   r   rt_band_to_label  s   	r  c                 C   s(   ddddddddd	d
dd}| | dS )NzGPS C/AzL1 & E1z
Glonass G1z	Beidou B1zGPS L2z
Glonass G2zL5 & E5AzG3 & B2z
Galileo E6z	Beidou B3zS1 C/A)r   r,   r   r   r  rz  r  r  r  r  r  zInvalid rt_subband!!r  )
rt_subbandr  r   r   r   rt_subband_to_label  s   r  c                 C   s   i ddddddddd	d
dddddddddddddddddddddd d!d"i d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdG}| | dS )HNr   unknownr   zL1-C/A r  z  L1C  rz  z  L1E  r  z  L2E  r  z  L2C  r  zL2-EorCr  z  L5   r  z  G1C  r  z  G1P  r  z  G2C  r  z  G2P  r  z  G3   rc  z  E1   r  z  E5A  r  z  E5B  r  zAltBOC r  z   E6  r  zE6 2nd r  z  B1   r  z  B2   r  z  B3   r  z  B1C  r  z  B2A  r  z  B2B  r  zAceBOC r  z L1CB  r  zL1SLAS r  z  LEX  r  zLEX-L6Er  zL5-C/A r  zS1-C/A "   z  X1   #   z  X5   zL1-SBOCz  X5D  )$   %   r  )
rt_subtyper  r   r   r   rt_subtype_to_label  s   	
 !"#'r  c           	   	   C   sz   t | dd|jf |k| dd|jf |k@ }t| |ddf |}g }|| D ]\}}|||t|||jf q)|S )ab  
    Helper function for get_LxLy_idx()
    Inputs: d = rec27/35:19 data
            k = rec27/35:19 key (from vd2arr)
            sv = satellite ID
            rt_sat_type = satellite type from T0x file
    Returns: list for all satellite signals:
       [ (Lx_freq, Lx_trk, label), ... ]
    (e.g., [(dRec27L1Band, dRec27Track_CA, 'GPS L1'), ...])
    N)r   r8  r9  get_signalsrC   rn  r  )	r   r   rF  rt_sat_typer=  signalsrx   freqrP  r   r   r   sv_to_Lx_info  s   0r  c                 C   s   t | dd|jf |k| dd|jf |k@ }t| |ddf |}g }|| D ]6\}}|| D ]\}	}
t||	fttjtjfkrDq1|	|krJ nq1||	krPq)||||	|
t	|||j
f q)|S )a  
    Helper function for get_LxLy_idx()
    Inputs: d = rec27/35:19 data
            k = rec27/35:19 key (from vd2arr)
            sv = satellite ID
            rt_sat_type = satellite type from T0x file
    Returns: list for all satellite signals:
       [ (Lx_freq, Lx_trk, Ly_freq, Ly_trk, label), ... ]
    (e.g., [(dRec27L1Band, dRec27Track_CA, dRec27L2Band, dRec27Track_CMCL, 'GPS L1'), ...])
    N)r   r8  r9  r  r   r&  r  r  rC   rn  r  )r   r   rF  r  r=  r  rx   r  rP  freq2track2r   r   r   sv_to_LxLy_info  s   0 r  c                 C   s  |t jkrt| |||t jt jt jd||
S |t jkr+t| |||t jt jt jt j||
S |t jkrAt| |||t jt jt jt j||
S |t j	krVt| |||t jt j
t jd||
S |t jks`|t jkrt| dd|jf |k| dd|jf |k@ }t| |ddf || }d\}}	t|dkr|D ]\}
}|
t jks|
t jks|
t jkr|
|}}	 nqt| |||t jt j||	||
S td| )a  
    Get index for intersecting GPS L1 and L2E/L2C times (or GLN G1CA and G2CA,
    or Galileo E1 & E5A, or Beidou B1 & B2)
    If there is no L2E/L2C data then L2E/L2C is ignored and i_L2E/i_L2C is empty.
    d = rec27 data
    k = rec27 key (e.g., from vd2arr)
    sv_id = satellite ID
    sat_type = RT_SatType_GPS, or GLONASS, or ...
    elev_mask_deg = elevation mask [deg]
    min_seg = minimum # of points in each non-slip segment (otherwise fill in Nan)
    Returns: (i_L1, i_L2)
    (i_L2 is for L2C if available, otherwise L2E)
    r   N)r   r   r,   r$  )r&  r'  rS  r  r  r  r(  rf  r  rd  r  r  RT_SatType_BEIDOU_ICDPRNsr)  r   r8  r9  r  rI   r  r  r  r  r/   )r   r   r+  r,  r?  r@  r=  r  band2r  	tmp_band2
tmp_track2r   r   r   get_L1L2_idx(  s>   





0

r  c                 C   sL   t | dd|jf d| dd|jf   }|rdd |D S dd |D S )z
    d = rec27 data
    k = rec27 key (e.g., from vd2arr)
    Return a list of unique satellites in rec27/35:9 [(sv,sat_type), ...]
    If desc=True, return triplet:
     [(sv,sat_type,sat_desc),...]
    NrE  c                 S   s4   g | ]}t |d  t |d  tt |d  jfqS rD  )r   rT  r^  r   r   r   r   r   [  s   4 zget_sv_list.<locals>.<listcomp>c                 S   rG  rD  rH  r   r   r   r   r   ]  rI  )rK  r8  r9  )r   r   r  sv_clistr   r   r   get_sv_listQ  s   ,r  c           	         s  |du r| j }t| dd|jf td> | dd|jf td>  | dd|jf td>  }i }|D ]4}|d? d@  |d? d@ }|d@ }|rV||t ||jf}n||f} |v rf|  	| q7|g| < q7|
 D ] t|   fddd| < qp|S )	ak  
    d = rec27 data (from vd2cls or vd2arr)
    k = None (or rec27 key from vd2arr)
    desc = False:
      Return a dictionary of unique signals in rec27/35:9 {sat_type:(freq,track), ...}
    desc = True:
      Return a dictionary of unique signals in rec27/35:9 {sat_type:(freq,track,description), ...}
      where "desription" is something like 'GPS L1CA'
    Nr  r  r   r  c                    s   t  | d | d jS r  )rn  rJ  r   r,  r   r   r   }  rc  zget_signals.<locals>.<lambda>)r   )r   rK  r9  r.  r   r;  r<  rn  r  rC   keysr   )	r   r   r  r  r  r   r  rP  	curr_itemr   r  r   r  _  s*   
r  c	                 C   s  t |dd|jf |k|dd|jf |k@ |dd|jf |k@ |dd|jf |k@ }	t |dd|jf |k|dd|jf |k@ |dd|jf |k@ |dd|jf |k@ }
t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }t | dd|jf |k| dd|jf |k@ | dd|jf |k@ | dd|jf |k@ }t||	|jf ||
|jf | ||jf | ||jf \}}}}}|	| }	|
| }
|| }|| }dd }dd }|||	ddf |}|| |ddf |}|||
ddf |}|| |ddf |}|| ||  }|||	ddf |}|| |ddf |}|||
ddf |}|| |ddf |}|| ||  }|||fS )a  
    Do a manual zero-baseline double-diff calculation.
    dr = rover rec27 data
    kr = rover rec27 key (e.g., from vd2arr)
    db = base rec27 data
    kb = base rec27 key (e.g., from vd2arr)
    ref_sv = reference satellite ID
    tst_sv = test satellite ID
    sat_type = satellite type
    freq = block type (frequency)
    track = track/signal type
    Returns: (t, code double diff[m], carrier double diff[cycles])
    Note - tries to remove cycle slips from carrier double diff...
    Nc                 S   sT   | d d |j f  d }tj}| d d |jf | d d |jf | |  |tj  S Nr1  )CLKBIASr   L1_WAVELENGTHRANGEDOPPr   r   r   r   
wavelengthr   r   r   
steer_code     6z"do_double_diff.<locals>.steer_codec                 S   sT   | d d |j f  d }tj}| d d |jf | d d |jf |  |tj |  S r
  )r  r   r  PHASEr  r   r  r   r   r   
steer_carr  r  z"do_double_diff.<locals>.steer_carr)r   r8  r9  r;  r<  rP  r   )drkrdbkbref_svtst_svr,  r  rP  ibribtirrirtr   ibr1ibt1irr1irt1r  r  base_ref_coderovr_ref_codebase_tst_coderovr_tst_code	diff_codebase_ref_carrrovr_ref_carrbase_tst_carrrovr_tst_carr	diff_carrr   r   r   do_double_diff  sP   ,,,,
r-  c                 C   sn  | |j  tjkr)| |j tjkrtjS | |j tjkr&tjtj	| |j
   S tjS | |j  tjkrG| |j tjkrDtjtj| |j
   S tjS | |j  tjkr]| |j tjkrZtjS tjS | |j  tjkrhtjS | |j  tjkrstjS | |j  tjkr~tjS | |j  tjkrtjS | |j  tjkrtjS | |j  tjkrtjS | |j  tjkrtj S | |j  tj!krtj"S d S ra   )#r;  r&  r  r9  rl  r   XONA_L1_FREQr(  GLONASS_L1_BASE_FREQGLONASS_L1_FREQ_OFFSETFDMAL1_FREQr  GLONASS_L2_BASE_FREQGLONASS_L2_FREQ_OFFSETL2_FREQr  XONA_L5_FREQL5_FREQr  GALILEO_E5B_FREQUENCYr  GALILEO_E5AltBOC_FREQUENCYr  GALILEO_E6_FREQUENCYr  BEIDOU_B1_FREQUENCYr  BEIDOU_B3_FREQUENCYdRec27E1BandBEIDOU_E1_FREQUENCYr  GLONASS_L3_FREQUENCYr  IRNSS_S1_FREQUENCYr   r   r   r   r   get_freq  s>   rB  c                 C   sL   d|v r| d d |j f t|j@ |jkS | d d |jf td@ dkS )NMEASr  )rC  r.  r   dMEAS_LOCK_POINTMEAS1rA  r   r   r   get_lp_known  s   $ rF  r0  c                 C   s  |r
| ||j f }ng }t|dkst|t|kr%tg tg tg fS |r6| ||j f | ||jf  }	n| ||j f }	|rH|	| ||jf 7 }	t| |d ddf |}
t| |d ddf |}|
| }|dkr|dkrtd|  tt|	j	 tg tg fS t
| ||jf |
|	| ||jf | ||jf ||| ||jf | ||jf t| |ddf |t| |ddf |@ 
\}}}|dkrtt| ||jf }td|d | d	d
\}}t|dkrt|||dd}t|dkrt|||dd}|||fS )a\  
    Compute iono-free stationary pseudorange (MPx)
    d = rec27/rec35:19 data
    k = rec27/rec35:19 key (e.g., from vd2arr)
    i_Lx = best Lx index for satellite - see get_GPS_L1L2_idx or get_LxLy_idx
    i_Ly = best Ly index for satellite
    filt_Tc = if > 0, lowpass filter MPx data with this time constant. 15s is OK.
    do_MPy = if True, return MPy.  If False returns [].
    use_CCFilt = if True use code/carrier filtered PR (need rec 35:19 diagnostic data)
    Returns: (MPx, atm1, MPy)
      MPx  = Lx code multipath
      atmx = Lx atmospheric correction
      MPy  = Ly code multipath
    r   NgGz?g)\(?z.get_MPx frequencies are too close - ratio %.3fr`  r   r   r   r   r  r   r   )r  rI   rR   CCDiffMPHatrB  r@   r   r  r   r7  r   r  rC  rF  r   r   r   r   )r   r   rA  rO  r5  do_MPy
use_CCFiltrm_MPHatrng_Lyrng_Lxfreq_xfreq_y
freq_ratioMPxatmxMPyr   r   r   r   r   r   get_MPx  s<   *
rT  c                    sN   t d|   fdd}t| }||}||ddd }t||ddd S )z
Inputs: x = random signal
        N = # of points to decay over
Returns envelope of 'x' based on a forward-backward estimate..
r0  c                    sn   t | j}t}t| D ])\}}t|r|}nt|r|  }n||k r.|  d  |  }n|}|||< q|S Nr,   )r   r   r   r   r2  )abs_xr  env_outr=  r   r   r   r   _helper	  s   


z signal_envelope.<locals>._helperNr   )exprd  maximum)r   r   rY  rV  y_fwdy_revr   rX  r   signal_envelope	  s   r^  c                 C   s$   |r
t tt| S t tt| S )zQ
    Return root-mean-square of x
    If ignore_nan==True, ignore NaN data..
    )r  nanmeansquarer"  )r   
ignore_nanr   r   r   rms2	  s   rb  c                 C   s2   |du rt dt|  }t|| |}| t|| S )z>Similar to detrend_linear but uses a polynomial of given orderNr   )r_rI   polyfitpolyval)r  ru  r   modelr   r   r   detrend_poly=	  s   rg  c                 C   sL   g }|D ]}t |d| k}t|dkr|| |d   q|d q|S )Nra  r   r`  )r   rI   rC   )rQ  rR  percentsr  rn  r=  r   r   r   get_cdf_percentsD	  s   ri  c
                    s  t jt jt jt jt jdtdkr+tdd d d gdddrEt	 }
t
d	td t
d
dtd t  rjt	 }t
dtd t	 }t
dtd rjt	 }t
dtd rt	 }t
dtd t	 }t
d td rt	 }t
dtd rt	 }t
d
td t	 }t
dtd rt	 }t
d	td  	
fdd}|d |d rd jdd d r<t	|j td td tdd t|  t	|j td td td tdd t|  r<t	|j td td td tdd t|  rt	|j td td tdd t|  t	|j td td td tdd t|  rt	|j td td td tdd t|  rt	|j td td tdd t|  t	|j td td td tdd t|  rt	|j td td td tdd t|  dS dS dS )z
Give quick summary of T0x vs POSPAC results.  Example usage:
pp = doload('POSLV-PPSmartBase.txt') # or pp=[lat,lon,hgt]
d1,k1=vd2arr('f1.T04')
d2,k2=vd2arr('f2.T04')
plt_pospac_truth( 'some title', pp, [(d1,k1,'ref'), (d2,k2,'tst')] )
show()
F)r   r0  r   r,   r   r  T      sharexo   c           %   
      s  d\}}}rt dd D  }|dtd  nt d d f gdd D R  }tD ]Y\}\}}}| rbrL|d d |jf }d}td }n$t d d f |d d |jf \}}}n|d }|d }|d|  }r|j| |f  }	|j| |f  }
|j| |f  }t|	d |
d  |d  }t|	d |
d  }t	|}t
|\}}t
|\}}t
|\}}t|||j|jd f |d f \}}}t|d |d  |d  }t|d |d  }t	|}t
|\}}t
|\}}t
|\}} r+| r+j||||jf d	|d
 j||||jf d	|d
 | r:r:j||d|d
 | rIrIj||d|d
 | rXrX
j||d|d
 | sruj|d| |d
 ruj|d| |d
 r j|d| |d
 rj|d| |d
 rj|d|  |d
 r	j|d| |d
 | rstd|t|f  q0| rtd|t|f  n
td|t|f  t||g d}!t||g d}"tdt|t|t|f  tdt|!  tdt|t|t|f  tdt|"  rQt||g d}!t||g d}"tdt|t|t|f  tdt|!  tdt|t|t|f  tdt|"  tddd t|||jf D ]%}#t|||jf |#k}$td|#t|$d t|||jf  f dd q`td q0d S )N)NNNc                 s   (    | ]\}}}|d d |j f V  qd S ra   r   r   r   r   rU  r   r   r   r,  	     & z6plt_pospac_truth.<locals>.show_data.<locals>.<genexpr>r,   c                 s   ro  ra   rp  rq  r   r   r   r,  	  rr  r   r   r   r  )labelz-xr  zAll '%s' len %dzAll '%s' data err (len %d):zCommon '%s' data err (len %d):)2   D   Z   _   r  z 3D max/rms/std %.1f %.2f %.2fz5 3D 50%%/68%%/90%%/95%%/99%% %.3f %.3f %.3f %.3f %.3fz 2D max/rms/std %.1f %.2f %.2fz5 2D 50%%/68%%/90%%/95%%/99%% %.3f %.3f %.3f %.3f %.3fz" 3D vel max/rms/std %.1f %.2f %.2fz9 3D vel 50%%/68%%/90%%/95%%/99%% %.3f %.3f %.3f %.3f %.3fz" 2D vel max/rms/std %.1f %.2f %.2fz9 2D vel 50%%/68%%/90%%/95%%/99%% %.3f %.3f %.3f %.3f %.3fz	 fixmode:r   )rK  z
 %d=%.1f%%r   )rP  insertslicer   r   VLONVLATVHGTr  rd  rX  r%  LATplotNTRKNUSEDr   rI   ri  rM  rb  stdre  rK  FIXTYPEr   )%for_allr   i_di_ppcommon_irZ   r   r   r[   dVEdVNdVUv_err_3dv_err_2d	v_err_hgtv_cx3v_cy3v_cx2v_cy2v_cxhv_cyhr"  r#  r$  err_3derr_2derr_hgtcx3cy3cx2cy2cxhcyhpercent3percent2rw  r=  ax2d_cdf
ax2d_cdf_vax2d_errax3d_cdf
ax3d_cdf_vax3d_erraxTr_1axTr_2	axhgt_cdfaxhgt_cdf_v	axhgt_errdPP_LATdPP_TIMEdPP_velEdPP_velNdPP_velUdkl_listdo_2ddo_3ddo_hgtdo_trackdo_vel	is_staticpp	print_allr   r   	show_data	  s   
&
,42
z#plt_pospac_truth.<locals>.show_datar  best)locr  zGPS time [s]z3D error [m]zCommon data CDF probability %z3D velocity error [m/s]z2D error [m]z2D velocity error [m/s]zHeight error [m]zHeight velocity error [m/s]N)PosPacConstr  r  r  r  r  r   rR   r  figuresubplotgridtight_layout	set_titlelegendnumberxlabelylabeltitle)txtr  r  r  r  r  r  r  do_padr  f_Trf_3d_errf_3d_cdf
f_3d_cdf_vf_2d_errf_2d_cdf
f_2d_cdf_v	f_hgt_err	f_hgt_cdff_hgt_cdf_vr  r   r  r   plt_pospac_truthN	  s   	$<V



















r  rz  c                 C   s  t | |}d}|D ]\}}t| dd|jf |k| dd|jf |k@ t| dd|jf d d d dk@ }|du rGtt| ||jf }t| ||jf }tt	||k}	t
|	D ]P\}
}|d dk sn|d t|krsd|	|
< q\t	| ||d  |jf | ||d  |jf  |d krd|	|
< q\t| ||d |d  |jf d	k rd|	|
< q\q\|	|	dk }	t|	dkrtd
||f | ||	 |jf  q	dS )z
Look for sudden SNR jumps in data.  Must only pass in data from master subchannel.
Usage:
(d,k) = vd2arr('file.T0x',rec='-d27',opt=['-t'])
find_SNR_dips(d,k)
NrE  r   r  r,   r   r   r   g      @@z	sv %d/%d:)r  r   r8  r9  int_r   r3  r   CNOrd  r   rI   r   )r   r   threshrL  r   rF  r,  r=  cno_diffijumpr   iar   r   r   find_SNR_dips'
  s0   
V8& r  r,   ?r   r   c                 K   s  | du rt  } |  }| jj}| jd||fd|d|}| jj }	| jj|	d |dkr5d| d gn| d dg}
tj	
|
d |
d |j| jj  }| |}|  }|dkrp| |j|j|j|j|j g dS | |j|j|j|j |jg dS )	z
Put legend on outside of plot.
Only tested example: legend_outside() # legend on right
See: https://stackoverflow.com/questions/42994338/creating-figure-with-exact-size-and-no-padding-and-legend-outside-the-axes/43001737
Nr,   )bbox_to_anchorr  bbox_transform)rendererrt  r   g      R@r   )gca
get_figurer  transFigurer  canvasget_rendererdraw
matplotlib
transformsScaledTranslationdpi_scale_transinvertedget_window_extenttransformedget_positionset_positionx0y0widthheight)axr  r  	direction	padpointsr@  figotransr   r  ppartrans2tboxbboxr   r   r   legend_outsideJ
  s    $
$$r  oc           "      C   sf  |du rt | dd|jf }d}d|v r$d}z| jrd}W n   Y nd}g }t|D ]\}}	t }
|dkr=td}ntd|d d}t| dd|jf |	k}t | ||jf }t| |ddf ||	 }i }t|D ]
\}\}}|D ] }z
|||f }d}W n   d}t	|	||j
}Y t| ||jf |k| ||jf |k@ | ||jf |k@ }t|dkrqw|| }|r|rt| ||jf t| jj@ dk}nt| ||jf t|j@ dk}n	t| ||jf }| ||jf  }t||kd |t||< |d	 }tt| ||jf }t|d
 }t||kd }t|dkr8t| ||jf |t}t||t}n	| ||jf }|}t||| dd||d\} |du r]|  }||||f< t| || |jf || | |dd|d |t|7 }qwqn|dkrt  q,d}!t|dkr|!d| 7 }!t|! tt t||t t!d t"  |#|
|	f q,|S )a;  
Plot tracking & cycle slip info from a T04 file.
Example:
  d,k=vd2arr(filename, rec='-d35:19')
  plot_tracking(d,k)
Inputs:
  sat_types = list of satellite types to plot, e.g., [0,2] for GPS/GLN
  title_txt = add extra info on title
  marker = what marker to use for the cycle slips
Returns: [(fig,sat_type),...]
NFrC  Tr   rn  rl  
_nolegend_g(\?r1  r,   z.-)
markersizers  colornone)mfcrs  r  ztrack/slip info : )$rK  r9  kfr   r  r  r   r8  r  rn  r  r;  r<  rI   rC  r.  r   
dMEAS_SLIPSLIP_FLGr  iscloserd  r   r   r   rx  r   r~  	get_colorr  r  yticksrJ  r  r  rC   )"r   r   	sat_types	title_txtmarkercombinedFlagis_rec35_19all_resultsloopr,  r  r  tot_leni_strL  sig_list
sig_colorssig_nr  rP  rF  r  rs  r=  rW  sv_yspacingr   expected_dtigapsv_xgapsv_ygaprn  r  r   r   r   plot_trackingc
  s   

&$
*
1r  c           $      C   sL  ddl m} |du rt| dd|jf }d|jfd|jfd|jfd|jfd|jfd	|j	fd
|j
fd|jfd|jfd|jfd|jfd|jff}| }g }t|D ]\}	}
t| dd|jf |
k}t| |ddf ||
 }t|}|dkrxqPt|dddd| fd\}}|dkr|g}t| ||jf }d}t|D ]i\}\}}|| }d}t|D ]\}\}}t| dd|jf |
k| dd|jf |k@ | dd|jf |k@ | dd|jf t|@ dk@ }| ||jf  }t|D ]\}}||t||< qt|dr
t|dni }t|dkrd}|j| ||j f ||d t|d   dd|d |t|7 }t|dkrE||  t|7  < q||7 }t|D ]\}}t| dd|jf |k| dd|jf |
k@ | dd|jf |k@ | dd|jf |k@ }t!t"| ||j f }t|t#|d kd } t| dkrt$| ||j f | t%}!t$|t&|j' | t%}"n| ||j f }!|t&|j' }"|j|!|"ddd qNt(|
||j)}#t|dkr|d |# }#|*|# |+t,t| |-|t |.d |dkrt/| q|dkr|st0| qP|1  |2||
f qPt3| |S )aZ  
Plot RAIM flags for each subchannel/signalfrom a T04 file.
Example:
  d,k=vd2arr(filename, rec='-d35:19 -t')
  plot_subchan_raim(d,k)
Inputs:
  sat_types = list of satellite types to plot, e.g., [0,2] for GPS/GLN
  title_txt = add extra info on title
  show_all = if False(default), hide plots with no RAIM faults.
Returns: [(fig,sat_type),...]
r   CounterNMMWLSKFrV  CNAVFFTr   SYSEPHNMAr  DUAL_ANTr,   Tr  g      @)rm  figsizer~  r  r  r   r  r  rs  r1  k.-r  r  )4collectionsr  rK  r9  dSV_FLAGS_FAULT_MM_RAIMdSV_FLAGS_FAULT_WLS_RAIMdSV_FLAGS_FAULT_KF_RAIMdSV_FLAGS_FAULT_SBAS_MSGdSV_FLAGS_FAULT_CNAVdSV_FLAGS_FAULT_FFT_CORRdSV_FLAGS_FAULT_RTX_POSdSV_FLAGS_FAULT_SYS_RAIMdSV_FLAGS_FAULT_EPHdSV_FLAGS_FAULT_NMA dSV_FLAGS_FAULT_CNO_DETECT_SPOOFdSV_FLAGS_FAULT_DUAL_ANT_SPOOFr   r   r  rI   subplotsr8  r;  r<  SUBCH_FLAGSr.  r   r  r  hasattrrt  r~  r   rd  r   r   rx  r   r  r   rn  r  r  
set_yticksrJ  set_yticklabelsr  r  r  r  rC   r@   )$r   r   r  r	  show_allr  raims	raims_cntr  r  r,  r  r  	n_signalsr  axesrL  tot_len_allsig_idxr  rP  r  r  rZ   rs  flagr=  r  sv_posrF  	plot_argsr   r  r  r  r  r   r   r   plot_subchan_raim
  s   2


rG  c                 C   sv  ddl m} |du rt| dd|jf }d|jfd|jfd|jfd|jfd|jfd	|j	fd
|j
fd|jfd|jfd|jfd|jfd|jff}| }g }t|D ]c\}	}
t }|	dkratd}ntd|d d}t| dd|jf |
k}t| ||jf }t|D ]r\}\}}t| dd|jf |
k| dd|jf t|@ dk@ }| ||jf  }t|D ]\}}||t||< qt|dkrd}t| ||jf ||d t|d   dd|d |t|7 }t|dkr||  t|7  < q|dkr|st  qPt|D ]h\}}t| dd|jf |k| dd|jf |
k@ }tt| ||jf }t|t |d kd }t|dkrWt!| ||jf |t"}t!|t#|j$ |t"}n| ||jf }|t#|j$ }t||ddd qt%|
| |d |j&f | |d |j'f j(}t|dkr|d | }t)| t*t+t||t t,d |dkrt-  |.||
f qPt/| |S )a8  
Plot RAIM flags from a T04 file.
Example:
  d,k=vd2arr(filename, rec='-d35:19 -t')
  plot_raim(d,k)
Inputs:
  sat_types = list of satellite types to plot, e.g., [0,2] for GPS/GLN
  title_txt = add extra info on title
  show_all = if False(default), hide plots with no RAIM faults.
Returns: [(fig,sat_type),...]
r   r  Nr  r  r  rV  r   r!  r   r"  r#  r$  r  r%  rn  rl  r  r,   r   r  r(  r1  r)  r*  r  T)0r+  r  rK  r9  r,  r-  r.  r/  r0  r1  r2  r3  r4  r5  r6  r7  r   r  r  r   r8  SV_FLAGSr.  r   r  r  rI   r~  r   r  rd  r   r   rx  r   r  r   rn  r;  r<  r  r  r  rJ  r  r  rC   r@   )r   r   r  r	  r=  r  r>  r?  r  r  r,  r  r  r  r  rL  rZ   rs  rD  r=  r  rE  rF  r   r  r  r  r  r   r   r   	plot_raim-  s|   
:00*
rI  c              
   C   s  t | dd|jf }i }g d|d< g d|d< g d|d< g d|d	< g d
|d< g d|d< g d|d< g d|d< g d|d< | d|jf }| dd|jf d| dd|jf |   }g }t|dkrmtd}	nt| dd|jf |dddf \}
}	}||ddf }t| |	|j|jd	 f |\}}}t	|d |d  }|df|dffD ]\}}t
 }|D ]w}t|}t| |	|jf |k}dtt| tt|	 }tt|| }|tdt|  }t|dk rt| d tt| d }nt| d d| d tt| d }d}z|| }W n   Y t|| || d d!||d" qtd# td$|  t|d%|   td& td'dd( t  || q|S ))a  Inputs: d,k = rec 35:2/16 position data & index info
    truth = an array of secs,lat,lon,height truth points
    txt = optional string to prepend to all plot titles
    Generate a height error plot and 2D error plot vs. time.
    Returns [ fig_height_err, fig_2d_err ]
    N)r,   r   r   r,   r   )r,   r   g333333?r,   r,   )r,   r   g333333?r,   r   )r,   r,   r   r,   r   )r,   r   r   r,   r  )r   r   r,   r,   r  )r   r,   r   r,   r  )r,   r   r,   r,   r  )r   r   r   r,   r  :	 Height2Dr   gffffff?r  z
 (points= )z 95% = z{:.3f}zm (points= r   rz  r  )r0   	edgecolorrg  rs  zTime [GPS Seconds]z%s Error [m]z	 %s ErrorTr  )r  markerscale)rK  r  WEEKr   rI   ry  rP  r%  r}  r  r  r   r   r.   r  rH  rd  PosTypeStrConstr   r  scatterr  r  r  r  r  r  rC   )r   r   truthr  unique_fixtypescolor_mapping
start_weekr   all_figsr  rU  i_trr"  r#  r$  r  err_valerr_namer  fixtyper=  	pos_yielderrTmperr95rs  r  r   r   r   plot_pos_err  sZ   ,
*$*r_  c                    s      d }dd | D }t|dkrdd   D }|d  }|D ]}|d q&t    D ]"}| }t|t|krDq5t||D ]\}}|g | qIq5 fdd} j	
d| d	S )
a  
    From http://matplotlib.org/examples/event_handling/legend_picking.html
    Given figure, make clicking on legend elements enable/disable lines.
    Assumes a single legend, so only label lines on a single subplot().
    If multiple subplots have the same number of lines as the legend, then
    clicking will affect all subplots.
    May want to use "figlegend()" or "legend(bbox_to_anchor=(1.1,1.05))"
    r   c                 S       g | ]}t |tjjkr|qS r   r   r  r  Legendr   r   r   r   r     r   z+make_legend_interactive.<locals>.<listcomp>c                 S   r`  r   ra  r   r   r   r   r     r   r  c                    sP   | j }| D ]}|  }|| q|r|d n|d  j  d S )NrG  g?)artistget_visibleset_visible	set_alphar  r  )eventleglineoriglinevisr  linedr   r   onpick  s   

z'make_legend_interactive.<locals>.onpick
pick_eventN)get_axesget_childrenrI   	get_lines
set_pickerrt  r   
setdefaultrC   r  mpl_connect)r  r  legall_leglinesrh  linesri  rm  r   rk  r   make_legend_interactive  s"   rx  c                   @   s6   e Zd Zdd Zdd Zdd Zdd Zdd
dZdS )VdClsc                 C   sD   t || }||_||_d|v r|d= t||_|j| |S )Nis_data_transposed)r  asarrayviewr   rT   r   r  update)clsinput_arrayr  r  rr  r   r   r   __new__  s   
zVdCls.__new__c                 C   s:   |d u rd S t |dd | _t |dd | _t |dd | _d S )Nr   rT   r  )r  r   rT   r  )r  rr  r   r   r   __array_finalize__  s   zVdCls.__array_finalize__c                 C   sH   || j v rt| jdkr| | j |  S | d d | j | f S td| )Nr,   z$'VdCls' object has no attribute '%s')r   rI   r   AttributeError)r  attrr   r   r   rs    s
   
zVdCls.__getattr__c                 C   s   | j | | j| d S ra   )r   r}  r  )r  key_valsr   r   r   add_keys	  s   zVdCls.add_keysFc                 C   s   t | | j|dS )N)r  )r  r   )r  r  r   r   r   r    s   zVdCls.get_sv_listNr]  )r^  r_  r`  r  r  rs  r  r  r   r   r   r   ry    s    ry  c                 C   s"   t | |d|d\}}}t|||S )a  Same as vd2arr, but output is wrapped together.  Needs work, but idea is:
      d = vd2cls( 'file.T04', '-d35:19' )
      print( d.SV )  # instead of "print( d[:,k.SV] )"
    To access keys, see "d.k"
    For flags, see "d.f"
    For keys+flags, see "d.kf"
    F)r  rS   )r  ry  )r%   r  rS   r   r   rD  r   r   r   vd2cls  s   r  c                  O   s  t |d dkr|d \}}d\}}n|d \}}}}g }g }| D ]<}|du r4t|j|k|j|k@ }	nt|j|k|j|k@ |j|k@ |j|k@ }	t | dkrX||j|	  ||	 q!t | dkryt| }
|
dd }dd t	| ||D S | d |d  S )	a  Grab a satellite from multiple "vd2cls" data sets.
    Example: md1, md2 = sv_intersect( d1, d2, sv=(14,10) )
             # sv=(sv,sat_type) or sv=(sv,sat_type,freq,track)
             plot( md1.TIME, md1.RANGE )
    md1/md2 are just "views" of d1/d2, so they take minimal memoryrF  r   r   Nr,   c                 S   s   g | ]\}}}|||  qS r   r   )r   r   r=  rW  r   r   r   r   5  s    z sv_intersect.<locals>.<listcomp>r   )
rI   r   r8  r9  r<  r;  rC   r   rP  r   )r?  r@  rF  r,  r  rP  timesidxr   r=  r   idx2r   r   r   sv_intersect  s$   
,r  c                  C   s   t i } d| _d| _d| _d| _d| _d| _d| _d| _d	| _	d
| _
d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _| S )z2Return indexes for StingerNavPC residuals.txt filer   r,   r   r   r  rz  r  r  r  r  r  r  r  r  r  rc  r  r  r  r  r  r  r  r  )r   weekr   r8  r9  r  CSTATEpr_availpr_respr_sigclk_bias_typer   clk_diff	dop_availdop_res	clk_driftclk_drift_diffr:  usedAZpos_err_est	iono_modesmooth_pr_rescc_filt_cntr1  rX  r   r   r   snpc_res_fields:  s4   r  c           	         s   ddl }ddl}g }| '  fddt| D }|D ]}| \}}}||||g qW d   n1 s8w   Y  |j|g ddS )zGiven list of T0x files, return DataFrame of: [[start_t, meas_dt,pos_dt],...]
    See get_ttff()
    Example:
      from glob import glob
      d = get_ttff_all(glob('/mnt/data_drive/TTFF/data/*20190430*.T04'))
      plot( d.start_t, d.meas_dt )
    r   Nc                    s   g | ]
} j t|fd qS ))r?  )apply_asyncget_ttffr   rT   r   r   r   r   d  r   z get_ttff_all.<locals>.<listcomp>)r  meas_dtpos_dt)columns)r   rJ   r  r   rn  rC   rv   )		filenamesmpr]   r   resultsresr  r  r  r   r  r   get_ttff_allX  s   
r  c           	      C   s   t d|  d}t| d }t d|  d}t| d }t d|  d}t| d }|  d	r<t d
|  d}nt d|  d}t| d }|| }|| }|| }d}|| d k rd||7 }|| d k ro||7 }|||fS )a  Given a T0x file, return: (start_gps_time, meas_dt,pos_dt)
    start_t = GPS secs in week that the receiver booted
    meas_dt = # of seconds after boot that first measurement was logged
    pos_dt = # of seconds after boot that first position was logged
    r  z  - SystemUptime =>r   z  - Time tag      :r  zviewdat -d29,35:2 zWeek :rz  t02zviewdat -d27 zTYPE 27:  SVzviewdat -d35:19 zTYPE 35:19 SVr   r   )r  r   rH   r.   r   r   )	r%   up_secsgps_secspos_secs	meas_secsstart_gps_timer  r  r  r   r   r   r  k  s&   
r  c                 C   sN   t d| }z
|t d| 7 }W n   Y z|t d| 7 }W |S    Y |S )a-  Utlility function for parse_load_diags()
    Calculates the CPU reserve from all of the background tasks
    Inputs: info - dictionary of the CPU load data
            extstr - Extension string for each CPU
                     Empty string for CPU0, otherwise 'CPUn'
    Returns: The CPU reserve
    zinfo.data.StingerBITzinfo.data.CheetahBackgroundTestzinfo.data.CoreBuildBackground)eval)rx   extstrr   r   r   r   calc_cpu_reserve  s   r  c                 C   s   ddl }ddl}ddl}d|  }| dkrd| }|j|||jd}g }g }g }d}		 |j 	 }
|
d	kr:nA|	sD|

d
rCd}	q-|
  }t|dk rQn*t|d }t|d dkre|dkred}|| ||d  |t|d  q.|||fS )ar  Parse processor load filename info.
    Inputs: filename = T04 file (since 5.20)
    Returns: task_names = name of each task (for quick lookup by 35:258 index)
             task_cores = core # of each task
    Example:
    IDs, names,cores = parse_load_diags_task_names("file.T04")
    IDs = [0,1,...]
    names = ['cyg_start','StingerLM',...]
    cores = [0,0,...]
    r   Nzviewdat -d35:259 r  zstdbuf -o0 r  FTr   zTask Names:r  r,   r   r   r   )rq   rr   r  r  rt   rH   ru   rk   r  r  rs   r  rI   r   rC   )r%   rq   rz   r  r}   r  task_IDs
task_names
task_coresgot_task_namesr[   r\   curr_IDr   r   r   parse_load_diags_task_names  s:   



r  c                    s  t | \}}}td| d |  td}ti }|dddf d |_ti |_|ddddf }t|jd d D ]Q}|| }	||   fdd	t|D }
t	t
|dd|
f dd
}dt	|dd|f  | }|t|d}|	|jv rt|j|	 |dd
|j|	< q:||j|	< q:t||_t|dkrt|d|_t|dkrt|d|_t|dkrt|d|_ti |_t||D ]	\}	  |j|	< q|S )a  Parse processor load diagnostic info.
    Inputs: filename = T04 file (since 5.20)
            opts = any other viewdat opts (e.g. "-e260000" to end early)
    Example:
    d = parse_load_diags("file.T04")
    plot( d.TIME, d.data.StingerLM )   # plots one line
    plot( d.TIME, d.data.HTTPDworker ) # plots several lines
    (d.core.StingerLM, etc. -> core #)
    (d.RESERVE is an alias for CBT+BIT CPU0)
    (d.RESERVECPUn is an alias for CBT+BIT CPUn, if present)
    zviewdat -d35:258 -mb rj   r  r,   Nr   r1  c                    s   g | ]
\}}| kr|qS r   r   )r   _i_xtcorer   r   r     r   z$parse_load_diags.<locals>.<listcomp>)axisr   CPU1r   CPU2r   CPU3)r  r  r.   r   r   r+   r   r   r   r   r   r  rI   rC   r  RESERVErM  RESERVECPU1RESERVECPU2RESERVECPU3corer   )r%   optsIDsr  r  r   rx   dtasksr=  r  cidxdiff_count_sum	curr_loadr   r  r   parse_load_diags  s6   



r  c                 C   s  ddl m }m} ddlm} t| d}| }|ds!td| }|ds.td|td	d
 	 }|
|d}|jddddd|| d d }d}||  | }	|	}
|t}g }t|D ]E\}}|	  }|d dkrt|d |	 }
|d dkr|dd
 }qft|D ]\}}|drt}nt|}|||  |
|f qqf| D ]
}t|| ||< q|W  d
   S 1 sw   Y  d
S )a-  The UNAVCO "teqc" program can generate raw data if you give it
    the options "+qc +plot".  For example, it may generate some_file.m12
    for raw MP12 data.  To plot MP12 for GPS SV #10 data you could then do:
      d = parse_compact3("some_file.m12")
      plot( d['G10'][:,0], d['G10'][:,1] )
    r   r  )defaultdictr2   COMPACT3zNot a COMPACT3 fileGPS_START_TIMEzUnexpected 2nd linezGPS_START_TIME Nz%Y %m %d %H %M %S.%f)hourminutesecondmicrosecondr  r  rJ  r   r,   z-1S)r  r  r+  r  r   r  rs   r   rI   r  r  rb   r  r  rd  r   rH   r.   r   r   rC   r  rR   )r%   r  r  r  rT   rf   
start_timeweek_roll_timesecs_in_weekstart_offset_scurr_offset_sr+   curr_svsr  r\   r   r   r   r   r   r   parse_compact3  sH   


$r  c                 C   sN  d}d}d}d}d}d}d}d}	t d|  }
	 |
 }|du r no|dkr)|	dkr)nf|dkr:|	dkr:|dkr:|dkr:nUd|v rR| d}t| t|d }d}n<d|v rj| d}t| t|d }d}n$d	|v r| d
d d}t| |d }t|d }|d }d}	q|dkrt||||| |||||fS |||fS )z4Returns the serial number from a T02/T04/DAT file
  NFr  TSessionMeasIntervalMsecsrj   r   SessionPosIntervalMsecs
ReceiverIdz=>r,   ,r   r   )r  r  rG   rH   r@   r   r  )r%   reportRatesserialNumberrxIDproductNameposRatemeasRategotPosgotMeasgotRXIDr+   rf   tokensr   r   r   getSerialNumber#  sT   
r  c                 C   sl  d}d}d}d}t d|  }	 | }|du sd|v rnLd|v r2| d}	|	d  d	d}n5d
|v rD| d}	|	d  }n#d|v rV| d}	|	d  }nd|v rg| d}	|	d  }q|dkrddddddddddddd}
| }	t|	d }|
|	d  }t|	d }d||||f }n|du rd||f }nd|||f }|r|d| 7 }|S ) zReturns the firmware version number and date from a T02/T04/DAT file
  commas are removed from the date in case this is saved in a CSV file.
  Only part of the data file is processed (up until we get a record 12), 
  so this is pretty quick to execute.
  r   Nzviewdat -d12 TzGPS weekzFirmware dater  r,   r  zNavigation processorzRelease targetzReceiver typer   r   r  rz  r  r  r  r  r  r  r  )JanFebMarAprMayJunJulAugSepOctNovDecr   r  r  z%s %4d-%02d-%02dz%s %sz%s-%s %srj   )r  r  r  rH   rG   rb   r   )r%   numericDatereportProductdateversion
subversionrxTyper+   rf   r  monthLUTFWYearFWMonthFWDayverStrr   r   r   getFirmwareVersionW  sN   r  c           
      C   s   t d|  }d}d}d}	 | }|  }|du rnN|dkr?t|dkr?|d dkr?|d dkr?t|d	 }t|d
 }	n+t|dkrj|d dkrj|d dkrj|d dkrjt|d	 }t|d }t|d }nq	 |dkrw||	|||fS |||fS )zReturns the 
  viewdat -d35:2 NTr  r   Weekr   Timer   rz  r  Latr  Lonr  Hgtr  r  r  r  r  rH   rI   r   r.   )
r%   
reportTimer+   r  r  r  rf   r  r  r  r   r   r   getRefPosition  s8   
r
  c                 C   s|   t d|  }g }g }	 | }|  }|du rn#t|dkr=|d dkr=|d dkr=t|d	 }t|d
 }	 ||fS q)z7Returns the time from the first 35:2 position record
  r  TNr  r   r  r   r  r   rz  r  )r%   r+   r  r  rf   r  r   r   r   getTime  s    r  c                 C   s   d}d }d }t d|  td|  }	 | }|d u r	 ||fS d|v r*t d d}n:|dkrEd|v rE| d}t d	| t|d
 }n|dkrdd|v rd| d}t d| t|d
 }	 ||fS q)NFzIn getMaskszviewdat -d30 TMASKSzFound Masksz
Elevation:r  z
Found Elevr,   PDOPz
Found PDOP)r@   r  r  r  rH   r   )r%   foundMaskTokenElevMaskPDOPMaskr+   rf   r  r   r   r   getMasks  s0   


r  c                    s  ddl m}m}m}	m}
 j|k djv rj|k djv tj	dd d D jd r>jd d	}t
tj| d
 t | d
t  }t||kr]||8 }j	d }|d }t \	tddd | d d d tdd\tdd\tg d}tt| }|	||drtg d}|
|dg|gdndtg d}rt \
| d d ttjdk rdnd||dt|t|t|d 	
fdd}	fd d!}| r)| | fd"d#}	jd$| |j  fS )%a  Plot FFT rec 35:25 (or rec 35:24) data interactively.
    antenna_num = 0 or 1
    sample_point = 0:default, 1=pre-miti, 2=post-miti
    spectrogram = show spectrogram?
    plot_max = plot max FFT data by default?
    autoscale = autoscale plots?
    title = plot title
    Usage:
     d=vd2cls("file.T04","-d35:25")
     plot_fft_data( d )
    Note: "." and "," keys can be used to step through time.
    r   )SliderButtonRadioButtonsCheckButtonsSAMP_PTMAX_FREQDATAc                 S      g | ]}d | qS z%.1fr   r  r   r   r   r     r   z!plot_fft_data.<locals>.<listcomp>r  FREQDATArJ  r         ?)leftbottom	Freq[MHz]zFFT[dB]Tg?r  333333?r   active)r`  g333333?r   r   rM  )labelsactivesN)r  rC  g?gQ?zGPS TOW [sec]zFrequency [MHz]g      >@rG  g      N@r  )valinitvalstepc              	      s@   j }j|k }tt|jj }tdd d |j|  d |d  }	| 
||d f  rY d rY	| 
||d f  n	
tdt   d}d} rt|d d |jj|jjd f }t|d d |jj|jjd f }|d |d	  tt|d d d f |gtt|d d d f |g 	j  rt||j\}}j|||d d |jj|jjd f d
||d}	d}
jD ]}|j}|d ur||	 d}
 nq|
s	
j|	d}|d d |d d  
j  d S d S )Nr         r1  r  r  r  r,   r   rainbow)cmapvminvmaxFTr'  r  ) r   value_selected
CENTERFREQargminrd  SECr   rc  BINSIZE	set_xdata	set_ydata
get_statusr  r   r   relimr3  r   r  FREQDATA_LASTrM  set_xlimset_ylimnanminnanmaxr  	draw_idlemeshgrid
pcolormeshr+  colorbarupdate_normal)rU  curr_freq_hzd0r=  freq_mhzr+  r,  XYpcm
found_cbarr   cbcbar)	autoscaler  ax1	center_hzcenter_labelsr   	fft_check	fft_radio
fft_sliderr  fig1freq_ifreq_i2has_maxplt_line	plt_line2spectrogramr   r   update_freqQ  sP   &

&&"


z"plot_fft_data.<locals>.update_freqc                    s    j }j|k }tt|jj }||d f  
r< d r<||		d f  n	t	
dt     ddd j  d S )Nr'  r   T)r   r-  r.  r/  rd  r0  r   r3  r4  r  r   r   r5  autoscale_viewr  r;  )rU  r@  rA  r=  )r  rK  rL  r   rM  rN  rO  r  rQ  rR  rS  rT  rU  r   r   update_timez  s   z"plot_fft_data.<locals>.update_timec                    s@   | j dkr  j  d S | j dkr  j  d S d S )Nr  r  )r   set_valr   )rg  )rO  r&  r   r   on_key  s
   

zplot_fft_data.<locals>.on_keykey_release_event)!matplotlib.widgetsr  r  r  r  ANTNUMr   r  rK  r.  aroundunwrapr0  rY  r   r8  subplots_adjustr  
set_xlabel
set_ylabelr  r~  rA  r/  rd  rM  r   r3  
on_clicked
on_changedr  rt  r-  )r   antenna_numsample_pointrV  plot_maxrI  r  r  r  r  r  r  secs_unwrapr@  curr_secraxi_activerax2axtimerW  rY  r[  r   )rI  r  rJ  rK  rL  r   rM  rN  rO  r  rP  rQ  rR  rS  rT  rU  rV  r&  r   plot_fft_data  sr   




&









,$)




ro  c           	         s   ddl m} j|k tjdd d D |r#jd njd jd }t \ tdd	  d
  	d  
d tg d}tt| }|||d} fdd}|| ||j t  |S )zPlot history of FFT rec 35:25 data interactively.
    Usage:
     d = vd2cls("file.T04","-d35:25")
     plot_history_fft_data( d )
    r   )r  c                 S   r  r  r   r  r   r   r   r     r   z)plot_history_fft_data.<locals>.<listcomp>r  r  r  gffffff?)r  r  z
Time[secs]Tr  r!  c              	      s    |  }j|kd d f }tdd d |jd  d |d  }t||j\}}dt v r8 j   	|||d d d f }t
| dd _    d	d	d	 j  d S )
Nr   r'  r(  r1  r  rG  
horizontalr  orientationT)r   r.  rc  r1  r<  r0  r  rG  remover=  r>  r5  rX  r  r;  )rs  r@  rA  rB  rC  rD  plt_imr  rK  rL  r   r  rQ  r   r   rW    s   &
"z*plot_history_fft_data.<locals>.update_freq)r]  r  r^  rK  r.  r   r8  ra  rb  rc  r  rA  r/  rd  rd  r-  show)	r   rf  do_maxr  r@  rk  rl  rN  rW  r   ru  r   plot_history_fft_data  s*   









rx  c                 C   s   |rt jt j| }t j|st | t }t|d|d |	d t
|}tt
dr=|djdt
jd}n|djdt
jjd}|j| dd	 d
S )a<  Save current plot as a PNG file. Matplotlib isn't very good at
    compressing PNG image files. Therefore, use PIL functions to
    compress a memory version of the file. The compressed images are
    close to half the size of the Matplotlib generated version.

    Note: this reduces the image to 256 colors, so in images with
    gradients or lots of colors you may notice the difference.

    Inputs: filename = output PNG name
    Optional inputs: dpi = resolution of image (default None)
                     make_dir = create directory if needed? (default True)
    png)r  dpir   ADAPTIVERGBr}  )palettePNG)r  N)r=   r>   r   r  existsmakedirsioBytesIOsavefigr  r	   r   r:  convertr{  Paletter  )r%   rz  make_dirr  ramimim2r   r   r   save_compressed_png  s   



r  c                 C   s   t | || jS ra   )r  r  	timetupletm_yday)r  r  r  r   r   r   date_to_doy  s   r  c                 C   s,   t  | ddt |d  }|j|j|jfS rU  )r  r  r  r  r  )r  doydateObjr   r   r   doy_to_date  s   r  returnc                 C   s0   t  dddddd}t j| t|dd}|| S )Ni  r,   r  r   r   )weeksseconds)r  r  round)	gps_weeksgps_sow	gps_epochdeltar   r   r   
gps_to_utc  s   r  r  -   ,  -d35:25c
               
   C   s  g d}
g d}g }|   dsd S t| |}||j|k }d|jv r+||j|k }|	r3|jd }n|jd }tt|
D ]1}z)||j|
| k }t|dkrjdgd }dgd }dgd }t|}t|D ]-}tdD ]&}||  || ||  7  < ||  || ||  || ||   7  < qpqjtdD ]}||  |  < || | || ||   }t	
|||< q||
| || t|||d	 |d kr| d d
 d ||  d }n
|d ||  d }t|jdk }|| }|jd }t \}}t	jdd d |jd  d |d  }t||j\}}dt|v r'|j  |j|||d d ||d f ||dd}t||dd|_|jd |d |d t|d ||   t  t||d t  W q>   Y q>|S )N)iFi Ii @KLiZ^iy^ic\)L5L2E6L1r  B1r   r  r  r  r   r'  )FreqFreqStrNumFFTsAverageSigmar  r  .pngiD:	 r(  r1  r  rG  r)  r+  r,  r*  verticalrq  Mean Power [dB]
Freq [MHz]
Time [Sec] - rz  )r   r   r  r^  r   r  r   rI   r.  r  r  rC   r   r0  r8  rc  r1  r<  r  rG  rs  r=  r>  	set_labelrb  rc  r  r  r  r  ) r%   	fig_titleout_filerootminpowermaxpowerrz  rg  rf  r  use_maxcenterFreqs
bandLabelssummaryr   rQ  rq  rA  avFFTsumSqsigFFT	numEpochsr=  r   varpng_filenamer@  r  r  rB  rC  rD  rt  r   r   r   plot_fft_data_png  sv   





.


(
*

r  rt  r  c               
   C   s  g }|   dsd S |rd}	nd}	zt| |	}
W n ty+   td|	 d Y d S w |
|
j|k }
|
jj}t	|
j
}d}|D ] }|
|
j
|k }t|dkrbdg| }dg| }dg| }t|}t|D ]-}t|D ]&}||  || ||  7  < ||  || ||  || ||   7  < qoqit|D ]
}||  |  < q|| | || ||   }t|||< ||t|||d |d u r| d d	 d
 t| d }n
|d
 t| d }|}|r|j}n|jd }t \}}tjd| |d  |jd  d |d  }t||\}}dt|v r|j  |j|||d d ||| f ||dd}t||dd|_|jd |d |d t|d t|  t  t ||d t!  qA|S )Nr   z-d35:38z-d35:42zNo MSS FFT data (z) found in file?r(   r   )r  r  r  r  r  r  r  rF  r   r1  r  rG  r)  r  r  rq  r  r  r  r  r  )"r   r   r  r/   r@   HW_IDXr   r  r  rK  	BASE_FREQrI   r   r  rC   r   SECSMSECSr8  rc  BIN_SIZEr<  r  rG  rs  r=  r>  r  rb  rc  r  r  r  r  ) r%   r  r  r  r  rz  
mss_hw_idxuse_avgr  r  r   rQ  r  NFFTrq  rA  r  r  r  r  r=  r   r  r  r@  timer  r  rB  rC  rD  rt  r   r   r   plot_mss_fft_data_pngS  s   




.





r  c                 C   sN   t | |k }t|| ||d  gf}t| | |gf}tj||d| S )Nr   r   )r   r  rE   trapz)rQ  rR  max_xr   sel_cysel_cxr   r   r   icdf  s   r  c                 C   s   t | tjs
td| jdkrtdt |tr|dk r td|t| kr*td| j| d |f}| j	d | j	d f}tj
jj| ||d}|jdddS )	a  
    Compute moving standard deviation over a 1D NumPy array.

    Parameters:
        arr (np.ndarray): Input 1D array.
        window (int): Size of the moving window (must be >= 1).

    Returns:
        np.ndarray: Array of moving standard deviations.
    zInput must be a NumPy array.r,   z"Input array must be 1-dimensional.z'Window size must be a positive integer.z/Window size cannot be larger than array length.r   )r   strides)r  ddof)
isinstancer  ndarray	TypeErrorndimr/   r   rI   sizer  libstride_tricks
as_stridedr  )arrr  r   r  windowsr   r   r   
moving_std  s   
r  r  )r   NTr   )r   ra   )T)r  NTTT)NF)FF)FrC  r   )r   Tr   )r`  T)r   Fr]  )r0  FFF)TTTFFFF)rz  )Nr,   r  r   r   )Nr   r  )Nr   F)r   )r   r   FFFr   )r   Fr*  )Nr  r  r  r   r   r  F)Nrt  r  r  r   F)
__future__r   r  r   scipy.signalr   r   sixr   	six.movesr   mutils.GnssConstr   mutils.RcvrConstr`  mutils.RTConstr&  mutils.PosTypeConstPosTypeConstmutils.PosPacConstr  r  r  r=   PILr	   numpyr  r  r
   r+  r   r  r   rQ  r`   rh   r   r   r   r   r   r  r/  r  rt  r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r%  r&  rP  rX  r  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r)  r,  r7  rB  rS  rT  rn  r  r  r  r  r  r  r  r  r  r-  rB  rF  rT  r^  rb  rg  ri  r  r  r  r  rG  rI  r_  rx  r  ry  r  r  r  r  r  r  r  r  r  r  r  r
  r  r  ro  rx  r  r  r  r  r  r  r  r  r  r   r   r   r   <module>   s  
5U
)
2
3: 

j2+
	

!
'
9#]3

!
1

u


I%*

)
"8#
4



 
Z
#gcR?-
%*2
,
4
;@ /"Zo