Skip to content

feat: Add runtime validation for option types#1466

Open
robertlipe wants to merge 8 commits into
masterfrom
kalman-2
Open

feat: Add runtime validation for option types#1466
robertlipe wants to merge 8 commits into
masterfrom
kalman-2

Conversation

@robertlipe
Copy link
Copy Markdown
Collaborator

This PR introduces a runtime validation mechanism to catch mismatches between declared and actual option types in arglist_t tables.

Key changes:

  • A get_type() virtual method was added to the Option class hierarchy to enable runtime type identification.
  • Validation logic was added to Vecs::validate_args to compare the declared argtype with the actual Option type, calling gbFatal on a mismatch.
  • This addresses an issue where an incorrect argtype in the kalman filter's options was not caught at startup.
  • The Option class hierarchy was refactored to fix various build errors, including breaking a circular dependency between defs.h and option.h.

@robertlipe robertlipe closed this Oct 1, 2025
@robertlipe robertlipe reopened this Oct 1, 2025
@robertlipe robertlipe force-pushed the kalman-2 branch 8 times, most recently from aeed048 to fb863d5 Compare October 1, 2025 08:50
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Oct 1, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.01% 77.50%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (cd991b4) 27512 17189 62.48%
Head commit (29c3155) 55103 (+27591) 34435 (+17246) 62.49% (+0.01%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#1466) 40 31 77.50%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

@robertlipe robertlipe force-pushed the kalman-2 branch 12 times, most recently from fd9e565 to f39325f Compare October 1, 2025 09:45
Add a `get_type()` virtual method to the `Option` class hierarchy to
enable runtime type identification.

Use this new method in `Vecs::validate_args` to validate that the
`argtype` specified in `arglist_t` tables matches the actual type of the
`Option` object. This will catch configuration errors at startup, such
as the one that was present in the kalman filter.

This change also includes several fixes to the `Option` class hierarchy
to resolve build errors that surfaced during development, including
breaking a circular dependency between `defs.h` and `option.h`.
This commit introduces several refinements to the Kalman filter
and updates its associated test suite.

Key changes include:
- **Pre-filtering Logic:** The pre-filtering logic in `kalman.cc` has been
  adjusted to use the configurable `gap_factor_` instead of a hardcoded
  value, and the condition for gap detection has been changed from `>` to `>=`
  to ensure more aggressive filtering of gaps.
- **Profile Differentiation:** The `MAX_REASONABLE_SPEED` for the `running`
  profile in `kalman.cc` has been set to `10.0` to differentiate its behavior
  from the `cycling` profile, allowing for more distinct testing.
- **Test Suite Enhancement:**
  - `testo.d/kalman.test` has been updated to include a new test case for
    `kalman_seen_track.gpx` with `gap_factor=10.0`, ensuring comprehensive
    testing of different `gap_factor` values.
  - Duplicate test cases in `testo.d/kalman.test` have been removed.
  - The `kalman_seen_track_out.gpx` and `kalman_out_running.gpx` reference
    files have been regenerated to reflect the updated filter behavior and
    `GPSBABEL_FREEZE_TIME=y` consistency.
- **Documentation Updates:**
  - `kalman.h` has been updated to correctly declare `gap_factor_`.
  - `reference/filter0.txt`, `reference/filter1.txt`, and `reference/help.txt`
    have been updated to reflect the new Kalman filter options and their `ARGTYPE`s.
  - New XML documentation files for Kalman filter options have been added
    (`xmldoc/filters/options/kalman-*.xml`).
  - `xmldoc/formats/options/igc-VAT.xml` has been created.
  - `CMakeLists.txt` has been updated to include `src/core/matrix.cc` and `src/core/matrix.h`.
Comment thread src/core/nvector.cc
@robertlipe
Copy link
Copy Markdown
Collaborator Author

Oof. Yes. Thers

@robertlipe
Copy link
Copy Markdown
Collaborator Author

Oof. Yes. Theres way more stuff in this or than I meant to expose. I'll integrate that and fix the fallout.

Thanx for a actually reading my scribbling.

Copy link
Copy Markdown
Collaborator

@tsteven4 tsteven4 left a comment

Choose a reason for hiding this comment

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

This review addresses extraneous changes in this PR, but doesn't get into the intent of the PR. Please address these issues, and merge with master, and I will do an additional review of the core of this PR, the addition of a kalman filter.

Once we get all the extraneous things flagged out I don't think you need to break this up into multiple PRs.

Comment thread defs.h
#include "inifile.h" // for inifile_t
#include "option.h"
#include "session.h" // for session_t

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As the mismatched options are already detectable at test please revert all changes to this file.

@@ -0,0 +1 @@
<para>Write timestamps with offset x to UTC time.</para>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is outside of scope of the kalman filter.

@@ -0,0 +1 @@
<para>Include Total Energy Variometer in IGC output.</para>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is outside of scope of the kalman filter.

@@ -0,0 +1 @@
<para>Include True Track in IGC output.</para>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is outside of scope of the kalman filter.

@@ -0,0 +1 @@
<para>Include True Airspeed in IGC output.</para>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is outside of scope of the kalman filter.this is outside of scope of the kalman filter.

Comment thread option.cc
{
return allow_trailing_data_;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As the mismatched options are already detectable at test please revert all changes to this file.

Comment thread GEMINI.md
@@ -0,0 +1,140 @@
This is GPSBabel, known publicly as https://gpsbabel.org and
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we really want to add this file? If so, it needs work. For example we may or may not use Makefiles, and if we do they need to be generated, so the Quick build instructions are wrong.

Comment thread gemini-tmp/kalman.h
@@ -0,0 +1,110 @@
/*
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

the whole gemini-tmp directory shouldn't be included.

Comment thread gemini-tmp/kalman.cc
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

the whole gemini-tmp directory shouldn't be included.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This file shouldn't be changed, please restore it.

Comment thread xmldoc/filters/kalman.xml
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs contentneeds content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs content

Comment thread testo.d/kalman.test
@@ -0,0 +1,40 @@
rm -f ${TMPDIR}/kalman_out.gpx
./gpsbabel -i gpx -f ${REFERENCE}/track/kalman_in.gpx -x kalman -o gpx -F ${TMPDIR}/kalman_in_filtered.gpx -o gpx -F ${TMPDIR}/kalman_out_filtered.gpx
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These should all be just gpsbabel, not ./gpsbabel. In test gpsbabel is a function.

Comment thread kalman.h
Comment thread kalman.cc
Comment on lines +59 to +60
// global_opts.debug_level = debugLevelInfo; // TODO: get from options
global_opts.debug_level = std::max(global_opts.debug_level, debugLevelInfo); // TODO: get from options
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think you are ready to just let main set global_options.debug_level, eliminating the body of this ctor.

Comment thread kalman.cc
@robertlipe
Copy link
Copy Markdown
Collaborator Author

It's hopefully clear that I never intended a majority of this PR to BE IN this PR and certainly not to be pushed publicly. Sorry that you've invested so much in it. I should have marked it as a draft, but I knew that only one person ever reads this stuff and thought he wasn't going to see it.

Then I got distracted and you invested in this. Sorry.

Whether I pull 80% of this into other PRs or pull the 20% of this into a single PRthat's actually worth human attention seemed like 6's (six of one, half a dozen...) at the time. I was choosing the latter and starting to break it into smaller pieces that can go in one at a time, though ordering might be tricky.

Things like gbDebug (or whatever we choose to call it) are arguably projects of their own. Maybe each module should have a Logging object that persists that could store its debugging level) inside it so that input could have one level and output could have its own level and we wouldn't keep creating static instances of these empty objects to pretend they're not globals. Then all the member calls become logging_.Warning(foo) and logging_.Debug(6, ...) and such. Maybe it.s logging_.(Warning, foo) vs. logging_.(Debug, 6, foo) or such. I've really not explored that. It's an example of a half-baked idea that just fell out during this process.

I had two big downfalls:

  1. Getting tired of being asked every time "can I run git diff? Can I run git reset" and answering 'y'. Chosing "don't ask me again" also gives it permission to do anything possible with git, like make more branches, push the tree, bring in all the scribbly files that yuou might exist in my ~/src/gpsbabel space, etc.
  2. Trying overlapping projects in the same workspace. This human can (and has for years) easily keeps separate "those files that have needed doc for years" and such and while it's convenient to have overlapping agents working on things, I've now learned that it makes a disastrous mess of things, owing somewhat to # 1, that then becomes Real Work to separate back apart.

I'm finally happy with the results of kalman.cc - I just have to do the work to get it product-worthy. It was probably the most difficult project I've tackled with AI (and clearly one I couldn't have done without out it) but it was still a really painful slog.

I'll be more careful to mark non-trivial things as WIP to be more respectful of your review input.

@tsteven4
Copy link
Copy Markdown
Collaborator

I tired this with some real world cycling data from a garmin edge device that was recording without issues. There wasn't a need to filter this data at all. However, without parameters, the filter introduced some artifacts. The recorded track and points are blue, the filtered track and points are red. I hadn't read your doc yet and didn't select a profile.
./bld/gpsbabel -i gpx -f ht.gpx -o kml -F ht.kml -x kalman -o kml -F htf.kml
Subsequently I tried
./bld/gpsbabel -i gpx -f ht.gpx -o kml -F ht.kml -x kalman,profile=cycling -o kml -F htfcyc.kml
but that showed the same artifacts.
The full data set is 24931 points.

I can get some problematic recordings from a phone that might benefit from filtering, but I haven't got them yet.

ht1
ht2
ht3

@tsteven4
Copy link
Copy Markdown
Collaborator

Perhaps the speeds are relevant, at the start of the artifacts they were 33.2 mph, 32.9 mph, 33.4 mph (14.8 mps, 14.7mps, 14.9mps). Faster speeds occur regularly when descending steeper terrain. The average speed of the entire data set was 15.4mph (6.9mps), so maybe the cycling profile is automatically selected (is auto selection described in document?). However, max_speed_option_.has_value() is true even when not set because of the default provided, so auto select isn't in play. I tried max_speed=30 but that didn't fix it.

@GPSBabelDeveloper
Copy link
Copy Markdown
Collaborator

GPSBabelDeveloper commented Oct 10, 2025 via email

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.

3 participants