Offline
Newbie
Karma: 0
Posts: 12
|
 |
« on: December 11, 2012, 05:21:36 am » |
is it possible? My project measures wheel speed by measuring time between interrupts. At low speed (<20hz) its fairly accurate and i can use a small array of 1 or 2 readings for fast response; but at 800hz and up i need a bigger array (8-10) to smooth out the readings. is it possible to have an array that changes size dynamically? if i tru declaring the array as anything but constant i get errors. right now the ISR changes the position of itself in the array and i want to keep that code small so i dont possibly miss any other interupts. anyway here is my in progress code: const int SnumRead = 8; const int pot = A0;
volatile unsigned long pulse0[SnumRead]; volatile unsigned long pIndex0 = 0; volatile unsigned long nowPulse0 = 0; volatile unsigned long lastPulse0 = 0; volatile unsigned long i0, sum0, average0 = 0; float rate0;
volatile unsigned long pulse1[SnumRead]; volatile unsigned long pIndex1 = 0; volatile unsigned long nowPulse1 = 0; volatile unsigned long lastPulse1 = 0; volatile unsigned long i1, sum1, average1 = 0; float rate1;
volatile unsigned long pulse2[SnumRead]; volatile unsigned long pIndex2 = 0; volatile unsigned long nowPulse2 = 0; volatile unsigned long lastPulse2 = 0; volatile unsigned long i2, sum2, average2 = 0; float rate2;
volatile unsigned long pulse3[SnumRead]; volatile unsigned long pIndex3 = 0; volatile unsigned long nowPulse3 = 0; volatile unsigned long lastPulse3 = 0; volatile unsigned long i3, sum3, average3 = 0; float rate3;
float slip; float threshold; float overslip; float overslipscale = 25;
void setup() { pinMode(13, OUTPUT); Serial.begin(115200); attachInterrupt(0, count0, FALLING); attachInterrupt(1, count1, FALLING); attachInterrupt(2, count2, FALLING); attachInterrupt(3, count3, FALLING ); }
void loop() { average0 = 0; sum0= 0; for (i0 = 0; i0 <= SnumRead; i0++) { sum0 +=pulse0[i0]; } average0 = sum0 / SnumRead; rate0 = (float)1000000 / average0; average1 = 0; sum1= 0; for (i1 = 0; i1 <= SnumRead; i1++) { sum1 +=pulse1[i1]; } average1 = sum1 / SnumRead; rate1 = (float)1000000 / average1; average2 = 0; sum2= 0; for (i2 = 0; i2 <= SnumRead; i2++) { sum2 +=pulse2[i2]; } average2 = sum2 / SnumRead; rate2 = (float)1000000 / average2; average3 = 0; sum3= 0; for (i3 = 0; i3 <= SnumRead; i3++) { sum3 +=pulse3[i3]; } average3 = sum3 / SnumRead; rate3 = (float)1000000 / average3;
threshold = analogRead(pot); threshold = threshold / 48.71; slip = max(rate0, rate1) / max(rate2, rate3); slip = 100 * (slip - 1); overslip = slip - threshold; if (overslip < 0) { overslip = 0; } else if (overslip > overslipscale) { overslip = overslipscale; } Serial.println(""); Serial.print(rate0,2); Serial.print(" / "); Serial.print(rate1,2); Serial.print(" / "); Serial.print(rate2,2); Serial.print(" / "); Serial.print(rate3),2; Serial.print(" --- "); Serial.print(threshold),2; Serial.print(" / "); Serial.print(slip),2; Serial.print(" / "); Serial.print(overslip),2; if (threshold < 21) { overslip = map(overslip, 0, overslipscale, 0, 255); analogWrite(11, overslip); digitalWrite(13, HIGH); } else { analogWrite(11, 0); digitalWrite(13, LOW); } delay(5); }
void count0() { nowPulse0 = micros(); pulse0[pIndex0] = nowPulse0 - lastPulse0; pIndex0++; if (pIndex0 > SnumRead) pIndex0 = 0; lastPulse0 = nowPulse0; } void count1() { nowPulse1 = micros(); pulse1[pIndex1] = nowPulse1 - lastPulse1; pIndex1++; if (pIndex1 > SnumRead) pIndex1 = 0; lastPulse1 = nowPulse1; nowPulse1 = 0; } void count2() { nowPulse2 = micros(); pulse2[pIndex2] = nowPulse2 - lastPulse2; pIndex2++; if (pIndex2 > SnumRead) pIndex2 = 0; lastPulse2 = nowPulse2; nowPulse2 = 0; } void count3() { nowPulse3 = micros(); pulse3[pIndex3] = nowPulse3 - lastPulse3; pIndex3++; if (pIndex3 > SnumRead) pIndex3 = 0; lastPulse3 = nowPulse3; nowPulse3 = 0; }
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #1 on: December 11, 2012, 05:28:10 am » |
right now the ISR changes the position of itself in the array and i want to keep that code small so i dont possibly miss any other interupts. No, it doesn't. The ISR is a function. It is not an array element, so it can't move itself in the array. There are ways to dynamically define arrays. You are advised not to use them. The Arduino (328-based, anyway) has little memory. Fragmenting that doing dynamic memory allocation is not advised. Clearly, you are not using a 328 based Arduino, since it does not have 4 interrupt pins. Still, small, static arrays are best.
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6813
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #2 on: December 11, 2012, 06:09:38 am » |
You can, but reallocating memory is probably not for a beginner. Just allocate space for the largest eventuality and save yourself some heartache.
______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #3 on: December 11, 2012, 07:16:32 am » |
is it possible? Yes. My project measures wheel speed by measuring time between interrupts. At low speed (<20hz) its fairly accurate and i can use a small array of 1 or 2 readings for fast response; but at 800hz and up i need a bigger array (8-10) to smooth out the readings. You do not need such (large) arrays to measure wheel speed. Maybe you want to rethink your approach instead.
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Tesla Member
Karma: 89
Posts: 6320
-
|
 |
