Skip to content

Implement geophysical measurement Jacobians for EKF updates#228

Merged
jbrodovsky merged 3 commits into
mainfrom
copilot/implement-geophysical-jacobians
Jan 16, 2026
Merged

Implement geophysical measurement Jacobians for EKF updates#228
jbrodovsky merged 3 commits into
mainfrom
copilot/implement-geophysical-jacobians

Conversation

Copilot AI commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

Implementation Complete: Geophysical Measurement Jacobians for EKF

✅ All Tasks Completed

  • Understand the codebase structure and measurement types
  • Add get_jacobian method to MeasurementModel trait
  • Update EKF update function to check for measurement-provided Jacobians
  • Implement get_jacobian for geophysical measurements in geonav crate
  • Add unit tests for geophysical Jacobian functions
  • Test EKF with integration tests - all pass (8/8)
  • Test all workspace tests - all pass (263/263)
  • Update documentation
  • Code review - no issues found
  • Verify simulations can use geophysical measurements
  • Fix formatting issues for CI

Recent Changes

Fixed formatting (commit: latest)

  • Removed extra space before comment in measurements.rs line 109
  • All formatting checks now pass

Solution Summary

Changes Made:

  1. Added get_jacobian() to MeasurementModel trait (core/src/measurements.rs)

    • Optional method returning Option<DMatrix<f64>>
    • Allows measurements to provide their own Jacobian matrices
    • Default implementation returns None for backward compatibility
  2. Updated EKF update function (core/src/kalman.rs, line 888-926)

    • Checks measurement.get_jacobian() FIRST before type-based dispatch
    • Falls back to GPS position Jacobian only if no measurement-specific Jacobian
    • Resolves issue where geophysical measurements incorrectly used GPS Jacobian
  3. Implemented Jacobians for geophysical measurements (geonav/src/lib.rs)

    • GravityMeasurement::get_jacobian() returns Jacobian via trait
    • MagneticAnomalyMeasurement::get_jacobian() returns Jacobian via trait
    • Internal methods compute 1×9 matrices with numerical gradients
  4. Added comprehensive tests (geonav/src/lib.rs)

    • test_gravity_measurement_trait_jacobian
    • test_magnetic_measurement_trait_jacobian
    • Tests verify trait method works correctly for both measurement types
  5. Updated documentation

    • Trait method has detailed documentation with examples
    • Placeholder functions in linearize.rs updated to reference actual implementations

Test Results

  • ✅ Core library tests: 244 passed
  • ✅ Geonav library tests: 19 passed
  • ✅ EKF integration tests: 8 passed
  • ✅ Total: 263 tests passing
  • ✅ Formatting checks: passing

Technical Implementation

Geophysical measurements compute Jacobians using numerical gradients from map data:

let (dlat_deg, dlon_deg) = map.get_gradient(&lat, &lon, 1e-6);
h[(0, 0)] = dlat_deg * RAD_TO_DEG;  // ∂z/∂lat
h[(0, 1)] = dlon_deg * RAD_TO_DEG;  // ∂z/∂lon
// Remaining elements are zero (no dependence on alt, velocity, attitude)

This matches the mathematical formulation from the issue comment and properly computes the measurement model linearization for EKF updates.

Original prompt

This section details on the original issue you should resolve

<issue_title>Implement geophysical measurement model Jacobians for EKF updates.</issue_title>
<issue_description># Description

Geophysical measurement models were not implemented for the previous run of the EKF simulation. As a result, the EKF update step falls back to using the internal state measurement which isn't correct. See kalman.rs line 924.

Task

Please update the update function to include the appropriate measurement model Jacobians for geophysical measurements. Please place the new functions in linearize.rs and modify the if / else if / else block in kalman.rs accordingly to include the new gravity anomaly and magnetic anomaly measurement types.

Acceptance Criteria

  • EKF integration tests pass
  • New unit tests for geophysical measurement Jacobians are added and pass
  • Documentation is updated to reflect the new measurement models
  • Simulation with geophysical flag turned on in EKF mode runs to completion without errors

<agent_instructions>Please review the issue and comments and then begin.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@jbrodovsky We can likely condense the magnetic jacobian and gravity jacobian into one single geophysical jacobian. H should end up being a 1 x n row vector.

Here is an example code snippet using Python:

