geodezyx.gnss_edu package

Created on 12/08/2025 14:58:49

@author: psakic

Submodules

geodezyx.gnss_edu.gnss_edu module

Created on Tue Feb 11 16:39:34 2025

@author: snahmani

geodezyx.gnss_edu.gnss_edu.Sagnac_rotate_around_z(row)

Calcule la correction Sagnac pour les coordonnées satellites. Retourne un pd.Series avec les nouvelles colonnes X_sat_corr, Y_sat_corr, Z_sat_corr.

geodezyx.gnss_edu.gnss_edu.best_prn_for_interval(df: DataFrame, t0: Timestamp, t1: Timestamp, snr_col: str, snr_min: float, sampling: Timedelta, pool_prns: list[str]) str | None

Pick a PRN from pool_prns that fully covers [t0, t1] with SNR>=snr_min. Tie-breaker: highest mean SNR over the interval.

Returns None if no PRN can fully cover the interval.

geodezyx.gnss_edu.gnss_edu.build_active_pivot_schedule(df: DataFrame, selected_prns: list[str], snr_col: str = 'S1', snr_min: float = 40.0, sampling: Timedelta = Timedelta('0 days 00:00:30'), switch_margin_db: float = 2.0) Series

Build a stable active pivot schedule from a pre-selected PRN set. Switch only if the best candidate is better than current by switch_margin_db.

Returns:

active_pivot

Return type:

pd.Series indexed by expected epochs, values are PRN or None

geodezyx.gnss_edu.gnss_edu.check_full_coverage_from_active_pivot(active_pivot: Series) dict

Simple proof helper: - counts None epochs - returns first/last None epoch if any

geodezyx.gnss_edu.gnss_edu.detect_intra_arc_holes(df, sampling=Timedelta('0 days 00:00:30'), gap=Timedelta('0 days 00:30:00'))

Detect missing observations inside satellite arcs.

A hole is defined as:

sampling*2 < dt < gap

Parameters:
  • df (pandas.DataFrame) – GNSS dataframe indexed by (epoch, prn)

  • sampling (Timedelta) – Expected RINEX sampling interval

  • gap (Timedelta) – Arc segmentation threshold

Returns:

epoch_prev : last valid observation epoch : first observation after the hole dt : time difference n_missing : number of missing epochs

Return type:

DataFrame with columns

geodezyx.gnss_edu.gnss_edu.enforce_min_dwell(df: DataFrame, active_pivot: Series, snr_col: str, snr_min: float, sampling: Timedelta, min_dwell: Timedelta) Series

Stability post-filter: If a segment is shorter than min_dwell, try to absorb it into the previous pivot if the previous pivot can cover the short interval.

This reduces last-minute tiny segments (e.g. 25 min) without harming coverage.

geodezyx.gnss_edu.gnss_edu.expected_epochs(t0: Timestamp, t1: Timestamp, sampling: Timedelta) DatetimeIndex

Return the expected epoch grid (inclusive endpoints) for a given sampling.

geodezyx.gnss_edu.gnss_edu.fix_short_pivot_segments(df: DataFrame, active_pivot: Series, snr_col: str, snr_min: float, sampling: Timedelta, min_duration: Timedelta, pool: str = 'selected_only', selected_prns: list[str] | None = None) Series

Remove segments shorter than min_duration.

Priority

  1. merge into previous pivot if it covers the short interval

  2. merge into next pivot if it covers the short interval

  3. fallback: pick best PRN that covers the short interval (optional pool)

returns:

active_pivot_fixed

rtype:

pd.Series

geodezyx.gnss_edu.gnss_edu.get_approx_position(fichier)

Recherche la ligne contenant ‘APPROX POSITION XYZ’ dans le fichier et retourne les trois premières valeurs sous forme de numpy.array.

geodezyx.gnss_edu.gnss_edu.greedy_pivot_set_cover(df: DataFrame, snr_col: str, snr_min: float, sampling: Timedelta = Timedelta('0 days 00:00:30'), require_full_coverage: bool = True, return_diagnostics: bool = True)

Greedy set-cover selection of PRNs to cover ALL expected epochs with SNR >= snr_min.

Guarantee: - If require_full_coverage=True: raise RuntimeError if full coverage is impossible.

Returns:

  • selected_prns (list[str])

  • diagnostics (dict (optional))

geodezyx.gnss_edu.gnss_edu.grep_file(pattern, filename)

Recherche un motif dans un fichier et retourne les lignes correspondantes.

geodezyx.gnss_edu.gnss_edu.load_and_clean_rinex(path)

Charge et nettoie un fichier RINEX d’observation.

Paramètres :
  • path : chemin vers le fichier RINEX.

