You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
3.2 KiB
C
91 lines
3.2 KiB
C
3 years ago
|
/*
|
||
|
(WORK IN PROGRESS)
|
||
|
Penguin's Circular Buffer Example -- Turning a noisy bell curve into a less
|
||
|
noisy bell curve
|
||
|
|
||
|
Here's an example of using the circular buffer library for sensor data:
|
||
|
|
||
|
Let's say I have a sensor that gives me temperature at 1khz (using ideals so
|
||
|
it is exactly 1khz) If this sensor was only giving me raw analog data, I
|
||
|
might want to do some processing on these values so that I can make sure the
|
||
|
values are as clean as possible. The more samples we have, the closer we are
|
||
|
to the actual value. The faster we gather samples, the closer we get to
|
||
|
representing our data in realtime.
|
||
|
|
||
|
Using the sample rate, I can decide on a sampling window (in seconds) and an
|
||
|
OSR (Oversampling Rate). The larger the buffer size, the more memory I need,
|
||
|
so it is useful to find a happy medium between a large buffer and clean
|
||
|
values.
|
||
|
|
||
|
A sampling window is the window of time in which we can accept values for an
|
||
|
average value. Depending on your application, a sampling window may need to
|
||
|
be extremely small or maybe not so small. A rocket going extremely fast using
|
||
|
some sensor for real time controls will want an extremely small sampling
|
||
|
window as well as a lot of measurements for both clean, near noiseless data
|
||
|
and as close to realtime data as possible.
|
||
|
|
||
|
The sampling windows is usually an engineering requirement given that can
|
||
|
match the sampling rate of the sensor with the following: sampling window (in
|
||
|
seconds) = 1 / frequency Here, the OSR is simply 1.
|
||
|
|
||
|
So at 1khz sample rate, let's say I decide I only need a 0.125 second sample
|
||
|
window and I want to clean up some noisy data. We can now use this equation:
|
||
|
OSR = frequency * sample window (in seconds)
|
||
|
|
||
|
All of these have ignored real world slowdowns like the time it takes to do
|
||
|
math on lower end hardware, interrupts slightly delaying the math, etc
|
||
|
Without wanting to do some hard analysis on whatever hardware we're using, I
|
||
|
usually take my frequency and half it to ensure timing requirements are met,
|
||
|
like so:
|
||
|
|
||
|
OSR = frequency / 2 * sample window
|
||
|
|
||
|
Please note: In applications that require real real-time data, this is not a
|
||
|
good way of doing things.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "p_cbuffer.h"
|
||
|
|
||
|
DEFINE_CBUFFER(int);
|
||
|
#define CBUFFER_SIZE (6)
|
||
|
|
||
|
void display(cbuffer_int_t* cbuffer)
|
||
|
{
|
||
|
printf("Cbuffer:\n");
|
||
|
for (int ind = 0; ind < cbuffer->msize; ind++)
|
||
|
{
|
||
|
printf("[%d]: %d\n", ind, cbuffer->buffer[ind]);
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
cbuffer_int_t cbuffer;
|
||
|
int data[CBUFFER_SIZE];
|
||
|
|
||
|
cbuffer_int_init(&cbuffer, data, CBUFFER_SIZE);
|
||
|
cbuffer.push(&cbuffer, 1);
|
||
|
cbuffer.push(&cbuffer, 2);
|
||
|
cbuffer.push(&cbuffer, 3);
|
||
|
cbuffer.push(&cbuffer, 4);
|
||
|
cbuffer.push(&cbuffer, 5);
|
||
|
printf("Is cbuffer filled? %s\n",
|
||
|
cbuffer.is_filled(&cbuffer) ? "Yes" : "No");
|
||
|
cbuffer.push(&cbuffer, 6);
|
||
|
printf("Is cbuffer filled? %s\n",
|
||
|
cbuffer.is_filled(&cbuffer) ? "Yes" : "No");
|
||
|
display(&cbuffer);
|
||
|
cbuffer.push(&cbuffer, 7);
|
||
|
display(&cbuffer);
|
||
|
printf("Emptying cbuffer...\n");
|
||
|
printf("Is cbuffer filled? %s\n",
|
||
|
cbuffer.is_filled(&cbuffer) ? "Yes" : "No");
|
||
|
cbuffer.empty(&cbuffer);
|
||
|
cbuffer.push(&cbuffer, 8);
|
||
|
display(&cbuffer);
|
||
|
printf("Is cbuffer filled? %s\n",
|
||
|
cbuffer.is_filled(&cbuffer) ? "Yes" : "No");
|
||
|
}
|