Core Module
Core utilities and constants for the Tracker Component Library.
This module provides foundational functionality used throughout the library: - Physical and mathematical constants - Input validation utilities - Array manipulation helpers compatible with MATLAB conventions - Custom exception hierarchy for consistent error handling - Optional dependency management - Module maturity classification system
- class pytcl.core.PhysicalConstants(c=299792458.0, G=6.6743e-11, h=6.62607015e-34, k_B=1.380649e-23, sigma=5.670374419e-08, e=1.602176634e-19, N_A=6.02214076e+23, R=8.314462618, g_0=9.80665)[source]
Bases:
objectContainer for fundamental physical constants.
This class groups physical constants for convenient access and documentation. All values follow CODATA 2018 recommendations.
Examples
>>> from pytcl.core.constants import PhysicalConstants >>> pc = PhysicalConstants() >>> print(f"Speed of light: {pc.c} m/s") Speed of light: 299792458.0 m/s
- __init__(c=299792458.0, G=6.6743e-11, h=6.62607015e-34, k_B=1.380649e-23, sigma=5.670374419e-08, e=1.602176634e-19, N_A=6.02214076e+23, R=8.314462618, g_0=9.80665)
- exception pytcl.core.TCLError(message, details=None)[source]
Bases:
ExceptionBase exception for all Tracker Component Library errors.
All custom exceptions in the library inherit from this class, allowing users to catch all TCL-specific errors with a single except clause.
- Parameters:
Examples
>>> raise TCLError("Something went wrong", details={"value": 42})
- exception pytcl.core.ValidationError(message, parameter=None, expected=None, actual=None, **kwargs)[source]
Bases:
TCLError,ValueErrorBase exception for input validation failures.
Raised when function inputs fail validation checks. This extends both TCLError (for TCL-specific catching) and ValueError (for compatibility with code expecting standard Python exceptions).
- Parameters:
Examples
>>> raise ValidationError( ... "Invalid matrix dimensions", ... parameter="P", ... expected="3x3 matrix", ... actual="2x4 array" ... )
- exception pytcl.core.DimensionError(message, expected_shape=None, actual_shape=None, parameter=None, **kwargs)[source]
Bases:
ValidationErrorException for array dimension and shape mismatches.
Raised when array dimensions or shapes don’t match requirements or aren’t compatible with each other.
- Parameters:
Examples
>>> raise DimensionError( ... "Covariance matrix must be 3x3", ... expected_shape=(3, 3), ... actual_shape=(2, 4), ... parameter="P" ... )
- exception pytcl.core.ParameterError(message, parameter=None, value=None, constraint=None, **kwargs)[source]
Bases:
ValidationErrorException for invalid parameter values.
Raised when a parameter value violates constraints (type, value range, allowed values, etc.).
- Parameters:
Examples
>>> raise ParameterError( ... "Variance must be positive", ... parameter="variance", ... value=-1.0, ... constraint="must be > 0" ... )
- exception pytcl.core.RangeError(message, parameter=None, value=None, min_value=None, max_value=None, **kwargs)[source]
Bases:
ValidationErrorException for out-of-range values.
Raised when a numeric value falls outside an allowed range.
- Parameters:
Examples
>>> raise RangeError( ... "Eccentricity must be in [0, 1) for elliptic orbits", ... parameter="e", ... value=1.5, ... min_value=0.0, ... max_value=1.0 ... )
- exception pytcl.core.ComputationError(message, algorithm=None, **kwargs)[source]
Bases:
TCLError,RuntimeErrorBase exception for numerical computation failures.
Raised when a numerical algorithm fails to produce a valid result. This extends RuntimeError for compatibility with code that catches standard computation errors.
- Parameters:
Examples
>>> raise ComputationError( ... "Failed to compute eigenvalues", ... algorithm="numpy.linalg.eig" ... )
- exception pytcl.core.ConvergenceError(message, algorithm=None, iterations=None, max_iterations=None, residual=None, tolerance=None, **kwargs)[source]
Bases:
ComputationErrorException for iterative algorithm convergence failures.
Raised when an iterative algorithm fails to converge within the maximum number of iterations.
- Parameters:
message (str) – Description of the convergence failure.
algorithm (str, optional) – Name of the algorithm.
iterations (int, optional) – Number of iterations performed.
max_iterations (int, optional) – Maximum iterations allowed.
residual (float, optional) – Final residual or error value.
tolerance (float, optional) – Convergence tolerance.
Examples
>>> raise ConvergenceError( ... "Kepler's equation did not converge", ... algorithm="Newton-Raphson", ... iterations=100, ... max_iterations=100, ... residual=1e-5, ... tolerance=1e-12 ... )
- exception pytcl.core.NumericalError(message, operation=None, condition_number=None, **kwargs)[source]
Bases:
ComputationErrorException for numerical stability issues.
Raised when numerical operations fail due to precision issues, overflow, underflow, or ill-conditioned computations.
- Parameters:
Examples
>>> raise NumericalError( ... "Matrix is ill-conditioned", ... operation="matrix inversion", ... condition_number=1e16 ... )
- exception pytcl.core.SingularMatrixError(message, matrix_name=None, determinant=None, **kwargs)[source]
Bases:
ComputationErrorException for singular or non-invertible matrix operations.
Raised when a matrix operation requires an invertible matrix but the matrix is singular or nearly singular.
- Parameters:
Examples
>>> raise SingularMatrixError( ... "Covariance matrix is singular", ... matrix_name="P", ... determinant=1e-20 ... )
- exception pytcl.core.StateError(message, object_type=None, current_state=None, required_state=None, **kwargs)[source]
Bases:
TCLErrorBase exception for object state violations.
Raised when an operation is attempted on an object that is not in a valid state for that operation.
- Parameters:
Examples
>>> raise StateError( ... "Cannot update without prediction", ... object_type="KalmanFilter", ... current_state="uninitialized", ... required_state="predicted" ... )
- exception pytcl.core.UninitializedError(message, object_type=None, required_initialization=None, **kwargs)[source]
Bases:
StateErrorException for uninitialized object access.
Raised when an operation requires an initialized object but the object hasn’t been properly initialized.
- Parameters:
Examples
>>> raise UninitializedError( ... "Tracker not initialized", ... object_type="SingleTargetTracker", ... required_initialization="call initialize() first" ... )
- exception pytcl.core.EmptyContainerError(message, container_type=None, operation=None, **kwargs)[source]
Bases:
StateErrorException for empty container operations.
Raised when an operation requires a non-empty container but the container has no elements.
- Parameters:
Examples
>>> raise EmptyContainerError( ... "Cannot query empty RTree", ... container_type="RTree", ... operation="nearest neighbor query" ... )
- exception pytcl.core.ConfigurationError(message, details=None)[source]
Bases:
TCLErrorBase exception for configuration and setup issues.
Raised when there are problems with algorithm configuration, method selection, or dependency availability.
- Parameters:
message (str) – Description of the configuration issue.
Examples
>>> raise ConfigurationError("Invalid filter configuration")
- exception pytcl.core.MethodError(message, method=None, valid_methods=None, **kwargs)[source]
Bases:
ConfigurationError,ValueErrorException for invalid method or algorithm selection.
Raised when an unknown or unsupported method/algorithm is specified.
- Parameters:
Examples
>>> raise MethodError( ... "Unknown assignment method", ... method="invalid_method", ... valid_methods=["hungarian", "auction", "greedy"] ... )
- exception pytcl.core.DependencyError(message, package=None, feature=None, install_command=None, **kwargs)[source]
Bases:
ConfigurationError,ImportErrorException for missing optional dependencies.
Raised when an optional dependency is required but not installed.
- Parameters:
Examples
>>> raise DependencyError( ... "plotly is required for interactive plotting", ... package="plotly", ... feature="3D visualization", ... install_command="pip install plotly" ... )
- exception pytcl.core.DataError(message, details=None)[source]
Bases:
TCLErrorBase exception for data format and structure issues.
Raised when input data has format or structural problems.
- Parameters:
message (str) – Description of the data issue.
Examples
>>> raise DataError("Invalid input data format")
- exception pytcl.core.FormatError(message, expected_format=None, actual_format=None, **kwargs)[source]
Bases:
DataError,ValueErrorException for invalid data format.
Raised when data doesn’t conform to the expected format.
- Parameters:
Examples
>>> raise FormatError( ... "Invalid TLE format", ... expected_format="69 characters per line", ... actual_format="line 1 has 65 characters" ... )
- exception pytcl.core.ParseError(message, data_type=None, position=None, reason=None, **kwargs)[source]
Bases:
DataError,ValueErrorException for data parsing failures.
Raised when data cannot be parsed or interpreted.
- Parameters:
Examples
>>> raise ParseError( ... "Failed to parse TLE checksum", ... data_type="TLE", ... position=68, ... reason="invalid checksum digit" ... )
- pytcl.core.validate_array(arr, name='array', *, dtype=None, ndim=None, shape=None, min_ndim=None, max_ndim=None, finite=False, non_negative=False, positive=False, allow_empty=True)[source]
Validate and convert an array-like input to a NumPy array.
- Parameters:
arr (array_like) – Input to validate and convert.
name (str, optional) – Name of the parameter (for error messages). Default is “array”.
dtype (type or np.dtype, optional) – If provided, ensure the array has this dtype (or can be safely cast).
ndim (int or tuple of int, optional) – If provided, ensure the array has exactly this number of dimensions. Can be a tuple to allow multiple valid dimensionalities.
shape (tuple, optional) – If provided, validate the shape. Use None for dimensions that can be any size. Example: (3, None) requires first dimension to be 3, second can be any size.
min_ndim (int, optional) – Minimum number of dimensions required.
max_ndim (int, optional) – Maximum number of dimensions allowed.
finite (bool, optional) – If True, ensure all elements are finite (no inf or nan). Default is False.
non_negative (bool, optional) – If True, ensure all elements are >= 0. Default is False.
positive (bool, optional) – If True, ensure all elements are > 0. Default is False.
allow_empty (bool, optional) – If False, raise an error for empty arrays. Default is True.
- Returns:
Validated NumPy array.
- Return type:
NDArray
- Raises:
ValidationError – If the input fails any validation check.
Examples
>>> validate_array([1, 2, 3], "position", ndim=1, finite=True) array([1, 2, 3])
>>> validate_array([[1, 2], [3, 4]], "matrix", shape=(2, 2)) array([[1, 2], [3, 4]])
- pytcl.core.validate_inputs(**param_specs)[source]
Decorator for validating multiple function parameters.
This decorator enables declarative input validation using specification objects (ArraySpec, ScalarSpec) or dictionaries of validation options.
- Parameters:
**param_specs (ArraySpec | ScalarSpec | dict) – Keyword arguments mapping parameter names to validation specs. Each spec can be: - ArraySpec: For array validation - ScalarSpec: For scalar validation - dict: Options passed to ArraySpec (for convenience)
- Returns:
Decorated function with input validation.
- Return type:
Callable
Examples
>>> @validate_inputs( ... x=ArraySpec(ndim=2, finite=True), ... P=ArraySpec(ndim=2, positive_definite=True), ... k=ScalarSpec(dtype=int, min_value=1), ... ) ... def kalman_update(x, P, z, H, R, k=1): ... # x and P are guaranteed valid here ... pass
Using dict shorthand:
>>> @validate_inputs( ... state={"ndim": 1, "finite": True}, ... covariance={"ndim": 2, "positive_definite": True}, ... ) ... def predict(state, covariance, dt): ... pass
Notes
Validation happens in the order parameters are defined in the decorator. If any validation fails, a ValidationError is raised with a descriptive message identifying the parameter and the constraint violated.
See also
ArraySpecSpecification class for array validation.
ScalarSpecSpecification class for scalar validation.
validate_arrayLower-level array validation function.
- pytcl.core.validate_same_shape(*arrays, names=None)[source]
Validate that all input arrays have the same shape.
- Parameters:
*arrays (array_like) – Arrays to compare.
names (sequence of str, optional) – Names for error messages. If not provided, uses “array_0”, “array_1”, etc.
- Raises:
ValidationError – If arrays have different shapes.
- pytcl.core.check_compatible_shapes(*shapes, names=None, dimension=None)[source]
Check that array shapes are compatible for operations.
- Parameters:
- Raises:
ValidationError – If shapes are not compatible.
Examples
>>> check_compatible_shapes((3, 4), (4, 5), names=["A", "B"], dimension=0) # Raises: A has 3 rows but B has 4 rows
>>> check_compatible_shapes((3, 4), (4, 5), names=["A", "B"]) # Passes (inner dimensions compatible for matrix multiply)
- class pytcl.core.ArraySpec(*, dtype=None, ndim=None, shape=None, min_ndim=None, max_ndim=None, finite=False, non_negative=False, positive=False, allow_empty=True, square=False, symmetric=False, positive_definite=False)[source]
Bases:
objectSpecification for array validation in @validate_inputs decorator.
- Parameters:
dtype (type or np.dtype, optional) – Required dtype.
ndim (int or tuple of int, optional) – Required dimensionality.
shape (tuple, optional) – Required shape (None for any size).
min_ndim (int, optional) – Minimum dimensions required.
max_ndim (int, optional) – Maximum dimensions allowed.
finite (bool, optional) – Require all finite values.
non_negative (bool, optional) – Require all values >= 0.
positive (bool, optional) – Require all values > 0.
allow_empty (bool, optional) – Allow empty arrays. Default True.
square (bool, optional) – Require square matrix.
symmetric (bool, optional) – Require symmetric matrix.
positive_definite (bool, optional) – Require positive definite matrix.
Examples
>>> spec = ArraySpec(ndim=2, finite=True, square=True) >>> @validate_inputs(matrix=spec) ... def process_matrix(matrix): ... return np.linalg.inv(matrix)
- class pytcl.core.ScalarSpec(*, dtype=None, min_value=None, max_value=None, finite=False, positive=False, non_negative=False)[source]
Bases:
objectSpecification for scalar validation in @validate_inputs decorator.
- Parameters:
dtype (type, optional) – Required type (int, float, etc.).
min_value (float, optional) – Minimum allowed value (inclusive).
max_value (float, optional) – Maximum allowed value (inclusive).
finite (bool, optional) – Require finite value.
positive (bool, optional) – Require value > 0.
non_negative (bool, optional) – Require value >= 0.
Examples
>>> spec = ScalarSpec(dtype=int, min_value=1, max_value=10) >>> @validate_inputs(k=spec) ... def get_k_nearest(k, data): ... return data[:k]
- pytcl.core.ensure_2d(arr, name='array', axis='auto')[source]
Ensure an array is 2D, promoting 1D arrays as needed.
- Parameters:
arr (array_like) – Input array.
name (str, optional) – Name of the parameter (for error messages).
axis ({'row', 'column', 'auto'}, optional) – How to promote 1D arrays: - ‘row’: Make 1D array a row vector (1, n) - ‘column’: Make 1D array a column vector (n, 1) - ‘auto’: Preserve as-is for 2D, use ‘column’ for 1D
- Returns:
2D array.
- Return type:
NDArray
Examples
>>> ensure_2d([1, 2, 3], axis='column') array([[1], [2], [3]])
>>> ensure_2d([1, 2, 3], axis='row') array([[1, 2, 3]])
- pytcl.core.ensure_column_vector(arr, name='vector')[source]
Ensure input is a column vector (n, 1).
- Parameters:
arr (array_like) – Input array, must be 1D or a column vector.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Column vector with shape (n, 1).
- Return type:
NDArray
Examples
>>> ensure_column_vector([1, 2, 3]) array([[1], [2], [3]])
- pytcl.core.ensure_row_vector(arr, name='vector')[source]
Ensure input is a row vector (1, n).
- Parameters:
arr (array_like) – Input array, must be 1D or a row vector.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Row vector with shape (1, n).
- Return type:
NDArray
Examples
>>> ensure_row_vector([1, 2, 3]) array([[1, 2, 3]])
- pytcl.core.ensure_square_matrix(arr, name='matrix')[source]
Ensure input is a square matrix.
- Parameters:
arr (array_like) – Input array.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Square matrix.
- Return type:
NDArray
- Raises:
ValidationError – If input is not a 2D square array.
- pytcl.core.ensure_symmetric(arr, name='matrix', rtol=1e-10, atol=1e-10)[source]
Ensure input is a symmetric matrix.
- Parameters:
- Returns:
Symmetric matrix (symmetrized if nearly symmetric).
- Return type:
NDArray
- Raises:
ValidationError – If input is not symmetric within tolerance.
- pytcl.core.ensure_positive_definite(arr, name='matrix', rtol=1e-10)[source]
Ensure input is a positive definite matrix.
- Parameters:
- Returns:
Positive definite matrix.
- Return type:
NDArray
- Raises:
ValidationError – If input is not positive definite.
- pytcl.core.wrap_to_pi(angle)[source]
Wrap angles to the interval [-π, π).
This is equivalent to MATLAB’s wrapToPi function.
- Parameters:
angle (array_like) – Angle(s) in radians.
- Returns:
Angle(s) wrapped to [-π, π).
- Return type:
NDArray
Examples
>>> wrap_to_pi(3 * np.pi) -3.141592653589793
>>> wrap_to_pi([-4, -3, -2, -1, 0, 1, 2, 3, 4]) array([ 2.28318531, -3. , -2. , -1. , 0. , 1. , 2. , 3. , -2.28318531])
- pytcl.core.wrap_to_2pi(angle)[source]
Wrap angles to the interval [0, 2π).
This is equivalent to MATLAB’s wrapTo2Pi function.
- Parameters:
angle (array_like) – Angle(s) in radians.
- Returns:
Angle(s) wrapped to [0, 2π).
- Return type:
NDArray
Examples
>>> wrap_to_2pi(-np.pi/2) 4.71238898038469
>>> wrap_to_2pi(3 * np.pi) 3.141592653589793
- pytcl.core.wrap_to_range(value, low, high)[source]
Wrap values to a specified interval [low, high).
- Parameters:
- Returns:
Value(s) wrapped to [low, high).
- Return type:
NDArray
Examples
>>> wrap_to_range(370, 0, 360) 10.0
>>> wrap_to_range(-10, 0, 360) 350.0
- pytcl.core.column_vector(arr)[source]
Convert an array-like to a column vector (n, 1).
- Parameters:
arr (array_like) – Input array.
- Returns:
Column vector with shape (n, 1).
- Return type:
NDArray
Examples
>>> column_vector([1, 2, 3]) array([[1], [2], [3]])
>>> column_vector([[1, 2, 3]]) array([[1], [2], [3]])
- pytcl.core.row_vector(arr)[source]
Convert an array-like to a row vector (1, n).
- Parameters:
arr (array_like) – Input array.
- Returns:
Row vector with shape (1, n).
- Return type:
NDArray
Examples
>>> row_vector([1, 2, 3]) array([[1, 2, 3]])
>>> row_vector([[1], [2], [3]]) array([[1, 2, 3]])
- pytcl.core.is_available(package)[source]
Check if an optional package is available.
- Parameters:
package (str) – Name of the package to check (e.g., “plotly”, “pywt”).
- Returns:
True if the package is installed and can be imported.
- Return type:
Examples
>>> from pytcl.core.optional_deps import is_available >>> if is_available("plotly"): ... from plotly import graph_objects as go ... # use plotly ... else: ... print("Plotly not available")
Notes
Results are cached for performance. Use
_clear_cache()if you need to re-check availability (e.g., after installing a package).
- pytcl.core.import_optional(module_name, *, package=None, extra=None, feature=None)[source]
Import an optional module with a helpful error message on failure.
- Parameters:
module_name (str) – Full module path to import (e.g., “plotly.graph_objects”).
package (str, optional) – Package name for error message. If not provided, extracted from module_name.
extra (str, optional) – Name of the pytcl extra that provides this dependency (e.g., “visualization”, “astronomy”).
feature (str, optional) – Description of the feature requiring this dependency.
- Returns:
module – The imported module.
- Return type:
ModuleType
- Raises:
DependencyError – If the module cannot be imported.
Examples
>>> go = import_optional( ... "plotly.graph_objects", ... package="plotly", ... extra="visualization", ... feature="3D plotting" ... )
- pytcl.core.requires(*packages, extra=None, feature=None)[source]
Decorator to mark a function as requiring optional dependencies.
When the decorated function is called, it checks if the required packages are available. If not, it raises a DependencyError with a helpful message.
- Parameters:
- Returns:
decorator – Decorator that wraps the function with dependency checking.
- Return type:
callable
Examples
>>> from pytcl.core.optional_deps import requires >>> >>> @requires("plotly", extra="visualization") ... def create_plot(data): ... import plotly.graph_objects as go ... return go.Figure(data) >>> >>> # This will raise DependencyError if plotly is not installed >>> create_plot([1, 2, 3])
Multiple packages:
>>> @requires("astropy", "jplephem", extra="astronomy") ... def compute_ephemeris(body, time): ... from astropy.time import Time ... import jplephem ... # ...
Notes
The decorator checks availability at call time, not at definition time. This allows the module to be imported even if the optional dependencies are not installed.
- pytcl.core.check_dependencies(*packages, extra=None)[source]
Check that all required packages are available.
- Parameters:
- Raises:
DependencyError – If any package is not available.
Examples
>>> from pytcl.core.optional_deps import check_dependencies >>> check_dependencies("plotly", extra="visualization") >>> # Raises DependencyError if plotly is not installed
- class pytcl.core.LazyModule(module_name, *, package=None, extra=None, feature=None)[source]
Bases:
objectA lazy module loader that imports the module on first access.
This allows optional dependencies to be “imported” at module level without triggering an import error until they’re actually used.
- Parameters:
Examples
>>> from pytcl.core.optional_deps import LazyModule >>> go = LazyModule("plotly.graph_objects", package="plotly") >>> # No import yet... >>> fig = go.Figure() # Import happens here
- pytcl.core.get_data_dir()[source]
Get the pytcl data directory for external data files.
The data directory is located at
~/.pytcl/data/by default. Can be overridden by setting thePYTCL_DATA_DIRenvironment variable.- Returns:
Path to the data directory.
- Return type:
Path
- class pytcl.core.MaturityLevel(value)[source]
Bases:
IntEnumMaturity level classification for modules.
- DEPRECATED = 0
- EXPERIMENTAL = 1
- MATURE = 2
- STABLE = 3
- pytcl.core.get_maturity(module_path)[source]
Get the maturity level of a module.
- Parameters:
module_path (str) – Module path relative to pytcl (e.g., “dynamic_estimation.kalman.linear”) or full path (e.g., “pytcl.dynamic_estimation.kalman.linear”).
- Returns:
The module’s maturity level. Returns EXPERIMENTAL if not classified.
- Return type:
Examples
>>> get_maturity("dynamic_estimation.kalman.linear") <MaturityLevel.STABLE: 3> >>> get_maturity("pytcl.core.constants") <MaturityLevel.STABLE: 3>
- pytcl.core.get_modules_by_maturity(level)[source]
Get all modules at a specific maturity level.
- Parameters:
level (MaturityLevel) – The maturity level to filter by.
- Returns:
Module paths at the specified maturity level.
- Return type:
Examples
>>> stable = get_modules_by_maturity(MaturityLevel.STABLE) >>> "core.constants" in stable True
- pytcl.core.get_maturity_summary()[source]
Get a summary count of modules at each maturity level.
- Returns:
Mapping from MaturityLevel to count of modules.
- Return type:
Examples
>>> summary = get_maturity_summary() >>> summary[MaturityLevel.STABLE] > 0 True
- pytcl.core.is_stable(module_path)[source]
Check if a module is stable (production-ready with frozen API).
- Parameters:
module_path (str) – Module path to check.
- Returns:
True if the module is stable.
- Return type:
Examples
>>> is_stable("dynamic_estimation.kalman.linear") True >>> is_stable("terrain.dem") False
- pytcl.core.is_production_ready(module_path)[source]
Check if a module is production-ready (STABLE or MATURE).
- Parameters:
module_path (str) – Module path to check.
- Returns:
True if the module is STABLE or MATURE.
- Return type:
Examples
>>> is_production_ready("dynamic_estimation.kalman.linear") True >>> is_production_ready("dynamic_estimation.imm") True >>> is_production_ready("terrain.dem") False
Constants
Physical and mathematical constants used throughout the Tracker Component Library.
This module provides standardized values for physical constants, with references to their sources. Constants are provided as module-level variables for convenience and as a PhysicalConstants class for documentation and grouping.
References
- pytcl.core.constants.GRAVITATIONAL_CONSTANT: Final[float] = 6.6743e-11
Newtonian gravitational constant [m^3 kg^-1 s^-2]
- pytcl.core.constants.STEFAN_BOLTZMANN_CONSTANT: Final[float] = 5.670374419e-08
Stefan-Boltzmann constant [W m^-2 K^-4]
- pytcl.core.constants.UNIVERSAL_GAS_CONSTANT: Final[float] = 8.314462618
Universal gas constant [J mol^-1 K^-1]
- pytcl.core.constants.STANDARD_ATMOSPHERE: Final[float] = 101325.0
Standard atmosphere pressure [Pa]
- pytcl.core.constants.EARTH_SEMI_MAJOR_AXIS: Final[float] = 6378137.0
Semi-major axis (equatorial radius) [m]
- pytcl.core.constants.EARTH_SEMI_MINOR_AXIS: Final[float] = 6356752.314245
Semi-minor axis (polar radius) [m]
- pytcl.core.constants.EARTH_FLATTENING: Final[float] = 0.0033528106647474805
Flattening factor (dimensionless)
- pytcl.core.constants.EARTH_ECCENTRICITY_SQ: Final[float] = 0.0066943799901413165
First eccentricity squared
- pytcl.core.constants.EARTH_ECCENTRICITY_PRIME_SQ: Final[float] = 0.006739496742276434
Second eccentricity squared
- pytcl.core.constants.EARTH_ROTATION_RATE: Final[float] = 7.292115e-05
Earth rotation rate [rad/s] (IERS Conventions 2010)
- pytcl.core.constants.EARTH_GM: Final[float] = 398600441800000.0
Earth’s gravitational parameter GM [m^3/s^2] (WGS84)
- pytcl.core.constants.EARTH_GM_EGM2008: Final[float] = 398600441500000.0
Earth’s gravitational parameter GM [m^3/s^2] (EGM2008, includes atmosphere)
- pytcl.core.constants.EARTH_MEAN_ANGULAR_VELOCITY: Final[float] = 7.2921151467e-05
Mean angular velocity of Earth [rad/s]
- pytcl.core.constants.EARTH_MEAN_RADIUS: Final[float] = 6371000.0
Nominal mean Earth radius [m] (IUGG)
- pytcl.core.constants.STANDARD_GRAVITY: Final[float] = 9.80665
Standard gravitational acceleration at sea level [m/s^2]
- pytcl.core.constants.SECONDS_PER_JULIAN_CENTURY: Final[float] = 3155760000.0
Seconds per Julian century
- pytcl.core.constants.DEG_TO_RAD: Final[float] = 0.017453292519943295
Degrees to radians conversion factor
- pytcl.core.constants.RAD_TO_DEG: Final[float] = 57.29577951308232
Radians to degrees conversion factor
- pytcl.core.constants.ARCSEC_TO_RAD: Final[float] = 4.84813681109536e-06
Arcseconds to radians conversion factor
- pytcl.core.constants.RAD_TO_ARCSEC: Final[float] = 206264.80624709636
Radians to arcseconds conversion factor
- class pytcl.core.constants.EllipsoidParameters(a, f, GM, omega, name='Custom')[source]
Bases:
objectParameters defining a reference ellipsoid.
- Properties
- ----------
- __init__(a, f, GM, omega, name='Custom')
- class pytcl.core.constants.PhysicalConstants(c=299792458.0, G=6.6743e-11, h=6.62607015e-34, k_B=1.380649e-23, sigma=5.670374419e-08, e=1.602176634e-19, N_A=6.02214076e+23, R=8.314462618, g_0=9.80665)[source]
Bases:
objectContainer for fundamental physical constants.
This class groups physical constants for convenient access and documentation. All values follow CODATA 2018 recommendations.
Examples
>>> from pytcl.core.constants import PhysicalConstants >>> pc = PhysicalConstants() >>> print(f"Speed of light: {pc.c} m/s") Speed of light: 299792458.0 m/s
- __init__(c=299792458.0, G=6.6743e-11, h=6.62607015e-34, k_B=1.380649e-23, sigma=5.670374419e-08, e=1.602176634e-19, N_A=6.02214076e+23, R=8.314462618, g_0=9.80665)
- pytcl.core.constants.WGS84: Final[EllipsoidParameters] = EllipsoidParameters(a=6378137.0, f=0.0033528106647474805, GM=398600441800000.0, omega=7.292115e-05, name='WGS84')
WGS84 ellipsoid parameters
- pytcl.core.constants.GRS80: Final[EllipsoidParameters] = EllipsoidParameters(a=6378137.0, f=0.003352810681182319, GM=398600500000000.0, omega=7.292115e-05, name='GRS80')
GRS80 ellipsoid parameters
- pytcl.core.constants.CLARKE1866: Final[EllipsoidParameters] = EllipsoidParameters(a=6378206.4, f=0.0033900753039276207, GM=398600500000000.0, omega=7.292115e-05, name='Clarke1866')
Clarke 1866 ellipsoid (NAD27)
- pytcl.core.constants.SPHERE_EARTH: Final[EllipsoidParameters] = EllipsoidParameters(a=6371000.0, f=0.0, GM=398600441800000.0, omega=7.292115e-05, name='Sphere')
Sphere with Earth mean radius
- pytcl.core.constants.ASTRONOMICAL_UNIT: Final[float] = 149597870700.0
Astronomical Unit [m] (IAU 2012)
- pytcl.core.constants.SUN_GM: Final[float] = 1.32712440018e+20
Sun gravitational parameter [m^3/s^2]
- pytcl.core.constants.MOON_GM: Final[float] = 4902869500000.0
Moon gravitational parameter [m^3/s^2]
- pytcl.core.constants.c = 299792458.0
Alias for SPEED_OF_LIGHT
- pytcl.core.constants.G = 6.6743e-11
Alias for GRAVITATIONAL_CONSTANT
Array Utilities
Array utility functions for the Tracker Component Library.
This module provides array manipulation functions that mirror MATLAB behavior, making it easier to port algorithms while maintaining Pythonic interfaces.
- pytcl.core.array_utils.wrap_to_pi(angle)[source]
Wrap angles to the interval [-π, π).
This is equivalent to MATLAB’s wrapToPi function.
- Parameters:
angle (array_like) – Angle(s) in radians.
- Returns:
Angle(s) wrapped to [-π, π).
- Return type:
NDArray
Examples
>>> wrap_to_pi(3 * np.pi) -3.141592653589793
>>> wrap_to_pi([-4, -3, -2, -1, 0, 1, 2, 3, 4]) array([ 2.28318531, -3. , -2. , -1. , 0. , 1. , 2. , 3. , -2.28318531])
- pytcl.core.array_utils.wrap_to_2pi(angle)[source]
Wrap angles to the interval [0, 2π).
This is equivalent to MATLAB’s wrapTo2Pi function.
- Parameters:
angle (array_like) – Angle(s) in radians.
- Returns:
Angle(s) wrapped to [0, 2π).
- Return type:
NDArray
Examples
>>> wrap_to_2pi(-np.pi/2) 4.71238898038469
>>> wrap_to_2pi(3 * np.pi) 3.141592653589793
- pytcl.core.array_utils.wrap_to_range(value, low, high)[source]
Wrap values to a specified interval [low, high).
- Parameters:
- Returns:
Value(s) wrapped to [low, high).
- Return type:
NDArray
Examples
>>> wrap_to_range(370, 0, 360) 10.0
>>> wrap_to_range(-10, 0, 360) 350.0
- pytcl.core.array_utils.wrap_to_pm180(angle)[source]
Wrap angles in degrees to the interval [-180, 180).
- Parameters:
angle (array_like) – Angle(s) in degrees.
- Returns:
Angle(s) wrapped to [-180, 180) degrees.
- Return type:
NDArray
Examples
>>> wrap_to_pm180(270) -90.0
- pytcl.core.array_utils.wrap_to_360(angle)[source]
Wrap angles in degrees to the interval [0, 360).
- Parameters:
angle (array_like) – Angle(s) in degrees.
- Returns:
Angle(s) wrapped to [0, 360) degrees.
- Return type:
NDArray
Examples
>>> wrap_to_360(-90) 270.0
- pytcl.core.array_utils.column_vector(arr)[source]
Convert an array-like to a column vector (n, 1).
- Parameters:
arr (array_like) – Input array.
- Returns:
Column vector with shape (n, 1).
- Return type:
NDArray
Examples
>>> column_vector([1, 2, 3]) array([[1], [2], [3]])
>>> column_vector([[1, 2, 3]]) array([[1], [2], [3]])
- pytcl.core.array_utils.row_vector(arr)[source]
Convert an array-like to a row vector (1, n).
- Parameters:
arr (array_like) – Input array.
- Returns:
Row vector with shape (1, n).
- Return type:
NDArray
Examples
>>> row_vector([1, 2, 3]) array([[1, 2, 3]])
>>> row_vector([[1], [2], [3]]) array([[1, 2, 3]])
- pytcl.core.array_utils.vec(arr, order='F')[source]
Vectorize a matrix (stack columns or rows into a single column).
This mirrors MATLAB’s vec operator which stacks columns.
- Parameters:
arr (array_like) – Input matrix.
order ({'F', 'C'}, optional) – ‘F’ (default): Stack columns (MATLAB-style, column-major). ‘C’: Stack rows (row-major).
- Returns:
Column vector with shape (m*n, 1).
- Return type:
NDArray
Examples
>>> A = np.array([[1, 2], [3, 4]]) >>> vec(A) # Stack columns: [1, 3, 2, 4] array([[1], [3], [2], [4]])
>>> vec(A, order='C') # Stack rows: [1, 2, 3, 4] array([[1], [2], [3], [4]])
- pytcl.core.array_utils.unvec(v, shape, order='F')[source]
Reshape a vector back into a matrix.
Inverse of the vec operation.
- Parameters:
- Returns:
Matrix with specified shape.
- Return type:
NDArray
Examples
>>> import numpy as np >>> from pytcl.core.array_utils import unvec >>> v = np.array([1, 2, 3, 4, 5, 6]) >>> M = unvec(v, (2, 3)) >>> M array([[1, 3, 5], [2, 4, 6]])
- pytcl.core.array_utils.block_diag(*arrays)[source]
Create a block diagonal matrix from provided arrays.
Equivalent to MATLAB’s blkdiag function.
- Parameters:
*arrays (array_like) – Input arrays to place on the diagonal.
- Returns:
Block diagonal matrix.
- Return type:
NDArray
Examples
>>> A = np.array([[1, 2], [3, 4]]) >>> B = np.array([[5]]) >>> block_diag(A, B) array([[1, 2, 0], [3, 4, 0], [0, 0, 5]])
- pytcl.core.array_utils.skew_symmetric(v)[source]
Create a 3x3 skew-symmetric matrix from a 3D vector.
The skew-symmetric matrix [v]× satisfies: [v]× @ u = v × u (cross product).
- Parameters:
v (array_like) – 3-element vector.
- Returns:
3x3 skew-symmetric matrix.
- Return type:
NDArray
Examples
>>> v = [1, 2, 3] >>> S = skew_symmetric(v) >>> S array([[ 0., -3., 2.], [ 3., 0., -1.], [-2., 1., 0.]])
>>> u = [4, 5, 6] >>> np.allclose(S @ u, np.cross(v, u)) True
- pytcl.core.array_utils.unskew(S)[source]
Extract the vector from a 3x3 skew-symmetric matrix.
Inverse of skew_symmetric.
- Parameters:
S (array_like) – 3x3 skew-symmetric matrix.
- Returns:
3-element vector.
- Return type:
NDArray
Examples
>>> import numpy as np >>> from pytcl.core.array_utils import unskew, skew_symmetric >>> v = np.array([1, 2, 3]) >>> S = skew_symmetric(v) >>> v_recovered = unskew(S) >>> np.allclose(v, v_recovered) True
- pytcl.core.array_utils.normalize_vector(v, axis=None, return_norm=False)[source]
Normalize vector(s) to unit length.
- Parameters:
- Returns:
v_normalized (NDArray) – Unit vector(s).
norm (NDArray, optional) – Original norm(s), only returned if return_norm=True.
- Return type:
ndarray[tuple[Any, …], dtype[floating[Any]]] | tuple[ndarray[tuple[Any, …], dtype[floating[Any]]], ndarray[tuple[Any, …], dtype[floating[Any]]]]
Examples
>>> normalize_vector([3, 4]) array([0.6, 0.8])
>>> v_unit, norm = normalize_vector([3, 4], return_norm=True) >>> norm 5.0
- pytcl.core.array_utils.outer_product(a, b)[source]
Compute the outer product of two vectors.
- Parameters:
a (array_like) – First vector (m,).
b (array_like) – Second vector (n,).
- Returns:
Outer product matrix (m, n).
- Return type:
NDArray
Examples
>>> outer_product([1, 2], [3, 4, 5]) array([[ 3, 4, 5], [ 6, 8, 10]])
- pytcl.core.array_utils.repmat(arr, m, n)[source]
Replicate and tile an array.
Equivalent to MATLAB’s repmat function.
- Parameters:
- Returns:
Tiled array.
- Return type:
NDArray
Examples
>>> repmat([1, 2], 2, 3) array([[1, 2, 1, 2, 1, 2], [1, 2, 1, 2, 1, 2]])
- pytcl.core.array_utils.meshgrid_ij(*xi, indexing='ij')[source]
Create coordinate matrices from coordinate vectors.
Wrapper around np.meshgrid with ‘ij’ indexing as default (MATLAB-style).
- Parameters:
*xi (array_like) – 1-D arrays representing coordinates.
indexing ({'ij', 'xy'}, optional) – Cartesian (‘xy’, default numpy) or matrix (‘ij’, MATLAB-style) indexing. Default is ‘ij’.
- Returns:
Coordinate matrices.
- Return type:
tuple of NDArray
Examples
>>> import numpy as np >>> from pytcl.core.array_utils import meshgrid_ij >>> x = np.array([1, 2, 3]) >>> y = np.array([4, 5]) >>> X, Y = meshgrid_ij(x, y) >>> X array([[1, 2, 3], [1, 2, 3]]) >>> Y array([[4, 4, 4], [5, 5, 5]])
- pytcl.core.array_utils.is_positive_definite(A, tol=1e-10)[source]
Check if a matrix is positive definite.
- Parameters:
A (array_like) – Square matrix to check.
tol (float, optional) – Tolerance for eigenvalue check. Default is 1e-10.
- Returns:
True if matrix is positive definite.
- Return type:
Examples
>>> A = np.array([[4, 2], [2, 5]]) >>> is_positive_definite(A) True
- pytcl.core.array_utils.nearest_positive_definite(A)[source]
Find the nearest positive definite matrix.
Uses the method from Higham (1988) “Computing a Nearest Symmetric Positive Semidefinite Matrix”.
- Parameters:
A (array_like) – Input matrix.
- Returns:
Nearest positive definite matrix.
- Return type:
NDArray
Examples
>>> import numpy as np >>> from pytcl.core.array_utils import nearest_positive_definite >>> A = np.array([[1, -2], [-2, 1]]) # Not PD >>> A_pd = nearest_positive_definite(A) >>> np.all(np.linalg.eigvalsh(A_pd) > 0) True
- pytcl.core.array_utils.safe_cholesky(A, max_attempts=10)[source]
Compute Cholesky decomposition with fallback for near-singular matrices.
If standard Cholesky fails, attempts to find nearest positive definite matrix.
- Parameters:
A (array_like) – Positive definite matrix.
max_attempts (int, optional) – Maximum regularization attempts. Default is 10.
- Returns:
Lower triangular Cholesky factor L such that A = L @ L.T
- Return type:
NDArray
- Raises:
np.linalg.LinAlgError – If Cholesky decomposition fails after all attempts.
Examples
>>> import numpy as np >>> from pytcl.core.array_utils import safe_cholesky >>> A = np.array([[4, 2], [2, 3]]) # PD matrix >>> L = safe_cholesky(A) >>> np.allclose(L @ L.T, A) True
Validation
Input validation utilities for the Tracker Component Library.
This module provides decorators and functions for validating input arrays, ensuring consistent behavior across the library and providing helpful error messages when inputs don’t meet requirements.
- pytcl.core.validation.validate_array(arr, name='array', *, dtype=None, ndim=None, shape=None, min_ndim=None, max_ndim=None, finite=False, non_negative=False, positive=False, allow_empty=True)[source]
Validate and convert an array-like input to a NumPy array.
- Parameters:
arr (array_like) – Input to validate and convert.
name (str, optional) – Name of the parameter (for error messages). Default is “array”.
dtype (type or np.dtype, optional) – If provided, ensure the array has this dtype (or can be safely cast).
ndim (int or tuple of int, optional) – If provided, ensure the array has exactly this number of dimensions. Can be a tuple to allow multiple valid dimensionalities.
shape (tuple, optional) – If provided, validate the shape. Use None for dimensions that can be any size. Example: (3, None) requires first dimension to be 3, second can be any size.
min_ndim (int, optional) – Minimum number of dimensions required.
max_ndim (int, optional) – Maximum number of dimensions allowed.
finite (bool, optional) – If True, ensure all elements are finite (no inf or nan). Default is False.
non_negative (bool, optional) – If True, ensure all elements are >= 0. Default is False.
positive (bool, optional) – If True, ensure all elements are > 0. Default is False.
allow_empty (bool, optional) – If False, raise an error for empty arrays. Default is True.
- Returns:
Validated NumPy array.
- Return type:
NDArray
- Raises:
ValidationError – If the input fails any validation check.
Examples
>>> validate_array([1, 2, 3], "position", ndim=1, finite=True) array([1, 2, 3])
>>> validate_array([[1, 2], [3, 4]], "matrix", shape=(2, 2)) array([[1, 2], [3, 4]])
- pytcl.core.validation.ensure_2d(arr, name='array', axis='auto')[source]
Ensure an array is 2D, promoting 1D arrays as needed.
- Parameters:
arr (array_like) – Input array.
name (str, optional) – Name of the parameter (for error messages).
axis ({'row', 'column', 'auto'}, optional) – How to promote 1D arrays: - ‘row’: Make 1D array a row vector (1, n) - ‘column’: Make 1D array a column vector (n, 1) - ‘auto’: Preserve as-is for 2D, use ‘column’ for 1D
- Returns:
2D array.
- Return type:
NDArray
Examples
>>> ensure_2d([1, 2, 3], axis='column') array([[1], [2], [3]])
>>> ensure_2d([1, 2, 3], axis='row') array([[1, 2, 3]])
- pytcl.core.validation.ensure_column_vector(arr, name='vector')[source]
Ensure input is a column vector (n, 1).
- Parameters:
arr (array_like) – Input array, must be 1D or a column vector.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Column vector with shape (n, 1).
- Return type:
NDArray
Examples
>>> ensure_column_vector([1, 2, 3]) array([[1], [2], [3]])
- pytcl.core.validation.ensure_row_vector(arr, name='vector')[source]
Ensure input is a row vector (1, n).
- Parameters:
arr (array_like) – Input array, must be 1D or a row vector.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Row vector with shape (1, n).
- Return type:
NDArray
Examples
>>> ensure_row_vector([1, 2, 3]) array([[1, 2, 3]])
- pytcl.core.validation.ensure_square_matrix(arr, name='matrix')[source]
Ensure input is a square matrix.
- Parameters:
arr (array_like) – Input array.
name (str, optional) – Name of the parameter (for error messages).
- Returns:
Square matrix.
- Return type:
NDArray
- Raises:
ValidationError – If input is not a 2D square array.
- pytcl.core.validation.ensure_symmetric(arr, name='matrix', rtol=1e-10, atol=1e-10)[source]
Ensure input is a symmetric matrix.
- Parameters:
- Returns:
Symmetric matrix (symmetrized if nearly symmetric).
- Return type:
NDArray
- Raises:
ValidationError – If input is not symmetric within tolerance.
- pytcl.core.validation.ensure_positive_definite(arr, name='matrix', rtol=1e-10)[source]
Ensure input is a positive definite matrix.
- Parameters:
- Returns:
Positive definite matrix.
- Return type:
NDArray
- Raises:
ValidationError – If input is not positive definite.
- pytcl.core.validation.validate_same_shape(*arrays, names=None)[source]
Validate that all input arrays have the same shape.
- Parameters:
*arrays (array_like) – Arrays to compare.
names (sequence of str, optional) – Names for error messages. If not provided, uses “array_0”, “array_1”, etc.
- Raises:
ValidationError – If arrays have different shapes.
- pytcl.core.validation.validated_array_input(param_name, *, dtype=None, ndim=None, shape=None, finite=False)[source]
Decorator factory for validating a specific array parameter.
- Parameters:
param_name (str) – Name of the parameter to validate.
dtype (type or np.dtype, optional) – Required dtype.
ndim (int or tuple of int, optional) – Required number of dimensions.
shape (tuple, optional) – Required shape (None for any size in a dimension).
finite (bool, optional) – If True, require all finite values.
- Returns:
Decorator that validates the specified parameter.
- Return type:
Callable
Examples
>>> @validated_array_input("x", ndim=1, finite=True) ... def my_func(x, y=1): ... return np.sum(x) + y
- class pytcl.core.validation.ArraySpec(*, dtype=None, ndim=None, shape=None, min_ndim=None, max_ndim=None, finite=False, non_negative=False, positive=False, allow_empty=True, square=False, symmetric=False, positive_definite=False)[source]
Bases:
objectSpecification for array validation in @validate_inputs decorator.
- Parameters:
dtype (type or np.dtype, optional) – Required dtype.
ndim (int or tuple of int, optional) – Required dimensionality.
shape (tuple, optional) – Required shape (None for any size).
min_ndim (int, optional) – Minimum dimensions required.
max_ndim (int, optional) – Maximum dimensions allowed.
finite (bool, optional) – Require all finite values.
non_negative (bool, optional) – Require all values >= 0.
positive (bool, optional) – Require all values > 0.
allow_empty (bool, optional) – Allow empty arrays. Default True.
square (bool, optional) – Require square matrix.
symmetric (bool, optional) – Require symmetric matrix.
positive_definite (bool, optional) – Require positive definite matrix.
Examples
>>> spec = ArraySpec(ndim=2, finite=True, square=True) >>> @validate_inputs(matrix=spec) ... def process_matrix(matrix): ... return np.linalg.inv(matrix)
- class pytcl.core.validation.ScalarSpec(*, dtype=None, min_value=None, max_value=None, finite=False, positive=False, non_negative=False)[source]
Bases:
objectSpecification for scalar validation in @validate_inputs decorator.
- Parameters:
dtype (type, optional) – Required type (int, float, etc.).
min_value (float, optional) – Minimum allowed value (inclusive).
max_value (float, optional) – Maximum allowed value (inclusive).
finite (bool, optional) – Require finite value.
positive (bool, optional) – Require value > 0.
non_negative (bool, optional) – Require value >= 0.
Examples
>>> spec = ScalarSpec(dtype=int, min_value=1, max_value=10) >>> @validate_inputs(k=spec) ... def get_k_nearest(k, data): ... return data[:k]
- pytcl.core.validation.validate_inputs(**param_specs)[source]
Decorator for validating multiple function parameters.
This decorator enables declarative input validation using specification objects (ArraySpec, ScalarSpec) or dictionaries of validation options.
- Parameters:
**param_specs (ArraySpec | ScalarSpec | dict) – Keyword arguments mapping parameter names to validation specs. Each spec can be: - ArraySpec: For array validation - ScalarSpec: For scalar validation - dict: Options passed to ArraySpec (for convenience)
- Returns:
Decorated function with input validation.
- Return type:
Callable
Examples
>>> @validate_inputs( ... x=ArraySpec(ndim=2, finite=True), ... P=ArraySpec(ndim=2, positive_definite=True), ... k=ScalarSpec(dtype=int, min_value=1), ... ) ... def kalman_update(x, P, z, H, R, k=1): ... # x and P are guaranteed valid here ... pass
Using dict shorthand:
>>> @validate_inputs( ... state={"ndim": 1, "finite": True}, ... covariance={"ndim": 2, "positive_definite": True}, ... ) ... def predict(state, covariance, dt): ... pass
Notes
Validation happens in the order parameters are defined in the decorator. If any validation fails, a ValidationError is raised with a descriptive message identifying the parameter and the constraint violated.
See also
ArraySpecSpecification class for array validation.
ScalarSpecSpecification class for scalar validation.
validate_arrayLower-level array validation function.
- pytcl.core.validation.check_compatible_shapes(*shapes, names=None, dimension=None)[source]
Check that array shapes are compatible for operations.
- Parameters:
- Raises:
ValidationError – If shapes are not compatible.
Examples
>>> check_compatible_shapes((3, 4), (4, 5), names=["A", "B"], dimension=0) # Raises: A has 3 rows but B has 4 rows
>>> check_compatible_shapes((3, 4), (4, 5), names=["A", "B"]) # Passes (inner dimensions compatible for matrix multiply)