kylecorry31 / Trail-Sense

An Android app that uses your phone's sensors to assist with wilderness treks or survival situations.
https://kylecorry.com/Trail-Sense/
MIT License
1.23k stars 75 forks source link

Temperature Calibration #250

Closed efraletti closed 3 years ago

efraletti commented 4 years ago

Hello,

Thanks for the excellent upgrades since last time.

The temperature sensor is great, and with local measurements I inferred if there was a way to calibrate the reading by a number, which in case is 10 °C, it would serve a correct enough bearing for the circumstances this instrument is being used.

The alert telling that internal temperatures on the phone will disturb values is very important, it could be the subtitle of the calibrate button.

kylecorry31 commented 4 years ago

Thank you!

It is really difficult to calibrate the temperature sensors on a phone - I originally had a slider which allowed you to correct the temperature to match a known ambient temperature, but as my phone cooled/heated up it became inaccurate again.

I'll definitely look into some options though.

efraletti commented 4 years ago

Nice,

It sure has low accuracy, since it depends directly on processor usage and the internal temperatures. GPS and maps can "fry an egg" on some phones.

Maybe averaging high and low values, in conjunction with a slider/constant value multiplier/constant value sum or subtract can give a nice enough value to have on hands/pocket, instead of relying on weather data collected from God knows where, even using openweathermap based apps.

kylecorry31 commented 4 years ago

I will explore some options around the slider based calibration - no wonder a lot of Android devices no longer ship with an ambient temperature sensor (Trail Sense uses the battery temperature on those devices if available). I'm trying to find some research papers around ambient temperature estimation, in hopes I can get a more accurate method.

As of right now, the only real use of the thermometer on a phone I found is when the phone is completely off for some time, and then getting a temperature reading when power is restored.

marcodiegomesquita commented 3 years ago

It is possible that the environment temperature can be estimated using Newton's law of cooling. According to it, the temperature of a body with time is given by the equation T(t) = T_env + A*e^(-kt) .

Consider taking 3 temperature readings T_0, T_1 and T_2 sampled during an interval. This way, while the device exchanges heat with the environment for a period, enough data could be gathered to calculate all the terms on the previous equation and evaluate the environment temperature. The result could then be calibrated using a linear interpolation.

Note that the sampled temperature measurements should vary monotonically. That is: T_0 <= T_1 <= T_2 or T_0 >= T_1 >= T_2 . Using a longer interval to sample the temperature may improve precision. While readings are performed, a screen showing progress should be displayed with an advancing progress bar, a text saying "Sampling temperature..." and a cancel button. A new setting can be added to adjust how long measurements can take. There may be problems if measurements do not vary monotonically, but these will be discussed later. The screen that displays the temperature should also have the warning: "To improve measurement precision stop heavy tasks on the device for some time and keep it away from sunlight, air currents and cold or heat sources."

For calibration I'd suggest a screen with 2 buttons: "Temperature 1: XºC" and "Temperature 2: YºC". It should have the following text: "To calibrate the temperature sensor use a working environment thermometer and click any of the calibration buttons. Two different calibration temperature values are needed. Precision is increased for temperatures between calibration values.". When any of these buttons is clicked, an environment non calibrated temperature is calculated and the user is asked with the text "Temperature reading from working environment thermometer:" for a correct environment temperature reading using a working thermometer or to cancel the calibration. If the action is not cancelled, the temperature given by the user is associated the sampled non calibrated temperature. With these data, it is possible to linearly interpolate non calibrated temperatures to match the calibrated given values.

There is still the problem when temperature does not varies monotonically with time. To minimize this possibility, the temperatures are not calculated using only 3 direct readings. Instead, they are calculated using averages of measurements that are continually sampled. For this, an increasing number of samples are periodically taken and stored in an array. After a minimum threshold number of samples are taken, 3 averages are calculated: T_avg_1 the average of the first 1/3 of the samples, T_avg_2 the average of the second 1/3 of the samples and T_avg_3 the average of the last 1/3 of the samples. These averages would then be updated with each new sample until one of the following conditions occur: the user cancels the action, a time limit is reached or the averages vary monotonically. If monotonically varying averages are achieved then everything proceeds as normally with T_0 = T_avg_1, T_1 = T_avg_2 and T_2 = T_avg_3; Otherwise, if action is not cancelled, the user is informed that temperature is calculated with "low precision mode". When in "low precision mode", it is assumed that the device has reached thermal equilibrium with the environment and an average of all the samples is used.

If you need any help with calculations, I can explain it better.

kylecorry31 commented 3 years ago

Thank you for the detailed explanation - I'll have to experiment to see how it performs

kylecorry31 commented 3 years ago

@marcodiegomesquita after implementing this formula (including the average readings), the results are still way off as even when exposed to cold conditions, the battery temperature still makes the readings inconsistent. What I was seeing was the following:

