lancaster-university / codal-microbit-v2

CODAL target for the micro:bit v2.x series of devices
MIT License
43 stars 52 forks source link

The sample rate for microphone input via `StreamSplitter` must be an integer multiple of existing sample rate #394

Closed dpgeorge closed 7 months ago

dpgeorge commented 10 months ago

In MicroPython we need to record samples from the microphone at a rate of 7812Hz, to be compatible with the output sample rate on micro:bit v1.

Creating a SplitterChannel and then calling SplitterChannel::requestSampleRate(7812) does not do anything. The internal logic is currently:

To get the desired rate of 7812Hz I can do:

That works because the first call requires a sample period of 64 which is smaller than the existing value of 90. So the sample period is decreased to 64. Then the second call to requestSampleRate() doesn't change the sample period, but does mean the down-sampling is now an exact multiple of the sample rate and so SplitterChannel::pull() can drop every second sample. Thus we get a rate of 7812Hz.

But, now the component that needs 11111Hz (I think it's the SPL) is going to get 7812*2=15624Hz, and probably won't work correctly anymore.


A suggested fix would be for SplitterChannel::pull() to have a more sophisticated down-sampling algorithm with a fractional step value, and averaging instead of dropping samples. Eg, average 2 samples, copy 1 sample, average 2 samples, copy 2 samples, then repeat. That case would turn 7 samples into 5, so convert a rate of 11111Hz into 7936Hz.

JohnVidler commented 7 months ago

This is no longer the case as of v0.2.65, as the SplitterChannel class actively resamples the stream to the requested rate.

Note that some extremely small values won't be possible (like requesting a 1Hz sample rate) with the lower bound bottoming out around 45-128Hz as the minimum lambda for any signal is proportional to the length of the buffer received. If truly tiny frequencies are required, additional buffering would be required as the SplitterChannel right now (by design) only handles 1 buffer at once to limit RAM usage.

dpgeorge commented 6 months ago

I can confirm that this is now fixed (tested using CODAL 0.2.66).