« Reply #4 on: December 11, 2012, 08:35:34 am » |
Just allocate space for the largest eventuality and save yourself some heartache.
Sounds like the best idea to me. I guess you are using the array as a FIFO buffer to work out a rolling average. In that case you would presumably be using it as a circular buffer. You can change the capacity of a circular buffer very easily, just by subtracting a value from the capacity calculation to prevent the buffer from filling beyond a threshold. If it's really just being used as an array then of course you can change the effective size even more easily, just pretend the array is the size you need and ignore any excess elements. A less precise but much easier approach would be to calculate a decaying average, in which case you don't need to remember historical results at all.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #5 on: December 11, 2012, 11:51:21 pm » |
right now the ISR changes the position of itself in the array and i want to keep that code small so i dont possibly miss any other interupts. No, it doesn't. The ISR is a function. It is not an array element, so it can't move itself in the array. There are ways to dynamically define arrays. You are advised not to use them. The Arduino (328-based, anyway) has little memory. Fragmenting that doing dynamic memory allocation is not advised. Clearly, you are not using a 328 based Arduino, since it does not have 4 interrupt pins. Still, small, static arrays are best. what do you mean it doesnt? nowPulse2 = micros(); pulse2[pIndex2] = nowPulse2 - lastPulse2; pIndex2++; if (pIndex2 > SnumRead) pIndex2 = 0; lastPulse2 = nowPulse2; nowPulse2 = 0;
it seems like its populating the various slots in the array. if i change the sample size it makes a difference. is it possible? Yes. My project measures wheel speed by measuring time between interrupts. At low speed (<20hz) its fairly accurate and i can use a small array of 1 or 2 readings for fast response; but at 800hz and up i need a bigger array (8-10) to smooth out the readings. You do not need such (large) arrays to measure wheel speed. Maybe you want to rethink your approach instead. care to elaborate on this? i need fairly high resolution (measure slip in 1/10 of a percent) so i'm measruring time between pulses. the way i have it setup works great but at high speed the small size of the array leads to some big jumps; upping the size makes it happier. /edit: my first attempt was just counting pulses but at low speed the reaction was way too slow; i need to update the output based on slip at least every 10ms (100hz). even at 20hz there wasn't enough pulses to have enough resolution to have useful data. this timing of pullses works much better. i think i have an idea though; leave the array with 8 spaces but at low speed only use the first 2 then at higher speed maybe 4 then highest speed use all 8. i'll have to try it but i think it'll work better than trying to reallocate memory
|
|
|
|
« Last Edit: December 11, 2012, 11:53:38 pm by computerjlt »
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13896
Lua rocks!
|
 |