For reference, here was the formula I was using to get the environmental temperature (I derived it from the equation above with times = 0, 1, and 2 [unitless, but equal time durations]): (temp0 temp2 - temp1 temp1) / (temp0 + temp2 - 2 * temp1)

And the temperature readings were only considered if they varied monotonically (the average method you recommended - sample size of 90 readings, taken at 500 ms intervals). I also tried with direct readings spaced at 1s, 2s, 4s, 8s, and 10s for each trial and got pretty much the same result.

kylecorry31 commented 3 years ago

(with some help from this: https://math.stackexchange.com/questions/3621120/newtons-law-of-cooling-question-but-without-ambient-temp-given)

marcodiegomesquita commented 3 years ago

You're fast! Amazing! I wasn't sure my suggestion would be taken seriously. Thanks for trying it.

@marcodiegomesquita after implementing this formula (including the average readings), the results are still way off as even when exposed to cold conditions, the battery temperature still makes the readings inconsistent. What I was seeing was the following:

  • The derived temperature mostly matched the reported temperature of the device
  • The derived temperature was sometimes a few degrees less than the reported temperature (so better than reported)
  • The derived temperature rapidly fluctuates as the devices battery heat plays a factor (and when the device was exposed to cold temperatures, most of the time, the reported temperature was closer than the derived)

Good. I read that as an improvement.

Now, since the battery, when the device is on or changing, behaves as a heat source itself, it is natural that the result is off by some amount. Assuming that the the error is constant or linearly dependent on the estimated temperature it can be corrected by the calibration method I described.

Does your tests include the calibration I described?

marcodiegomesquita commented 3 years ago

If it helps: let U_1 and U_2 be respectively non-calibrated temperatures 1 and 2. Let C_1 and C_2 be respectively calibrated temperatures 1 and 2. A calibrated value C can be obtained from a non-calibrated reading U by C = C_1 + (C_2 - C_1)(U_1 - U)/(U_1 - U_2) .

kylecorry31 commented 3 years ago

Thanks! I'll try the calibration out tomorrow

kylecorry31 commented 3 years ago

The calibration seems to work great, and will be something I try to implement fully soon. But the implementation with the law of cooling is exhibiting really inconsistent behavior. I noticed that when my phone is exposed to cold temperatures, the temperature mostly decreases, but occasionally it will start to increase, which throws the results way off. (and the opposite happens when exposed to hotter temperatures) I'm still experimenting with sampling durations and filtering to try to avoid this, but so far I'm getting better results with the calibrated raw battery temperature. I'll update if I get different results.

Thanks for the help!

marcodiegomesquita commented 3 years ago

Hmm... It is a bit sad that the Law of cooling is not helping as I expected. I'm happy the calibration seems to work well though.

I don't know exactly what may cause such behavior. One possibility is the OS changing the processor frequency based on the device temperature. So way we are actively fighting the device. Maybe the samples should be acquired before or after inconsistent heating kicks but not during it.

When the inconsistent behavior happens, doesn't getting the average of all samples works well?

kylecorry31 commented 3 years ago

Yeah, I'm not entirely sure what the cause is, though I can say it consistently happens. And I tested with averaging, and it doesn't seem to help in this case because the heating/cooling happens over the course of several seconds.

marcodiegomesquita commented 3 years ago

I've just seen you implemented a hand warmer tool. I think it can be used to calculate the environment temperature: first heat the device to a predetermined high temperature, then use Newton's law of cooling to determine environment temperature while it cools.

kylecorry31 commented 3 years ago

@marcodiegomesquita you are probably correct there, but the hand warmer (I actually didn't implement it yet - just going to do more research into it) does use a lot of battery to reach the desired temperature (and may not be good for the device in the long run - more research needed), which would not be ideal for just checking the temperature

marcodiegomesquita commented 3 years ago

Yeah. Makes me think of https://xkcd.com/1172/ . I'm still curious to know if it would work well. Maybe this could be called "high precision mode" and come with a warning about the battery...

marcodiegomesquita commented 3 years ago

I'd suggest the following routine:

I think this can be much cheaper power-wise.

kylecorry31 commented 3 years ago

I'll consider it, but I'm not sure if I'm willing to do that because of the following trade offs:

I'm going to move the discussion on Law of Cooling to issue https://github.com/kylecorry31/Trail-Sense/issues/358 so this can be closed out once temperature calibration is in place.

marcodiegomesquita commented 3 years ago

I'll consider it, but I'm not sure if I'm willing to do that because of the following trade offs:

  • Will use battery power to increase the temperature of the device

Price to pay for a more advanced measurement.

  • Every device will heat up differently

Law of cooling combined with calibration should be enough to counter this.

  • This will probably make the user wait a while, which for a temperature reading (that may not be accurate), I don't think is worth it (since they can feel the temperature themselves)

Price to pay for a more advanced measurement.

I'm going to move the discussion on Law of Cooling to issue #358 so this can be closed out once temperature calibration is in place.

Still, I'm curious about how well it could work. If you ever run any test or make a debug version available with such feature, please tell me.