Retourne :
  • dfDataFrame nettoyé, indexé par [‘epoch’, ‘prn’],

    et contenant une colonne ‘ind_ligne’ indiquant le numéro de ligne.

geodezyx.gnss_edu.gnss_edu.pivot_schedule_to_segments(active_pivot: Series, sampling: Timedelta, drop_none: bool = True) DataFrame

Convert an active pivot schedule to segments: columns = prn, start, end, duration, n_epochs.

geodezyx.gnss_edu.gnss_edu.plot_gnss_sd_by_prn(df_SD: DataFrame, observable: str = 'SD_L1', **kwargs)

Convenience wrapper for SD plots (keeps the TP API stable).

geodezyx.gnss_edu.gnss_edu.plot_gnss_timeseries_by_prn(df: DataFrame, y: str, gap: Timedelta = Timedelta('0 days 00:30:00'), label_arcs: bool = True, arc_label_fontsize: int = 8, arc_label_xytext: tuple[int, int] = (3, 3), show_legend: bool = False, legend_outside: bool = True, legend_ncol: int = 4, title: str | None = None, xlabel: str = 'Time (epoch)', ylabel: str | None = None, figsize: tuple[int, int] = (10, 6))

Plot a GNSS time series by satellite PRN with gap handling.

This function is generic: it works for any DataFrame that:
  • is indexed by a MultiIndex with levels (‘epoch’, ‘prn’)

  • contains a numeric column y

Parameters:
  • df (pandas.DataFrame) – MultiIndex (epoch, prn).

  • y (str) – Column name to plot.

  • gap (pandas.Timedelta) – Time gap threshold used to split continuous segments (“arcs”).

  • label_arcs (bool) – If True, write PRN text at the start of each arc.

  • arc_label_fontsize (int) – Font size for PRN labels.

  • arc_label_xytext (tuple) – (dx, dy) offset in points for the arc labels.

  • show_legend (bool) – If True, show legend (often unnecessary if label_arcs=True).

  • legend_outside (bool) – If True, place legend outside the axes (right side).

  • legend_ncol (int) – Legend columns.

  • title (str or None) – Plot title. If None, a default title is generated.

  • xlabel (str) – X axis label.

  • ylabel (str or None) – Y axis label. If None, uses y.

  • figsize (tuple) – Figure size.

Return type:

fig, ax

geodezyx.gnss_edu.gnss_edu.plot_residual_analysis(A, B, dP_est, figure_title=None, save_path=None, P_est=None, P_rnx_header=None)
Computes residuals (v_est = B - A @ dP_est) and creates a figure containing:
  1. Time series of residuals (displayed as points)

  2. Histogram of residuals (number of observations per bin)

  3. Q-Q Plot of residuals

  4. Scatter plot of residuals vs predicted values

  5. Text box displaying statistics (mean, variance, std dev, skewness, kurtosis)

  6. (Optional) Text box with additional position information: - Distance between estimated position and initial RINEX header position - Local ENU coordinates computed via tools.toolCartLocGRS80

Parameters:
  • A (-) – array-like, design matrix.

  • B (-) – array-like, observation vector.

  • dP_est (-) – array-like, estimated parameter vector.

  • figure_title (-) – str, overall figure title.

  • save_path (-) – str, full path (name + extension) to save the figure.

  • P_est (-) – array-like, estimated position (for additional info computation).

  • P_rnx_header (-) – array-like, initial position from RINEX header.

Returns:

matplotlib Figure object containing all subplots.

Return type:

  • fig

geodezyx.gnss_edu.gnss_edu.plot_sd_derivative_by_prn(df_SD: DataFrame, obs: str, gap: Timedelta = Timedelta('0 days 00:30:00'), label_arcs: bool = True, normalize_by_dt: bool = True, elev_col: str | None = None, cutoff_deg: float | None = None, title: str | None = None, phase_to_meters: bool = False, wavelength_m: float | None = None)

Plot temporal derivative of a single-difference observable by PRN.

Notes (pedagogical)

  • If obs is a carrier-phase SD_L* (stored in cycles), you may set phase_to_meters=True to convert cycles -> meters using the wavelength. This is ONLY for comparison with code (meters); it does not remove ambiguities.

param df_SD:

MultiIndex (epoch, prn). Must contain column obs.

type df_SD:

DataFrame

param obs:

Column to differentiate (e.g., “SD_L1” cycles, “SD_C1” meters).

type obs:

str

param phase_to_meters:

If True and obs starts with “SD_L”, convert cycles to meters before differencing.

type phase_to_meters:

bool

param wavelength_m:

Override wavelength (meters) used for cycles->meters conversion. If None and obs is SD_L1/SD_L2/SD_L5, use conv.L*_WAVELENGTH.

type wavelength_m:

float or None

