Too large float array

I’m trying to measure the resistance from a gas sensor at 0.1 s intervals for 5 minutes, amounting to 3000 data points for the readings and time values. After which I would compute the slope of the data set I have stored in float arrays, readingList and timeList. However, this amounts to more than the SRAM available for the Arduino Uno. Do you guys have any suggestions? Thanks in advance :slight_smile:

void loop() {
  
unsigned long currentMillis = millis();
if ((millis()/1000) <= 300){
  if ((currentMillis - previousMillis) >= interval){
    previousMillis = currentMillis;
    float V2 = analogRead(A0) * 5.0/1023.0;
    float R1 = ((5/V2)-1)* R2;
    readingList[index] = R1;
    timeList[index] = (interval/1000) * index;
    index = index + 1;
    lcd.setCursor(0, 0);
    lcd.print("Resistance: ");
    lcd.setCursor(0, 1);
    lcd.print(R1);
    lcd.setCursor(12, 1);
    lcd.print(millis()/1000);
    }
}

The integer divisions on millis() are unusual but they might work.

Why are you recording time in an array? you know every reading was taken at a defined time?

You don't show what calculations you are trying to do on this data, can you not do those calculations on the fly and then just print the result?

If you need all of those data points then you have to communicate them off the Arduino. Either send them to the PC by Serial or save them to an SD crd or flash memory.

Do you guys have any suggestions?

How will you be calculating the slope ? Can you calculate the result with a running calculation after each analogRead() ?

The gas sensor works by changing its resistance due to the presence of a gas in a container with the sensor. Since the response is asymptotic, we waited for 5 minutes for the resistance reading to stabilize, then we take the last 2 minutes worth of data to compute the slope of the curve. Therefore we need to gather all the data first before making the computations. Also, since we plan on making this portable, the microcontroller will not be connected to a PC. Although there is a requested option to insert an SD card to obtain the data values.

else if((millis()/1000) > 300){ 
  float x = 0;
  float y = 0;
  float xy = 0;
  float x2 = 0;
  float y2 = 0;
  x = x + timeList[i];
  y = y + readingList[i];
  xy = xy + readingList[i] * timeList[i];
  x2 = x2 + timeList[i]*timeList[i];
  y2 = y2 + readingList[i] * readingList[i];
  float Sxx = x2 - (x*x)/(3000);
  float Syy = y2 - (y*y)/(3000);
  float Sxy = xy - (x*x)/(3000);
  float r2 = (Sxy*Sxy)/(Sxx*Syy);
  lcd.setCursor(0, 0);
  lcd.print("Slope:");
  lcd.setCursor(0, 1);
  lcd.print(Sxy/Sxx);
}

This is probably not a viable solution, but you might consider a Teensy 3.1. It has 64K of SRAM and is clocked at about 4x an Uno and all of the Arduino code I've run compiles just fine. One downside is that it costs about $20.

Edit:

See: https://www.pjrc.com/store/teensy31.html

@econjack: How similar is this to the arduino? I'm not quite comfortable using other boards at the moment, though some people in school might be, but I'll still consider it as this can solve our research problem. Thank you :)

The company provides a download that adds the Teensy board to the Arduino IDE. Once run, the Teensy shows up in the Tools --> Board menu option. From that point, I've compiled about a dozen different sketches within the modified IDE and all ran successfully. Note that the 3.1 is 5V tolerant while the 3.0 is not. It's actually smaller than a Nano. More details and the download can be seen at:

https://www.pjrc.com/teensy/index.html

Their promo material states (https://www.pjrc.com/teensy/teensyduino.html):

Most programs written for Arduino work on Teensy. All of the standard Arduino functions (digitalWrite, pinMode, analogRead, etc) all work on Teensy. Teensyduino is also compatible with many Arduino libraries.

For $20, it might be worth trying one.

@econjack: Thanks!

For the meantime, are there any more suggestions for my problem here? :)

CSVIIXI:
I’m trying to measure the resistance from a gas sensor at 0.1 s intervals for 5 minutes, amounting to 3000 data points for the readings and time values. After which I would compute the slope of the data set I have stored in float arrays, readingList and timeList. However, this amounts to more than the SRAM available for the Arduino Uno. Do you guys have any suggestions? Thanks in advance :slight_smile:

Just collect all the statistics needed to compute a regression - sum of values, sum of squares, sum of products

If you don’t understand go and look up the formula for a straight line regression and see what I mean.

we waited for 5 minutes for the resistance reading to stabilize,

You only need to save a few values to establish that the reading is stable, not 3000.

you could store the raw integer analog reads and keep the interval constant… (4x less memory needed)
you can do the analysis on the raw data and convert it to float when needed.

void loop() 
{
  unsigned long currentMillis = millis();
  if (millis() <= 300000UL)
  {
    if ((currentMillis - previousMillis) >= interval)
    {
      previousMillis += interval;
      int raw = analogRead(A0);
      float V2 = raw * 5.0/1023.0;
      float R1 = ((5/V2)-1) * R2;
      
      readingList[index] = raw;  // just store the raw data 
      index++;
      
      lcd.setCursor(0, 0);
      lcd.print("Resistance: ");
      lcd.setCursor(0, 1);
      lcd.print(R1);
      lcd.setCursor(12, 1);
      lcd.print(millis() * 0.001);
    }
  }
}

UKHeliBob: You only need to save a few values to establish that the reading is stable, not 3000.

5 minutes was when the sensor was exposed to air for the base reading and the asymptotic approach to a stable value. The 5 minute measurement time and the 2 minute worth of data used to compute the slope was to adjust to the different curves obtained from different setups while maintaining constant parameters. So though the reading was stable at around 3-4 minutes, we kept it until 5 minutes for the sake of consistency.

So though the reading was stable at around 3-4 minutes, we kept it until 5 minutes for the sake of consistency.

But however long you need the reading to be stable you only need to save a few values, not one every 0.1 second for the duration of the period.

It looks like the original design is a FIR (finite impulse response) filter = collect 3000 values and apply some calculations on those. Consider switching to a IIR (infinite impulse response.) Doesn't "infinite" sound better?

So run for 10 seconds, at 0.1sec intervals, and add all of those to one big accumulator. Divide by 100 and you have an average reading for those 10 seconds. Do the same for another 10 seconds and compare the two averages. Rising, falling or stable? If 1 minute is a better averaging period for your data, then use that.

No, just compute the linear regression to get the slope, this is a completely standard result from stats, you do not need to save all the values, just the relevant statistics on the values.

Even if he needed 3000 floats, if that's the only memory intensive thing he wanted to do, that's 12k, and it would fit in 1284p's 16k of SRAM, and thats an AVR so it's much more like a normal Arduino.... just sayin...