« Reply #6 on: December 12, 2012, 12:07:09 am » |
My project measures wheel speed by measuring time between interrupts.
This might help: http://gammon.com.au/forum/?id=11504Two techniques are described near the start of that thread. Counting (getting the frequency directly) and measuring the period and inverting it. One is better for low frequencies and one is better for high frequencies.
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6813
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #7 on: December 12, 2012, 12:11:00 am » |
PaulS commented on this the ISR changes the position of itself in the array You are now saying this populating the various slots in the array. if i change the sample size it makes a difference. Two totally different things. eave the array with 8 spaces but at low speed only use the first 2 then at higher speed maybe 4 then highest speed use all 8. i'll have to try it but i think it'll work better than trying to reallocate memory Sounds like a better plan. _____ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #8 on: December 12, 2012, 10:39:47 pm » |
My project measures wheel speed by measuring time between interrupts.
This might help: http://gammon.com.au/forum/?id=11504Two techniques are described near the start of that thread. Counting (getting the frequency directly) and measuring the period and inverting it. One is better for low frequencies and one is better for high frequencies. the frequencies i'm dealing with are much slower; from about 10hz-2000hz so i'd have to have a huge window for it to count in which would make the response of the output unuseable. the method i have works and with enough smoothing seems to work well. i played with the variable sized index for a 8 space array and got it to work but i think my math is broke somewhere. i'll have to spend more time on it. PaulS commented on this the ISR changes the position of itself in the array You are now saying this populating the various slots in the array. if i change the sample size it makes a difference. Two totally different things. eave the array with 8 spaces but at low speed only use the first 2 then at higher speed maybe 4 then highest speed use all 8. i'll have to try it but i think it'll work better than trying to reallocate memory Sounds like a better plan. _____ Rob i meant the latter; the isr changes the index position for the array or resets it to 0 if +1 is too many
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6813
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #9 on: December 12, 2012, 11:07:57 pm » |
i meant the latter; Us engineers are a pedantic lot who tend to take things literally  Part of the job description I suppose. ______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #10 on: December 12, 2012, 11:45:30 pm » |
i meant the latter; Us engineers are a pedantic lot who tend to take things literally  Part of the job description I suppose. ______ Rob understandable lol i'm still very new to all this so all the proper nomenclature eludes me :-/
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #11 on: December 13, 2012, 12:20:35 am » |
anyone have any bright ideas why my math isn't working? if i go over 30hz the rate0 jumps. i know its adding another value in there but if i fix the math in the loop (SnumRread + 1) then its wrong if i go under 30hz..... here is the code thats not working: const int SnumReadCC = 5; volatile int SnumRead = 1; const int pot = A0;
volatile unsigned long pulse0[SnumReadCC]; volatile unsigned long pIndex0 = 0; volatile unsigned long nowPulse0 = 0; volatile unsigned long lastPulse0 = 0; volatile unsigned long nxtLastPulse0 = 0; volatile unsigned long i0, sum0, average0 = 0; float rate0;
volatile unsigned long pulse1[SnumReadCC]; volatile unsigned long pIndex1 = 0; volatile unsigned long nowPulse1 = 0; volatile unsigned long lastPulse1 = 0; volatile unsigned long i1, sum1, average1 = 0; float rate1;
volatile unsigned long pulse2[SnumReadCC]; volatile unsigned long pIndex2 = 0; volatile unsigned long nowPulse2 = 0; volatile unsigned long lastPulse2 = 0; volatile unsigned long i2, sum2, average2 = 0; float rate2;
volatile unsigned long pulse3[SnumReadCC]; volatile unsigned long pIndex3 = 0; volatile unsigned long nowPulse3 = 0; volatile unsigned long lastPulse3 = 0; volatile unsigned long i3, sum3, average3 = 0; float rate3;
float slip; float threshold; float overslip; float overslipscale = 25;
void setup() { pinMode(13, OUTPUT); Serial.begin(115200); attachInterrupt(0, count0, FALLING); attachInterrupt(1, count1, FALLING); attachInterrupt(2, count2, FALLING); attachInterrupt(3, count3, FALLING ); }
void loop() { average0 = 0; sum0= 0; for (i0 = 0; i0 <= (SnumRead); i0++) { sum0 = sum0 + pulse0[i0]; } average0 = sum0 / (SnumRead + 1); rate0 = (float)1000000 / average0; average1 = 0; sum1= 0; for (i1 = 0; i1 <= (SnumRead + 1); i1++) { sum1 +=pulse1[i1]; } average1 = sum1 / (SnumRead + 1); rate1 = (float)1000000 / average1; average2 = 0; sum2= 0; for (i2 = 0; i2 <= (SnumRead + 1); i2++) { sum2 +=pulse2[i2]; } average2 = sum2 / (SnumRead + 1); rate2 = (float)1000000 / average2; average3 = 0; sum3= 0; for (i3 = 0; i3 <= (SnumRead + 1); i3++) { sum3 +=pulse3[i3]; } average3 = sum3 / (SnumRead + 1); rate3 = (float)1000000 / average3;
threshold = analogRead(pot); threshold = threshold / 48.71; slip = max(rate0, rate1) / max(rate2, rate3); slip = 100 * (slip - 1); overslip = slip - threshold; if (overslip < 0) { overslip = 0; } else if (overslip > overslipscale) { overslip = overslipscale; } Serial.println(""); Serial.print(rate0,2); Serial.print(" / "); Serial.print(rate1,2); Serial.print(" / "); Serial.print(rate2,2); Serial.print(" / "); Serial.print(rate3),2; Serial.print(" --- "); Serial.print(threshold),2; Serial.print(" / "); Serial.print(slip),2; Serial.print(" / "); Serial.print(overslip),2; if (threshold < 21) { overslip = map(overslip, 0, overslipscale, 0, 255); analogWrite(11, overslip); digitalWrite(13, HIGH); } else { analogWrite(11, 0); digitalWrite(13, LOW); }
if (rate0 <= 30) { SnumRead = 1; } else if (rate0 > 30) { SnumRead = 5; }
Serial.print(" / "); Serial.print(SnumRead); delay(5); }
void count0() { nowPulse0 = micros(); pulse0[pIndex0] = nowPulse0 - lastPulse0; pIndex0++; if (pIndex0 > (SnumRead)) pIndex0 = 0; nxtLastPulse0 = lastPulse0; lastPulse0 = nowPulse0; } void count1() { nowPulse1 = micros(); pulse1[pIndex1] = nowPulse1 - lastPulse1; pIndex1++; if (pIndex1 > (SnumRead + 1)) pIndex1 = 0; lastPulse1 = nowPulse1; nowPulse1 = 0; } void count2() { nowPulse2 = micros(); pulse2[pIndex2] = nowPulse2 - lastPulse2; pIndex2++; if (pIndex2 > (SnumRead + 1)) pIndex2 = 0; lastPulse2 = nowPulse2; nowPulse2 = 0; } void count3() { nowPulse3 = micros(); pulse3[pIndex3] = nowPulse3 - lastPulse3; pIndex3++; if (pIndex3 > (SnumRead + 1)) pIndex3 = 0; lastPulse3 = nowPulse3; nowPulse3 = 0; }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #12 on: December 13, 2012, 12:29:59 am » |
i think i fixed it; i removed the = sign in my for loop average0 = 0; sum0= 0; for (i0 = 0; i0 <= (SnumRead); i0++) { sum0 = sum0 + pulse0[i0]; } average0 = sum0 / SnumRead; rate0 = (float)1000000 / average0;
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 12
|
 |
