I'm trying to poll an accelerometer every x ms on 3 axiz, and trying to figure out how to determine the peaks and troughs of the readings I get.
Ideally, I wouldn't want to collect a whole bunch of data before I can start counting the peaks - maybe every 10 minutes at most if data collection is first required. The peaks should also only be counted if the absolute value of the peak is within an acceptable "distance" of the average set of peaks - to prevent a very small peak from being counted...
I would appreciate any pointers wrt doing this?
You can start with calculation of standard deviation and count peaks which deviates more than a specified level.
Wiki article
It depends on what your signal looks like. I solved a similar problem with a sinusoidal signal using an used a IIR filter on the signal to smooth out the noise and prevent false peaks.
You might try something like this:
int signalPin = 3; // accel connected to pin 3
float signal;
float gain = 0.1;
void setup()
{
pinMode(signalPin, INPUT);
signal = analogRead(signalPin); // get initial reading
}
void loop()
{
// allow a new reading of the accel to slightly change the signal (depending on the value of gain)
signal += (analogRead(signalPin)*gain - signal); // IIR filter
}
You will probably also want to use the map function to adjust the value obtained from analogRead, as well as use int or long instead of float if you're worried about efficiency.
Now you can use a strategy like the following:
Read a new value from the accel (checking if a new value is higher than the previous and if so, save it as the new max. When they stop increasing, that is your max value. You can require N number of samples within a certain threshold to verify you are at the flat top of the peak. Hopefully, this gets you started.
Related
I'm trying to port an Arduino AVR routine either to ESP32/8266 or a Python script and would appreciate understanding how to crack the operation of this program. I'm self-teaching and am only looking to get something that works - pretty isn't required. This is a hobby and I am the only audience. The basic operations are understood (99% certain ;)) - there are 4 arrays total: Equilarg and Nodefactor contain 10 rows of 37 values; startSecs contains the epochtime values for the start of each year (2022-2032); and speed contains 37 values.
I believe each row of the Equilarg and Nodefactor arrays corresponds to the year, but I can't work out how the the specific element is pulled from each of the 3, 37 element arrays.
Here is the operating code:
// currentTide calculation function, takes a DateTime object from real time clock.
float TideCalc::currentTide (DateTime now)
{
// Calculate difference between current year and starting year.
YearIndx = now.year() - startYear;
// Calculate hours since start of current year. Hours = seconds / 3600
currHours = (now.unixtime() - pgm_read_dword_near (&startSecs[YearIndx])) / float(3600);
// Shift currHours to Greenwich Mean Time
currHours = currHours + adjustGMT;
// **************Calculate current tide height**********
// initialize results variable, units of feet.
// (This is 3.35 if it matters to understanding how it works)
tideHeight = Datum;
for (int harms = 0; harms < 37; harms++)
{
// Step through each harmonic constituent, extract the relevant
// values of Nodefactor, Amplitude, Equilibrium argument, Kappa
// and Speed.
currNodefactor = pgm_read_float_near (&Nodefactor[YearIndx][harms]);
currAmp = pgm_read_float_near (&Amp[harms]);
currEquilarg = pgm_read_float_near (&Equilarg[YearIndx][harms]);
currKappa = pgm_read_float_near (&Kappa[harms]);
currSpeed = pgm_read_float_near (&Speed[harms]);
// Calculate each component of the overall tide equation
// The currHours value is assumed to be in hours from the start of
// the year, in the Greenwich Mean Time zone, not the local time zone.
tideHeight = tideHeight + currNodefactor * currAmp
* cos ((currSpeed * currHours + currEquilarg - currKappa) * DEG_TO_RAD);
}
//***************End of Tide Height calculation**********
// Output of tideCalc is the tide height, units of feet.
return tideHeight;
}
I've made several attempts to reverse engineer by running the code on an AVR board and trapping the input values and then work backwards but I'm just not seeing a basic part or two. In this instance knowing "kinda" what's going on falls too short.
pgm_read_float_near reads a float value from flash memory. It needs the address of the value. We give it the address of the indexed value when we use &Amp[harms] for example. Both Nodefactor and Equilarg are doubly indexed - by year and then by harmonic, while the other three are indexed by the harmonic alone.
It sounds like this is a Fourier series curve fit for the tide height. So they're summing up a series of cosine values, each with different amplitude, frequency, and phase.
As #Tom suggests, copy the code to a plain C file, make a little routine for a dummy pgm_read_float_near and see how it works on your PC. Many times I write and debug algorithms on a "big" computer, and later plop the code into the Arduino.
Have fun!
Hi I have a file with following format where am trying to calculate the position of aircraft from radar (approaching airport) every 10 msecs.
Position_X
Position_Y
Heading
Speed
t1
t2 w1
t3 w2
t4
Where w1, w2 = turn rate
in this case {t1, t2, t3, t4} = 200secs ~ 200000 msecs
and evaluating position after every 10 msecs
This is how am processing:
// defined in Plane.h
QElapsedTimer t;
QTimer timer;
// Plane.cpp
Plane::Plane : timer() {
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(computePosition()));
timer.start(10);
t.start();
}
void Plane::computePosition()
{
if (!t.hasExpired(t1)
{
//do
}
if (t.hasExpired(t2) || t.hasExpired(t3))
{
//do
}
if (t.hasExpired(t3) || t.hasExpired(t4))
{
// do
}
if (t.hasExpired(t5))
{
// do
}
if(t.hasExpired(t5 + 100))
timer.stop();
qDebug() << QDateTime::currentMSecsSinceEpoch()<< t.elapsed()
<< Position_X << Position_Y;
}
am not able to match system time with elapsed time or condition time. timer interval rate is 10 ms but in debug I see it varies from 15-40 secs. And also the approach time is 200 ms but with using elapsed timer to evaluate position pushes the plane matrix way out of the airport.
How do I make sure my program is running at time intervals t1, t2, t3, t4 & t5 and position is evaluated correctly.
Appreciate any ideas or help. Thanks!
Calculation of positions is not a problem.I want to do the calculations at time t1..t5 in conjugation with QTimer (interval is 10 ms).
First of all, you don't need to use timers to do calculations: you can precalculate everything in advance, the calculations use a time variable that doesn't need to be coupled to any timer. It's just a variable you increment as you execute steps of a numerical integration. You have to tell us why you think that the program has to run at some intervals - because thus far it's simply false. It's hardly even a Qt problem, it's plain old numerical methods. The calculations are simple; for every time step:
Start at t=0.
Update heading according to current turn rate.
Convert radial speed to cartesian speed.
Integrate speed into position.
Select next turn rate if current t is past given t_i.
Increment t by 10ms.
Repeat from #2 unless current time t is past end time.
That's it. You're free to choose whatever integration rule you want. t is just a variable. It doesn’t have anything to do with passage of time on the computer that computes the results.
The rest depends on what is the meaning of the times t1-t4, and what are the outputs you're looking for - whether you want time time history from starting position until some time t4+0.1s, or just 4 outputs - one for each time t1-t4, etc.
QTimer most likely won't be able to maintain strict 10 ms ticks. QElapsedTimer can be more accurate, but it's meant more to measure performance of functions, methods, etc.
If you want to simulate an interval of X ms, just set up the QTimer to fire at a particular interval. Then, you can maintain a counter that increments each time the timeout signal is emitted. From there, you can calculate your "simulated time", which would be T = X * count. There's no need for a QElapsedTimer at all.
QTimer isn't "hard real-time". If you absolutely must have hard real-time, you'll have to look elsewhere.
Can someone please guide me how to generate lookup table for generating 50 hz sine wave using PWM in Atmega32.
This is what i have done so far but confused of what to do.
50 Hz sine wave so 20 ms time period
256 samples (No. of divisions)
step i need to increase = 20 ms/256 = 0.078125 ms (Period of PWM signal)
angle step rate = 360/256 = 1.40625
Amplitude of sine wave should be 1.
I think you are starting from the wrong end and getting lost because of that.
Ignoring the lookup table, can you generate a 50 Hz PWM signal usign explicit calls to sin() ? Good. Now the lookup table saves you those expensive sin calls. sin is a periodic function, so you need to store only one period (*). How many points that are depends on your digital output frequency, which is going to be much more than 50 Hz. How much more defines the number of points in your lookup table.
To fill your lookup table, you don't send the result of your PWM function to the digital output but youwrite it to the lookup table. To use the lookup table, you don't call the expensive function but you just copy the table entries straight to your output.
There is one common optimization: A since function has a lot of repetition. You don't need to store the send half, that's just the inverse of the first half, and the second quarter is just the first quarter mirrored.
I've just hooked up a electret microphone to an Arduino, and I'd like to sample between the ranges of 1 kHz and 4 kHz.
I understand this is limited to the machine code and the ADC, so I'm trying to keep the sketch simple.
Is it possible to sample between these frequencies with the sketch below?
const int analogPin = 0;
int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
int mn = 1024;
int mx = 0;
for (int i = 0; i < 5; ++i) {
int val = analogRead(analogPin);
mn = min(mn, val);
mx = max(mx, val);
}
if (mx-mn >= 50) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
}
Arduino is a prototyping platform consisting of a number of hardware boards plus a software abstraction layer. For a question like this, it is useful to consider the capabilities of the underlying hardware, as these provide the ultimate limits. I'll assume you are using Arduino Uno/Nano, the story is different for Due.
According to the datasheet, each ADC reading (beyond the first one) takes 13 ADC clock cycles. ADC clock (different from the MCU) clock is derived by dividing the system clock by some factor, at least 2. So at 16Mhz board this amounts to 0.6 million samples per second. So far so good. However, that's not the end of the story, you still need to read the data. If you use interrupts, even if you do something very simple, experience suggests that you will lose about 100 clock to interrupt processing. Now you are down to 126K samples/second. But this is a theoretical maximum.
The datasheet states that for maximum accuracy for the ADC requires 50kHz - 200kHz ADC clock. In the Arduino code (in wiring.c), a division factor of 128 is chosen:
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
This means that each conversion takes 128*13 = 1764 clocks, which yields a theoretical maximum of 10K samples per second. It is a little bit worse than that given that the readAnalog() function does something beyond just starting the ADC conversion and waiting for it to finish, but it shouldn't be too much worse. This doesn't involve your code of course: any processing you do on the results of readAnalog() will make it more difficult to capture more samples. But yes, to capture at 4Khz you will need to make sure that you code spends less than 1.5k clock cycles/sample, which should be doable. Note that if you are doing five readings like you are doing in the code you posted, the maximum capture rate will be 2kHz if your code does very little.
As far as how to capture the data, you need to make deal with the fact that microphones without amplification will not give you 0-5V readings that you might expect if you are using analogRead(). In fact, microphone output voltages swing from positive to negative, however, the negative voltages will not be picked up by the ADC, and show up as just zeros, unless you give your microphone a voltage offset.
I am not exactly sure what your code that compares minimum amplitude to maximum amplitude is supposed to be doing. Are you wanting to digitize the audio? In this case you need to save all the amplitude readings collected from analogRead(), and then you can run FFTs on them on another computer: Arduino is most likely not going to be fast enough to do frequency analysis on the data.
I have heard, or rather remember reading, that the ADC could handle up to 10k-samples per second, so it should be OK up to 5 kHz. However, I have not tried this nor do I have a link to back it up at the moment.
Just try and see.
Now I know some of the Arduino library functions are slow, notably the DigitalRead/Write that has overhead of hundreds of cycles. Most of this is the sanity checking that allows people to just perform DigitalRead/Write without thinking much about setting everything up.
However, to squeeze out the maximum performance you could look into writing your own AnalogRead that is optimized for your use case.
At least some links on the subject:
Pin I/O performance (JeeLabs)
C++ Template method for faster access (JeeLabs)
I happen to have just tried this using an Arduino Uno and similar code to yours and I've been able to sample an average of 8000 times a second. That is the Nyquist frequency for 4 kHz so you're good but not much margin for error.
I have a buffer full of real/imaginary sample values of a signal, and would like to shift the signal in the frequency domain by multiplying a sinusoid.
I see myself with four options:
some IPP function (I could not find one though)
manually calculate the result (probably slower than IPP)
generate the sinusoid in a separate buffer (probably requires lots of memory)
generate parts of the sinusoid in a separate buffer (requires recalculating the tone buffer)
I'm wondering what would be the best approach here, and/or whether I have just missed that there is a readymade function for frequency shifting a complex signal.
If you are going for speed, do it in the frequency domain.
FFT -> circular shift by N bins -> IFFT
I have found the ffw++ wrapper quite handy.
If you are really set on doing it in the time domain, you could use Intel's VML functions in some fashion like this:
// Create a single period of frequency offset wave
vector<complex<float> > cxWave(period);
for(int i = 0; i < period; ++i)
cxWave = i * 2 * M_PI / period;
vcExp( period, &cxWave.at(0), &cxWave.at(0) );
// Multiply entire signal by the complex sinusoid
for(int frame=0; frame < numFrames; ++frame)
{
vcMul( period, &input.at(frame*period), &cxWave.at(0), &cxWave.at(0) );
}
You would of course need to fill in the blanks.