Skip to content

Add CircularUKF filter for circular (angular) state spaces#1587

Open
Copilot wants to merge 5 commits intomainfrom
copilot/add-circular-ukf-class
Open

Add CircularUKF filter for circular (angular) state spaces#1587
Copilot wants to merge 5 commits intomainfrom
copilot/add-circular-ukf-class

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

Adds a CircularUKF class — a modified Unscented Kalman Filter for 1-D circular state spaces on [0, 2π), backed by bayesian_filters.UnscentedKalmanFilter.

New: pyrecest/filters/circular_ukf.py

  • predict_identity(gauss_sys) — additive Gaussian convolution with mod 2π wrap
  • predict_nonlinear(f, gauss_sys) — UKF sigma-point propagation through arbitrary f: [0,2π) → [0,2π)
  • update_identity(gauss_meas, z) — direct Kalman gain update with circular wrap-around handling
  • update_nonlinear(f, gauss_meas, z, measurement_periodic=False) — UKF update through nonlinear measurement function; optional periodic wrap for the measurement
  • Configurable sigma-point parameters (alpha, beta, kappa) on the constructor
from pyrecest.filters import CircularUKF
from pyrecest.distributions import GaussianDistribution
import numpy as np

f = CircularUKF()
f.filter_state = GaussianDistribution(np.array([1.0]), np.array([[0.5]]))
f.predict_nonlinear(lambda x: x, GaussianDistribution(np.array([0.0]), np.array([[0.1]])))
f.update_identity(GaussianDistribution(np.array([0.0]), np.array([[0.3]])), 1.2)

Supporting changes

  • pyrecest/filters/__init__.py — exports CircularUKF
  • pyrecest/tests/filters/test_circular_ukf.py — 10 unit tests covering all predict/update methods, including wrap-around edge cases and nonlinear functions

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/ec1df03f-95d4-47c6-85e1-edef727f014e

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ COPYPASTE jscpd yes no no 6.74s
✅ JSON prettier 2 0 0 0 0.37s
✅ JSON v8r 2 0 0 1.88s
✅ MARKDOWN markdownlint 1 0 0 0 0.53s
✅ MARKDOWN markdown-table-formatter 1 0 0 0 0.21s
✅ PYTHON bandit 249 0 0 2.74s
✅ PYTHON black 249 1 0 0 4.19s
✅ PYTHON flake8 249 0 0 1.56s
✅ PYTHON isort 249 1 0 0 0.4s
✅ PYTHON mypy 249 0 0 3.53s
✅ PYTHON pylint 249 0 0 64.36s
✅ PYTHON ruff 249 1 0 0 0.04s
✅ REPOSITORY checkov yes no no 21.76s
✅ REPOSITORY gitleaks yes no no 4.18s
✅ REPOSITORY git_diff yes no no 0.02s
✅ REPOSITORY secretlint yes no no 5.93s
✅ REPOSITORY syft yes no no 3.4s
✅ REPOSITORY trivy-sbom yes no no 2.25s
✅ REPOSITORY trufflehog yes no no 17.62s
✅ YAML prettier 4 0 0 0 0.44s
✅ YAML v8r 4 0 0 4.36s
✅ YAML yamllint 4 0 0 0.37s

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@9.4.0 --custom-flavor-setup --custom-flavor-linters PYTHON_PYLINT,PYTHON_BLACK,PYTHON_FLAKE8,PYTHON_ISORT,PYTHON_BANDIT,PYTHON_MYPY,PYTHON_RUFF,COPYPASTE_JSCPD,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_GITLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@FlorianPfaff
Copy link
Copy Markdown
Owner

@copilot Can you suppress the two warnings that megalinter found?

auto-merge was automatically disabled March 31, 2026 19:41

Head branch was pushed to by a user without write access

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 31, 2026

@copilot Can you suppress the two warnings that megalinter found?

Added # pylint: disable=too-many-arguments,too-many-positional-arguments to the _make_ukf function definition in commit 227ce38.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

Test Results

    4 files   -     8      4 suites   - 8   19m 59s ⏱️ - 2h 46m 14s
  596 tests +   63    596 ✅ +   63  0 💤 ±    0  0 ❌ ±0 
2 532 runs   - 4 076  2 532 ✅  - 2 900  0 💤  - 1 176  0 ❌ ±0 

Results for commit bda580b. ± Comparison against base commit f5c0f75.

♻️ This comment has been updated with latest results.

@FlorianPfaff
Copy link
Copy Markdown
Owner

@copilot Can you use prod(x.shape) instead of x.shape for compatibility with all interfaces? Also use flatten( ) instead of flat.

=========================== short test summary info ============================
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_predict_nonlinear_identity_function - ValueError: expected size(x) 1, but size is <built-in method size of Tensor object at 0x7f343338ea30>
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_predict_nonlinear_true_nonlinear - ValueError: expected size(x) 1, but size is <built-in method size of Tensor object at 0x7f32a8f42b20>
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_update_identity - AttributeError: 'Tensor' object has no attribute 'flat'
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_update_identity_different_measurement - AttributeError: 'Tensor' object has no attribute 'flat'
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_update_identity_nonzero_noise_mean - AttributeError: 'Tensor' object has no attribute 'flat'
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_update_nonlinear_identity_function - AttributeError: 'Tensor' object has no attribute 'flat'
FAILED pyrecest/tests/filters/test_circular_ukf.py::CircularUKFTest::test_update_nonlinear_periodic_measurement - AttributeError: 'Tensor' object has no attribute 'flat'
= 7 failed, 508 passed, 66 skipped, 5563149 warnings, 11 subtests passed in 958.51s (0:15:58) =

…rcular_ukf

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/ef6fa5e6-c48f-444f-8950-4c71eeacca32

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
auto-merge was automatically disabled April 2, 2026 11:30

Head branch was pushed to by a user without write access

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 2, 2026

@copilot Can you use prod(x.shape) instead of x.shape for compatibility with all interfaces? Also use flatten( ) instead of flat.

=========================== short test summary info ===============...

Done in commit bda580b. Changes made:

  • z.shape[0]int(prod(z.shape)) (added prod to backend imports)
  • All .flat[0].flatten()[0] (including in update_identity)
  • x[0] in fx/hx callbacks → x.flatten()[0] for robustness with different array shapes
  • ukf.x[0]ukf.x.flatten()[0] when reading back the UKF result

All 10 tests pass.

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.

2 participants