« Reply #13 on: December 13, 2012, 12:40:23 am » |
i still dont think its quite right; SnumRead is set to 5; which is 6 spots in an array.
for that bit of code in the loop i should have a sample size of 6 samples but then to figure the avage its dividing by SnumRead which is set to 5. but the frequency is right (output matches my function gen)?
hmmmmmmmmm anyone have some insight?
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #14 on: December 13, 2012, 07:25:22 am » |
for (i0 = 0; i0 <= (SnumRead); i0++) Why are there parentheses around SnumRead? for (i1 = 0; i1 <= (SnumRead + 1); i1++) Why does this loop loop a different number of times? You really need to start using arrays and functions. Nothing about those 4 blocks of code (expect the bizarre discrepancy in the number of times each loops) is different, except which array is read from. There is, for instance, absolutely no reason to use four different loop index variables or 4 different accumulators. Casting 1000000 to a float may not be achieving the result you expect. Using 1000000.0 instead would eliminate the need for the cast. Also, the compiler knows that a literal with a decimal place in it is not an int. Without that decimal point, it assumes that the value IS an int (which it isn't). What happens when that value is cast to a float is anyone's guess. I wouldn't write code that requires guessing. Your mileage may vary. Your ISRs are theoretically all firing at different times. Yet, SnumRead is the same for all 4 situations. Why?
|
|
|
|
|
Logged
|
|
|
|
|
|