rust-embedded-community / rust-measurements

Metric, Imperial, and other measurement handling for Rust. Length, Temperature, Weight, and Volume
https://crates.io/crates/measurements
28 stars 10 forks source link

Humidity functions for no-std #39

Closed pukeko37 closed 3 years ago

pukeko37 commented 3 years ago

Feature proposal

Provide calculation of dew-point from relative humidity for no_std using a compensated rule-of-thumb formula that provides reasonable accuracy within the range 50% <= RH <= 100% and 0° < t < 30°C. Provide accuracy caveats in the documentation.

This will mean that users of the humidity module will obtain different results depending whether they are running std or no_std.

Remove the #[cfg(not(feature = "no_std"))] restriction on fn as_absolute_humidity() and fn as_vapor_pressure(), since these functions are linear and are supported by no_std.

Discussion

The new humidity module does not provide humidity, dew-point and vapor pressure calculations for no_std. Embedded systems often use sensors that detect temperature and relative humidity (RH). It is reasonable to expect to be able to convert relative humidity to dew-point (td).

Humidity calculations are non-linear, and approximation formulas of reasonable accuracy rely on functions such as f64.ln() and f64.exp(), which are not available on no_std.

However, for RH > 50% the relationship becomes nearly linear, and a compromise to provide some features for no_std is possible.

So that raises the question, how accurate do calculations need to be? For example, there is a common rule of thumb for relatively moist air:

td = t - ((100 - RH) / 5).

This can be calculated under no_std, and would provide accuracy to better than +/- 1°C for td or +/- 5% for RH for most of the range 0° < t < 30°C and 50% < RH < 100%.

A more accurate variation on this formula includes compensation terms, with coefficients chosen to minimize the root-mean-square error for 40% < RH < 100% and 0° < t <30°C (while insisting that the intercept at RH = 100% is td = t):

td = t - ((100 - RH) / 5) ((273.15 + t)/300)^2 - 0.00135(RH-84.0)^2 + 0.35

The maximum error in td of this equation is +/- 0.3°C over the whole range of 50% <= RH <= 100% and 0° < t < 30°C.

The inverse function: from_dewpoint() for no_std is unavailable, since no_std does not provide square roots. However, the basic rule-of-thumb could be used td = t - ((100 - RH) / 5) to provide from_dewpoint() for no_std, but with lower accuracy.

eldruin commented 3 years ago

I used libm to implement these functions in #40. Would that solve this or are there further concerns?

pukeko37 commented 3 years ago

Yes, that's a good suggestion. I didn't know about libm. I see there is exp() and presumably log() is the same as f64.ln().

I'll add no_std functions using libm to humidity, and test to ensure the results are the same as std. Expect a new PR whwn Im done.

Cheers,

eldruin commented 3 years ago

@pukeko37 I have already implemented the no-std version of the humidity functions in #40. The functions also pass the same tests as the std version.

pukeko37 commented 3 years ago

Great. Even better!

I must set up a dev environment and take a look, properly.

I also have some concerns about function parameter bounds checking/ contract enforcement. E.g., relative humidity < 0.0% or > 100%, or dewpoint > temperature.

I'm thinking of assert! panics, or returning NaN. Any thoughts?