Noob - For Loop with Arrays

Guy, i am a noob and am in the process of transferring a project for my home heating across from Picaxe with Basic to Arduino.

I have an Ethermega from Freetronics in Australia.

I am using Arduino 1.04.

I have my Picaxe and Arduino integrated through the use of I2c and this is working well - i have a DS1307 that the Arduino controls and passes time though i2c to the picaxe. The picaxe is passing back Integer based temperature measurements plus some PIn state information through 5 byte variables - all of this is working well.

My next step is to take those measurements from 4 distinct sensors and keep 4 running average - on the picaxe i do this by keeping a running tally of 10 readings for each sensor, and i have a subroutine for each measurement that essentially shuffles the newest measurement onto the top of the list and moves every reading down the list and then drops the oldest off.

I am trying to do this on the Arduino by have a single Function that i call and that i pass the following parameters to

  1. ArrayName to manipulate
  2. Temp Value to add

And this function should then return the new average value in a global variable

I have put together the following code

//Build an Array and calculate the running average for the previous 10 temperature readings
//we want this to be generic for all the averages so try and pass the following to it when calling
// Array Name - which of the arrays are we recalculating, the Temp reading we are passing it
void CalculateAverageTemp(String ArrayName, int TempValueIn){

//essentially we want to take the value passed in and sanity check it - if OK - then shuffle all the existing values
//down and drop the last one

if (TempValueIn > 0 and TempValueIn < 255) // only run the code is the temp measurement are valid

{
for (int i=9; i >= 0; i--){
        Serial.print("Before ");
       Serial.print(TankTempArray[i]);
      TankTempArray[i] = TankTempArray[i-1];
      Serial.print(" After ");
      Serial.print(TankTempArray[i]);
      Serial.println();
      delay(1000);
   } 
   TankTempArray[0] = TempValueIn;
   Serial.println();
}  


  
}

Obviously i have not written the averaging part yet, however with the print to serial in there i am not seeing what i would expect

If i leave the array names hardcoded (In this case TankTempArray (the temperature of the hot water tank) then all works as expected (as in the above)

if on the other hand i call the function and attempt to pass it the name of the array i am interested in (TankTempArray) so that i can use this one routine to average values for multiple sensors - then it does not work

i.e. i change all instances of TankTempArray to ArrayName

Doing a serial print shows strange values.

My Question - Is declaring the
void CalculateAverageTemp(String ArrayName, int TempValueIn)

the correct way to declare the String to pass across ? and when i call the function is calling it like this correct ?

CalculateAverageTemp(“TankTempArray”, TankTemp);

thanks for any help

Craig

You can't reference variables dynamically by there name without some sort of hash table. The compiler turns TankTempArray into a memory address by the time it finishes, so the String "TankTempArray" has no meaning to it. You can instead, use a multidimensional array (array of arrays) and pass the index of which one you wish to refer to.

No, that API is not the way to achieve what you want.

If you want to pass in an array then the function formal arguments need to be a pointer to the array element type, for example:

void CalculateAverageTemp(int *history, int TempValueIn)
{
	//essentially we want to take the value passed in and sanity check it - if OK - then shuffle all the existing values
	//down and drop the last one
	
	if (TempValueIn > 0 and TempValueIn < 255) // only run the code is the temp measurement are valid
	{
		for (int i=9; i >= 0; i--)
		{
			Serial.print("Before ");
			Serial.print(history[i]);
			history[i+1] = history[i];
			Serial.print(" After ");
			Serial.print(history[i]);
			Serial.println();
			delay(1000);
		} 
		history[0] = TempValueIn;
		Serial.println();
	}  
}

Call it like this:

    CalculateAverageTemp(TankTempArray, newValue);

I changed your indentation slightly because I didn’t like the original layout.

I change the code doing the actual shifting because the array indices in the original looked wrong to me.

The hard-coded array size (10) should have been defined by a suitable global constant.

It would have been possible to avoid the shifting entirely by using the array as a circular buffer.

It would have been possible to avoid using the array entirely by adopting a decaying average instead of the average of the last ten samples.

Arrch: You can't reference variables dynamically by there name without some sort of hash table. The compiler turns TankTempArray into a memory address by the time it finishes, so the String "TankTempArray" has no meaning to it. You can instead, use a multidimensional array (array of arrays) and pass the index of which one you wish to refer to.

Arch - OK thanks for the pointer on this - i will do some research on the terms you have given me and see what i can work out

regards

Craig

PeterH:
No, that API is not the way to achieve what you want.

If you want to pass in an array then the function formal arguments need to be a pointer to the array element type, for example:

void CalculateAverageTemp(int *history, int TempValueIn)

{
//essentially we want to take the value passed in and sanity check it - if OK - then shuffle all the existing values
//down and drop the last one

if (TempValueIn > 0 and TempValueIn < 255) // only run the code is the temp measurement are valid
{
	for (int i=9; i >= 0; i--)
	{
		Serial.print("Before ");
		Serial.print(history[i]);
		history[i+1] = history[i];
		Serial.print(" After ");
		Serial.print(history[i]);
		Serial.println();
		delay(1000);
	} 
	history[0] = TempValueIn;
	Serial.println();
}  

}





Call it like this:



CalculateAverageTemp(TankTempArray, newValue);



I changed your indentation slightly because I didn't like the original layout.

I change the code doing the actual shifting because the array indices in the original looked wrong to me.

The hard-coded array size (10) should have been defined by a suitable global constant.

It would have been possible to avoid the shifting entirely by using the array as a circular buffer.

It would have been possible to avoid using the array entirely by adopting a decaying average instead of the average of the last ten samples.

Peter thanks for taking the time to do this - i think i get what you say - however with *History defined in the function does this not mean that i can not pass the name of the array ?? i.e. i have 4 different arrays i want to use this one function for - all of which do the same thing ?

yes i have defined the array as a global constant with 10 elements

I will do some looking up on the circular buffer concept - i will also study your rewritten code (thanks for doing that) and see if i can see the differences (and the effects) from mine

With the rewritten code - wouldn’t this line you have written go outside the bounds of the array on the first pass through ?

history[i+1] = history*;*
regards
Craig

With the rewritten code - wouldn't this line you have written go outside the bounds of the array on the first pass through ?

history[i+1] = history;

Probably, but you didn't specify how big the array was. And the original would almost certainly have written outside the bounds on the last pass through.

does this not mean that i can not pass the name of the array ??

You can't pass the NAME of any variable to a function. By the time the compiler gets done, all NAMES are gone. All that is left is values and addresses.

Quit thinking that NAMES mean anything, and start asking questions that make sense.

i have 4 different arrays i want to use this one function for - all of which do the same thing ?

You can pass a reference to your arrays to functions, that is what functions are for. :)

