(Update: I finally changed the formulas to use the real time for the formula instead of 'ticks' because thats how its supposed to work. If you looked at the original version and used it, please verify your math. Thanks.)
While still waiting for all the kits to arrive(did anyone get their stuff already?), I started to look into the software side of things. Over the holidays there was not so much progress, since I spend the time with the family (and we had a birthday too).
For assessing the effect an impact has on a person, I started to look at how this is handled by the medical and biological sciences. There I found the so-called 'Head Injury Criterion' which is used to determine the effect acceleration / deceleration has on a head. To do so, it focuses to only on the acceleration as such, but also on its durations.
The formula to calculate the HIC is:
t1 and t2 are (sliding) start and end time of the time window for calculation. a(t) is the acceleration at a specific point in time.
What this calculation does is to look at the acceleration curve, take a sliding window out of it (between 3 and 36ms wide, but typically 15ms is used), and calculates an average acceleration during that window. From all the sliding time windows the maximum value is taken.
The additional exponent of 2.5 has been chosen to reflect the specific sensitivity of the head to acceleration. For other body parts different exponents are used.
Measurement and calculation
Calculation would be rather easy if acceleration measurement happens in steps of one millisecond. Then the integration is just summing of the values of the current time window and some multiplications / divisions. If there would be 1024 measurements per second some of these even could be done by just right-shifting values.
Unfortunately the ADXL series runs with either 1600 or 800 (or even less) measurements per second, making this more difficult. So whats a good strategy to make the calculation fast enough? (I'm running on a tight energy budget, so the calculation needs to be fast to not take so much energy).
For a single value to calculate, the formula is
I should run with 1600 Hz measurement rate, so I can get accurate values (running with less could mean to miss short but severe impacts). Using a time window of 20ms would then give 32 acceleration values for each time window. But for calculation its still the time difference (20ms) that needs to be used:
To replace the integration with a simple sum, each of the measured values needs to be divided by its time-length, so we get
In addition the measured values need to be corrected. The ADXL375 returns 16 bit results, with the LSB corresponding to 49mg. So the maximum value for 200g is about 4000. This is corrected by the additional division by 20. So 'm' represents the measured value instead of using the acceleration #a'.
For now, lets simplify that formula a little bit. First, move the constant factor out of the sum:
When scaling the values by 1600, this constant factor will show us how to take back that scaling later on.
Lets now represent the sum of the value by a single variable 'S', to make the formula easier:
Next step to simplify is the exponentiation. Raising to the power of 2.5 is not exactly trivial in integer math, but fortunately that can be simplified a little bit:
and the exponentiation of the sum can be expressed as
(because raising to the power of 0.5 is the same as taking the square root). Now we have simple multiplication, but the square root looks scary. There are algorithms to do that fast in integers, but with a small trick we can do even faster. Lets change the formula to
which is the same as before. But now there is the term
in there which is the inverse of the square root - and there is a really fast algorithm for it. So I have three multiplications (the constant factor on the right can be handled during compile time), the fast inverse square root and a division for each of the windows. Unfortunately I need to to that 1600 times per second still
Remember that the sum (expressed as s) is still using the measured values directly, so there is no scaling involved.
Getting measured values
Another task to think about is how to get the measured acceleration as effectively as possible. The ADXL375 has a FIFO that can store 32 values. So it seems like a good idea to to a batched transfer of the values instead of reading 1600 times per second (so the PSoC4 needs to wake up only 50 times per second). Each transfer should at least calculate the aggregated values (the sum term above) for the last 32 windows. That can be done effectively with a sliding value (taking the last stored sum, add the next value to it, and remove the last value not in it anymore).
That way the slower calculation of the HIC can be done maybe once per second. I might even go as far as to not doing that on the PSoC, but on the display device (phone or tablet). It doesn't do anything thats really needed for alerting or the like. The HIC depends only on the integral of the measured values over a given time window, and the rest of the formula scales it in a non-linear way.
The PSoC4 BLE has 16k RAM, out of which some is needed for the Bluetooth stack already. So lets say we have 4k available for storing result data. Thats by not enough to store data with a 1600 Hz data rate. So some kind of compression is needed.
A good schema is a round-robin database, where the data is compressed in several steps. That way a high data resolution is available for new data, but the resolution gets worse the older the data gets.
So for example, from the 1600 values calculated per second the maximum is stored, rounded to single G's. So one minute needs 60 bytes. For each minute, also the maximum value is stored, so one hour needs also 60 bytes. Storing data that way for a 10 hour ski tour needs 10*60+60=660 bytes. No too bad. Additionally, there might be a buffer storing data some additional data when a severe impact (over a certain threshold) is detected, so that can be looked at later on).
One of my Christmas presents was to upgrade my PC (new SSD, more memory, faster CPU), so I'm still busy working on that. On the upside, that now makes the virtual machine I'm using for PSoC Creator much more usable. Having done that, I will continue work on the BLE communication.