Thought I had a Pow function problem but it was a conditional statement error

This is not even about accuracy. It is about wanting to compute the function pow() with exponents greater than 2 but only getting 0 as a result.
I am using Arduino UNO R4 WiFi to estimate the flow in a channel by calculating the distance w an ultrasonic sensor.
My sketch:

 The following variables are automatically generated and updated when changes are made to the Thing

  CloudFlowRate gasto;
  CloudTemperatureSensor temperatura_atm;
  CloudLength distancia;
  CloudLength tirante;
  CloudPercentage porcentajeQ;
  CloudRelativeHumidity humedad_atm;
  CloudTime date;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include <Adafruit_Sensor.h> //para el sensor DHT
#include <DHT.h> //para el sensor DHT
#include <SD.h>  //para el SD
#include <SPI.h> //para el SD
#include <Wire.h> //para el reloj
#include <RTClib.h> //para el reloj
#include <Arduino.h>

#define trigPin 6
#define echoPin 5
#define DHTPIN 2
#define DHTTYPE DHT11

const int chipSelect = 10;
DHT dht(DHTPIN, DHTTYPE);

String ano;
String dia;
String mes;
String horas;
String minutos;
String segundos;
String Fecha;
String Hora;
String Nombrearchivo;
String Imprimir;

float H_canal = 146.30; //height between the base of the channel and the ultrasonic sensor
float tirante2 = -9999.00;
float Q2 = -9999.00;
float Qmax = 9.6601;
//creating variables to later save the values obtained with pow function:
float y_3 = -9999.00;
float y_4 = -9999.00;
float y_5 = -9999.00;

