Open-Gamma-Detector
Open-Gamma-Detector copied to clipboard
Dead Time Correction inaccurate
In some of my tests, thanks to @dc1rdb, I've discovered that the dead time corrected cps values for the energy and geiger modes deviate from each other. Geiger mode always seems to undershoot the actual value, while energy mode always overshoots a little bit. It looks to me, however, that energy mode is a lot more accurate over larger ranges of different count rates.
Sending in 20kcps from a pulse generator with a pulse duration of 5µs, shows around 22000 in energy mode and only 16500 in geiger mode. This might be related to the fact that for geiger mode the dead time only reports as 1µs or sometimes even 0µs.
I'm not sure what's causing this, it's somewhat related to how the software takes in the interrupts behind the scenes and obviously, how the dead time is measured. For now, I'll leave the dead time correction in, though, because IMO it's much better to have it than not to, even if it's not 100% accurate.
In the future, I might add a small factor to the dead time to compensate delays in the interrupt that are not measured.
Further testing will reveal if this issue still persists on the Pico 2 with the significant decrease in dead time. I will update if I have any news.
Have you checked the elapsed time for ADC reading step here? I think that is the problem where the time may change sporadically.
I suggest to trigger the Raspberry Pi Pico 2's ADC without CPU intervention, utilize the Direct Memory Access (DMA) interface and a GPIO interrupt. Configure a GPIO pin to trigger the ADC conversion and link it to a DMA channel that will initiate the ADC read. The DMA channel can then store the ADC value in memory, and you can read it.
Have you checked the elapsed time for ADC reading step here?
Yes, of course, this time is added to the computed dead time. I think this has mostly something to do with a more or less constant overhead of the ISR getting called or something. The guys over at @OpenDosimeter did in fact add this kind of constant to the dead time and it looks like it works pretty well that way.
Q: Why you are attaching the interruption by falling not rising peak front in https://github.com/OpenGammaProject/Open-Gamma-Detector/blob/main/software/ogd_pico/ogd_pico.ino#L1302?
This is an easy and 100% safe way to only trigger the ADC readings when the peak and hold circuitry does not increase the peak voltage anymore. If you trigger at the rising edge, the ADC will read the voltage as soon as the peak is over the threshold, however, it will very likely not have settled yet.
This might help you resolve the issue. I've implemented a DMA-based ADC channel (checkout releases), which runs much faster compared to the CPU-based analogRead used in the eventInt method. Previously, I had about 11 µs of dead time; with DMA, it's down to just 2 µs. Of course, there's a tradeoff: I had to remove the temperature reading code due to the complexity of switching ADC channels mid-stream, which didn’t provide much benefit in return.
Assuming the RP Pico 2 supports a 500 kSPS ADC sampling rate, this gives a theoretical throughput of 250 kcps, which is quite acceptable.
What are you comparing exactly?
The analogRead(pin) function, without DMA or anything, has a tested throughput of 260 ksps, which equates to short of 4 µs. Because of this, most of the dead time is not actually due to the ADC reads at all, but simply the data processing happening around that.
I was comparing the eventInt() procedure with and without if-else and other boilerplate code. You're right — readAnalog isn't a bottleneck in this method. I'm considering a variant using an external ADC with a built-in Sample & Hold function to eliminate all the mentioned boilerplate. In that case, the ADC could be triggered directly by a peak without CPU intervention. As a result, the ADC's digital output could be read quickly via sequential GPIO access. Of course, this sounds like a significant change and will lead a major version update.