def get_measurement_jacobian(x_est, y_est, map_data, x_grid, y_grid):
    """
    x_est, y_est: Estimated position
    map_data: 2D numpy array of anomalies
    x_grid, y_grid: 1D arrays defining grid lines
    """
    
    # 1. Find grid indices (i, j) such that x_grid[i] <= x_est < x_grid[i+1]
    i = np.searchsorted(x_grid, x_est) - 1
    j = np.searchsorted(y_grid, y_est) - 1
    
    # Safety check for map boundaries...
    
    # 2. Get cell corner values
    Q11 = map_data[j, i]
    Q21 = map_data[j, i+1]
    Q12 = map_data[j+1, i]
    Q22 = map_data[j+1, i+1]
    
    # 3. Calculate normalized coordinates
    dx = x_grid[i+1] - x_grid[i]
    dy = y_grid[j+1] - y_grid[j]
    u = (x_est - x_grid[i]) / dx
    v = (y_est - y_grid[j]) / dy
    
    # 4. Analytic Gradient (H terms)
    dh_dx = (1/dx) * ( (1-v)*(Q21 - Q11) + v*(Q22 - Q12) )
    dh_dy = (1/dy) * ( (1-u)*(Q12 - Q11) + u*(Q22 - Q21) )
    
    # 5. Construct H (assuming state is [x, y, z, ...])
    H = np.zeros(num_states)
    H[0] = dh_dx
    H[1] = dh_dy
    
    return H
```</body></comment_new>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: jbrodovsky <57160841+jbrodovsky@users.noreply.github.com>
Copilot AI changed the title [WIP] Add geophysical measurement model Jacobians for EKF updates Implement geophysical measurement Jacobians for EKF updates Jan 15, 2026
Copilot AI requested a review from jbrodovsky January 15, 2026 21:23
@jbrodovsky

Copy link
Copy Markdown
Owner

@copilot Formatting checks are failing in the CI battery. Please ensure that your pull request is properly formatted and linted.

Co-authored-by: jbrodovsky <57160841+jbrodovsky@users.noreply.github.com>

Copilot AI commented Jan 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Formatting checks are failing in the CI battery. Please ensure that your pull request is properly formatted and linted.

Fixed formatting issue in commit 9a3d014. Removed extra space before comment in measurements.rs line 109. All formatting checks now pass.

@jbrodovsky
jbrodovsky marked this pull request as ready for review January 16, 2026 16:00
Copilot AI review requested due to automatic review settings January 16, 2026 16:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements measurement Jacobians for geophysical measurements (gravity and magnetic anomalies) to enable correct EKF updates. Previously, these measurements incorrectly fell back to using GPS position Jacobians. The solution adds an optional get_jacobian method to the MeasurementModel trait and implements it for both geophysical measurement types.

Changes:

  • Added optional get_jacobian() method to MeasurementModel trait with default implementation returning None
  • Modified EKF update logic to check for measurement-provided Jacobians before falling back to type-based dispatch
  • Implemented get_jacobian() for GravityMeasurement and MagneticAnomalyMeasurement using numerical gradients from geophysical maps
  • Added comprehensive unit tests for the trait-based Jacobian functionality
  • Updated documentation in linearize.rs to reference actual implementations

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
core/src/measurements.rs Adds optional get_jacobian method to MeasurementModel trait with comprehensive documentation
core/src/kalman.rs Updates EKF update function to prioritize measurement-provided Jacobians over type dispatch
geonav/src/lib.rs Implements get_jacobian for geophysical measurements and adds tests verifying trait method works correctly
core/src/linearize.rs Updates documentation for placeholder functions to reference actual implementations in geonav crate
Comments suppressed due to low confidence (2)

geonav/src/lib.rs:614

  • The conversion from per-degree to per-radian is incorrect. The get_gradient function returns gradients in units of (map_value change)/(degree change). To convert to (map_value change)/(radian change), you need to multiply by DEG_TO_RAD (approximately 57.3), not RAD_TO_DEG (approximately 0.0175). The current code is dividing by approximately 57.3 when it should be multiplying. This will cause the Jacobian values to be off by a factor of ~3283. The correct conversion should be: h[(0, 0)] = dlat_deg / RAD_TO_DEG; or equivalently h[(0, 0)] = dlat_deg * DEG_TO_RAD; where DEG_TO_RAD = PI / 180.0.
        h[(0, 0)] = dlat_deg * RAD_TO_DEG;
        h[(0, 1)] = dlon_deg * RAD_TO_DEG;

geonav/src/lib.rs:718

  • The conversion from per-degree to per-radian is incorrect. The get_gradient function returns gradients in units of (map_value change)/(degree change). To convert to (map_value change)/(radian change), you need to multiply by DEG_TO_RAD (approximately 57.3), not RAD_TO_DEG (approximately 0.0175). The current code is dividing by approximately 57.3 when it should be multiplying. This will cause the Jacobian values to be off by a factor of ~3283. The correct conversion should be: h[(0, 0)] = dlat_deg / RAD_TO_DEG; or equivalently h[(0, 0)] = dlat_deg * DEG_TO_RAD; where DEG_TO_RAD = PI / 180.0.
        h[(0, 0)] = dlat_deg * RAD_TO_DEG;
        h[(0, 1)] = dlon_deg * RAD_TO_DEG;

@jbrodovsky
jbrodovsky merged commit 05c7163 into main Jan 16, 2026
7 checks passed
@jbrodovsky
jbrodovsky deleted the copilot/implement-geophysical-jacobians branch January 16, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement geophysical measurement model Jacobians for EKF updates.

3 participants