Where to store array of doubles

Hei,

In my library im writing im generating a array what has ~120 double elements. This generation is called from setup() part of a sketch.
Now i was wondering is it possible to store this array in PROGMEM or do the array must be there allready at compile time to store it in PROGMEM?

What would be other options storing this array?

Priit.

You can't write to PROGMEM at run time.

Will the array always be the same? If so, you can put the constants into PROGMEM.

Heres the main consept how this will work:
I have couple of "input values" what are used to generate data what is stored hold in the array. There is no actual need to generate the array every time arduino starts, only when these "input values" are changed. So, no, the array will not be always the same but it will be the same most of the times since the "input values" are not changed so often.

120 doubles or floats take ~500 bytes, that can be in RAM if the rest of your application is not too RAM hungry.

If the changes are rare you could place the doubles in EEPROM, optionally an I2C EEPROM

Or store them in a file on an SD card

So far the storage alternatives, but there are more alternatives:

You said you calculate the doubles during setup(). that means that it is technically possible to calculate the floats if you need them. That probably means less RAM but extra time.

Another option might be finding the function that generates these 120 doubles given the inouts 0..120 (it is more difficult than you think but easier if you think)

And of course, why an array of doubles? Can the info not be stored in integers?

Finally there is interpolation, if the values can be interpolated you could use the map() or the multimap() functions.

In short:
Can you tell more about your doubles, how they are generated and how they are used?

robtillaart:
120 doubles or floats take ~500 bytes, that can be in RAM if the rest of your application is not too RAM hungry.

If the changes are rare you could place the doubles in EEPROM, optionally an I2C EEPROM

Or store them in a file on an SD card

So far the storage alternatives, but there are more alternatives:

You said you calculate the doubles during setup(). that means that it is technically possible to calculate the floats if you need them. That probably means less RAM but extra time.

Another option might be finding the function that generates these 120 doubles given the inouts 0..120 (it is more difficult than you think but easier if you think)

And of course, why an array of doubles? Can the info not be stored in integers?

Finally there is interpolation, if the values can be interpolated you could use the map() or the multimap() functions.

In short:
Can you tell more about your doubles, how they are generated and how they are used?

Im not calculating the values when i need them because this gives me option to move the calculation off the arduino and just send the values to arduino.

Array itself is basically a lookup table. Its holding hue values and the position in array represent temperature. So if the current temperature is 37 then i get matching hue for that: double hue = _colors[temp]; and then il use this hue to set rgb led color.

What i realise now is that my HsvToRgb method doesn't care anyway if its a double it uses it as a int anyway. So yes, i can hold them as int-s.

Im not familiar with interpolation (had to even look it up on google) so not sure i could use map() or the multimap() functions.

What i realise now is that my HsvToRgb method doesn't care anyway if its a double it uses it as a int anyway. So yes, i can hold them as int-s.

That saves you a factor 2 !

About interpolation:
Interpolation is often linear. Supose you have an input value between 0 and 1023 (analogRead) and you want to controll a servo with it which uses 0..179 degrees. You know that 0 maps on 0 and 1023 maps on 179. Than you can derive a formula

float val = 1.0 * analogRead(A0) * 179 /1023; This function interpolates the ouutput for every value of analogRead().

The function becomes a bit complexer if e.g. 17..876 must be mapped upon 423..56 and that is where the map() function comes in. Google Arduino map.

If the interpolation is not linear you can use multimap() which approaches the nonlinear function with linear intervals.

Suppose your project range has the following {temp, hue} pairs :

0,0 10,20 20,30 30,50 40, 80 50, 90 60,110 70,115 80, 120 90, 140 100, 160

Definitely not linear, so multimap could be used, see - Arduino Playground - HomePage -

Give it a read :wink:

Ok, but when using multimap then i would need 2 arrays - temperatures and hues:

int hues[] = {150,140,130,120,110,100, 90, 80, 70, 60, 50, 40, 30, 20};
int temps[]  = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33};
val = getTemp();
hue = multiMap(val, temps, hues, 14);

This way i would double the space used.

Here's the method how im mapping the values now:

void LedDriverClass::CalcHues(byte startTemp, byte endTemp, int startHue, int endHue)
{
	double difference = (double)(startHue - endHue);
	if (difference < 0)
		difference = difference + 360;
	double multiplier = difference/(endTemp - startTemp);

	for(int i = tempStart; i<= tempEnd; ++i)
	{
		int hue = startHue - ((int) (i - startTemp)*multiplier);
		if (hue < 0)
			hue = hue + 360;
		_colors[i] = hue;
	}
}

Now when i call this method and give it for example startTemp 0 and endTemp 10, startHue 20 and endHue 0 then the result array would be:
_colors[] = {20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, ...}
All the rest values in the array would be 0 (thats is also intentional). Now when i get temperature something like 5 i would just do _colors[5] and i will get the hue value what is 10 in this example.

But as i said before, i might be moving this calculation off the arduino and just upload/send the pre calculated values to arduino. And the question is where would be the best place to store these values?

(Since i havent got the microSD shield working with my Wifly shield (see topic: http://arduino.cc/forum/index.php/topic,98025.0.html)) then storing the values on SD card is out of options)

int hues[] = {150,140,130,120,110,100, 90, 80, 70, 60, 50, 40, 30, 20};
int temps[] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33};
val = getTemp();
hue = multiMap(val, temps, hues, 14);

If these are the real values it a 100% linear mapping that can be expressed in a formula which is far simpler than multiMapping.

float temp = getTempC();
float hue = 150 - (temp-20) *10;

Please try the formula.

You would need multiMap() if there was no linear relation e.g. like below.

int hues[] = {255,240,220,200,190,160, 140, 110, 90, 80, 75, 40, 25, 20};
int temps[]  = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33};
val = getTemp();
hue = multiMap(val, temps, hues, 14);

On the other hand you could use multimap and replace the hue array for different colormaps, just read 14 ints from somewhere or use another array.

There's no so much calculation there that the Arduino can't do it on-the-fly:

int LedDriverClass::getHue(byte temperature, byte startTemp, byte endTemp, int startHue, int endHue)
    {
    if (temperature < startTemp || temperature > endTemp)
        return 0;

    if (endHue <= startHue)
        endHue += 360;

    return map(temperature, startTemp, endTemp, startHue, endHue) % 360;
    }

johnwasser:
There's no so much calculation there that the Arduino can't do it on-the-fly:

int LedDriverClass::getHue(byte temperature, byte startTemp, byte endTemp, int startHue, int endHue)

{
    if (temperature < startTemp || temperature > endTemp)
        return 0;

if (endHue <= startHue)
        endHue += 360;

return map(temperature, startTemp, endTemp, startHue, endHue) % 360;
    }

The problem i see there is that i need to support changing hue both ways - up or down. Basically if i want the color to change from blue to red then the hue value must start decreasing when temperature is rising.

soend:
The problem i see there is that i need to support changing hue both ways - up or down. Basically if i want the color to change from blue to red then the hue value must start decreasing when temperature is rising.

Just add a parameter for clockwise (increasing hue) or counterclockwise (decreasing hue).

int LedDriverClass::getHue(byte temperature, byte startTemp, byte endTemp, int startHue, int endHue, bool clockwise)
    {
    if (temperature < startTemp || temperature > endTemp)
        return 0;

    if (clockwise && endHue <= startHue)
        endHue += 360;

    if (!clockwise && startHue <= endHue)
        startHue += 360;

    return map(temperature, startTemp, endTemp, startHue, endHue) % 360;
    }