DS18B20 algorithm

I’m running on 3 hours of sleep and I’m relatively new at Arduino so please criticize lightly. :wink:

I’m trying to make an algorithm for returning the temperature accurately/consistently. I’m trying a 15 to 1 median filter that writes to an array, then when the array has 5 values it needs to be averaged.

The first bit collects data, then it’s sorted and wrote to the array then once its full it adds the whole array and divides by how many are in the array.

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 12

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature tempSensor(&oneWire);

 float Celcius = 0;
 float CMedian = 0;
 float rawSpeedOfSound = 0;
 float calcSpeedOfSound = 0;
 float SOSBuffer[4];      //Zero Indexed, keep odd
 float SOSReadings = 4;     //Zero Indexed, keep odd
 float tempBuffer[14];    //Zero Indexed, keep odd
 int tempReadings = 14;   //Zero Indexed, keep odd

 
void setup(){
  //pinMode(ONE_WIRE_BUS,INPUT_PULLUP);
  Serial.begin(9600);
  tempSensor.begin();
  delay(1000);
}



void getSOS(){
  float swapper;
  float calcSOSBuffer = 0;
  for (int i = 0; i <= SOSReadings; i++){
    for (int x = 0 ; x < tempReadings; x++){
      tempSensor.requestTemperatures();
      delay(100); 
      Celcius=tempSensor.getTempCByIndex(0);
      tempBuffer[x] = 0;
      tempBuffer[x] = Celcius;
    }
    for(int y = 0 ; y <= tempReadings; y++) {  // outer loop
      if( tempBuffer[y] > tempBuffer[y+1] ) {   // out of order?       
          swapper = tempBuffer[y];
          tempBuffer [y] = tempBuffer[y+1]; // swap them:
          tempBuffer[y+1] = swapper;
          delay(10);
          y = 0;
        }else if ( tempBuffer[y-1] > tempBuffer[y] ){
          swapper = tempBuffer[i];
          tempBuffer [y] = tempBuffer[y-1]; // swap them:
          tempBuffer[y-1] = swapper;
          delay(10);
          y = 0;
        } 
      }
      CMedian = tempBuffer[tempReadings / 2];
      
      rawSpeedOfSound = (331.3 * sqrt(1+(CMedian/273.15))/1000);
      Serial.print("raw  "); Serial.println(rawSpeedOfSound , 3);
      SOSBuffer[i] = 0;
      SOSBuffer[i] = rawSpeedOfSound;
      
      Serial.print(SOSBuffer[i]); Serial.print(" in "); Serial.println(i);
      
  }
  for (int z = 0; z <= SOSReadings; z++){
    //Serial.println(calcSOSBuffer);
    calcSOSBuffer = calcSOSBuffer + SOSBuffer[z];
    
    Serial.print(SOSBuffer[z]); Serial.print(" to "); ;Serial.println(calcSOSBuffer);
    
    Serial.print(" in "); Serial.print(z); Serial.print(" adding ");Serial.print(SOSBuffer[z]); Serial.print(" to "); Serial.println(calcSOSBuffer);
  
  }
  calcSpeedOfSound = calcSOSBuffer / (SOSReadings+1);
  Serial.print("calc "); Serial.println(calcSpeedOfSound , 3);
}



void loop(void){ 
getSOS();
}

I keep getting (to me it seems) array leaking, there’s only supposed to be the data I put in the array when I read it (and there is) but when I read it in a different code block it has random numbers…

This is the output of one cycle

raw  0.345
0.35 in 0
raw  0.345
0.35 in 1
raw  0.345
0.35 in 2
raw  0.345
0.35 in 3
raw  0.345
0.35 in 4

 in 0 adding 23.37

 in 1 adding 23.37

 in 2 adding 0.35

 in 3 adding 0.35

 in 4 adding 0.35

I don’t know what I’m doing wrong and I just need some help… Thank you.

The DS18B20 works very well, is very consistent and rarely returns an outlier (and if so, it is usually obvious, like the error returns 85C and -127C).

Why do you think you need such complex treatment of the data? Please post some raw readings obtained using one of the simple example programs.

I never need to do more than to average a few readings, but you can gain some accuracy by individually calibrating each sensor against a laboratory standard thermometer.

