In Lower PVC frequency, I promised “I’ll report on the algorithms when I get something a little better than I have now.”

I’ve played with three algorithms this week:

- Doing spike detection, then measuring the time for 2
*n*periods by looking at the time between the spikes*n*before and*n*after the current spike. This gives a fine resolution both in time and frequency, and provides smoothing because adjacent measurements overlap by 2(*n*-1) periods. It is, however, very susceptible to errors due to miscalling the spikes. Missed spikes result in too low a frequency, and extraneous spikes result in too high a frequency. I could increase*n*to reduce the effect of miscounts, but at some loss of time resolution when pulse rate changed. - Taking FFT of a block of samples (say 4096, which is about 17 seconds at 240 Hz) and looking for a high energy frequency. Temporal resolution is poor (even with 50% overlapping blocks we get one measurement every 8.5s) and frequency resolution also poor (bins are about 3.5 bpm wide). I tried improving the frequency resolution by looking at the phase change for the peak between adjacent windows, but that didn’t solve the main problem, which was that choosing the right peak in the spectrum was often difficult. The simple algorithms I tried for choosing the peak often failed. I eventually gave up on this technique.
- Taking the autocorrelation of a block of samples (using rfft and irfft) and looking for a peak. The time for that peak is the period, which can be inverted to get the frequency. This method provides the same coarse time resolution as the FFT method (same size blocks), but has much better frequency resolution, as even the fastest reasonable pulse rate (240bpm or 4Hz) has 60 samples at a sampling rate of 240Hz. I tried accentuating peaks “of the right width” in the autocorrelation by doing some filtering of the autocorrelation, and I tried looking for harmonic errors (where 150bpm might result in a larger peak in the autocorrelation at 75bpm, 50bpm, or 37.5bpm). Even with all the tweaks I could think of, I still had a number of way-off estimates, though median filtering removed most of the anomalies. Of course, median-of-5 filter makes the time resolution even worse, as median could have come from any of 5 windows (with 50% overlap, that means a time range of 12288 samples or 51.2 seconds!).

I did most of my algorithm testing on one data set (the exercise set from 23 March 2022), and the algorithm is almost certainly overtrained on that data.

Although the autocorrelation measure makes a nice smooth plot on the exercise data set, I sacrificed a lot of temporal resolution to get that. I think that I would do better to make a more robust spike detector to improve the period-based measurements.