craigcurtin: Peter thanks for taking the time to do this - i think i get what you say - however with *History defined in the function does this not mean that i can not pass the name of the array ?? i.e. i have 4 different arrays i want to use this one function for - all of which do the same thing ?

The array used by the function is determined by the arguments you supply when you call it. This call passes in TankTempArray:

CalculateAverageTemp(TankTempArray, newValue);

If you want to apply the same function to a different array somewhere else then in the other call you would replace TankTempArray with the other array.

craigcurtin: With the rewritten code - wouldn't this line you have written go outside the bounds of the array on the first pass through ?

Yes, I screwed it up too. If you have an array with 10 elements then you need to shift 9 of them. If you're shifting element i to position i+1 then you need to do it for i in the range 8 .. 0 (inclusive); if you did it the other way by shifting element i-1 to position i then you need to do it for i in the range 9 .. 1 (inclusive).

PeterH:

craigcurtin: Peter thanks for taking the time to do this - i think i get what you say - however with *History defined in the function does this not mean that i can not pass the name of the array ?? i.e. i have 4 different arrays i want to use this one function for - all of which do the same thing ?

The array used by the function is determined by the arguments you supply when you call it. This call passes in TankTempArray:

CalculateAverageTemp(TankTempArray, newValue);

If you want to apply the same function to a different array somewhere else then in the other call you would replace TankTempArray with the other array.

craigcurtin: With the rewritten code - wouldn't this line you have written go outside the bounds of the array on the first pass through ?

Yes, I screwed it up too. If you have an array with 10 elements then you need to shift 9 of them. If you're shifting element i to position i+1 then you need to do it for i in the range 8 .. 0 (inclusive); if you did it the other way by shifting element i-1 to position i then you need to do it for i in the range 9 .. 1 (inclusive).

Excellent thanks Peter - thanks for the clarification. I will play around some and advise.

regards

Craig

PaulS:

does this not mean that i can not pass the name of the array ??

You can’t pass the NAME of any variable to a function. By the time the compiler gets done, all NAMES are gone. All that is left is values and addresses.

Quit thinking that NAMES mean anything, and start asking questions that make sense.

PaulS - YES YOU !!

Why are you seemingly the only person on this forum that is deliberately abrasive ? I asked a question and in the title explained i was a NOOB. I therefore worded to the best of my ability what i hoped to achieve and what my investigation and initial experimentation had revealed.

Once i had received responses i then posted a follow up query in relation to those to get better clarification.

As far as i am concerned at my level - NOOB - the questions do make sense - if they do not then point me in the right direction - not abuse me.

Anytime you want to be taken to school let me know and we can have an indepth conversation about IP V6 network routing protocols.

Craig

Is it OK if I try to answer this one?

Why are you seemingly the only person on this forum that is deliberately abrasive ?

Well, first off, stick around a little bit and you'll find more people who are seemingly abrasive. Why? Because it is effective. You did notice PaulS's post count, right? And the karma rating, right? His job on this forum is to help people solve problems, and he's very good at it. His job isn't to try to mind-read how thin your skin is so you don't get offended. Most of us are more interested in what is said than how it is said. He actually answered your question and pointed you in the right direction. No, you can't pass the name of an array, or any variable for that matter, because the compiler removes them. Try passing values or addresses. Sorry the answer wasn't to your liking.

Luckily for you, someone less abrasive not only solved your problem for you, but also gave you several excellent ideas for improving your code. The best idea is probably the running average, but I don't know if you'll even get to that.

You have a lot of expertise in other areas, just not in programming yet. Your expertise could be valuable to others on the forum. It would be sad if this were to be such a big issue for you that you would have to go elsewhere to get your problems solved. It isn't likely that your opinion will change how PaulS interacts on the forum. It might have one desired effect for you, though. He may decide you aren't worth the trouble and never post in your threads again. His post obviously didn't solve your problem, although it wasn't his fault. That way you wouldn't have to worry about being abused by him again. You also wouldn't get the benefits of his expertise.

I asked a question and in the title explained i was a NOOB. I therefore worded to the best of my ability what i hoped to achieve and what my investigation and initial experimentation had revealed.

Yes, you did. Then, it was explained to you that the compiler strips names and uses only addresses. And, it was explained how you could use addresses instead of names.

And, then, you asked, yeah, but how do I do it with names.

That's when I grabbed you by the ears and said "Hey, pay attention!"

Ok thanks guys - it is now working and allowing me to do as i initially was hoping.

I am currently doing some reading on using an array as a circular buffer, and also researching the concept of decaying averages and how to implement.

Thanks to everyone (including Pauls !) for the advice and input

regards

Craig