Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by BooleanMattock »

I have been trying to use the shake() function in adafruit.lis3dh with the LIS3DH accelerometer on a Pi Pico, and it has been behaving rather inconsistently. I took a look at the code for the shake() function, and in the end made a copy of it in my own code so I could add some print() statements. The code in question is:

Code: Select all

        shake_accel = (0, 0, 0)
        for _ in range(avg_count):
            # shake_accel creates a list of tuples from acceleration data.
            # zip takes multiple tuples and zips them together, as in:
            # In : zip([-0.2, 0.0, 9.5], [37.9, 13.5, -72.8])
            # Out: [(-0.2, 37.9), (0.0, 13.5), (9.5, -72.8)]
            # map applies sum to each member of this tuple, resulting in a
            # 3-member list. tuple converts this list into a tuple which is
            # used as shake_accel.
            shake_accel = tuple(map(sum, zip(shake_accel, self.acceleration)))
            time.sleep(total_delay / avg_count)
        avg = tuple(value / avg_count for value in shake_accel)
        total_accel = math.sqrt(sum(map(lambda x: x * x, avg)))
        return total_accel > shake_threshold
The code is a little dense, but it appears that it is sampling (x,y,z) acceleration values, and keeping a separate running total of x-acceleration, y-acceleration, and z-acceleration. It then divides the totals by the number of samples to get an average for each. It then computes sqrt(x**2+y**2+z**2) on the averages to give a magnitude, and compares it with a threshold.

I'm pretty sure this isn't correct. Imagine if you are shaking the accelerometer backwards and forwards parallel to the x-axis. That will give both positive and negative x-acceleration values: if you total them up, the positive and negative values will cancel out and you'll end up with approximately zero. That means when you compute the average and magnitude, you'll likely end up with a value below the threshold, no matter how vigorously you shake the accelerometer. Indeed when I shake the accelerometer and look at the values, sometimes total_accel is a lower value than when standing still.

Can someone check my understanding, and hopefully tell me where I've gone wrong?

Any input gratefully received!

(PS If I'm correct and there is an issue, I believe I have a simple fix!)

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by BooleanMattock »

Update - I wrote my own version of the shake() function and tested it - does seem to work a lot better than the library code without being any more complex.

User avatar
robcranfill
 
Posts: 142
Joined: Wed Feb 13, 2013 4:14 pm

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by robcranfill »

BooleanMattock wrote: Sat Jan 28, 2023 10:39 pm Update - I wrote my own version of the shake() function and tested it - does seem to work a lot better than the library code without being any more complex.
Would you care to share that somewhere, like GitHub or something? I'd love to see it.

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by BooleanMattock »

robcranfill wrote: Fri Feb 03, 2023 11:13 pm
BooleanMattock wrote: Sat Jan 28, 2023 10:39 pm Update - I wrote my own version of the shake() function and tested it - does seem to work a lot better than the library code without being any more complex.
Would you care to share that somewhere, like GitHub or something? I'd love to see it.
Sure, I can post it here, it's not many lines of code.

Do you agree with my reasoning as to why the existing code is not correct?

User avatar
blakebr
 
Posts: 942
Joined: Tue Apr 17, 2012 6:23 pm

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by blakebr »

Hi,
Something doesn’t sound right. The square of a negative number should be a positive number. There should be no negative numbers offsetting positive numbers. Sounds like good old RMS to me. The RMS of x, y, and z should be independently calculated then added together.
Bruce

User avatar
blakebr
 
Posts: 942
Joined: Tue Apr 17, 2012 6:23 pm

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by blakebr »

For x, y, and z take a reading every millisecond.
At the end of a second square each value.
Add up each vector’s squares and divide by 1000.
Take the square root of each vector. aka RMS
Add the vector’s together.
If the result is over the threshold, take action.

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by adafruit_support_carter »

Does seem like a potential flaw in the code. The issue is the squaring is being delayed until after the summing. The tally should be the sum of the squares, not the square of the sums.

Can be demonstrated with this example code:

Code: Select all

import math

# synthesize acceleration data for shaking that perfectly
# bounces between + and - 1G on all 3 axis
accel_data = (
    (-9.8, -9.8, -9.8),
    (9.8, 9.8, 9.8),
    (-9.8, -9.8, -9.8),
    (9.8, 9.8, 9.8),  
)

avg_count = len(accel_data)

shake_accel = (0, 0, 0)
for i in range(avg_count):
    shake_accel = tuple(map(sum, zip(shake_accel, accel_data[i])))
    print("shake_accel = ", shake_accel)

avg = tuple(value / avg_count for value in shake_accel)
print("avg = ", avg)
total_accel = math.sqrt(sum(map(lambda x: x * x, avg)))
print("total_accel = ", total_accel)
Which outputs:

Code: Select all

$ python3 accel_test.py 
shake_accel =  (-9.8, -9.8, -9.8)
shake_accel =  (0.0, 0.0, 0.0)
shake_accel =  (-9.8, -9.8, -9.8)
shake_accel =  (0.0, 0.0, 0.0)
avg =  (0.0, 0.0, 0.0)
total_accel =  0.0
Please open a new issue in the library repo:
https://github.com/adafruit/Adafruit_Ci ... 3DH/issues

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Pi Pico adafruit.lis3dh.shake() - incorrect calculation?

Post by BooleanMattock »

adafruit_support_carter wrote: Tue Feb 07, 2023 4:33 pm Does seem like a potential flaw in the code. The issue is the squaring is being delayed until after the summing. The tally should be the sum of the squares, not the square of the sums.

Please open a new issue in the library repo:
https://github.com/adafruit/Adafruit_Ci ... 3DH/issues
Done, thank you!

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”