-
-
Notifications
You must be signed in to change notification settings - Fork 39.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reimplements WPM feature to be smaller & precise #13902
Conversation
Ah, the |
Testing this out, it seems to jump around a lot. It's not a smooth increase or drop, but very drastic and very sudden. I think that the smoothing code was explicitly to prevent this. |
Mm, interesting. For my use case, I definitely wanted much faster updates to give me a pretty accurate current-wpm value as I typed. If the idea is that we want the value to move more smoothly, then there are definitely some strategies we could use to ease the transitions from one value to another (without going so far as taking 45 seconds to drop from 100wpm back to 0wpm, ofc!) |
This new commit should not be merged as is! This updated commit is an experimental revision which values making the returned WPM changes occur much more smoothly. This necessarily introduces some lag into the updates, but I've tried to minimise that. I'm interested in whether this sort of behaviour is more what the maintainers have in mind for the feature. If so, please let me know and I'll give it a proper spruce and tidy! |
Yeah, that feels a lot better. It feels like it may be updating a bit fast still... but ... it creates a "rolling" sort of effect for the one's place, which is actually neat. |
Here's another revision on this update. New in this update:
Stuff still to discuss: 'Launch Control' is based on the name of the feature in some electric cars which optimise for fast acceleration from a standing start, but maybe that's too whimsical/esoteric for the name of a feature like this. It's really just intended to avoid the latency you get in accurate WPM readings when you're just starting to type and you have a really large sample buffer which is mostly empty because you haven't been typing that long yet. I'm not in love with the name 'WPM_UNFILTERED', just because you wind up with code like Finally, it's worth noting that I have not tested that this is working on the slave side of a split keyboard, yet. That absolutely needs to get done before we can even consider merging this in. |
Nice. And naming is hard. I think the unfiltered name should be okay, but yeah, codewise, it doesn't read the best. But I'm not sure what the best naming should be here. I'd also say that the smooth behavior should be the default, IMO. And it should be defines. As for the slave side, it's not needed. the wpm task is ran solely on the master side, via |
Agreed; the smooth behaviour should be and already is the default. Another option would be to remove the ‘unfiltered’ option entirely, and instead just expose a second public function to access the unfiltered values; |
Well, to be honest, a lot of the keymaps using WPM... are squeezing every bit out, so that 70 bytes savings may be worth it. Eg, it may be worth hiding And I have to say, I really do like the current implementation for it. It's VERY pleasing, graphically. |
Whoops, no, I just hadn't set |
Just a heads up, launch control is bugged. It works initially, but it can get into a state where it just .... cycles numbers randomly, and may or may not stop. |
I've reproduced this without the launch control feature; this problem is definitely in the smoothing itself. Working on sorting it out now! |
I haven't seen it do it on the smoothing option, but it happens very reliably on the launch control, at least. |
It happens for me pretty easily if increase the smoothing time window to like ten seconds, even without launch control. I'm pretty certain that it's an integer overflow problem when it's transitioning between very different numbers (which can happen more easily with launch control enabled!) Still looking for a way to reformulate the smoothing to make it more robust without losing any of its charm. |
Any updates on this? |
Apologies, life has been absurdly busy! I still really want to get back to this but I'm not sure when I'm going to have the spare time. |
No worries! I'm throwing the "in progress" label on the PR to make sure stale-bot doesn't close the PR, for now. Look forward to when you have more free time (but it's already working pretty well, as is, aside from stated issues) |
8193d77
to
1bcfee7
Compare
This build has made a few changes:
A couple other notes:
|
- Now calculates exact WPM over the last up to three seconds of typing. - WPM_SMOOTHING removed, as it's no longer needed. - WPM_SAMPLE_SECONDS added, to specify how long a period to average WPM over, set to 5 seconds by default. - WPM_SAMPLE_PERIODS added, to specify how many sampling buffers we'll use. Each one uses one extra byte of space. Having more will lead to smoother decay of WPM values. Defaults to 50 (we're saving so many bytes of firmware space I felt like being extravagent, and this change is still a big size saving overall) - WPM_UNFILTERED option added (defaults to unset), which disables all filtering within the WPM feature. This saves some space in the firmware and also reduces latency between typing and the WPM calculation measuring it. (saves 70 bytes in my tests) - WPM_LAUNCH_CONTROL added (defaults to unset). When typing begins while the current displayed WPM value is zero, the WPM calculation only considers the time elapsed since typing began, not the whole WPM_SAMPLE_SECONDS buffer. The result of this is that the displayed WPM value much more rapidly reaches an accurate WPM value, even when results are being filtered. (costs 22 bytes in my tests) - Updates documentation to reflect changed options. Saves about 900 bytes, in my tests, compared against the previous implementation, with default settings.
1bcfee7
to
1e465b7
Compare
This update has the missing documentation update which was overlooked from the previous commit. No code changes. |
|
Co-authored-by: Sergey Vlasov <sigprof@gmail.com>
* qmk/develop: (32 commits) [Keyboard] Add macro3 PCB support (qmk#15131) [Keyboard] Add layout options, hotswap version to portal 66 (qmk#14719) [Keyboard] Add Bourgeau 75% PCB (qmk#15072) [Keyboard] Fix bandominedoni via keymap compilation (qmk#15171) Fix additional board sizes for RGB Matrix (qmk#15170) kb_elmo/m0116_usb: Fix Configurator Key Sequence (qmk#15147) Require explicit enabling of RGB Matrix modes (qmk#15018) Reimplements WPM feature to be smaller & precise (qmk#13902) Add support for deferred executors. (qmk#14859) Add needed include to pointing_device.c (qmk#15167) Fix uart function prototypes (qmk#15162) Rework and expand Pointing Device support (qmk#14343) Partially reinstate CI formatting process (qmk#15155) kb_elmo/elmopad: fix macro reference in info.json (qmk#15142) kb_elmo/m0110a_usb: Fix Configurator Key Sequence (qmk#15143) Update UART driver API (qmk#14839) Fix hebrew emoji in langs.md (qmk#15140) [Keyboard] Add space between Cradio info.json layout (qmk#15127) add wait to unicode for win (qmk#15061) [Docs] Correct logic of tap hold statement (qmk#14992) ...
Changes the WPM feature to provide a correct WPM value instead of only a rough estimate.
This change is similar to the one in this PR, which I hadn't known about at the time I made this change locally. It's worth checking that one out for comparison to this one!
Description
The original WPM feature worked by measuring the time between two keypresses, estimating a WPM value from that delay between keypresses, and then interpolating a rolling average "WPM" value by 4.87% of the difference between the current average and the new calculation (which we're told is equivalent to averaging over 40 keypresses). If no keys are pressed, then after one second the rolling average would be reduced by 4.87%.
There were some problems with this original calculation; if you were typing at 100wpm and then entirely stopped typing, it took the original implementation approximately 45 seconds for your WPM value to drop back to 0, because it was only dropping by less than 5% per second.
This new implementation instead uses a ring buffer. We define 6 "periods" within this buffer, each representing half a second of time. We track the number of keys pressed during each period, with a timer telling us when to move from one period to the next within the ring buffer, and then we can simply count the number of keys pressed and how long has passed and calculate WPM exactly, without any of the mathematical complexity of the original implementation.
When
WPM_ALLOW_COUNT_REGRESSION
is defined, we count keys like backspace as "negative" keys. I'm not sure that this is the right behaviour; most real-world WPM calculations work by counting each mistakenly pressed key as a full negative word and ignoring backspaces entirely. However, since we can't actually detect "errors" the way that normal WPM tests do, the implementation in this PR just gives backspace presses a similar impact to what they had in the original feature. (that part of the functionality was less important to me personally, so I figured I'd make it mirror the general impact of the old behaviour as much as I could)Since we're no longer doing a "smoothing" calculation at all, but instead are actually calculating WPM correctly over an actual period of time, we no longer need the
WPM_SMOOTHING
#define, and it has been removed both from the code and from the documentation.This change saves 998 bytes in the firmware, in my tests, compared against the previous implementation, and maintains all the same external interfaces as the original implementation, so it should just work for everything that was already using the WPM feature; they'll just get more accurate WPM numbers now than they did before.
Discussion Points:
It'd take a small amount of extra space to store more sampling periods, or the sampling period could be made longer without adding extra periods just by moving those #define values (
MAX_PERIODS
andPERIOD_DURATION
) from wpm.c to wpm.h, with changed names to make it more obvious that they're part of the WPM feature. I didn't do that in the initial PR because I felt like the 3-second measurement period was a pretty good starting point and I'm not sure whether anyone really wants their keyboard storing WPM data for much longer than that, so maybe best to keep configuration options and documentation as light as possible.But I'm very interested in feedback here and could absolutely amend this PR with those configuration options if anybody feels that they might be useful to somebody!
Types of Changes
Issues Fixed or Closed by This PR
Checklist