dynamic array? or varrying the size of the array based on something?

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;
}

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.

You can, but reallocating memory is probably not for a beginner. Just allocate space for the largest eventuality and save yourself some heartache.


Rob

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.

Graynomad:
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.

PaulS:

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.

dhenry:

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

computerjlt:
My project measures wheel speed by measuring time between interrupts.

This might help:

Two 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.

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

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.

Graynomad:
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

i meant the latter;

Us engineers are a pedantic lot who tend to take things literally :slight_smile: Part of the job description I suppose.


Rob

Graynomad:

i meant the latter;

Us engineers are a pedantic lot who tend to take things literally :slight_smile: 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 :-/

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;
}

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;

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?

  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?

PaulS:

  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?

i figured out the problem it was the = sign in the isr.

the reason for the different indexes is because each isr in theory will be firing at a different time at slightly different frequencies. i'll try removing the float cast and see what happens

snumread is the number of spaces in the array to use; each block of code takes the same number of samples. the parentheses were an error; that was some in between code i was working on. i fixed it here:

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;
float correction0 = 1;

volatile unsigned long pulse1[SnumReadCC];
volatile unsigned long pIndex1 = 0;
volatile unsigned long nowPulse1 = 0;
volatile unsigned long lastPulse1 = 0;
volatile unsigned long nxtLastPulse1 = 0;
volatile unsigned long i1, sum1, average1 = 0;
float rate1;
float correction1 = 1;

volatile unsigned long pulse2[SnumReadCC];
volatile unsigned long pIndex2 = 0;
volatile unsigned long nowPulse2 = 0;
volatile unsigned long lastPulse2 = 0;
volatile unsigned long nxtLastPulse2 = 0;
volatile unsigned long i2, sum2, average2 = 0;
float rate2;
float correction2 = 1;

volatile unsigned long pulse3[SnumReadCC];
volatile unsigned long pIndex3 = 0;
volatile unsigned long nowPulse3 = 0;
volatile unsigned long lastPulse3 = 0;
volatile unsigned long nxtLastPulse3 = 0;
volatile unsigned long i3, sum3, average3 = 0;
float rate3;
float correction3 = 1;

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() {
  
  if((micros() - nxtLastPulse0) > 400099)
  {
  rate0 = 0;
  }
  else
  {
  average0 = 0;
  sum0= 0;
  for (i0 = 0; i0 < SnumRead; i0++)
  {
    sum0 = sum0 + pulse0[i0];
  }
  average0 = sum0 / SnumRead;
  rate0 =  correction1 * ((float)1000000 / average0);
  }
  
  if((micros() - nxtLastPulse1) > 400099)
  {
  rate1 = 0;
  }
  else
  {
  average1 = 0;
  sum1= 0;
  for (i1 = 0; i1 < SnumRead; i1++)
  {
    sum1 +=pulse1[i1];
  }
  average1 = sum1 / SnumRead;
  rate1 =  correction1 * ((float)1000000 / average1);
  }
  
  
  if((micros() - nxtLastPulse2) > 400099)
  {
  rate2 = 0;
  }
  else
  {
  average2 = 0;
  sum2= 0;
  for (i2 = 0; i2 < SnumRead; i2++)
  {
    sum2 +=pulse2[i2];
  }
  average2 = sum2 / SnumRead;
  rate2 =  correction2 * ((float)1000000 / average2);
  }
  
  
  if((micros() - nxtLastPulse3) > 400099)
  {
  rate3 = 0;
  }
  else
  {
  average3 = 0;
  sum3= 0;
  for (i3 = 0; i3 < SnumRead; i3++)
  {
    sum3 +=pulse3[i3];
  }
  average3 = sum3 / SnumRead;
  rate3 =  correction3 * ((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 (max(max(rate0, rate1), max(rate2, rate3)) <= 30)
  {
  SnumRead = 1;
  }
  if (max(max(rate0, rate1), max(rate2, rate3)) > 30)
  {
  SnumRead = 5;
  }

  Serial.print(" / ");
  Serial.print(SnumRead);  
  Serial.print(" / ");
  
  
  delay(5);
}

void count0()
{
  nowPulse0 = micros();
  nxtLastPulse0 = nowPulse0;
  pulse0[pIndex0] = nowPulse0 - lastPulse0;
  pIndex0++;
  if (pIndex0 >= SnumRead)
    pIndex0 = 0;
  lastPulse0 = nowPulse0;
  }
void count1()
{
  nowPulse1 = micros();
  nxtLastPulse1 = nowPulse1;
  pulse1[pIndex1] = nowPulse1 - lastPulse1;
  pIndex1++;
  if (pIndex1 >= SnumRead)
    pIndex1 = 0;
  lastPulse1 = nowPulse1;
  nowPulse1 = 0;
}
void count2()
{
  nowPulse2 = micros();
  nxtLastPulse2 = nowPulse2;
  pulse2[pIndex2] = nowPulse2 - lastPulse2;
  pIndex2++;
  if (pIndex2 >= SnumRead)
    pIndex2 = 0;
  lastPulse2 = nowPulse2;
  nowPulse2 = 0;
}
void count3()
{
  nowPulse3 = micros();
  nxtLastPulse3 = nowPulse3;
  pulse3[pIndex3] = nowPulse3 - lastPulse3;
  pIndex3++;
  if (pIndex3 >= SnumRead)
    pIndex3 = 0;
  lastPulse3 = nowPulse3;
  nowPulse3 = 0;
}