geodezyx.gnss_edu.gnss_edu.plot_series(df, col1, col2=None, coeff1=1.0, coeff2=1.0, seuil=3600, renderer='browser')

Affiche les séries temporelles pour chaque satellite. Si col2 est fourni, affiche la série : coeff1 * col1 - coeff2 * col2. Sinon, affiche la série de la colonne col1 directement. La série est découpée en segments lorsqu’un “trou” (écart > seuil) est détecté.

Paramètres

dfDataFrame

DataFrame avec un index multi-niveaux contenant au moins le niveau ‘prn’ et les colonnes col1 (et éventuellement col2).

col1str

Nom de la première colonne.

col2str, optional

Nom de la seconde colonne (optionnel). Si None, on affiche col1.

coeff1float

Coefficient multiplicateur pour la première colonne (défaut 1.0).

coeff2float

Coefficient multiplicateur pour la seconde colonne (défaut 1.0).

seuilfloat

Seuil en secondes pour considérer un “trou” dans la série (défaut 3600).

rendererstr

Renderer Plotly (ex : “browser” ou “iframe”).

Retourne

figFigure

Figure Plotly contenant les courbes tracées.

geodezyx.gnss_edu.gnss_edu.plot_tracking_timeline(df: DataFrame, sampling: Timedelta = Timedelta('0 days 00:00:30'), snr_col: str | None = None, snr_min: float | None = None, title: str | None = None)

Timeline heatmap of tracking availability by PRN.

Black = epoch exists for this PRN (and SNR >= snr_min if provided) White = missing epoch (or SNR < snr_min)

Parameters:
  • df (DataFrame) – Must be indexed by MultiIndex (‘epoch’,’prn’).

  • sampling (Timedelta) – Expected observation interval (e.g. 30 s).

  • snr_col (str or None) – Column name for SNR (e.g., ‘S1’). If None, only presence/absence is shown.

  • snr_min (float or None) – If provided with snr_col, only epochs with SNR >= snr_min are considered “present”.

geodezyx.gnss_edu.gnss_edu.plot_tracking_timeline_with_pivots(df: DataFrame, selected_prns: list[str], sampling: Timedelta = Timedelta('0 days 00:00:30'), snr_col: str = 'S1', snr_min: float = 40.0, active_pivot: Series | None = None, title: str | None = None)

Tracking timeline with SNR threshold + pivot satellites highlighted.

Color meaning

0 = white : missing epoch OR SNR < snr_min 1 = black : usable (SNR >= snr_min) but NOT selected as pivot 2 = green : usable (SNR >= snr_min) AND selected as pivot 3 = dark green : active pivot at this epoch (provided by active_pivot)

param df:

MultiIndex (epoch, prn). Must contain snr_col.

type df:

DataFrame

param selected_prns:

PRNs selected by the greedy algorithm (candidate pivots).

type selected_prns:

list[str]

param sampling:

Expected sampling interval (e.g. 30 s).

type sampling:

Timedelta

param snr_col:

SNR column name (e.g., “S1”).

type snr_col:

str

param snr_min:

Minimum SNR threshold to consider a satellite usable.

type snr_min:

float

param active_pivot:

Series indexed by expected_epochs, values are PRN (string) or None/NaN. If provided, it is used to mark state=3 (dark green).

type active_pivot:

pd.Series | None

param title:

Plot title override.

type title:

str | None

rtype:

fig, ax, info

geodezyx.gnss_edu.gnss_edu.prn_covers_interval(df: DataFrame, prn: str, t0: Timestamp, t1: Timestamp, snr_col: str, snr_min: float, sampling: Timedelta) bool

True if PRN has non-NaN SNR >= snr_min at ALL expected epochs in [t0, t1].

geodezyx.gnss_edu.gnss_edu.prn_snr_on_grid(df: DataFrame, prn: str, snr_col: str, epochs: DatetimeIndex) Series

Return SNR series for one PRN reindexed on epochs. Missing epochs -> NaN.

geodezyx.gnss_edu.gpt3 module

Created on Fri Feb 9 07:43:47 2024

@author: snahmani

geodezyx.gnss_edu.gpt3.gpt3_5_fast(mjd=None, lat=None, lon=None, h_ell=None, it=None, grid=None)
geodezyx.gnss_edu.gpt3.gpt3_5_fast_readGrid(filename='./gpt3_5.grd')

geodezyx.gnss_edu.klobuchar module

Created on Tue Feb 6 10:30:57 2024

Filière ING3 - PPMD - Traitement de la mesure de phase

@author: Samuel Nahmani (1,2) https://www.ipgp.fr/annuaire/nahmani/) contact : nahmani@ipgp.fr ou samuel.nahmani@ign.fr (1) Université Paris Cité, Institut de physique du globe de Paris, CNRS, IGN, F-75005 Paris, France. (2) Univ Gustave Eiffel, ENSG, IGN, F-77455 Marne-la-Vallée, France.

