Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 49 additions & 49 deletions src/gps/l1c_d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ first decoded.
- `Ω_0::Float64`: Reference right ascension angle (rad).
- `i_0::Float64`: Inclination angle at reference time (rad).
- `ΔΩ_dot::Float64`: Rate of right ascension difference (rad/s).
- `i_0_dot::Float64`: Rate of inclination angle (rad/s).
- `i_dot::Float64`: Rate of inclination angle (rad/s).
- `C_is::Float64`, `C_ic::Float64`: Sine/cosine inclination harmonic corrections (rad).
- `C_rs::Float64`, `C_rc::Float64`: Sine/cosine orbit-radius harmonic corrections (m).
- `C_us::Float64`, `C_uc::Float64`: Sine/cosine argument-of-latitude harmonic corrections (rad).
Expand All @@ -336,7 +336,7 @@ CRC-valid SF3 page regardless of whether its page format is parsed.
- `t_ot::Int64`: UTC reference time of week (s).
- `WN_ot,WN_LSF::Int64`: UTC and leap-second reference week numbers.
- `DN::Int64`: leap-second reference day number (1-7).
- `α0,α1,α2,α3,β0,β1,β2,β3::Float64`: Klobuchar ionospheric coefficients.
- `α_0,α_1,α_2,α_3,β_0,β_1,β_2,β_3::Float64`: Klobuchar ionospheric coefficients.
- `ISC_L1CA,ISC_L2C,ISC_L5I5,ISC_L5Q5::Float64`: inter-signal corrections (s).

## Page 2 — GGTO + EOP
Expand All @@ -348,7 +348,7 @@ CRC-valid SF3 page regardless of whether its page format is parsed.
"GGTO ID" by IRN-IS-800J-003.)
- `t_EOP::Int64`: EOP reference time of week (s).
- `PM_X,PM_X_dot,PM_Y,PM_Y_dot::Float64`: polar-motion values/rates.
- `ΔUT1,ΔUT1_dot::Float64`: UT1-UTC difference and rate.
- `ΔUT_GPS,ΔUT_GPS_dot::Float64`: UT1-GPS (UT1−GPST) difference and rate.

## Pages 3/4/5 — keyed dictionaries (`nothing` until first decoded)

Expand Down Expand Up @@ -391,7 +391,7 @@ Base.@kwdef struct GPSL1C_DData <: AbstractGNSSData
Ω_0::Union{Nothing,Float64} = nothing
i_0::Union{Nothing,Float64} = nothing
ΔΩ_dot::Union{Nothing,Float64} = nothing
i_0_dot::Union{Nothing,Float64} = nothing
i_dot::Union{Nothing,Float64} = nothing
C_is::Union{Nothing,Float64} = nothing
C_ic::Union{Nothing,Float64} = nothing
C_rs::Union{Nothing,Float64} = nothing
Expand All @@ -417,14 +417,14 @@ Base.@kwdef struct GPSL1C_DData <: AbstractGNSSData
WN_LSF::Union{Nothing,Int64} = nothing
DN::Union{Nothing,Int64} = nothing
Δt_LSF::Union{Nothing,Int64} = nothing
α0::Union{Nothing,Float64} = nothing
α1::Union{Nothing,Float64} = nothing
α2::Union{Nothing,Float64} = nothing
α3::Union{Nothing,Float64} = nothing
β0::Union{Nothing,Float64} = nothing
β1::Union{Nothing,Float64} = nothing
β2::Union{Nothing,Float64} = nothing
β3::Union{Nothing,Float64} = nothing
α_0::Union{Nothing,Float64} = nothing
α_1::Union{Nothing,Float64} = nothing
α_2::Union{Nothing,Float64} = nothing
α_3::Union{Nothing,Float64} = nothing
β_0::Union{Nothing,Float64} = nothing
β_1::Union{Nothing,Float64} = nothing
β_2::Union{Nothing,Float64} = nothing
β_3::Union{Nothing,Float64} = nothing
ISC_L1CA::Union{Nothing,Float64} = nothing
ISC_L2C::Union{Nothing,Float64} = nothing
ISC_L5I5::Union{Nothing,Float64} = nothing
Expand All @@ -442,8 +442,8 @@ Base.@kwdef struct GPSL1C_DData <: AbstractGNSSData
PM_X_dot::Union{Nothing,Float64} = nothing
PM_Y::Union{Nothing,Float64} = nothing
PM_Y_dot::Union{Nothing,Float64} = nothing
ΔUT1::Union{Nothing,Float64} = nothing
ΔUT1_dot::Union{Nothing,Float64} = nothing
ΔUT_GPS::Union{Nothing,Float64} = nothing
ΔUT_GPS_dot::Union{Nothing,Float64} = nothing

# --- Subframe 3, pages 3/4/5: per-SV keyed dictionaries ---
reduced_almanacs::Union{Nothing,Dictionary{Int,GPSL1C_DReducedAlmanac}} = nothing
Expand Down Expand Up @@ -481,7 +481,7 @@ function GPSL1C_DData(
Ω_0 = data.Ω_0,
i_0 = data.i_0,
ΔΩ_dot = data.ΔΩ_dot,
i_0_dot = data.i_0_dot,
i_dot = data.i_dot,
C_is = data.C_is,
C_ic = data.C_ic,
C_rs = data.C_rs,
Expand All @@ -504,14 +504,14 @@ function GPSL1C_DData(
WN_LSF = data.WN_LSF,
DN = data.DN,
Δt_LSF = data.Δt_LSF,
α0 = data.α0,
α1 = data.α1,
α2 = data.α2,
α3 = data.α3,
β0 = data.β0,
β1 = data.β1,
β2 = data.β2,
β3 = data.β3,
α_0 = data.α_0,
α_1 = data.α_1,
α_2 = data.α_2,
α_3 = data.α_3,
β_0 = data.β_0,
β_1 = data.β_1,
β_2 = data.β_2,
β_3 = data.β_3,
ISC_L1CA = data.ISC_L1CA,
ISC_L2C = data.ISC_L2C,
ISC_L5I5 = data.ISC_L5I5,
Expand All @@ -527,8 +527,8 @@ function GPSL1C_DData(
PM_X_dot = data.PM_X_dot,
PM_Y = data.PM_Y,
PM_Y_dot = data.PM_Y_dot,
ΔUT1 = data.ΔUT1,
ΔUT1_dot = data.ΔUT1_dot,
ΔUT_GPS = data.ΔUT_GPS,
ΔUT_GPS_dot = data.ΔUT_GPS_dot,
reduced_almanacs = data.reduced_almanacs,
midi_almanacs = data.midi_almanacs,
differential_corrections = data.differential_corrections,
Expand Down Expand Up @@ -556,7 +556,7 @@ function GPSL1C_DData(
Ω_0,
i_0,
ΔΩ_dot,
i_0_dot,
i_dot,
C_is,
C_ic,
C_rs,
Expand All @@ -579,14 +579,14 @@ function GPSL1C_DData(
WN_LSF,
DN,
Δt_LSF,
α0,
α1,
α2,
α3,
β0,
β1,
β2,
β3,
α_0,
α_1,
α_2,
α_3,
β_0,
β_1,
β_2,
β_3,
ISC_L1CA,
ISC_L2C,
ISC_L5I5,
Expand All @@ -602,8 +602,8 @@ function GPSL1C_DData(
PM_X_dot,
PM_Y,
PM_Y_dot,
ΔUT1,
ΔUT1_dot,
ΔUT_GPS,
ΔUT_GPS_dot,
reduced_almanacs,
midi_almanacs,
differential_corrections,
Expand Down Expand Up @@ -935,7 +935,7 @@ function decode_subframe2(state::GNSSDecoderState{<:GPSL1C_DData}, sf2_symbols)
Ω_0 = get_twos_complement_num(word, word_length, 240, 33) * 2.0^-32 * PI
i_0 = get_twos_complement_num(word, word_length, 273, 33) * 2.0^-32 * PI
ΔΩ_dot = get_twos_complement_num(word, word_length, 306, 17) * 2.0^-44 * PI
i_0_dot = get_twos_complement_num(word, word_length, 323, 15) * 2.0^-44 * PI
i_dot = get_twos_complement_num(word, word_length, 323, 15) * 2.0^-44 * PI
C_is = get_twos_complement_num(word, word_length, 338, 16) * 2.0^-30
C_ic = get_twos_complement_num(word, word_length, 354, 16) * 2.0^-30
C_rs = get_twos_complement_num(word, word_length, 370, 24) * 2.0^-8
Expand Down Expand Up @@ -970,7 +970,7 @@ function decode_subframe2(state::GNSSDecoderState{<:GPSL1C_DData}, sf2_symbols)
Ω_0,
i_0,
ΔΩ_dot,
i_0_dot,
i_dot,
C_is,
C_ic,
C_rs,
Expand Down Expand Up @@ -1062,14 +1062,14 @@ function parse_sf3_page1(raw::GPSL1C_DData, word::UInt288, PI::Float64)
Δt_LSF = get_twos_complement_num(word, word_length, 105, 8),
# Klobuchar ionospheric coefficients (IS-GPS-200 Table 20-X; all 8-bit
# two's-complement, scaled in seconds / seconds-per-semicircle^n).
α0 = get_twos_complement_num(word, word_length, 113, 8) * 2.0^-30,
α1 = get_twos_complement_num(word, word_length, 121, 8) * 2.0^-27,
α2 = get_twos_complement_num(word, word_length, 129, 8) * 2.0^-24,
α3 = get_twos_complement_num(word, word_length, 137, 8) * 2.0^-24,
β0 = get_twos_complement_num(word, word_length, 145, 8) * 2.0^11,
β1 = get_twos_complement_num(word, word_length, 153, 8) * 2.0^14,
β2 = get_twos_complement_num(word, word_length, 161, 8) * 2.0^16,
β3 = get_twos_complement_num(word, word_length, 169, 8) * 2.0^16,
α_0 = get_twos_complement_num(word, word_length, 113, 8) * 2.0^-30,
α_1 = get_twos_complement_num(word, word_length, 121, 8) * 2.0^-27,
α_2 = get_twos_complement_num(word, word_length, 129, 8) * 2.0^-24,
α_3 = get_twos_complement_num(word, word_length, 137, 8) * 2.0^-24,
β_0 = get_twos_complement_num(word, word_length, 145, 8) * 2.0^11,
β_1 = get_twos_complement_num(word, word_length, 153, 8) * 2.0^14,
β_2 = get_twos_complement_num(word, word_length, 161, 8) * 2.0^16,
β_3 = get_twos_complement_num(word, word_length, 169, 8) * 2.0^16,
# Inter-signal corrections (Fig 3.5-2; 13-bit two's complement, 2^-35 s).
ISC_L1CA = get_twos_complement_num(word, word_length, 177, 13) * 2.0^-35,
ISC_L2C = get_twos_complement_num(word, word_length, 190, 13) * 2.0^-35,
Expand All @@ -1095,14 +1095,14 @@ function parse_sf3_page2(raw::GPSL1C_DData, word::UInt288, PI::Float64)
# EOP (Table 3.5-5). All fields are contiguous in the info block; Figure
# 3.5-3 only *draws* PM_X across its 100-bit row boundary — the 2 MSBs end
# row 1 (bits 99-100) and the 19 LSBs begin row 2 (bits 101-119) — so the
# plain 21-bit read at bit 99 is correct (likewise ΔUT1 spans the next row).
# plain 21-bit read at bit 99 is correct (likewise ΔUT_GPS spans the next row).
t_EOP = Int(get_bits(word, word_length, 83, 16)) * 2^4,
PM_X = get_twos_complement_num(word, word_length, 99, 21) * 2.0^-20,
PM_X_dot = get_twos_complement_num(word, word_length, 120, 15) * 2.0^-21,
PM_Y = get_twos_complement_num(word, word_length, 135, 21) * 2.0^-20,
PM_Y_dot = get_twos_complement_num(word, word_length, 156, 15) * 2.0^-21,
ΔUT1 = get_twos_complement_num(word, word_length, 171, 31) * 2.0^-24,
ΔUT1_dot = get_twos_complement_num(word, word_length, 202, 19) * 2.0^-25,
ΔUT_GPS = get_twos_complement_num(word, word_length, 171, 31) * 2.0^-23,
ΔUT_GPS_dot = get_twos_complement_num(word, word_length, 202, 19) * 2.0^-25,
)
end

Expand Down
34 changes: 17 additions & 17 deletions src/gps/l1ca.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ which the decoder stores in `δi`.
- `Ω_0::Float64`: Longitude of ascending node at weekly epoch (rad)
- `ω::Float64`: Argument of perigee (rad)
- `M_0::Float64`: Mean anomaly at reference time (rad)
- `af0::Float64`: SV clock bias correction coefficient (seconds)
- `af1::Float64`: SV clock drift correction coefficient (s/s)
- `a_f0::Float64`: SV clock bias correction coefficient (seconds)
- `a_f1::Float64`: SV clock drift correction coefficient (s/s)

# Reference

Expand All @@ -78,8 +78,8 @@ Base.@kwdef struct GPSL1CAAlmanac
Ω_0::Union{Nothing,Float64} = nothing
ω::Union{Nothing,Float64} = nothing
M_0::Union{Nothing,Float64} = nothing
af0::Union{Nothing,Float64} = nothing
af1::Union{Nothing,Float64} = nothing
a_f0::Union{Nothing,Float64} = nothing
a_f1::Union{Nothing,Float64} = nothing
end

"""
Expand All @@ -103,7 +103,7 @@ subframes 1, 2, and 3 of the GPS LNAV message. All parameters conform to IS-GPS-
- `trans_week::Int64`: GPS week number (modulo 1024)
- `codeonl2::Int64`: Code on L2 channel (0=invalid, 1=P-code, 2=C/A-code, 3=invalid)
- `ura::Float64`: User Range Accuracy (meters), derived from URA index
- `svhealth::String`: 6-bit satellite health status ("000000" = healthy)
- `sv_health::String`: 6-bit satellite health status ("000000" = healthy)
- `IODC::String`: Issue of Data, Clock (10-bit binary string)
- `l2pcode::Bool`: L2 P-code data flag (1=LNAV OFF on P-code)
- `T_GD::Float64`: L1-L2 group delay correction (seconds)
Expand Down Expand Up @@ -152,7 +152,7 @@ Base.@kwdef struct GPSL1CAData <: AbstractGNSSData
trans_week::Union{Nothing,Int64} = nothing
codeonl2::Union{Nothing,Int64} = nothing
ura::Union{Nothing,Float64} = nothing
svhealth::Union{Nothing,String} = nothing
sv_health::Union{Nothing,String} = nothing
IODC::Union{Nothing,String} = nothing
l2pcode::Union{Nothing,Bool} = nothing
T_GD::Union{Nothing,Float64} = nothing
Expand Down Expand Up @@ -230,7 +230,7 @@ function GPSL1CAData(
trans_week = data.trans_week,
codeonl2 = data.codeonl2,
ura = data.ura,
svhealth = data.svhealth,
sv_health = data.sv_health,
IODC = data.IODC,
l2pcode = data.l2pcode,
T_GD = data.T_GD,
Expand Down Expand Up @@ -290,7 +290,7 @@ function GPSL1CAData(
trans_week,
codeonl2,
ura,
svhealth,
sv_health,
IODC,
l2pcode,
T_GD,
Expand Down Expand Up @@ -409,7 +409,7 @@ function is_subframe1_decoded(data::GPSL1CAData)
!isnothing(data.trans_week) &&
!isnothing(data.codeonl2) &&
!isnothing(data.ura) &&
!isnothing(data.svhealth) &&
!isnothing(data.sv_health) &&
!isnothing(data.IODC) &&
!isnothing(data.l2pcode) &&
!isnothing(data.T_GD) &&
Expand Down Expand Up @@ -731,12 +731,12 @@ function decode_syncro_sequence(state::GNSSDecoderState{<:GPSL1CAData}, buffer)
end

# Satellite Health
svhealth = bitstring(get_bits(word3, 30, 17, 6))[(end-5):end]
sv_health = bitstring(get_bits(word3, 30, 17, 6))[(end-5):end]
if get_bit(word3, 30, 17)
@warn "Bad LNAV Data, SV-Health critical", svhealth
@warn "Bad LNAV Data, SV-Health critical", sv_health
end

GPSL1CAData(state.raw_data; trans_week, codeonl2, ura, svhealth)
GPSL1CAData(state.raw_data; trans_week, codeonl2, ura, sv_health)
end

state = can_decode_two_words(state, buffer, 3, 8) do word3, word8, state
Expand Down Expand Up @@ -1270,8 +1270,8 @@ function decode_almanac_page(state::GNSSDecoderState{<:GPSL1CAData}, buffer, sv_
Ω_0 = alm_Ω_0,
ω = alm_ω,
M_0 = alm_M_0,
af0 = alm_af0,
af1 = alm_af1,
a_f0 = alm_af0,
a_f1 = alm_af1,
)

almanac = something(state.raw_data.almanac, Dictionary{Int64,GPSL1CAAlmanac}())
Expand Down Expand Up @@ -1405,13 +1405,13 @@ $(TYPEDSIGNATURES)

Check if the GPS satellite is healthy and usable for positioning.

Examines the 6-bit satellite health field (`svhealth`) from subframe 1. A satellite
Examines the 6-bit satellite health field (`sv_health`) from subframe 1. A satellite
is considered healthy only if all health bits are zero (`"000000"`).

!!! warning

This function requires that subframe 1 has been successfully decoded.
Check that `state.data.svhealth` is not `nothing` before relying on this result.
Check that `state.data.sv_health` is not `nothing` before relying on this result.

# Arguments

Expand All @@ -1437,5 +1437,5 @@ end
- [`decode`](@ref): Decode navigation data
"""
function is_sat_healthy(state::GNSSDecoderState{<:GPSL1CAData})
state.data.svhealth == "000000"
state.data.sv_health == "000000"
end
Loading
Loading