Note: the following has serious errors. The code attempts to access and possibly overwrites an array element that does not exist.

    for(int y = 0 ; y <= tempReadings; y++) {  // outer loop
      if( tempBuffer[y] > tempBuffer[y+1] ) {   // out of order? 
          tempBuffer [y] = tempBuffer[y+1]; // swap them:
          tempBuffer[y+1] = swapper;

There may be other such array boundary violations. Suggest also to get rid of the useless delay() statements.

I'm using it to calculate the speed of sound and while yes it is very accurate, the smallest fluctuation changes my speed of sound calculations by a few mm. The readings are fine and semi-consistent in the example code for it (+-2c). everything works correctly EXCEPT my array reading and writing. Am I doing it right?

Pull the sorting code out into a separate function, and test it. You have too much
code stuck together in a big lump, this will hinder progress - small functions that each do one
thing are much easier to write correctly, test, and comprehend later.

If you want an array of 5 elements indexed from 0 to 4, then the array must be declared as
having 5 elements, not 4.

I think you are indexing the arrays with the wrong index at points too, for instance i is indexing
tempBuffer, but i ranges upto SOSReadings.

@MarkT Can you explain the array indexing to me then? I thought 0-4 was 5 because of 0=1, 1=2, 2=3 and so on. Also, what do you mean by it ranges up to SOSReadings?

correctly EXCEPT my array reading and writing. Am I doing it right?

NO! See reply #1.

jremington:
NO! See reply #1.

Thank you…
I realized I had sparse knowledge of how an array worked so I decided to fix that. (First I took a nap ;D )Then, I went and read all the articles from Arduino about arrays and watched some educating videos on them. I rewrote all my code with this newfound knowledge. (It works perfectly as far as I can see) Please point out any flaws if you see any.

  • Thank you.
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 12

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature tempSensor(&oneWire);

 float Celcius = 0;
 float tempBuffer[15];    //Zero Indexed, DONT CHANGE, keep odd
 float CMedian = 0;
 float rawSpeedOfSound = 0;
 float calcSpeedOfSound = 0;
 float SOSBuffer[5];      //Zero Indexed, keep odd


 
void setup(){
  //pinMode(ONE_WIRE_BUS,INPUT_PULLUP);
  Serial.begin(9600);
  tempSensor.begin();
  delay(1000);
}



void writeTempData(float data[], int size){  
  for (int i = 0 ; i < size; i++){
    tempSensor.requestTemperatures();
    delay(100); 
    Celcius=tempSensor.getTempCByIndex(0);
    data[i] = Celcius;
//    Serial.print(i); Serial.print(" : "); Serial.println(data[i]);
  }
}


void sortData(float data[], int size) {
  float swapper;
    for(int i = 0; i<(size-1); i++) {
        for(int o = 0; o<(size-(i+1)); o++) {
            if(data[o] > data[o+1]) {
                swapper = data[o];
                data[o] = data[o+1];
                data[o+1] = swapper;
            }
        }
    }
}

void readData(float data[], int size){
  Serial.println("Sorted Array: ");
  for(int i=0; i<size; i++) {
  Serial.print(i); Serial.print(" : "); Serial.println(data[i],4);
  }
}

void getSOS(){
  float calcSOSBuffer = 0;
  for (int i = 1; i <= 5; i++){
    writeTempData(tempBuffer,15);
    sortData(tempBuffer,15);              //Pass in the values and the size.
    CMedian = tempBuffer[7];              //set to middle of tempBuffer
    rawSpeedOfSound = (331.3 * sqrt(1+(CMedian/273.15))/1000);
    SOSBuffer[i-1] = rawSpeedOfSound;
  }
  sortData(SOSBuffer,5); //Pass in the values and the size.
  for (int i = 0; i < 5; i++){
    calcSOSBuffer = calcSOSBuffer + SOSBuffer[i];
  }
  calcSpeedOfSound = calcSOSBuffer / 5;
  Serial.print("\nCalculated SOS: "); Serial.println(calcSpeedOfSound , 5);
}



void loop() {
  getSOS();
}

Yay, that looks more like it - haven't checked in depth, glad its working now. One good test of a program
is whether you can understand it in 6 months time when you've forgotten the details...

(MarkT)
Hahahaha all day today I have gone through the code adding comments precisely to avoid that problem :smiley: I ran it all night as a stability test for my sensor and it matched and stayed within (+-)0.1 degrees Celsius of my thermometer from the lab. It works amazing!

(jremington)
Thank you for giving me the little extra push to go and learn arrays :wink: