I created a circuit that measures two different location's temperature via two thermistors. When the difference in temperature is greater than 0.7, I want an LED (pin 7) to turn on and off. The thermistors are pretty spastic and show up as significantly different temperatures when they are touching the same surface. They are Panasonic 10k NTC thermistors. I want to troubleshoot this by averaging out the temp difference of 5 readings and then assessing that number in the if statement. I want the output of the average to print every 2.5 seconds but the temperature difference calculated every 500 ms (so an output after 5 samples for the average) Or if theres a better way to get it to be more stable lmk. My code follows as:
double InputVoltage = 5.12;
double Thermistor1 = A1;
double Thermistor2 = A2;
double T1Voltage;
double T2Voltage;
float T1Resistance = 0.0; //Main Resistance variable is set as a floating point variable
float T2Resistance = 0.0;
double MainTempK1 = 0.0; //The temperature of the main thermistor is set as a floating point variable
double MainTempC1 = 0.0;
double MainTempK2 = 0.0;
double MainTempC2 = 0.0;
double BM = 3375; //The Beta value for the YSI 400 thermistor between 33-40 C
double RTResistance1 = 10000; //The room temperature resistance of the main thermistor
double RTResistance2 = 10000;
double RTM = 298.15; //The room temperature for the main resistance above
const double R1 = 10000; //Since a voltage divider is being used R1 is used to calculate the resistance of the main thermistor
const double R2 = 10000;
double Temp1[11]; //A 100 number array that contains measures from the main thermistor
double Temp2[11];
void setup() {
Serial.begin(9600);
pinMode(4, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
T1Voltage = (analogRead(Thermistor1) * 0.00488);
T2Voltage = (analogRead(Thermistor2) * 0.00488);
T1Resistance = (T1Voltage * R1) / (InputVoltage - T1Voltage);
T2Resistance = (T2Voltage * R2) / (InputVoltage - T2Voltage);
double LogResistance1 = log(T1Resistance / RTResistance1);
double LogResistance2 = log(T2Resistance / RTResistance2);
MainTempK1 = (1 / ((LogResistance1 / BM) + (1 / RTM)));
MainTempK2 = (1 / ((LogResistance2 / BM) + (1 / RTM)));
MainTempC1 = MainTempK1 - 273.15;
MainTempC2 = MainTempK2 - 273.15;
double TempDifference = MainTempC1 - MainTempC2;
TempDifference = abs(TempDifference);
delay(100);
AvgDifference
if (TempDifference < 0.7) {
//if (TempDifference < 5.0) {
digitalWrite(7, LOW);
digitalWrite(4, HIGH);
Serial.println(MainTempC1);
Serial.println(MainTempC2);
Serial.print("Safe temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
else {
digitalWrite(4, LOW);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
Serial.println(MainTempC1);
Serial.println(MainTempC2);
Serial.print("Temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
}
That is normal, as they are not calibrated. Accuracy can be quite good (accurate to a fraction of a degree, F or C) if you take the time to calibrate them. I recommend this general tutorial: Why Calibrate? | Calibrating Sensors | Adafruit Learning System
Also, you can do much better by fitting individual Steinhart-Hart coefficients to each thermistor. You will need a multimeter, and this on line calculator.
Thank you for the pointers! I will try callibrating and changing the beta value. If I did want to change the code to incorporate an average reading and output though, do you know where to insert that?
I'm assuming you mean the readings are not stable.
You should add a low pass filter at the input of your A/C pins. A good start would be a 0.1µF capacitor very close to the board pins and board ground.
If you need to go higher than this you should put a 1k resistor between the capacitor and the A/D input. This will protect the Arduino from damage if the board input power drops to 0 quickly (ie a short in the wiring or similar issue).
After this you can do you averaging. The average approach I've found to work the best (for me) is:
Take an odd number of readings (in an array). Say 11 readings. Sort them and average the middle 3 readings. Simply discard the other readings.
I am trying to take the average of 5 temperature conversions and then subtract them to find the difference. Everything compiled and uploaded, but the output reads 0 for the averages and thus 0 for the difference. Is there anything I did wrong? The code runs successfully without the averaging arrays but the thermistors' output is super unstable. TIA and lmk!
double InputVoltage = 5.12;
double Thermistor1 = A1;
double Thermistor2 = A2;
double T1Voltage;
double T2Voltage;
float T1Resistance = 0.0; //Main Resistance variable is set as a floating point variable
float T2Resistance = 0.0;
double MainTempK1 = 0.0; //The temperature of the main thermistor is set as a floating point variable
double MainTempC1 = 0.0;
double MainTempK2 = 0.0;
double MainTempC2 = 0.0;
double BM = 3348.66; //The Beta value for the Panasonic thermistor between 25-50 C
double RTResistance1 = 10000; //The room temperature resistance of the main thermistor
double RTResistance2 = 10000;
double RTM = 298.15; //The room temperature for the main resistance above
const double R1 = 10000; //Since a voltage divider is being used R1 is used to calculate the resistance of the main thermistor
const double R2 = 10000;
double Temp1[11]; //A 100 number array that contains measures from the main thermistor
double Temp2[11];
void setup() {
Serial.begin(9600);
pinMode(4, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
T1Voltage = (analogRead(Thermistor1) * 0.00488);
T2Voltage = (analogRead(Thermistor2) * 0.00488);
T1Resistance = (T1Voltage * R1) / (InputVoltage - T1Voltage);
T2Resistance = (T2Voltage * R2) / (InputVoltage - T2Voltage);
double LogResistance1 = log(T1Resistance / RTResistance1);
double LogResistance2 = log(T2Resistance / RTResistance2);
MainTempK1 = (1 / ((LogResistance1 / BM) + (1 / RTM)));
MainTempK2 = (1 / ((LogResistance2 / BM) + (1 / RTM)));
MainTempC1 = MainTempK1 - 273.15;
MainTempC2 = MainTempK2 - 273.15;
float theFirstArray[5] = {};
float theSecondArray[5] = {};
long avgTemp1 = 0.0;
long avgTemp2 = 0.0;
int arrayIndex1 = 0;
int arrayIndex2 = 0;
theFirstArray[arrayIndex1] = MainTempC1;
arrayIndex1++;
theSecondArray[arrayIndex2] = MainTempC2;
arrayIndex2++;
if (arrayIndex1 == 5 && arrayIndex2 == 5) {
for (int i = 0; i < 5; i++) {
avgTemp1 = avgTemp1 + theFirstArray[i];
avgTemp2 = avgTemp2 + theSecondArray[i];
}
avgTemp1 = avgTemp1 / 5;
avgTemp2 = avgTemp2 / 5;
}
double TempDifference = avgTemp1 - avgTemp2;
TempDifference = abs(TempDifference);
if (TempDifference < 0.7) {
//if (TempDifference < 5.0) {
digitalWrite(7, LOW);
digitalWrite(4, HIGH);
Serial.println(avgTemp1);
Serial.println(avgTemp2);
Serial.print("Safe temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
else {
digitalWrite(4, LOW);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
Serial.println(avgTemp1);
Serial.println(avgTemp2);
Serial.print("Unsafe temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
}
You have this in loop() so every time that loop() repeats the arrays are redeclared and their contents reset to random values as they are local variables. Is that what you meant to do ?
Thanks for pointing this out - nope not what I meant to do. I want the first array to store 5 temperature reading from thermistor 1 and the same for second array. When the loop repeats I want 5 new temperature readings from the respective thermistor, reflecting the change in environmental condition. Do you know what I should change it to?
Declare the arrays, the average temperatures and the index variables globally. Actually you only need a single index variable
Then in loop() take the 2 readings and save them at the current index positions until you have saved 5 of them and then do whatever you need with the 2 arrays
I have not looked at your calculations but it would be a good idea to print any intermediate results to see whether they look reasonable
This sets them to whatever was in the memory allocated to the arrays. There is no way of knowing what those values will be. That is close enough to random for me
Ok, I was able to get it. The outputted averages for both thermistors are the same values for several rounds of the loop. Does this mean there is still a code bug or is the temperature just that stable? I am afraid i went from too unstable, to too stable and want a stimulus (like applying heat to a thermistor) to trigger the pin 7 LED. Does this have anything to do with the timing of the filling the array vs the if statement interpreting the temperature difference? I changed the code as follows below.
double InputVoltage = 5.12;
double Thermistor1 = A1;
double Thermistor2 = A2;
double T1Voltage;
double T2Voltage;
float T1Resistance = 0.0; //Main Resistance variable is set as a floating point variable
float T2Resistance = 0.0;
double MainTempK1 = 0.0; //The temperature of the main thermistor is set as a floating point variable
double MainTempC1 = 0.0;
double MainTempK2 = 0.0;
double MainTempC2 = 0.0;
double BM = 3348.66; //The Beta value for the Panasonic thermistor between 25-50 C
double RTResistance1 = 10000; //The room temperature resistance of the main thermistor
double RTResistance2 = 10000;
double RTM = 298.15; //The room temperature for the main resistance above
const double R1 = 10000; //Since a voltage divider is being used R1 is used to calculate the resistance of the main thermistor
const double R2 = 10000;
double Temp1[11]; //A 100 number array that contains measures from the main thermistor
double Temp2[11];
double theFirstArray[5];
double theSecondArray[5];
double avgTemp1 = 0.0;
double avgTemp2 = 0.0;
int arrayIndex;
void setup() {
Serial.begin(9600);
pinMode(4, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
T1Voltage = (analogRead(Thermistor1) * 0.00488);
T2Voltage = (analogRead(Thermistor2) * 0.00488);
T1Resistance = (T1Voltage * R1) / (InputVoltage - T1Voltage);
T2Resistance = (T2Voltage * R2) / (InputVoltage - T2Voltage);
double LogResistance1 = log(T1Resistance / RTResistance1);
double LogResistance2 = log(T2Resistance / RTResistance2);
MainTempK1 = (1 / ((LogResistance1 / BM) + (1 / RTM)));
MainTempK2 = (1 / ((LogResistance2 / BM) + (1 / RTM)));
MainTempC1 = MainTempK1 - 273.15;
MainTempC2 = MainTempK2 - 273.15;
theFirstArray[arrayIndex] = MainTempC1;
theSecondArray[arrayIndex] = MainTempC2;
arrayIndex++;
if (arrayIndex == 5) {
avgTemp1 = theFirstArray[0] + theFirstArray[1] + theFirstArray[2] + theFirstArray[3] + theFirstArray[4];
avgTemp2 = theSecondArray[0] + theSecondArray[1] + theSecondArray[2] + theSecondArray[3] + theSecondArray[4];
avgTemp1 = avgTemp1 / 5;
avgTemp2 = avgTemp2 / 5;
arrayIndex = 0;
}
double TempDifference = avgTemp1 - avgTemp2;
TempDifference = abs(TempDifference);
if (TempDifference < 0.7) {
//if (TempDifference < 5.0) {
digitalWrite(7, LOW);
digitalWrite(4, HIGH);
Serial.println(avgTemp1);
Serial.println(avgTemp2);
Serial.print("Safe temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
else {
digitalWrite(4, LOW);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
Serial.println(avgTemp1);
Serial.println(avgTemp2);
Serial.print("Unsafe temperature difference: ");
Serial.println(TempDifference);
delay(5000);
}
}
If you'd rather not bother with indexing, etc. here's an alternative.
In setup(), set your average value to a single reading for each input.
Then, in loop(), multiply the average by (factor-1)/factor, then add to it 1/factor * a new reading. That accomplishes the same smoothing very quickly, and usually suffices without wasting memory buffering data.
If you want to play with smoothing factors, you can use a constant for the multiplier, instead of having to adjust array lengths. Try this out(untested, but compiles):
const int input1 = A0; //change to suit processor, design
const int input2 = A1; //change to suit processor, design
const float fact = 5; //change to suit; range 2 -> ~
float avg1;
float avg2;
void setup() {
Serial.begin(115200); //Remember to set Serial Monitor to the same value
avg1 = analogRead(input1); //preloads the average value with a first sample
avg2 = analogRead(input2); //preloads the average value with a first sample
//startup messaging
Serial.println("Reset. Started scanning"); //say hello, so we know where sampling starts in Serial Monitor display
Serial.print(avg1);
Serial.print(" ");
Serial.println(avg2);
}
void loop() {
avg1 = avg1 * (fact - 1) / fact + analogRead(input1) / fact; //note, the compiler will optimize out the (fact - 1) / fact
avg2 = avg2 * (fact - 1) / fact + analogRead(input2) / fact;
Serial.print(avg1);
Serial.print(" ");
Serial.println(avg2);
delay(100); //keeps display scrolling reasonably slow
}
Can you provide a reference for that as it is not what I previously believed to be the case. I am not able to find a reference for what happens either way and could well be wrong, but I would like to know if I am
Trying to find a definitive answer to my question on that site caused me to get lost in a maze of twisty little passages, all alike, so I think that I will stick to my normal practice of expressly initialising local arrays if they need default values
Well, as Sheryl Crow wrote, if it makes you happy...
(I'm a fan of economic brevity, so I'll stick with the empty braces, and let the compiler do the heavy lifting)
I have merged your topics due to them having too much overlap on the same subject matter @ervorpahl.
In the future, please only create one topic for each distinct subject matter and be careful not to cause them to converge into parallel discussions.
The reason is that generating multiple threads on the same subject matter can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.