function returns "growing" values

hey @all,

i’m new programming arduinos. But it’s funny! I’ve played around with it and now
i’m trying to make my first sketch. Everything was ok and works well…until i make
a new function:

void setHeight(float press, float temp) {
  float h = 0;
  h = ((pow((basepress / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;
      Serial.print("h = ");
      Serial.println(h);
  if (h > maxHeight) maxHeight = h;
  if (h < minHeight) minHeight = h;
}

When this function is called repeatedly from loop() with nearly identical values, the
value of h is “growing” :astonished: and i don’t understand what’s going on.
Here’s the output from prints in loop():

loop...
h = 2.76
temp 19.39
press 986.28
avgP 986.32
minH 0.86
maxH 3.34
loop...
h = 2.82
temp 19.39
press 986.29
avgP 986.32
minH 0.86
maxH 3.34
loop...
h = 2.98
temp 19.38
press 986.22
avgP 986.30
minH 0.86
maxH 3.34
loop...
h = 3.06
temp 19.39
press 986.25
avgP 986.29
minH 0.86
maxH 3.34
loop...
h = 3.13
temp 19.40
press 986.25
avgP 986.28
minH 0.86
maxH 3.34
.....
loop...
h = 5.35
temp 19.50
press 986.05
avgP 986.02
minH 0.86
maxH 5.57
loop...
h = 5.25
temp 19.49
press 986.08
avgP 986.04
minH 0.86
maxH 5.57
loop...
h = 5.21
temp 19.49
press 986.06
avgP 986.04
minH 0.86
maxH 5.57
loop...
h = 5.19
temp 19.49
press 986.05
avgP 986.04
minH 0.86
maxH 5.57

Perhaps someone can help?

Siggi (confused)

We'd need to see more (all) of your code, and more debug output. What happens to basepress? What happens to maxHeight? minHeight?

Printing press inside the function is more useful than printing it somewhere else.

  h = ((pow((basepress / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;

Mixing types in an expression is rarely a good idea. You KNOW that 1 is the same as 1.0. The compiler KNOWS that it is not. When what you know and what the compiler knows are not the same thing, problems arise.

ok, if you want it…

#include <PString.h>

#include <LCD5110_Graph.h>
#include <I2C.h>
#include <JeeLib.h>

#include <Wire.h>
#include <MS561101BA.h>
#include <EEPROM.h>

#define LPDADRESS 0	//EEPROM Adresse für die dauerhafte Speicherung des eingestellten Kanals
#define OFFSETADRESS 1  //EEPROM Adresse für die dauerhafte Speicherung des eingestellten Offsets
#define SENSADRESS 2    //EEPROM Adresse für die dauerhafte Speicherung der Empfindlichkeit
#define MINPULSADRESS 3  // Speicher fuer eine int, 2 Byte
#define MAXPULSADRESS 5  // Speicher fuer eine int, 2 Byte

#define GRUNDTON 400 //Grundton des Varios

#define DIFFTON_UP 25            //Änderung bei Steigen
#define DIFFTON_DOWN 3           //Änderung bei Sinken

#define PRESS_FILTER_GRAD 5	 //Barry Dorr Filter
#define DIFF_FILTER_GRAD 2       //Barry Dorr Filter
#define ZEILE(n) n*(myGLCD.cfont.y_size + 1)

float press_filter_reg;
float diff_filter_reg;
char tmp[50];

MS561101BA baro = MS561101BA();
PString tmpstr(tmp,50);
LCD5110 myGLCD(3,6,5,4,8);
extern uint8_t TinyFont[];

//Vario
float altpress, diff, avg;
float Value;
unsigned int Verstaerkung, Faktor=200, Empfindlichkeit=10;
int servosignal;
int servopin = +7;
unsigned int lpdkanal = 22; //voreingestelleter LPD-Kanal
unsigned int lpdoffset = 1127; //Basiswert für die Einstellung der LPD-Frequenz 
int DIFF_UP = 0; //Definiert die Empfindlichkeit ab wann der Varioton reagiert
int DIFF_DOWN = 0; //Definiert die Empfindlichkeit ab wann der Varioton reagiert

int MinPuls = +0;       // 100 groeßer als kleinste Impulsbreite
int MaxPuls = +0;       // 100 kleiner als groeste Impulsbreite 
unsigned int freqraster;  // (MaxPuls - MinPuls) / 69
int tmplen;
char leerzeile[] = "                     ";
float basepress = NULL;
float minHeight = 1000.00;
float maxHeight = 0.00;

void setup() 
{
        union {uint16_t val; uint8_t raw[2]; } edata;
        
        myGLCD.InitLCD();
        myGLCD.setFont(TinyFont);
        myGLCD.clrScr();
        myGLCD.print("Init...", LEFT, ZEILE(0));
        myGLCD.update();
        
	pinMode(servopin, INPUT); // Bestimmt den PIN7 als Input für das Servosignal
	I2c.begin();

        //I2c.scan();
        I2c.pullup(0); // Keine PullUp's
	baro.init(MS561101BA_ADDR_CSB_HIGH);//Initianlisiert den MS5611

	if(EEPROM.read(LPDADRESS) != 255) lpdkanal = EEPROM.read(LPDADRESS);
	if(EEPROM.read(SENSADRESS) != 255) Empfindlichkeit = EEPROM.read(SENSADRESS);
        
        tmpstr = "Kanal = ";
        tmpstr += lpdkanal;
        myGLCD.print(tmp, LEFT, ZEILE(1));
        myGLCD.update();
        
	rf12_reset(lpdoffset,lpdkanal); //Initialisiert das RFM12B Modul auf die Grundfrequenz
	Verstaerkung = Faktor*Empfindlichkeit;
        edata.raw[1] = int(EEPROM.read(MINPULSADRESS));
        edata.raw[0] = int(EEPROM.read(MINPULSADRESS + 1));
        MinPuls = edata.val;
        //MinPuls = -1;
        edata.raw[1] = int(EEPROM.read(MAXPULSADRESS));
        edata.raw[0] = int(EEPROM.read(MAXPULSADRESS + 1));
        MaxPuls = edata.val;
        if (MinPuls == -1){ 
          doMinMax(); // kleinste und groeste Impulsbreite ermitteln
          delay(2000);
        }
        freqraster = (MaxPuls - MinPuls) / 69;
        if (pulseIn(servopin, HIGH) > MaxPuls){
          doEinstellungen();
          myGLCD.clrScr();
          myGLCD.update();
        }
        
	Serial.begin(9600); // default for SerialMonitor
}

void loop() 
{  
    float temp = NULL, press = NULL, pdiff = NULL;
    while(temp == NULL) {
      temp = baro.getTemperature(MS561101BA_OSR_4096); //liest die Temperatur
    }
    while(press == NULL) {
      press = baro.getPressure(MS561101BA_OSR_4096);//liest den Druck als Funktion der Temperatur
    }
    //Barry Dorr Filter zum ermitteln des "mittleren" Druckwertes
    press_filter_reg = press_filter_reg - (press_filter_reg / PRESS_FILTER_GRAD) + press; // ergänzt den Tiefpassfilter um den aktuellen Wert
    avg = press_filter_reg / PRESS_FILTER_GRAD;	// bildet den Mittelwert
    pdiff = press - avg;
    
    Serial.println("loop...");
    
    if (abs(pdiff) < 0.40 and basepress == NULL) basepress = press;
    if (basepress != NULL){
      setHeight(avg, temp);
      Serial.print("temp ");
      Serial.println(temp);
      Serial.print("press ");
      Serial.println(press);
      Serial.print("avgP ");
      Serial.println(avg);
      Serial.print("minH ");
      Serial.println(minHeight);
      Serial.print("maxH ");
      Serial.println(maxHeight);
      myGLCD.clrScr();
      myGLCD.print("Aktuell", CENTER, ZEILE(0));
      tmpstr.begin();
      tmpstr = "Kanal = ";
      tmpstr += lpdkanal;
      myGLCD.print(tmp, LEFT, ZEILE(2));
      tmpstr.begin();
      tmpstr = "min H. = ";
      tmpstr += minHeight;
      myGLCD.print(tmp, LEFT, ZEILE(4));
      tmpstr = "max H. = ";
      tmpstr += maxHeight;
      myGLCD.print(tmp, LEFT, ZEILE(6));
      myGLCD.update();
    }
    diff=altpress-avg;  //Positive Differenz bei Steigen
	
    //Barry Dorr Filter zum ermitteln des "mittleren" Variowertes
    diff_filter_reg = diff_filter_reg - (diff_filter_reg / DIFF_FILTER_GRAD) + diff; // ergänzt den Tiefpassfilter um den aktuellen Wert
    diff = diff_filter_reg / DIFF_FILTER_GRAD;	// bildet den Mittelwert
    
    Value=127+Verstaerkung*diff; //Berechnet das Vario-Signal 0..127..255

    if (Value > 254) Value=254; //Verhindert einen Überlauf
    if (Value < 1) Value=1; //Verhindert einen Unterlauf
    Send(Value);

    altpress=avg;//Speichert den Mittelwert für den naechsten Loop
    Empfindlichkeit_einstellen(); //über den Servokanal jederzeit einstellbar
}
.........
void setHeight(float press, float temp) {
  float h;
      Serial.print("p_press = ");
      Serial.println(press);
      Serial.print("p_temp = ");
      Serial.println(temp);
  h = 0.00;
  h = ((pow((basepress / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;
      Serial.print("h = ");
      Serial.println(h);
  if (h > maxHeight) maxHeight = h;
  if (h < minHeight) minHeight = h;
}

the prints inside the function show the same values as in loop()

regards
Siegfried

    float temp = NULL, press = NULL, pdiff = NULL;

NULL and 0.0 are not the same value. Why are you assigning NULL to float variables?

      Serial.print("p_press = ");
      Serial.println(press);

Why does the name printed not match the variable name? There is nothing wrong with the syntax, but this is equivalent to:

      Serial.print("A = ");
      Serial.println(B);

which I can not imagine doing.

Typically, when debugging, I print values before the function call, to make sure that I am passing the correct values to the function, then I print the values in the function, to assure that I get the correct values in the function. I don’t see you doing that.

  h = ((pow((basepress / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;

Lots of intermediate calculations here - some necessary some not. 1/5.257 will produce the same result every time the function is called. Save some time; use a calculator.

What value does basepress divided by press return? There is no checking that you are not dividing by 0. What value does the pow() function return?

The function in question is called with a variable named avg. This implies average, which implies something other than a constant value.

Try a simple sketch that calls the function in a loop, 100 times, with the same input. If the output remains constant, the problem is not with the function. If the output drifts, it is.

If the problem is not with the function, then it is with the input.

so a long reply, many thanks for your effort.

so let me explain

i set the floats to NULL because 0.00 is a possible valid value and i want to identify the unset state. How do you solve such problems?

i print out "p_press" to know where the value comes from (in this case out of the function) and the local name of the variable is press. I can't see there any problem.

I print definitly the variables before and in the function!?!? In loop() i first call the function setHeight and then i print out in loop() the used parameter variables for the call. ok, i can do it before the call, but i'm sure, that makes no difference.

You are right, there is no 0 checking in the function: the values are pressures, 0 is absent per definition.

And again, your are right, mostly not the program is the problem, it's the programmer :grin: :grin:

I think, not the function is the problem. It must be something behind the scene.

regards Siegfried

and i want to identify the unset state.

There really is no such thing as an unset state. You either keep track, separately, whether you have assigned a meaningful value to the variable(s), or you assign them an initial value that is not in the range of valid values.

For instance, press(ure) and temp(erature) might always, for your purposes at least, be positive, so an initial value of -1.0 would mean that they had not been set, yet.

In your code, the variables are local, so they are not initialized to anything, so ANY initial value is better than nothing.

i print out "p_press" to know where the value comes from (in this case out of the function) and the local name of the variable is press. I can't see there any problem.

There isn't. I would have used "(loop) press:" and "(fun) press:", instead, but your method, now that you have explained it works, too.

Printing intermediate values in the function might help pin down where the problem is occurring.

In your code, the variables are local, so they are not initialized to anything, so ANY initial value is better than nothing.

ok, but i can't believe that! Local variables are not initialized to NULL? So why does my code work at that place? Every time loop() is called they are reset to NULL. What i understand is: when i write "float xxx = -1.00;" that will work but "float xxx = NULL" will not work???

regards Siegfried

flieger_siggi:

In your code, the variables are local, so they are not initialized to anything, so ANY initial value is better than nothing.

ok, but i can’t believe that! Local variables are not initialized to NULL? So why does my code work at that
place? Every time loop() is called they are reset to NULL.
What i understand is:
when i write “float xxx = -1.00;” that will work
but “float xxx = NULL” will not work???

regards
Siegfried

I think the main problem is that NULL is supposed to only be used with pointers, and is actually defined as 0. However, to a seasoned programmer, “float xxx = NULL” is like saying “float xxx = INPUT” or “float xxx = SERIAL”, both of which happen to be defined as 0 in Arduino.h but make no sense in context.

Also, if you use 0 (NULL) and 0 is a possible result, you have no way of knowing if the calculation was done and got the result of 0 or if you didn’t do the calculation. Why not use NaN?

float val = NAN;
if (analogRead(A0) > 400) {
   val = analogRead(A0)*0.00003;
}

if (!isnan(val)) {
   Serial.println(val);
}

sorry, my fault. :blush: (i'm aprogrammer since many years, but no c/cpp...) Thanks for the hint. I will change my code.

But how to solve my problem? Any further idea?

regards Siegfried

I ran this sketch:

float maxHeight, minHeight, basepress = 7.0;

void setHeight(float press, float temp) {
  float h;
      Serial.print("p_press = ");
      Serial.println(press);
      Serial.print("p_temp = ");
      Serial.println(temp);
  h = 0.00;
  h = ((pow((basepress / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;
      Serial.print("h = ");
      Serial.println(h);
  if (h > maxHeight) maxHeight = h;
  if (h < minHeight) minHeight = h;
}

void setup() {
    Serial.begin(115200);
}

void loop() {
    setHeight(8.0, 43.0);
    delay(500);
}

and got this output:

h = -1219.89
p_press = 8.00
p_temp = 43.00
h = -1219.89
p_press = 8.00
p_temp = 43.00
h = -1219.89
p_press = 8.00
p_temp = 43.00
h = -1219.89

h doesn’t seem to be growing ,so doesn’t that mean it’s not a problem with the setHeight function?

ok, pls see attached complete code with libraries i’ve used.
The sketch need some times, in serial monitor 2-3 minutes and then
the values begin to “grow”
I’m using a arduino mini pro board.

regards
Siegfried

VolksvarioProGesamt.ino (11.1 KB)

libraries.zip (88.2 KB)

so no one else another idea what's going wrong?