Documentation
¶
Index ¶
- func ComputeElevationWeight(elevationDeg float64, exponent float64) float64
- func CountValidObservables(states []*pipeline.SatelliteState) int
- func FilterByQuality(states []*pipeline.SatelliteState, config TDCPConfig) []*pipeline.SatelliteState
- func ValidateContinuity(current *pipeline.SatelliteState, previous *pipeline.SatelliteState, ...) bool
- type CombinationType
- type ConfigError
- type CycleSlipDetector
- type EKFConfig
- type ENUVelocity
- type EpochBuffer
- func (b *EpochBuffer) Clear()
- func (b *EpochBuffer) Count() int
- func (b *EpochBuffer) GetCurrentTime() time.Time
- func (b *EpochBuffer) GetPrevious(satKey observation.SatelliteKey) *pipeline.SatelliteState
- func (b *EpochBuffer) HasPrevious(satKey observation.SatelliteKey) bool
- func (b *EpochBuffer) UpdateEpoch(states []*pipeline.SatelliteState, epochTime time.Time)
- type GeometryFreeData
- type LeastSquaresSolver
- type SolverType
- type TDCPConfig
- type TDCPEphemerisProcessor
- type TDCPObservableProcessor
- func (p *TDCPObservableProcessor) GetEpochBuffer() *EpochBuffer
- func (p *TDCPObservableProcessor) Name() string
- func (p *TDCPObservableProcessor) Process(ctx context.Context, state *pipeline.SatelliteState) error
- func (p *TDCPObservableProcessor) UpdateEpoch(states []*pipeline.SatelliteState, epochTime time.Time)
- type TDCPSolverProcessor
- type VelocityResidual
- type VelocitySolution
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeElevationWeight ¶
ComputeElevationWeight calculates the elevation-dependent weight for a satellite. Weight = sin(elevation)^exponent This gives higher weight to satellites at higher elevations which typically have better signal quality and less multipath.
func CountValidObservables ¶
func CountValidObservables(states []*pipeline.SatelliteState) int
CountValidObservables returns the number of satellites with valid TDCP observables. This is a utility method for logging and diagnostics.
func FilterByQuality ¶
func FilterByQuality(states []*pipeline.SatelliteState, config TDCPConfig) []*pipeline.SatelliteState
FilterByQuality filters satellite states based on quality criteria. This can be used to exclude satellites with: - Detected cycle slips - Low elevation - Health issues - etc.
Returns a new slice containing only satellites that pass all quality checks.
func ValidateContinuity ¶
func ValidateContinuity( current *pipeline.SatelliteState, previous *pipeline.SatelliteState, detector *CycleSlipDetector, ) bool
ValidateContinuity checks if two satellite states represent continuous tracking. This is a helper for TDCP processing to determine if epoch-to-epoch differencing is valid.
Returns true if: - No cycle slip is detected - Satellite is tracked in both epochs - Required observations are available
Types ¶
type CombinationType ¶
type CombinationType int
CombinationType specifies which carrier phase combination to use for TDCP.
const ( // CombinationIF uses the ionosphere-free (L1-L2) combination. // This eliminates first-order ionospheric effects and is the recommended default. CombinationIF CombinationType = iota // CombinationNL uses the narrow-lane combination. // This has lower noise but is affected by ionosphere. CombinationNL )
func (CombinationType) String ¶
func (c CombinationType) String() string
String returns a human-readable name for the combination type.
type ConfigError ¶
ConfigError represents a configuration validation error.
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
Error implements the error interface.
type CycleSlipDetector ¶
type CycleSlipDetector struct {
// contains filtered or unexported fields
}
CycleSlipDetector detects cycle slips using multiple methods. Phase 1: LLI flags and Melbourne-Wübbena differencing Phase 2: Magnitude estimation (planned)
func NewCycleSlipDetector ¶
func NewCycleSlipDetector(mwThreshold float64) *CycleSlipDetector
NewCycleSlipDetector creates a new cycle slip detector with the specified threshold.
func (*CycleSlipDetector) DetectSlip ¶
func (d *CycleSlipDetector) DetectSlip( current *pipeline.SatelliteState, previous *pipeline.SatelliteState, ) *pipeline.CycleSlipInfo
DetectSlip checks for cycle slips between current and previous satellite states. It returns a CycleSlipInfo struct with detection results.
Detection methods (in order of priority): 1. Loss of Lock Indicator (LLI) flags from observations (both epochs) 2. Melbourne-Wübbena combination difference
Returns nil if no slip is detected.
func (*CycleSlipDetector) EstimateSlipMagnitude ¶
func (d *CycleSlipDetector) EstimateSlipMagnitude( current *pipeline.SatelliteState, previous *pipeline.SatelliteState, slipInfo *pipeline.CycleSlipInfo, ) *float64
EstimateSlipMagnitude attempts to quantify the cycle slip in cycles. This is a Phase 2 feature - placeholder for future implementation.
The basic approach would be: 1. Compare predicted phase (from geometry) to measured phase 2. Compute the difference and quantize to nearest integer cycle 3. Verify consistency across frequencies
Returns the estimated slip in cycles, or nil if estimation fails.
type EKFConfig ¶
type EKFConfig struct {
// Position process noise [m/√s]
// Controls how much the position is allowed to change between epochs
// Typical value: 0.1 (10 cm/√s)
PositionStdDev float64
// Velocity process noise [(m/s)/√s]
// Controls how much the velocity is allowed to change between epochs
// Typical value: 0.01 (1 cm/s/√s)
VelocityStdDev float64
// Clock offset process noise [m/√s]
// Typical value: 100 (for typical receiver clocks)
ClockStdDev float64
// Clock drift process noise [(m/s)/√s]
// Typical value: 0.1
ClockDriftStdDev float64
// Pseudorange measurement noise [m]
// Typical value: 1.0 meter
PseudorangeSigma float64
// Carrier phase measurement noise [m]
// Typical value: 0.01 meters (1 cm)
CarrierPhaseSigma float64
}
EKFConfig contains Extended Kalman Filter-specific parameters. These are only used when SolverType == SolverEKF.
func DefaultEKFConfig ¶
func DefaultEKFConfig() EKFConfig
DefaultEKFConfig returns EKF parameters with recommended default values.
type ENUVelocity ¶
type ENUVelocity struct {
East float64 // East component [m/s]
North float64 // North component [m/s]
Up float64 // Up component [m/s]
}
ENUVelocity represents velocity in the local East-North-Up coordinate frame.
type EpochBuffer ¶
type EpochBuffer struct {
// contains filtered or unexported fields
}
EpochBuffer maintains a thread-safe 2-epoch sliding window for TDCP differencing. It stores satellite states from the previous epoch to enable epoch-to-epoch carrier phase differencing for velocity estimation.
func (*EpochBuffer) Clear ¶
func (b *EpochBuffer) Clear()
Clear resets the epoch buffer, removing all stored states. This is useful when starting a new processing session or recovering from errors.
func (*EpochBuffer) Count ¶
func (b *EpochBuffer) Count() int
Count returns the number of satellites in the previous epoch. This can be useful for diagnostics and logging.
func (*EpochBuffer) GetCurrentTime ¶
func (b *EpochBuffer) GetCurrentTime() time.Time
GetCurrentTime returns the time of the current epoch. This is the time of the most recent UpdateEpoch call.
func (*EpochBuffer) GetPrevious ¶
func (b *EpochBuffer) GetPrevious(satKey observation.SatelliteKey) *pipeline.SatelliteState
GetPrevious retrieves the satellite state from the previous epoch. Returns nil if the satellite was not present in the previous epoch. The returned state is a pointer to the stored state - callers should not modify it.
func (*EpochBuffer) HasPrevious ¶
func (b *EpochBuffer) HasPrevious(satKey observation.SatelliteKey) bool
HasPrevious checks if a satellite exists in the previous epoch. This is useful for determining continuity before attempting TDCP processing.
func (*EpochBuffer) UpdateEpoch ¶
func (b *EpochBuffer) UpdateEpoch(states []*pipeline.SatelliteState, epochTime time.Time)
UpdateEpoch advances the epoch window, storing the current epoch states as the new "previous" epoch for the next processing cycle. This method stores pointers to the given states and does not perform a deep copy.
type GeometryFreeData ¶
type GeometryFreeData struct {
System gnss.System
SatelliteID observation.SatelliteID
Elevation float64 // Elevation [degrees]
Azimuth float64 // Azimuth [degrees]
PPLatitude float64 // Ionospheric pierce point latitude [degrees]
PPLongitude float64 // Ionospheric pierce point longitude [degrees]
PPHeight float64 // Ionospheric pierce point height [meters]
Phase float64 // Rate of change of geometry-free phase [meters/interval]
Range float64 // Rate of change of geometry-free range [meters/interval]
TEC float64 // Rate of change of slant TEC [TECU/interval]
TECFiltered float64 // High-pass filtered TEC rate [TECU/interval]
}
GeometryFreeData contains geometry-free TEC rate information for a single satellite. This is useful for ionospheric monitoring and analysis.
type LeastSquaresSolver ¶
type LeastSquaresSolver struct {
// contains filtered or unexported fields
}
LeastSquaresSolver implements weighted least squares velocity estimation for TDCP. This is a stateless solver that processes epoch-by-epoch.
func NewLeastSquaresSolver ¶
func NewLeastSquaresSolver(config TDCPConfig) *LeastSquaresSolver
NewLeastSquaresSolver creates a new least squares solver with the given configuration.
func (*LeastSquaresSolver) Solve ¶
func (s *LeastSquaresSolver) Solve( states []*pipeline.SatelliteState, epochTime time.Time, timeDelta time.Duration, ) (*VelocitySolution, error)
Solve computes the velocity solution from TDCP observables using weighted least squares.
The observation equation is: y - b = A * x Where:
y = measured delta-phase observations [meters] b = modeled range changes [meters] A = geometry matrix, each row is [dx/rho, dy/rho, dz/rho, 1] x = unknowns [Δvx, Δvy, Δvz, Δclock] (velocity deltas over time interval)
Solution: x = (A'WA)^-1 A'W(y-b) Where W is a diagonal weight matrix based on satellite elevation.
type SolverType ¶
type SolverType int
SolverType specifies the algorithm used for velocity estimation.
const ( // SolverLS uses weighted least squares for velocity estimation. // This is a simple, stateless approach suitable for epoch-by-epoch processing. SolverLS SolverType = iota // SolverEKF uses an Extended Kalman Filter for velocity estimation. // This provides smoothing and can fuse SPP position with TDCP velocity. // Planned for Phase 3 implementation. SolverEKF )
func (SolverType) String ¶
func (s SolverType) String() string
String returns a human-readable name for the solver type.
type TDCPConfig ¶
type TDCPConfig struct {
// Solver method to use for velocity estimation
SolverType SolverType
// Carrier phase combination to use for delta-phase computation
Combination CombinationType
// Cycle slip detection threshold for Melbourne-Wübbena combination [meters]
// Default: 0.5 meters
MWSlipThreshold float64
// Enable cycle slip magnitude estimation (Phase 2 feature)
// When enabled, the processor will attempt to quantify the slip in cycles
EnableSlipEstimation bool
// Output configuration
OutputResiduals bool // Include post-fit residuals in results
OutputGeometryFree bool // Include geometry-free TEC rate data (Phase 4 feature)
// EKF-specific configuration (used when SolverType == SolverEKF)
// Phase 3 feature
EKFConfig EKFConfig
// Receiver position for geometry calculations and ENU conversion
// This must be provided for TDCP processing
ReceiverPosition coordinates.Vector3D
// Minimum number of satellites required for a solution
// Default: 4 (minimum for 3D velocity + clock drift)
MinSatellites int
// Elevation weighting exponent
// Weight = sin(elevation)^WeightExponent
// Default: 2.0 (standard elevation-dependent weighting)
WeightExponent float64
}
TDCPConfig contains all configuration parameters for TDCP velocity processing.
func DefaultTDCPConfig ¶
func DefaultTDCPConfig() TDCPConfig
DefaultTDCPConfig returns a TDCP configuration with recommended default values.
func (*TDCPConfig) Validate ¶
func (c *TDCPConfig) Validate() error
Validate checks if the configuration is valid and returns an error if not.
type TDCPEphemerisProcessor ¶
type TDCPEphemerisProcessor struct {
// contains filtered or unexported fields
}
TDCPEphemerisProcessor is a specialized ephemeris processor for TDCP that ensures consistent ephemeris usage across consecutive epochs.
Unlike the standard EphemerisProcessor which looks up ephemeris at each epoch's time, this processor uses a reference time (from the previous epoch) to look up ephemeris for the current epoch. This matches the legacy TDCP behavior and prevents noise from ephemeris message changes between closely-spaced epochs.
func NewTDCPEphemerisProcessor ¶
func NewTDCPEphemerisProcessor(store *ephemeris.EphemerisStore) *TDCPEphemerisProcessor
NewTDCPEphemerisProcessor creates a new TDCP ephemeris processor.
func (*TDCPEphemerisProcessor) GetReferenceTime ¶
func (p *TDCPEphemerisProcessor) GetReferenceTime() time.Time
GetReferenceTime returns the current reference time.
func (*TDCPEphemerisProcessor) Name ¶
func (p *TDCPEphemerisProcessor) Name() string
Name returns the processor name for logging and error messages.
func (*TDCPEphemerisProcessor) Process ¶
func (p *TDCPEphemerisProcessor) Process(ctx context.Context, state *pipeline.SatelliteState) error
Process looks up and attaches ephemeris to the satellite state using a consistent reference time.
func (*TDCPEphemerisProcessor) UpdateReferenceTime ¶
func (p *TDCPEphemerisProcessor) UpdateReferenceTime(t time.Time)
UpdateReferenceTime updates the reference time for ephemeris lookups. This should be called after processing an epoch to set the reference time for the next epoch.
type TDCPObservableProcessor ¶
type TDCPObservableProcessor struct {
// contains filtered or unexported fields
}
TDCPObservableProcessor computes TDCP (Time-Differenced Carrier Phase) observables for each satellite. This is a stateful processor that maintains an epoch buffer to enable epoch-to-epoch carrier phase differencing.
Processing steps: 1. Check if satellite exists in previous epoch (continuity) 2. Detect cycle slips via LLI flags and Melbourne-Wübbena 3. Compute delta-phase from ionosphere-free or narrow-lane combination 4. Compute geometry matrix row (unit vector to satellite) 5. Compute modeled range change (geometry + corrections) 6. Compute elevation-based weight 7. Store VelocityObservable in state.Velocity 8. Store CycleSlipInfo in state.CycleSlip
func NewTDCPObservableProcessor ¶
func NewTDCPObservableProcessor(config TDCPConfig) *TDCPObservableProcessor
NewTDCPObservableProcessor creates a new TDCP observable processor.
func (*TDCPObservableProcessor) GetEpochBuffer ¶
func (p *TDCPObservableProcessor) GetEpochBuffer() *EpochBuffer
GetEpochBuffer returns the internal epoch buffer for testing or advanced usage.
func (*TDCPObservableProcessor) Name ¶
func (p *TDCPObservableProcessor) Name() string
Name returns the processor name for logging and debugging.
func (*TDCPObservableProcessor) Process ¶
func (p *TDCPObservableProcessor) Process(ctx context.Context, state *pipeline.SatelliteState) error
Process implements the pipeline.Processor interface. It computes TDCP observables for a single satellite by differencing with the previous epoch.
func (*TDCPObservableProcessor) UpdateEpoch ¶
func (p *TDCPObservableProcessor) UpdateEpoch(states []*pipeline.SatelliteState, epochTime time.Time)
UpdateEpoch advances the epoch buffer to prepare for the next epoch. This should be called after all satellites in the current epoch have been processed.
type TDCPSolverProcessor ¶
type TDCPSolverProcessor struct {
// contains filtered or unexported fields
}
TDCPSolverProcessor aggregates TDCP observables from all satellites and computes the velocity solution.
NOTE: This processor does NOT implement the standard pipeline.Processor interface because it requires access to ALL satellites, not just one at a time. It is invoked separately after the pipeline has processed all satellites.
func NewTDCPSolverProcessor ¶
func NewTDCPSolverProcessor(config TDCPConfig) *TDCPSolverProcessor
NewTDCPSolverProcessor creates a new TDCP solver processor.
func (*TDCPSolverProcessor) GetConfig ¶
func (p *TDCPSolverProcessor) GetConfig() TDCPConfig
GetConfig returns the current configuration. This can be useful for inspecting or modifying the configuration.
func (*TDCPSolverProcessor) ProcessEpoch ¶
func (p *TDCPSolverProcessor) ProcessEpoch( ctx context.Context, states []*pipeline.SatelliteState, epochTime time.Time, ) (*VelocitySolution, error)
ProcessEpoch computes the velocity solution from all satellite states. This method should be called after the pipeline has processed all satellites in the current epoch.
The context parameter can be used for cancellation. The states parameter should contain all satellites from the current epoch. The epochTime parameter is the timestamp of the current epoch.
Returns the velocity solution or an error if the solution cannot be computed.
func (*TDCPSolverProcessor) UpdateConfig ¶
func (p *TDCPSolverProcessor) UpdateConfig(config TDCPConfig) error
UpdateConfig updates the solver configuration. Note: This will recreate internal solvers, so use with caution.
type VelocityResidual ¶
type VelocityResidual struct {
System gnss.System
SatelliteID observation.SatelliteID
Residual float64 // Post-fit residual [meters]
Elevation float64 // Elevation [degrees]
Azimuth float64 // Azimuth [degrees]
}
VelocityResidual contains post-fit residual information for a single satellite.
type VelocitySolution ¶
type VelocitySolution struct {
// Timestamp of the current epoch
Timestamp time.Time
// Time interval between epochs used for differencing
TimeDelta time.Duration
// Velocity in ECEF (Earth-Centered Earth-Fixed) frame [m/s]
ECEF coordinates.Vector3D
// Velocity in local ENU (East-North-Up) frame [m/s]
ENU ENUVelocity
// Receiver clock drift [m/s]
// This is the rate of change of the receiver clock offset
ClockDrift float64
// Number of satellites used in the solution
SatelliteCount int
// Post-fit residuals for each satellite
// Only populated if OutputResiduals is enabled in configuration
Residuals []VelocityResidual
// Geometry-free TEC rate data for each satellite
// Only populated if OutputGeometryFree is enabled in configuration
GeometryFree []GeometryFreeData
// Optional: Filtered position estimate (for EKF solver)
// This is the position state from the Kalman filter when using SPP+TDCP fusion
FilteredPosition *coordinates.Vector3D
}
VelocitySolution contains the complete velocity estimation result. This is the primary output type from the TDCP solver.
func (*VelocitySolution) ToLegacyGeometryFree ¶
func (v *VelocitySolution) ToLegacyGeometryFree(streamID string) *tdcp.GeometryFreeOutput
ToLegacyGeometryFree converts the modern geometry-free data to the legacy tdcp.GeometryFreeOutput type. Returns nil if no geometry-free data is present.
func (*VelocitySolution) ToLegacyResiduals ¶
func (v *VelocitySolution) ToLegacyResiduals(streamID string) *tdcp.Residuals
ToLegacyResiduals converts the modern residuals to the legacy tdcp.Residuals type. Returns nil if no residuals are present.
func (*VelocitySolution) ToLegacyVelocity ¶
func (v *VelocitySolution) ToLegacyVelocity(streamID string) tdcp.Velocity
ToLegacyVelocity converts the modern VelocitySolution to the legacy tdcp.Velocity type. This enables backward compatibility with code using the old TDCP API. The streamID parameter is application-specific and not part of the core velocity data.