Skip to content

fix(flexcontrol): snap encoder accumulator to step grid and reset on absolute tune (#3260). Principle XI.#3267

Merged
aethersdr-agent[bot] merged 1 commit into
mainfrom
aetherclaude/issue-3260
May 29, 2026
Merged

fix(flexcontrol): snap encoder accumulator to step grid and reset on absolute tune (#3260). Principle XI.#3267
aethersdr-agent[bot] merged 1 commit into
mainfrom
aetherclaude/issue-3260

Conversation

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Summary

Fixes #3260

What was changed

fix(flexcontrol): snap encoder accumulator to step grid and reset on absolute tune (#3260). Principle XI.

Files modified

  • src/gui/MainWindow.cpp
 src/gui/MainWindow.cpp | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

Generated by AetherClaude (automated agent for AetherSDR)


🤖 aethersdr-agent · cost: $11.7561 · model: claude-opus-4-7

…absolute tune (#3260). Principle XI.

FlexControl knob produced a residual +60 Hz offset on every tune step on
macOS (and silently on Windows/Linux). Root cause is the persistent
encoder target m_flexTargetMhz interacting with the #1524 1 kHz
jitter-suppression tolerance plus the lack of step-grid alignment when
re-initializing the base.

Three coordinated edits in MainWindow.cpp, all mirroring patterns that
already work on the MIDI tune-knob path:

1. applyFlexControlWheelAction: when (re)initializing m_flexTargetMhz
   from s->frequency(), snap to the nearest step-Hz multiple instead of
   copying verbatim. This is the same `(curHz + stepHz/2) / stepHz *
   stepHz` snap the MIDI rx.tuneKnob path uses, so encoder ticks land
   on clean grid values even when the slice is off-grid.

2. RxApplet::stepSizeChanged hook: invalidate m_flexTargetMhz,
   m_midiTuneTargetMhz and stop their coalesce/idle timers when the
   user changes step size. This forces the next encoder tick to rebase
   + re-snap against the new step grid (va3mw's repro: step 20 Hz →
   500 Hz then turn knob).

3. applyTuneRequest: on CommandedTargetCenter and AbsoluteJump intents
   (typed VFO entry, spectrum click, spot/bandstack recall), reset
   encoder accumulators and stop their timers. The #1524 1 kHz
   tolerance otherwise keeps a stale m_flexTargetMhz alive whenever the
   typed frequency lands inside that window, producing the OP repro
   (type 7.188.000 with stale base 7.187.960 + 100 Hz step → 7.188.060).

The #1524 jitter-suppression behavior during sustained knob spinning is
preserved: incremental encoder ticks still skip the reset path and the
1 kHz tolerance still gates mid-tune rebases from lagging radio echoes.

Blast radius: applyFlexControlWheelAction risk_score=0.4587,
11 high-risk affected (top: MainWindow::MainWindow,
AppSettings::instance, AppSettings::value). All downstream calls are
existing member-variable reads/writes (m_flexTargetMhz,
m_flexCoalesceTimer, m_midiTuneTargetMhz, m_midiTuneIdleTimer); no
signatures, link surface, or call graph topology changed. Upstream
callers — handleFlexControlTuneSteps and handleVirtualFlexControlWheel —
are unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aethersdr-agent aethersdr-agent Bot requested a review from a team as a code owner May 29, 2026 16:30
@aethersdr-agent aethersdr-agent Bot enabled auto-merge (squash) May 29, 2026 16:30

@jensenpat jensenpat left a comment

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.

Snap to step grid like MIDI wheel path to prevent VFO drift.

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reviewed the diff against #3260 and the surrounding tuning paths. The fix is well-targeted:

  • Encoder-base snap in applyFlexControlWheelAction mirrors the existing MIDI tune-knob path at src/gui/MainWindow.cpp:3895-3902 byte-for-byte (same ((curHz + stepHz/2) / stepHz) * stepHz round-to-nearest). Consistent with the codebase's existing pattern, and guarded on stepHz > 0.
  • Step-size handler invalidation at MainWindow.cpp:3325 correctly resets both m_flexTargetMhz and m_midiTuneTargetMhz (under HAVE_MIDI). Stopping the coalesce/idle timers along with the sentinel reset is the right thing — otherwise the next tick within the coalesce window would skip the re-snap.
  • applyTuneRequest invalidation correctly limits the reset to CommandedTargetCenter and AbsoluteJump intents and leaves IncrementalTune (the encoder's own intent) alone, so the encoder doesn't clobber its own accumulator on each tick. The comment ties the change back to the #1524 1 kHz jitter-suppression tolerance, which is the actual mechanism that preserved the stale residual — accurate diagnosis.

The +60 Hz reproduction in #3260 fits the explanation: typing 7.188.000 landed inside the 1 kHz tolerance of a previously-accumulated off-grid m_flexTargetMhz, so the next encoder tick added steps * stepHz to the stale base instead of the freshly typed frequency. Invalidating on absolute intents fixes this directly.

No conventions issues (AppSettings used correctly, RAII fine, no allocations). Scope is contained to src/gui/MainWindow.cpp as advertised.

Thanks @aethersdr-agent — clean fix.


🤖 aethersdr-agent · cost: $7.9267 · model: claude-opus-4-7

@aethersdr-agent aethersdr-agent Bot merged commit d60f7ac into main May 29, 2026
5 checks passed
@aethersdr-agent aethersdr-agent Bot deleted the aetherclaude/issue-3260 branch May 29, 2026 17:39
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
…absolute tune (aethersdr#3260). Principle XI. (aethersdr#3267)

## Summary

Fixes aethersdr#3260

### What was changed

fix(flexcontrol): snap encoder accumulator to step grid and reset on
absolute tune (aethersdr#3260). Principle XI.

### Files modified

- `src/gui/MainWindow.cpp`

```
 src/gui/MainWindow.cpp | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)
```

---
Generated by AetherClaude (automated agent for AetherSDR)

---
<sub>🤖 aethersdr-agent · cost: $11.7561 · model: claude-opus-4-7</sub>

Co-authored-by: aethersdr-agent[bot] <273844287+aethersdr-agent[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

FlexControl knob: 60Hz always added to VFO (Mac version)

1 participant