Pothole data smoothing and detection of accelerometer data
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
C1 = "=B1*0.01*32"
C2 = "=C1+B2*0.01*32"
D1 = "=C1*0.01*12"
D2 = "=D1+C2*0.01*12"
Here is the plot for acceleration(G), velocity(ft/sec) and displacement(in). This says the pothole was about 4" deep.
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
WOW Thanks for your hard work, I don't get the formulas you used, care to explain , and I'm not sure where the 4inches is comming from on the graph confused haha.
Would this be possible to do in real time on the arduino in 1 second windows to tell how deep the potholes are in say... 1 second windows of data? or any length of time of windows. I guess the length of the window would be important because if the pothole event is divided between two windows then it would miss the depth and displacement. so the window size would have to capture a pothole completely right?
Would this be possible to do in real time on the arduino in 1 second windows to tell how deep the potholes are in say... 1 second windows of data? or any length of time of windows. I guess the length of the window would be important because if the pothole event is divided between two windows then it would miss the depth and displacement. so the window size would have to capture a pothole completely right?
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
The third graph is displacement. The end point after one second says that the sensor had dropped about 4" below it's starting point. You would need to extract some data covering some time before and after an event to see the sensor come out of the pothole and back to the road average surface height.
The cell equations above are the content of the first two rows in the velocity(C) and displacement(D) columns of a spreadsheet. The left two columns are your original data for time and acceleration. The spreadsheet was the only way I could find to do the running sum numerical integration and the graphs. Column B, acceleration, integrates to C, velocity. Column C then integrates to D, displacement. C1 and D1 are the initial values for the integration of the column data. C2 and D2 are the beginning of the running sum. They needed a value in row 1 to start. The content of C2 and D2 can be copied into the row under themselves and all the way to the bottom. The spreadsheet will adjust the row numbers in the expression in each cell. The last row will have an expression that will include itself and the value above, the sum of all previous in that column.
In the mega, it will be very straight forward. In the loop() statement, you would collect the data in a circular buffer at your normal rate, probably 100Hz. The buffer would be long enough to hold perhaps five seconds of data. A circular buffer is one where the index pointer starts over at the beginning after reaching the end. The index minus one then always points to the most recent piece of data. As the data is collected, the running sum integration is updated for the velocity and displacement arrays. They would use the same pointer and have the same size. The output of those arrays would trigger threshold events. The sampling rate would be adjusted to be as fast as possible while allowing all worse case actions to be performed in the loop.
The cell equations above are the content of the first two rows in the velocity(C) and displacement(D) columns of a spreadsheet. The left two columns are your original data for time and acceleration. The spreadsheet was the only way I could find to do the running sum numerical integration and the graphs. Column B, acceleration, integrates to C, velocity. Column C then integrates to D, displacement. C1 and D1 are the initial values for the integration of the column data. C2 and D2 are the beginning of the running sum. They needed a value in row 1 to start. The content of C2 and D2 can be copied into the row under themselves and all the way to the bottom. The spreadsheet will adjust the row numbers in the expression in each cell. The last row will have an expression that will include itself and the value above, the sum of all previous in that column.
In the mega, it will be very straight forward. In the loop() statement, you would collect the data in a circular buffer at your normal rate, probably 100Hz. The buffer would be long enough to hold perhaps five seconds of data. A circular buffer is one where the index pointer starts over at the beginning after reaching the end. The index minus one then always points to the most recent piece of data. As the data is collected, the running sum integration is updated for the velocity and displacement arrays. They would use the same pointer and have the same size. The output of those arrays would trigger threshold events. The sampling rate would be adjusted to be as fast as possible while allowing all worse case actions to be performed in the loop.
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
To do the integration itself, I would use the same forumulas you used in the spreadsheet? is the 32 from gravity 32/ft/sec?
I found this library, since all the data is floats : this seems to handle floats:
http://siggiorn.com/arduino-circular-byte-buffer/
A float on the Arduino is 4 bytes, @ 100HZ sampling rate 1sec = 100 floats = 400 bytes, for three arrays that is 1600 bytes
Then for 4 seconds of data: thats 4800 bytes for all three arrays
WOW lol I'll see if I can get away with maybe 60HZ sampling
I found this library, since all the data is floats : this seems to handle floats:
http://siggiorn.com/arduino-circular-byte-buffer/
A float on the Arduino is 4 bytes, @ 100HZ sampling rate 1sec = 100 floats = 400 bytes, for three arrays that is 1600 bytes
Then for 4 seconds of data: thats 4800 bytes for all three arrays
WOW lol I'll see if I can get away with maybe 60HZ sampling
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
Yes, the 32 is the conversion from G to ft/sec. In the D column, the 12 is feet to inches. The 0.01 in both columns is the integration time span or "dt" in the integral.
PS
We should look into scripting in SciDAVis using either muParser or Python. I didn't learn anything from the help file as it's for an earlier version and many of the screens and tables have changed. The matrix method should have worked for two columns but it didn't run as expected.
PS
We should look into scripting in SciDAVis using either muParser or Python. I didn't learn anything from the help file as it's for an earlier version and many of the screens and tables have changed. The matrix method should have worked for two columns but it didn't run as expected.
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
Didn't know SciDavis took Python scripting sweeet.
I don't know if I'll need external SRAM to hold all these floats or not in memory, I'll try 50HZ sampling rate and if it needs increased I'll increase it. I have to work on coding the circuilar buffer, not sure if that library would work out or not
Would I have to be concerned with drifting error of the accelerometer in the integration? I don't have to be 100% accurate, I would think since we are only looking a couple seconds at a time the error could be reset so it doesn't build up?
I don't know if I'll need external SRAM to hold all these floats or not in memory, I'll try 50HZ sampling rate and if it needs increased I'll increase it. I have to work on coding the circuilar buffer, not sure if that library would work out or not
Would I have to be concerned with drifting error of the accelerometer in the integration? I don't have to be 100% accurate, I would think since we are only looking a couple seconds at a time the error could be reset so it doesn't build up?
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
Can you check if I'm doing this right, I basically set up on my desktop, using rand() to generate random acceleration from -1.6 to 1.6 G's, capturing 3 seconds of data @ a simulated 50HZ sampling rate
It looks like you run *nix, I'm using Sleep() from Windows.h to make the 20mS delay
I just wanted to see if the code looks right to you, I didn't do the cicular buffer yet, I'm kinda confused on how to implement it: the commented out code, is from the class I'm working on for it, but I don't understand it 100% yet
SAMPLE RUN:
It looks like you run *nix, I'm using Sleep() from Windows.h to make the 20mS delay
I just wanted to see if the code looks right to you, I didn't do the cicular buffer yet, I'm kinda confused on how to implement it: the commented out code, is from the class I'm working on for it, but I don't understand it 100% yet
Code: Select all
#include <cstdlib>
#include <iostream>
#include <BANNED>
#include <ctime> // USED BY RAND
#include <windows.h> // Used for delay
using namespace std;
#define SAMPLE_RATE 0.020 // Sample rate in Milliseconds
#define GRAVITYFT_SEC 32 // Gravity velocity 32 feet/sec
#define INCH_FOOT 12 // 12 inches in foot, from velocity to inch displacement calculation
int main(int argc, char *argv[])
{
srand((unsigned)time(0)); // SEED RAND() for simulation of Geforce Readings
// SIMULATING ACCELERATION READINGS INTO A CIRCULAR BUFFER
// circular_buffer Acceleration; // Create a new Circular buffer for Acceleration
// cb_init(&Acceleration, 150, 4); // Sampling @ 50HZ, 3 seconds of data = 150, size is float data of 4 bytes
//Simulate a sample run of Acceleration data using Rand()
// WE WILL BE SIMULATING "RANDOM" GEFORCE RATINGS using the rand() function constraining to -1.6 to 1.6 GFORCE
// These ratings are consistent with our road tests of apparently random vibration and Geforce readings not exceeding about 1.6 G's
float Gforce[150]; // Random Geforce for 3 second window of data
float velocity[150]; // Hold velocity information
float displacement[150]; // Hold Displacement information
float LO = -1.6; // Low GForce limit recorded from 6 road tests at different speeds
float HI = 1.6; // High GForce limit recorded from 6 road tests at different speeds
for(int i = 0; i < 150; i++) // 3 Second iwndow of random acceleration data
{
Gforce[i] = LO + (float)rand()/((float)RAND_MAX/(HI-LO)); // Borrowed from Stackexchange : http://stackoverflow.com/questions/686353/c-random-float
if( i == 0) // Initial values @ first Acceleration
{
velocity[i] = Gforce[i] * SAMPLE_RATE * GRAVITYFT_SEC; // Initial velocity
displacement[i] = velocity[i] * SAMPLE_RATE * INCH_FOOT; // Initial Displacement
}
else
{
velocity[i] = velocity[0] + (Gforce[i] * SAMPLE_RATE * GRAVITYFT_SEC); // Calculate running velocity into buffer
displacement[i] = displacement[0] +(velocity[i] * SAMPLE_RATE * INCH_FOOT); // Calculate running displacement into buffer
}
//cout << endl << Gforce[i]; // Debugging
//cb_push_back(&Acceleration, &Gforce[i]); // Push the GeForce into the circular buffer
Sleep(SAMPLE_RATE*1000); // 20mS delay simulates 50HZ sampling rate Sleep() expects number in mS already so * 1000
}
// PRINT RESULTS
for (int j = 0; j < 150; j++)
{
cout << setprecision (3) << Gforce[j] << "\t\t" << velocity[j] << "\t\t" << displacement[j] << endl;
}
// READ THE BUFFER
//cb_free(&Acceleration); // Pervent Memory leaks
system("PAUSE");
return EXIT_SUCCESS;
}
Code: Select all
GFORCE FT/SEC Inch Displacement Z axis
-0.93 -0.595 -0.143
-0.377 -0.836 -0.344
0.343 -0.375 -0.233
1.16 0.148 -0.107
-0.559 -0.953 -0.371
0.601 -0.211 -0.193
0.124 -0.516 -0.267
-1.27 -1.41 -0.48
0.809 -0.0775 -0.161
-1.06 -1.27 -0.448
-1.16 -1.34 -0.463
-1.1 -1.3 -0.455
-1.33 -1.44 -0.489
0.256 -0.431 -0.246
-1.44 -1.52 -0.507
1.26 0.211 -0.0923
0.932 0.0015 -0.142
0.789 -0.0903 -0.164
0.318 -0.392 -0.237
-0.355 -0.822 -0.34
1.49 0.357 -0.057
1.38 0.289 -0.0733
1.13 0.131 -0.111
-0.342 -0.814 -0.338
-1.52 -1.57 -0.519
-0.406 -0.855 -0.348
-1.22 -1.37 -0.473
-0.182 -0.712 -0.314
0.0257 -0.579 -0.282
0.112 -0.523 -0.268
-0.624 -0.994 -0.381
-0.35 -0.819 -0.339
0.323 -0.388 -0.236
-1.26 -1.4 -0.479
-1.4 -1.49 -0.501
0.409 -0.333 -0.223
0.328 -0.385 -0.235
-0.713 -1.05 -0.395
-1.33 -1.45 -0.49
0.926 -0.00219 -0.143
1.39 0.293 -0.0725
-0.613 -0.987 -0.38
0.0183 -0.583 -0.283
-0.909 -1.18 -0.425
1.19 0.17 -0.102
1.47 0.345 -0.0601
0.844 -0.0549 -0.156
1.46 0.342 -0.0607
0.555 -0.24 -0.2
0.851 -0.0502 -0.155
1.19 0.164 -0.103
0.324 -0.387 -0.236
-0.951 -1.2 -0.432
0.75 -0.115 -0.17
-0.0729 -0.642 -0.297
0.641 -0.185 -0.187
0.909 -0.0133 -0.146
-0.149 -0.69 -0.308
0.461 -0.3 -0.215
-1.32 -1.44 -0.488
-0.402 -0.852 -0.347
-1.03 -1.25 -0.443
0.711 -0.14 -0.176
1.14 0.137 -0.11
0.797 -0.0849 -0.163
1.31 0.241 -0.085
-0.795 -1.1 -0.408
-0.658 -1.02 -0.387
1.1 0.107 -0.117
1.54 0.388 -0.0497
-0.688 -1.04 -0.391
0.0859 -0.54 -0.272
1.3 0.234 -0.0865
-0.853 -1.14 -0.417
-1.47 -1.53 -0.511
-0.973 -1.22 -0.435
0.409 -0.333 -0.223
-0.793 -1.1 -0.407
-0.664 -1.02 -0.388
1.31 0.247 -0.0836
1.27 0.22 -0.09
0.733 -0.126 -0.173
-0.324 -0.803 -0.335
0.894 -0.0229 -0.148
-0.528 -0.933 -0.367
-0.0603 -0.634 -0.295
-0.363 -0.828 -0.341
0.928 -0.00119 -0.143
-0.749 -1.07 -0.401
-1.14 -1.32 -0.46
1.55 0.399 -0.0469
-0.544 -0.943 -0.369
-0.644 -1.01 -0.384
-1.32 -1.44 -0.488
-1.52 -1.57 -0.519
0.383 -0.35 -0.227
-1.13 -1.32 -0.46
0.191 -0.473 -0.256
-1.27 -1.41 -0.481
-0.505 -0.918 -0.363
1.13 0.129 -0.112
0.39 -0.345 -0.226
1.32 0.248 -0.0832
-0.787 -1.1 -0.406
-1.27 -1.41 -0.48
1.23 0.191 -0.097
-1.04 -1.26 -0.445
-1.43 -1.51 -0.505
0.726 -0.13 -0.174
0.241 -0.441 -0.249
0.123 -0.516 -0.267
-0.663 -1.02 -0.387
-1.29 -1.42 -0.484
1.57 0.408 -0.0448
-0.408 -0.856 -0.348
0.341 -0.376 -0.233
0.191 -0.473 -0.256
1.05 0.0739 -0.125
1.18 0.16 -0.104
-1.43 -1.51 -0.505
0.157 -0.494 -0.261
-0.109 -0.665 -0.302
-0.511 -0.922 -0.364
1.06 0.0844 -0.123
0.161 -0.492 -0.261
0.659 -0.174 -0.184
-1.17 -1.34 -0.465
-1.06 -1.27 -0.448
0.201 -0.466 -0.255
1.58 0.417 -0.0426
-1.39 -1.48 -0.499
0.509 -0.269 -0.207
-0.881 -1.16 -0.421
0.595 -0.214 -0.194
0.852 -0.0494 -0.155
1.01 0.0509 -0.131
-0.804 -1.11 -0.409
-0.462 -0.891 -0.357
1.18 0.163 -0.104
-1.11 -1.31 -0.456
-0.542 -0.942 -0.369
0.64 -0.185 -0.187
-0.204 -0.725 -0.317
0.155 -0.496 -0.262
-1.01 -1.24 -0.441
-1.41 -1.5 -0.503
0.0378 -0.571 -0.28
-1.04 -1.26 -0.446
1.14 0.136 -0.11
-1.34 -1.45 -0.491
Press any key to continue . . .
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
The code will not generate an integral or running sum as written. The fix is simple.
You have -> velocity = velocity[0] + (Gforce * SAMPLE_RATE * GRAVITYFT_SEC);
That adds the new value to the first and not the previous sum. This code should fix the problem.
Fixed code -> velocity = velocity[i-1] + (Gforce * SAMPLE_RATE * GRAVITYFT_SEC);
The same error is found in the next statement for displacement. Just change the "0" to "i-1". The spreadsheet looks like your code should be that way but when you copy the content of C2 into C3, the referenced cell is always the previous one and not C1. That's accomplished by the "i-1" index.
You have -> velocity = velocity[0] + (Gforce * SAMPLE_RATE * GRAVITYFT_SEC);
That adds the new value to the first and not the previous sum. This code should fix the problem.
Fixed code -> velocity = velocity[i-1] + (Gforce * SAMPLE_RATE * GRAVITYFT_SEC);
The same error is found in the next statement for displacement. Just change the "0" to "i-1". The spreadsheet looks like your code should be that way but when you copy the content of C2 into C3, the referenced cell is always the previous one and not C1. That's accomplished by the "i-1" index.
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
AH man
I fixed it and the displacement is running up to like 180... so that would mean like a total displacement of 180 inches over 3 seconds ? Obviously if this was real data that would mean a pothole owuld be your least concern lol
Also do I put all three arrays in the circular buffer? I don't understand how to keep the data moving and locking in the 3 second windows with continous flow
I fixed it and the displacement is running up to like 180... so that would mean like a total displacement of 180 inches over 3 seconds ? Obviously if this was real data that would mean a pothole owuld be your least concern lol
Also do I put all three arrays in the circular buffer? I don't understand how to keep the data moving and locking in the 3 second windows with continous flow
Code: Select all
GFORCE FT/SEC Inch Displacement Z axis
-0.882 -0.565 -0.136
0.199 -0.437 -0.24
-1.32 -1.29 -0.549
0.928 -0.691 -0.715
0.6 -0.307 -0.788
1.47 0.635 -0.636
0.849 1.18 -0.353
-0.247 1.02 -0.108
1.29 1.85 0.335
0.298 2.04 0.824
-1.04 1.37 1.15
1.1 2.08 1.65
1.52 3.05 2.38
0.078 3.1 3.12
-0.0125 3.09 3.87
1.24 3.88 4.8
0.845 4.42 5.86
0.25 4.58 6.96
0.0463 4.61 8.06
1.37 5.49 9.38
-0.15 5.39 10.7
0.947 6 12.1
1.18 6.75 13.7
-0.791 6.25 15.2
-1.43 5.33 16.5
-1.58 4.32 17.5
1.52 5.29 18.8
-0.208 5.16 20.1
1.36 6.03 21.5
-0.294 5.84 22.9
1.22 6.62 24.5
1.14 7.35 26.3
1.01 8 28.2
0.284 8.18 30.1
1.18 8.93 32.3
-1.43 8.02 34.2
-0.167 7.91 36.1
1.14 8.64 38.2
-1.4 7.74 40
-1.49 6.79 41.7
-0.926 6.2 43.2
-0.575 5.83 44.6
0.978 6.46 46.1
-0.909 5.87 47.5
1.46 6.81 49.2
0.353 7.04 50.8
-1.12 6.32 52.4
-1.12 5.6 53.7
-0.141 5.51 55
0.463 5.8 56.4
-1.1 5.1 57.6
0.591 5.48 59
0.0912 5.54 60.3
-0.47 5.23 61.5
-0.437 4.96 62.7
0.734 5.42 64
-0.343 5.21 65.3
0.836 5.74 66.7
-1.11 5.03 67.9
-0.771 4.54 69
-0.783 4.04 69.9
-0.501 3.72 70.8
-0.569 3.35 71.6
0.765 3.84 72.5
0.568 4.21 73.5
-1.45 3.28 74.3
0.391 3.53 75.2
0.339 3.75 76.1
0.797 4.26 77.1
1.3 5.09 78.3
0.237 5.24 79.6
1.52 6.21 81.1
0.314 6.41 82.6
0.369 6.65 84.2
-0.598 6.26 85.7
-0.905 5.68 87.1
-0.732 5.22 88.3
-1.47 4.27 89.4
0.828 4.8 90.5
0.261 4.97 91.7
0.0473 5 92.9
1.53 5.98 94.3
1.24 6.77 96
-0.0228 6.76 97.6
-0.0453 6.73 99.2
-1.07 6.04 101
-0.345 5.82 102
0.652 6.24 104
1.37 7.12 105
1.15 7.85 107
0.0238 7.87 109
1.43 8.79 111
1.08 9.48 113
1.53 10.5 116
-0.709 10 118
-0.811 9.48 121
-1.06 8.8 123
-1.22 8.02 125
-1.4 7.13 126
0.129 7.21 128
0.199 7.34 130
-0.182 7.22 132
0.135 7.31 133
0.885 7.87 135
0.678 8.31 137
0.922 8.9 139
-1.54 7.91 141
-1.16 7.16 143
-0.632 6.76 145
1.3 7.59 146
-0.67 7.16 148
0.124 7.24 150
-1.19 6.48 151
-0.728 6.01 153
1.22 6.79 154
-1.33 5.94 156
-0.402 5.69 157
-0.532 5.35 159
1.27 6.16 160
0.323 6.37 162
0.428 6.64 163
0.414 6.91 165
-0.614 6.51 166
1.37 7.39 168
0.449 7.68 170
0.55 8.03 172
1.33 8.88 174
-1.2 8.11 176
-0.641 7.7 178
-1.59 6.69 179
1.02 7.34 181
-0.86 6.79 183
-1.55 5.79 184
-0.515 5.46 189
0.352 5.69 187
0.824 6.22 188
1.14 6.94 190
-1.03 6.29 192
-1.13 5.56 193
0.139 5.65 194
0.293 5.84 196
1.08 6.53 197
-1.23 5.75 199
-1.1 5.04 200
-1.17 4.29 201
-0.8 3.78 202
-0.905 3.2 203
-0.0769 3.15 203
-0.323 2.95 204
-0.0189 2.93 205
Press any key to continue . . .
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
Each of the three arrays would be a circular buffer which would be continuously filled and evaluated during actual road use. For your testing purposes, you can fill the accel array with real data for some length of time and calculate the other two arrays at the same index position as you collect each data point, just as you're doing now. The line that gets the random number would be replaced by an analog read of the sensor data. You could just clamp the sensor to a table and smack it with a book somewhere during the capture. Accel and velocity should ring and displacement should show some disturbance with the same height before and after the smack.
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
hmmm I'm perplexed can't get my circular buffer to work it keeps crashing :///
Code: Select all
#include <cstdlib>
#include <iostream>
#include <BANNED>
#include <ctime> // USED BY RAND
#include <windows.h> // Used for delay
using namespace std;
#define SAMPLE_RATE 0.020 // Sample rate in Milliseconds
#define GRAVITYFT_SEC 32 // Gravity velocity 32 feet/sec
#define INCH_FOOT 12 // 12 inches in foot, from velocity to inch displacement calculation
void READ_BUFFER();
class RingBuffer
{
private:
int size;
float* buffer;
int start;
int end;
int cnt;
public:
RingBuffer(int size);
~RingBuffer();
void push(float value);
float pop();
float peek();
int count();
};
RingBuffer::RingBuffer(int size)
: size(size), start(0), end(0), cnt(0)
{
buffer = (float*)calloc(size, sizeof(float));
}
RingBuffer::~RingBuffer()
{
free(buffer);
}
void RingBuffer::push(float value)
{
buffer[end] = value;
if (++end > size) end = 0;
if (cnt == size) {
if (++start > size) start = 0;
} else {
++cnt;
}
}
float RingBuffer::pop()
{
float value = buffer[start];
if (cnt > 0) {
--cnt;
if (++start > size) start = 0;
}
return value;
}
float RingBuffer::peek()
{
return buffer[start];
}
int RingBuffer::count()
{
return cnt;
}
RingBuffer Gforce(150);
RingBuffer velocity(150);
RingBuffer displacement(150);
int main(int argc, char *argv[])
{
srand((unsigned)time(0)); // SEED RAND() for simulation of Geforce Readings
// SIMULATING ACCELERATION READINGS INTO A CIRCULAR BUFFER
//Simulate a sample run of Acceleration data using Rand()
// WE WILL BE SIMULATING "RANDOM" GEFORCE RATINGS using the rand() function constraining to -1.6 to 1.6 GFORCE
// These ratings are consistent with our road tests of apparently random vibration and Geforce readings not exceeding about 1.6 G's
//float Gforce[150]; // Random Geforce for 3 second window of data
//float velocity[150]; // Hold velocity information
// float displacement[150]; // Hold Displacement information
float LO = -1.6; // Low GForce limit recorded from 6 road tests at different speeds
float HI = 1.6; // High GForce limit recorded from 6 road tests at different speeds
for(int i = 0; i < 300; i++) // 6 Second iwndow of random acceleration data pretend this is streaming data from analogREAD()
{
if (Gforce.count() == 150) // if we are at a 3 second window
READ_BUFFER(); // READ the contents
Gforce.push(LO + (float)rand()/((float)RAND_MAX/(HI-LO))); // Borrowed from Stackexchange : http://stackoverflow.com/questions/686353/c-random-float
/*
if( i == 0) // Initial values @ first Acceleration
{
velocity.push((Gforce.peek() * SAMPLE_RATE * GRAVITYFT_SEC)); // Initial velocity
displacement.push((velocity.peek() * SAMPLE_RATE * INCH_FOOT)); // Initial Displacement
}
*/
velocity.push(velocity.peek() + (Gforce.pop() * SAMPLE_RATE * GRAVITYFT_SEC)); // Calculate running velocity into buffer
displacement.push(displacement.peek() +(velocity.pop() * SAMPLE_RATE * INCH_FOOT)); // Calculate running displacement into buffer
Sleep(SAMPLE_RATE*1000); // 20mS delay simulates 50HZ sampling rate Sleep() expects number in mS already so * 1000
}
system("PAUSE");
return EXIT_SUCCESS;
}
void READ_BUFFER()
{
// PRINT RESULTS
cout << "GFORCE" << "\t\t" << "FT/SEC" << "\t\t" << "Inch Displacement Z axis" << endl << endl;
for (int j = 0; j < 150; j++)
{
cout << setprecision (3) << Gforce.pop() << "\t\t" << velocity.pop() << "\t\t" << displacement.pop() << endl;
}
}
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
Here's a short sketch to collect the acceleration data and calculate the velocity and displacement arrays. The data will appear in the serial monitor and can then be copied and pasted into a spreadsheet. A few values in the #define section will have to be changed to match your experiment. Also, the ADC initializing in setup() and scaling and offset needs to be adjusted in loop(). If this works OK for you then I'll add the circular buffer part for continuous capture and threshold triggering. You may need to use a Mega due to memory requirements for the arrays.
Code: Select all
// Pothole Detector V1.0 by Arctic_Eddie, 2/5/2013
// This sketch detects and processes data collected from an accelerometer for a fixed length of time
// Define constants
#define SAMPLE_DELAY 200 // Sample delay in milliseconds, probably 20
#define GRAVITYFT_SEC 32.174 // Gravity to velocity,feet/sec
#define G_OFFSET 2.0 // Make the G reading zero for the resting state
#define G_SCALE 4.0 // If accelerometer is on +/- 2G scale
#define INCH_FOOT 12.0 // 12 inches in foot, from velocity to inch displacement calculation
#define NUM_SAMPLES 20 // Capture 6 seconds, probably 300
#define ACCEL_PIN A0 // Use analog pin A0
// Define global veriables
uint16_t indeX = 0; // Pointer into data arrays
uint32_t dTime; // Clock time for delayed reading
float acceleration[NUM_SAMPLES]; // Space for accel samples
float velocity[NUM_SAMPLES]; // Space for velocity samples
float displacement[NUM_SAMPLES]; // Space for displacement samples
// Set up system
void setup()
{
Serial.begin( 115200 ); // Prepare the serial monitor to receive the data
Serial.println( "\n\rTime, Acceleration, Velocity, Displacement" ); // Print heading
// Initialize the accelerometer ****************************
// Start the delay clock
dTime = millis();
}
void loop()
{
// Collect the specified amount of data, calculate other values, and print results
// This section is for a single pass to fill the arrays once ********************
// Get a random value or use accelerometer reading here
acceleration[indeX] = ( ( analogRead( ACCEL_PIN ) / 1024.0 ) * G_SCALE ) - G_OFFSET; // Get an acceleration reading
// Calculate the running sum integral for velocity and displacement
if( indeX == 0 ) // First reading, no previous data to add to running sum
{
velocity[indeX] = acceleration[indeX] * SAMPLE_DELAY * GRAVITYFT_SEC / 1000.0;
displacement[indeX] = velocity[indeX] * SAMPLE_DELAY * INCH_FOOT / 1000.0;
}
else // Not the first reading so add the data from the previous index
{
velocity[indeX] = ( acceleration[indeX] * SAMPLE_DELAY * GRAVITYFT_SEC / 1000.0 )
+ velocity[indeX-1]; // The running sum
displacement[indeX] = ( velocity[indeX] * SAMPLE_DELAY * INCH_FOOT / 1000.0 )
+ displacement[indeX-1]; // The running sum
}
// Print the results in spreadsheet readable format
Serial.print( float( indeX * SAMPLE_DELAY ) / 1000.0 ); // The actual time value
Serial.print( ", " ); // Add a comma separator
Serial.print( acceleration[indeX] ); // Acceleration
Serial.print( ", " ); // Add a comma separator
Serial.print( velocity[indeX] ); // Velocity
Serial.print( ", " ); // Add a comma separator
Serial.println( displacement[indeX] ); // Displacement
// Pause until the next interval
// Check clock for correct delay
while( ( millis() - dTime ) < ( SAMPLE_DELAY * indeX ) ) {} // Pause here until sample interval has passed
indeX++;
if( indeX > NUM_SAMPLES ) // Stall here, test is over
{
Serial.print( "End of test" );
while( true ) {} // Stall here
}
}
// Supporting routines go here *********************************************
-
- Posts: 25
- Joined: Thu Aug 16, 2012 6:21 pm
Re: Pothole data smoothing and detection of accelerometer data
Yeah nice seems to work similar to my previous code.
The continuous sampling into the circular buffer with triggering is the hardest part I can't get working hahah Its bugging me right now haha
My accelerometer is -3g to +3g so scale would be 6.0 right? seems to be working
Here are some of my thoughts,
We will be sampling continously as long as the Arduino is running.
The continuously data is being streamed into the circular buffer of a "window" size of N seconds
The window size "array size" of N samples is then operated on by integration for velocity and displacement.
The current running sum, will get the total displacement for the window size of N seconds correct?
so for a pothole event, trigger, there would have to be a routine to find the max displacement given in the window at that time. Or the average then max, not sure
Would negative and positive displacement, be a key signature, if you have a large negative displacement and a large positive displacement within the window, that could be a pothole, or would we take the ABS() and not worry about the negative.
Also, would each "window" be independent, meaning everything gets reset as old data is being replaced by new data. I think if each window's displacement dependended on previous windows displacement, it would have a very large approaching infinity integration error?
The continuous sampling into the circular buffer with triggering is the hardest part I can't get working hahah Its bugging me right now haha
My accelerometer is -3g to +3g so scale would be 6.0 right? seems to be working
Here are some of my thoughts,
We will be sampling continously as long as the Arduino is running.
The continuously data is being streamed into the circular buffer of a "window" size of N seconds
The window size "array size" of N samples is then operated on by integration for velocity and displacement.
The current running sum, will get the total displacement for the window size of N seconds correct?
so for a pothole event, trigger, there would have to be a routine to find the max displacement given in the window at that time. Or the average then max, not sure
Would negative and positive displacement, be a key signature, if you have a large negative displacement and a large positive displacement within the window, that could be a pothole, or would we take the ABS() and not worry about the negative.
Also, would each "window" be independent, meaning everything gets reset as old data is being replaced by new data. I think if each window's displacement dependended on previous windows displacement, it would have a very large approaching infinity integration error?
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
The G_SCALE would be 6.0. However, if the ADC range, 0 - 1023, equals -3G to +3G then you can modify the map() function to get an fmap() function. Then fmap() the raw ADC reading directly to G. You can make the function by copying map() to fmap() then change the data type from long to float. You would still need to apply the G_OFFSET or you could skew the G map range so that the offset is included, -2G to +4G.
The window values will start with the end of the previous data, unless you reset the window arrays, preferred. Otherwise, your threshold detector might be confused if you had been going up or down a hill. You may have to maintain a running average of previous data as a baseline.
If the window arrays are reset each time then a pothole is some negative value relative to the starting value. You'll have to do some actual tests with an A-frame mounted sensor to see the real profile.
I'm working on the continuous version now. It doesn't have a window but is a continuous stream using a revolving short buffer. You would add threshold detectors and resets to the output arrays.
The window values will start with the end of the previous data, unless you reset the window arrays, preferred. Otherwise, your threshold detector might be confused if you had been going up or down a hill. You may have to maintain a running average of previous data as a baseline.
If the window arrays are reset each time then a pothole is some negative value relative to the starting value. You'll have to do some actual tests with an A-frame mounted sensor to see the real profile.
I'm working on the continuous version now. It doesn't have a window but is a continuous stream using a revolving short buffer. You would add threshold detectors and resets to the output arrays.
- arctic_eddie
- Posts: 233
- Joined: Tue Feb 28, 2012 6:01 pm
Re: Pothole data smoothing and detection of accelerometer data
Here is the continuous version. You will have to add your sensor initialization and adjust some of the #define statements. For continuous sampling, you don't need a buffer but only the sum of the previous values for the running integral. However, if you want a past history window for a running average then you will need the buffer. The buffer should hold data for twice the length of the event you want to detect. The running average will use the oldest half so that when the event is complete then the averaging window is just entering the event window.
Good luck on your project.
Good luck on your project.
Code: Select all
// Pothole Detector V2.0 by Arctic_Eddie, 2/5/2013
// This sketch detects and processes data collected from an accelerometer on a continuous basis.
// Threshold detectors can be added which operate on the three arrays to count particular events.
// Define constants
#define SAMPLE_DELAY 200.0 // Sample delay in milliseconds, probably 20
#define GRAVITYFT_SEC 32.174 // Gravity to velocity,feet/sec
#define G_OFFSET 1.0 // Make the G reading zero for the resting state, usually 1.0 for actual use
#define G_SCALE 6.0 // If accelerometer is on +/- 3G scale
#define INCH_FOOT 12.0 // 12 inches in foot, from velocity to inch displacement calculation
#define NUM_SAMPLES 20 // Capture 6 seconds, probably 300
#define ACCEL_PIN A0 // Use analog pin A0
// Define global veriables
uint8_t firstTime = true; // First time through loop so initial calc not same as first rollover
uint16_t indeX = 0; // Pointer into data arrays
uint32_t tindeX = 0; // Total index counter and not reset
uint32_t dTime; // Clock time for startup reading
float acceleration[NUM_SAMPLES]; // Space for acceleration samples
float velocity[NUM_SAMPLES]; // Space for velocity samples
float displacement[NUM_SAMPLES]; // Space for displacement samples
// Set up system
void setup()
{
Serial.begin( 115200 ); // Prepare the serial monitor to receive the data
Serial.println( "\n\rTime, Acceleration, Velocity, Displacement" ); // Print heading
randomSeed( analogRead( A1 ) ); // Seed the random number generator with noise
// Initialize the accelerometer ****************************
// Start the delay timer
dTime = millis();
}
void loop()
{
// Collect continuous data, calculate other values, and print results
// This section is for continuous running to fill the arrays
// Get a random value or use accelerometer reading here
///acceleration[indeX] = ( ( analogRead( ACCEL_PIN ) / 1024.0 ) * G_SCALE ) - G_OFFSET; // Get an acceleration reading
acceleration[indeX] = float( random( 1025 ) - 512 ) / 1024.0; // Make it +/- 0.5G
// Calculate the running sum integral for velocity and displacement
if( indeX == 0 ) // First reading, no previous data to add to running sum
{
if( firstTime == true ) // Load the first position with initial data
{
velocity[indeX] = acceleration[indeX] * SAMPLE_DELAY * GRAVITYFT_SEC / 1000.0;
displacement[indeX] = velocity[indeX] * SAMPLE_DELAY * INCH_FOOT / 1000.0;
firstTime = false; // Prevent first time from happening again
}
else // Use last position, NUM_SAMPLES-1, just before rollover for accumulated values
{
velocity[indeX] = ( acceleration[indeX] * SAMPLE_DELAY * GRAVITYFT_SEC / 1000.0 )
+ velocity[NUM_SAMPLES-1]; // The previous running sum
displacement[indeX] = ( velocity[indeX] * SAMPLE_DELAY * INCH_FOOT / 1000.0 )
+ displacement[NUM_SAMPLES-1]; // The previous running sum
}
}
else // Not the first reading so add the data from the previous index
{
velocity[indeX] = ( acceleration[indeX] * SAMPLE_DELAY * GRAVITYFT_SEC / 1000.0 )
+ velocity[indeX-1]; // The running sum
displacement[indeX] = ( velocity[indeX] * SAMPLE_DELAY * INCH_FOOT / 1000.0 )
+ displacement[indeX-1]; // The running sum
}
// Insert threshold detector, running average, and reset action here *******************
// Print the results in spreadsheet readable format
Serial.print( float( tindeX * SAMPLE_DELAY ) / 1000.0 ); // The actual time value
Serial.print( ", " ); // Add a comma separator
Serial.print( acceleration[indeX] ); // Acceleration
Serial.print( ", " ); // Add a comma separator
Serial.print( velocity[indeX] ); // Velocity
Serial.print( ", " ); // Add a comma separator
Serial.println( displacement[indeX] ); // Displacement
// Pause until the next interval, check clock for correct delay
while( ( millis() - dTime ) < ( SAMPLE_DELAY * tindeX ) ) {} // Pause here until sample interval has passed
// Index the pointers
tindeX++; // Increment the total index pointer
indeX = ++indeX % NUM_SAMPLES; // Increment the array indexer but cause rollover, circular buffer
}
// Supporting routines go here *********************************************
float fmap( float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Please be positive and constructive with your questions and comments.