Version: 1.0 Dépendances: numpy, geodezyx, datetime

geodezyx.gnss_edu.klobuchar.klobuchar(phi, lambda_, elev, azimuth, tow, alpha, beta)

Compute ionospheric range correction for GPS L1 frequency using Klobuchar model.

Translation to Python of Meysam Mahooti (2024). Klobuchar Ionospheric Delay Model https://www.mathworks.com/matlabcentral/fileexchange/59530-klobuchar-ionospheric-delay-model MATLAB Central File Exchange. Retrieved February 7, 2024.

Parameters:
  • phi (float) – Geodetic latitude of receiver (degrees).

  • lambda (float) – Geodetic longitude of receiver (degrees).

  • elev (float) – Elevation angle of satellite (degrees).

  • azimuth (float) – Geodetic azimuth of satellite (degrees).

  • tow (float) – Time of Week (seconds).

  • alpha (array_like) – The coefficients of a cubic equation representing the amplitude of the vertical delay (4 coefficients - 8 bits each).

  • beta (array_like) – The coefficients of a cubic equation representing the period of the model (4 coefficients - 8 bits each).

Returns:

d_ion1 – Ionospheric slant range correction for the L1 frequency (metres).

Return type:

float

References

Klobuchar, J.A., (1996) “Ionospheric Effects on GPS”, in Parkinson, Spilker (ed), “Global Positioning System Theory and Applications, pp.513-514.

ICD-GPS-200, Rev. C, (1997), pp. 125-128

NATO, (1991), “Technical Characteristics of the NAVSTAR GPS”, pp. A-6-31 - A-6-33

geodezyx.gnss_edu.read_vmf1_grid module

read_vmf1_grid.py — autonome (sans jdutil) Lecture + interpolation des coefficients VMF1 (ah, aw) aux coordonnées station et à des dates MJD arbitraires, à partir des fichiers VMFG_YYYYMMDD.HHH.

  • Interpolation spatiale:
    • tente scipy.interpolate.griddata (linear)

    • sinon repli nearest neighbor (NumPy) si SciPy indisponible

  • Interpolation temporelle: linéaire entre pas 6h

  • Chemins: ./Mapping_Fcn/vmf1/VMFG_YYYYMMDD.HHH

Format attendu des fichiers (après les lignes commençant par ‘!’):

lat lon ah aw zhd zwd (au minimum: lat, lon, ah, aw)

Auteur: adapté pour être autonome (remplacement de jdutil)

class geodezyx.gnss_edu.read_vmf1_grid.VMFPoint(lat: 'float', lon: 'float', ah: 'float', aw: 'float')

Bases: object

ah: float
aw: float
lat: float
lon: float
geodezyx.gnss_edu.read_vmf1_grid.add_hours(dt, hours: int)
geodezyx.gnss_edu.read_vmf1_grid.datetime_to_mjd(dt) float

Convertit un datetime UTC naïf/aware en MJD (UTC).

geodezyx.gnss_edu.read_vmf1_grid.floor_to_6h(dt)

Ramène dt à l’heure multiple de 6h immédiatement inférieure (UTC).

geodezyx.gnss_edu.read_vmf1_grid.jd_to_calendar(jd: float) Tuple[int, int, int, float]

Convertit un Julian Day (float) en (year, month, day, hour_float). Implémentation autonome (remplace jdutil.jd_to_date).

geodezyx.gnss_edu.read_vmf1_grid.mjd_to_datetime(mjd: float)

Conversion MJD -> datetime UTC naïf (sans tzinfo).

geodezyx.gnss_edu.read_vmf1_grid.mjd_to_jd(mjd: float) float
geodezyx.gnss_edu.read_vmf1_grid.read_vmf1_grid(mjd: Iterable[float], ell: Iterable[float]) Tuple[ndarray, ndarray]

Retourne (ah_vec, aw_vec) pour chaque MJD donné et une station ell=[lat_deg, lon_deg, h_m].

Paramètres

mjdIterable[float]

Liste/array de dates en Modified Julian Day (UTC).

ell[lat_deg, lon_deg, h_m]

Latitude (deg), Longitude (deg), Hauteur ellipsoïdale (m). (La hauteur n’est pas utilisée ici pour ah/aw, mais on garde la signature d’interface.)

Renvoie

ah_vec : np.ndarray shape (N,) aw_vec : np.ndarray shape (N,)

Notes

  • Les fichiers requis sont:

    ./Mapping_Fcn/vmf1/VMFG_YYYYMMDD.H{00,06,12,18}

    pour les 6h entourant chaque MJD.

  • Interpolation temporelle: linéaire entre t0=⌊MJD⌋_6h et t1=t0+6h.