void setup() {
  Serial.begin(9600);
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  Serial.println("Inicializando reloj RTC...");
  if(! rtc.begin())
  { Serial.println("No se encontró RTC");
  Serial.flush();
  while (1) delay(10);
  //abort();
  }
  if (rtc.lostPower())
  { Serial.println("RTC no está activado, colocar la hora");
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  else
  { Serial.println("RTC inicializado");
  }
  
  Serial.println("Inicializando tarjeta SD...");
  if (!SD.begin(chipSelect))
  { Serial.println("No se pudo inicializar la SD, o no está conectada");
  }
  else
  { Serial.println("SD inicializada");
  }
  
  dht.begin();
  
}

void loop() {
  ArduinoCloud.update();
  
  // Your code here 
  //if (millis()-lastSensorRead > 30000) {
  date = ArduinoCloud.getLocalTime();

  delay (2000);
  float h2 = dht.readHumidity();
  float t2 = dht.readTemperature(); 
  if (isnan(t2) || isnan(h2)) 
  { Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  float d = 133.88; //since calculating the distance with the ultrasonic sensor is not the problem, just change this value between 0 and H_canal stated at the beginning of the sketch
  
  if (d<0)
  {
    tirante2 = -9999.00;
    Q2 = -9999.00;  
  }
  else
  { tirante2 = (H_canal - d)/100.00;
     tirante = tirante2;
    Serial.println(tirante2);
    y_3 = pow(tirante2, 3.0);
    y_4 = pow(tirante2, 4.0);
    y_5 = pow(tirante2, 5.0);
    Serial.println(y_3);
    Serial.println(y_4);
    Serial.println(y_5);
  } 
   
  if (tirante2<0)
  {
    tirante2 = -9999.00;
    Q2 = -9999.00;
  }
  else if (tirante2=0)
  {
    Q2 = 0.00;
  }
  else if ((tirante2>0) && (tirante2<=0.11))
  {
    float x1 = 4047.1*y_5;
    float x2 = - 960.19*y_4;
    float x3 = 80.27*y_3;
    float x4 = 2.0888*pow(tirante2, 2.00);
    float x5 = 0.0306*tirante2;
    float a1 = - 0.00003;
    Q2 = x1 + x2 + x3 + x4 + x5 + a1;
  }
  else if ((tirante2>0.11) && (tirante2<0.2))
  {
    float x1 = 28.294*pow(tirante2, 2.0);
    float x2 = - 4.7767*(tirante2);
    float a1 = 0.1907;
    Q2 = x1 + x2 + a1;
  }
  else
  {
    float x1 = -4.5949*y_3;
    float x2 = 13.727*pow(tirante2, 2.0);
    float x3 = 2.2187*tirante2;
    float a1 = - 0.6172;
    Q2 = x1 + x2 + x3 + a1;
  }
  
  porcentajeQ = Q2*100.00/Qmax;
  
  DateTime now = rtc.now();
  ano = String(now.year());
  mes = String(now.month());
  dia = String(now.day());
  horas = String(now.hour());
  minutos = String(now.minute());
  segundos = String(now.second());
  Fecha = ano + "/" + mes + "/" + dia;
  Hora = horas + ":" + minutos + ":" + segundos;
  Nombrearchivo = ano + mes + dia + ".csv"; //nombre máximo de 8 caracteres

  Imprimir = "EHA_3 ";
  Imprimir += Fecha;
  Imprimir += " ";
  Imprimir += Hora;
  Imprimir += " Tirante: ";
  Imprimir += tirante2;
  Imprimir += " m Gasto: ";
  Imprimir += Q2;
  Imprimir += " l/s Temperatura: ";
  Imprimir += t2;
  Imprimir += " °C Humedad: ";
  Imprimir += h2;
  Imprimir += " % dist_sensor: ";
  Imprimir += d;
  Imprimir += " cm Q%:";
  Imprimir += porcentajeQ;
  Imprimir += " %";
  
  File dataFile = SD.open(Nombrearchivo, FILE_WRITE);
  if (dataFile)
  { dataFile.println(Imprimir);
    dataFile.close();
    Serial.println(Imprimir);
  }
  else
  { Serial.println("Error al intentar escribir en el archivo!");
  }

  tirante = tirante2;
  gasto = Q2;
  humedad_atm = h2;
  temperatura_atm = t2;
  distancia = d;

  ArduinoCloud.update();
  delay(20000);
  ArduinoCloud.update();
  delay(20000);
}

This is what I get as a result in the Serial Monitor when using my program in the channel:

13:13:39.402 -> SD inicializada
13:13:41.484 -> 0.12
13:13:41.484 -> 0.00
13:13:41.484 -> 0.00
13:13:41.484 -> 0.00
13:13:41.603 -> EHA_3 2025/5/27 13:13:30 Tirante: 0.00 m Gasto: -0.63 l/s Temperatura: 34.30 °C Humedad: 43.00 % dist_sensor: 133.88 cm Q%:-6.48 %

For some reason my value in "tirante2" (and therefore, "tirante") gets automatically erased and it is equalled to zero although it did get a different value at the beggining. And I have changed the Pow() function to multiplying directly as:

 y_3 = tirante2*tirante2*tirante2;
 y_4 = tirante2*tirante2*tirante2*tirante2;
 y_5 = tirante2*tirante2*tirante2*tirante2*tirante2;

But the problem remains the same, I get zero as a value.

No.

Consider:

void setup() {
   Serial.begin(115200);
   delay(3000);
   float x;
   x = 0.12;
   for( int i=0; i<5; ++i ) {
      Serial.println(x);
      x = x * 0.12;
   }
   x = 0.12;
   for( int i=0; i<5; ++i ) {
      Serial.println(x,6);
      x = x * 0.12;
   }
}

void loop() {
}

Output:

0.12                                                    
0.01                                                    
0.00                                                    
0.00                                                    
0.00
0.120000
0.014400
0.001728
0.000207
0.000025

0.001728, as an example, is displayed as 0.00 when the output is limited to 2 decimal places. But it is not, in fact, actually zero.

1 Like

Just to add to what @van_der_decken explained and narrow it down to your specifics - change this code

To add more digits . This will print 6 digits after the decimal point.

    Serial.println(y_3, 6);
    Serial.println(y_4, 6);
    Serial.println(y_5, 6);

The default value is 2 digits if you don’t pass a parameter.

I understand what you're trying to say but this is not the case, and it is reflected when "Q2" (the flow in the channel) is calculated. It does saves the values as just zero since my flow "Gasto" is negative when it is supposed to be positive for any "tirante2" value (the water depth in the channel), and Arduino UNO R4 saves values in 32-bits. The polynominals stated in the sketch have already been evaluated and they will always calculate a positive water flow value.

Right now, what I am noticing the program kind of goes crazy once it evaluates the conditionals after calculating tirante2 = (H_canal - d)/100.00; and using several even if conditionals shouldn't be a problem, although I'm starting to think about that that indeed is the problem .... and I do have examples but I'll make another topic for that ...

Thanks anyways!

If you say so. I'll leave you to it then.

You might want to look at this How to get the best out of this forum before you proceed any further.

Look at the rules about starting what some would see as a duplicate post.

1 Like

It does go crazy because one of the conditionals is:

else if (tirante2 = 0)

when it should have said:

else if (tirante2==0)

:clown_face: :clown_face: :clown_face:

2 Likes

The default println(float, decimals) has some limitations.

  • it prints "ovf" if the abs(float) is above 4294967040 ~~ max uint32_t ish (AVR) while floats can be much larger and valid.
  • it can print the smallest floats using e.g. 40 decimals mostly resulting in an "output layout nightmare"

You might use GitHub - RobTillaart/printHelpers: Arduino library to help formatting data for printing
It supports among others scientific format of floats e.g. 0.35e15 or 0.789e-22 or -0.32e00
(and yes, it takes a few extra CPU cycles)

else if 0 = (tirante2)

would have resulted in an error. see Yoda conditions

Forget or never learn Yida, that's a 20th century holdover. To a first approximation no one uses it - it only makes ppls' brains hurt.

else if (tirante2 = 0)... 

generates a compiler warning, but the default setting is too low.

Go now to the IDE preferences and crank up,the verbosity and warning levels so you get as much info as is available in that way, then heed the red ink that spills.

a7

1 Like

It's a nice trick that most programmers don't use as it's compromising readability (I don't like it).

Modern languages do not allow variable assignments within conditionals which is a good way to solve this issue :slight_smile: