Conversation
The rain rate icon sweep was a repeating Kivy Animation, which updates rain_rate_x once per frame and so redraws the window at the configured maxfps for as long as the rain rate is non-zero. The sweep takes 12 seconds, so nothing about the visible motion needs that rate. Drive it from Clock.schedule_interval at 12 fps instead. The step is derived from the elapsed time rather than a fixed increment, so the sweep still takes RAIN_RATE_PERIOD seconds whether a frame is late or the rate is changed. Measured headless over one 12 second sweep at maxfps = 60: 719 rain_rate_x updates before, 144 after - 80% fewer redraws. Also: - start/stop are now named methods rather than inline hasattr blocks, and stop resets rain_rate_x so the sweep restarts from the left edge - on_rain_rate_x is gone: the wrap is now part of the step - the "rain rate unavailable" branch sets rain_rate_y = -1.00 unconditionally, rather than only when an animation happened to be running tests/test_rainfall.py covers the animation state machine, the sweep geometry and period, the redraw rate at maxfps 30/60/120, and the rain_rate_y level curve, which this change must not alter. 13 tests, headless with the mock window and GL backends and a synthetic clock: no Pi, no display, no weather station. tests/measure_rain_redraw.py is the measurement above, runnable. Refs peted-davis#186
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is remedy 1 from #186, written as code so there is something concrete to accept, change or reject. The diagnosis in that issue is @mzac's; what I have added is the patch, a test suite for the panel, and a measurement.
What changes
animate_rain_rate()started a repeatingAnimation, which updatesrain_rate_xonce per frame and therefore redraws the window at the configuredmaxfpsfor the whole of the rainfall. The sweep takes 12 seconds, so none of that rate reaches the eye.It is now a
Clock.schedule_intervalat 12 fps. The step is derived fromdtrather than being a fixed increment, so the sweep still takesRAIN_RATE_PERIODseconds if a frame is late or if you changeRAIN_RATE_FPS. The three tunables are module constants at the top of the file:Measured, not asserted
tests/measure_rain_redraw.pycountsrain_rate_xdispatches over one full sweep atmaxfps = 60, headless, on a synthetic clock:I have no Pi 3B, so I cannot give you the °C figure — that is the part only you or @mzac can confirm. What I can show is that the redraw count the temperature follows is down by a factor of five, and that it is now bounded by a constant in the file rather than by the window's frame rate.
Three smaller things in the same diff
start_rain_rate_animation/stop_rain_rate_animationreplace the inlinehasattrblocks, which were repeated in three places. Stopping now also resetsrain_rate_xto 0, so the sweep restarts from the left edge rather than from wherever the rain happened to stop.on_rain_rate_xis gone. The wrap at the end of travel is part of the step now, rather than a property callback reacting to a rounded comparison against-0.875.rain_rate_yis set to-1.00unconditionally. Previously it was only reset if an animation happened to be running, so a panel that lost its observations while the rate was exactly 0 kept the last level it had.Tests
tests/test_rainfall.py, 13 tests, all green:Headless with the mock window and GL backends, a stubbed app and observation dict, and a clock whose time the test advances. No Pi, no display, no weather station, no network, no real time — the suite runs in 40 ms on an x86 laptop. They cover:
-or 0, start when it rains, stop when it stops or becomes unavailable, repeated observations do not stack a second animation, stop is idempotent[RAIN_RATE_TRAVEL, 0], and takesRAIN_RATE_PERIODseconds at a different window fpsmaxfps30, 60 and 120 — the regression guard for Rain-rate animation redraws at maxfps: +18°C CPU and thermal throttling on Pi 3B #186rain_rate_ylevel curve, which this change must not alter: monotonic in rain rate and saturating at the 50 mm/hr cut-offThe suite fails against
main(the panel has nostop_rain_rate_animation), so it is testing the change rather than passing vacuously.One test caught something worth knowing: at
maxfps = 30the step runs 121 times rather than 144, because a scheduled interval can only fire on a frame and 1/12 does not divide 1/30. That is harmless — the sweep keeps its period because the step readsdt— so the assertion is a bound rather than an equality, and the comment says why.What I have not done
Remedies 2 and 3 from the issue — animating only while the panel is visible, and documenting a recommended
maxfpsfor Pi 3-class hardware — are untouched. 2 needs the panel framework's visibility semantics, which are yours to decide; 3 needs hardware I do not have. Happy to follow up on either if this direction is right.If you would rather have this as a smaller diff — just the animation change, no tests directory — say so and I will cut it down. I added the tests because a performance change with no regression guard is one that comes back.