0.2.5 Temperature

This commit is contained in:
rob tillaart 2021-12-29 12:34:24 +01:00
parent fd0df277d5
commit ac771f1efd
17 changed files with 813 additions and 0 deletions

View File

@ -0,0 +1,11 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- due
- zero
- leonardo
- m4
- esp32
- esp8266
- mega2560

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:
pattern: "\\.json$"

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2022 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,71 @@
[![Arduino CI](https://github.com/RobTillaart/Temperature/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/Temperature/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/Temperature/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/Temperature/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/Temperature/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/Temperature/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/Temperature.svg?maxAge=3600)](https://github.com/RobTillaart/Temperature/releases)
# Temperature
Arduino library with dewPoint, humidex, heatIndex and wind-chill functions.
## Description
This library contains weather related functions.
These functions are approximations based on work of NOAA a.o.
These functions can be used with temperature and humidity sensors e.g.
DHT22 or Sensirion, to make a weather station application.
## Interface
### Conversion
- **float Fahrenheit(float Celsius)** idem.
- **float Celsius(float Fahrenheit)** idem.
- **float Kelvin(float Celsius)** idem.
### DewPoint, humidex
- **float dewPoint(float Celsius, float humidity)** idem.
- **float dewPointFast(float Celsius, float humidity)** idem.
- **float humidex(float Celsius, float dewPoint)** idem.
### heatIndex
- **float heatIndex(float Fahrenheit, float humidity)** idem.
- **float heatIndexC(float Celsius, float humidity)** idem.
### WindChill
Wind speed @ 10 meter, if **convert** is true => wind speed will be converted to 1.5 meter
else ==> formula assumes wind speed @ 1.5 meter
- **float WindChill_F_mph(float Fahrenheit, float milesPerHour, bool convert = true)**
- **float WindChill_C_kmph(float Celsius, float kilometerPerHour, bool convert = true)**
- **float WindChill_C_mps(float Celsius, float meterPerSecond, bool convert = true)**
## Operations
The functions have a limited scope so one cannot use it for all input values possible.
The user should be aware of that. Check the references mentioned in the code and or
Wikipedia to confirm the applicability of the values generated.
The functions do not check the inputs.
See examples for typical usage.
# Future
- improve documentation
- expand number of formulas
-

View File

@ -0,0 +1,78 @@
//
// FILE: dewpoint_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-04
#include "temperature.h"
uint32_t start;
uint32_t duration1;
uint32_t duration2;
float maxError;
volatile float dp;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println("takes ~40 seconds");
Serial.println(dewPoint(25, 50), 2);
Serial.println(dewPointFast(25, 50), 2);
Serial.println("\ndewPoint()");
start = millis();
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
dp = dewPoint(cel, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.println("\ndewPointFast()");
start = millis();
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
dp = dewPointFast(cel, hum);
}
}
duration2 = millis() - start;
Serial.println(duration2);
Serial.print("RATIO:\t");
Serial.println((1.0 * duration1) / duration2, 3);
Serial.println("\ndewPointFast() vs dewPoint()");
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
float x = abs(dewPoint(cel, hum) - dewPointFast(cel, hum));
if (x > maxError) maxError = x;
}
}
Serial.print("ERROR:\t");
Serial.println(maxError, 3);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,53 @@
//
// FILE: heatindexC_table.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-04
#include "temperature.h"
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int t = 25; t <= 45; t += 1)
{
Serial.print("\t");
Serial.print(t);
}
Serial.println();
Serial.println();
for (int hum = 40; hum <= 100; hum += 5)
{
Serial.print(hum);
for (int t = 25; t <= 45; t += 1)
{
float hi = heatIndexC(t, hum);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,45 @@
//
// FILE: heatindexC_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-04
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(heatIndexC(25, 50), 2);
start = millis();
for (int cel = 10; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
hi = heatIndexC(cel, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,53 @@
//
// FILE: heatindex_table.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-04
#include "temperature.h"
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int t = 80; t <= 110; t += 2)
{
Serial.print("\t");
Serial.print(t);
}
Serial.println();
Serial.println();
for (int hum = 40; hum <= 100; hum += 5)
{
Serial.print(hum);
for (int t = 80; t <= 110; t += 2)
{
float hi = heatIndex(t, hum);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,44 @@
//
// FILE: heatIndex_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-04
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(heatIndex(100, 50), 2);
start = millis();
for (int t = 40; t < 110; t++)
{
for (int hum = 1; hum < 100; hum++)
{
hi = heatIndex(t, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,51 @@
//
// FILE: humidex_table.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-05
#include "temperature.h"
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int cel = 20; cel < 45; cel++)
{
Serial.print("\t");
Serial.print(cel);
}
Serial.println();
Serial.println();
for (int hum = 100; hum > 15; hum -= 2)
{
Serial.print(hum);
for (int cel = 20; cel < 45; cel++)
{
float dp = dewPoint(cel, hum);
float hi = humidex(cel, dp);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,46 @@
//
// FILE: humidex_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-04-05
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(humidex(25, 50), 2);
start = millis();
for (int t = 25; t <= 45; t++)
{
for (int hum = 1; hum <= 100; hum++)
{
float dp = dewPoint(t, hum);
hi = humidex(t, dp);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,23 @@
{
"name": "Temperature",
"keywords": "Temperature, Kelvin, Celsius, Fahrenheit, dewPoint, humidex, heatIndex, windChill",
"description": "Library with weather related functions.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Temperature"
},
"version": "0.2.5",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
"headers": "temperature.h"
}

View File

@ -0,0 +1,11 @@
name=Temperature
version=0.2.5
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with weather related functions.
paragraph=Kelvin Celsius Fahrenheit dewPoint humidex heatIndex windChill
category=Data Processing
url=https://github.com/RobTillaart/Temperature
architectures=*
includes=temperature.h
depends=

View File

@ -0,0 +1,169 @@
#pragma once
//
// FILE: temperature.h
// VERSION: 0.2.5
// DATE: 2015-03-29
// PURPOSE: collection temperature functions
//
// HISTORY:
// 0.1.0 2015-03-29 initial version
// 0.1.1 2017-07-26 double to float (issue #33)
// 0.2.0 2020-04-04 #pragma once, removed WProgram.h, readme.md, comments
// replaced obsolete links with new ones,
// tested and removed some code
// 0.2.1 2020-05-26 added wind-chill formulas
// 0.2.2 2020-06-19 fix library.json
// 0.2.3 2020-08-27 fix #5 order of functions, typo, fixed 1 example
// 0.2.4 2021-01-08 Arduino-CI + unit tests
// 0.2.5 2021-12-28 Arduino-CI, library.json, readme.md, license, minor edits
#define TEMPERATURE_VERSION (F("0.2.5"))
inline float Fahrenheit(float celsius)
{
return 1.8 * celsius + 32; // 5.0 / 9.0 = 1.8
}
inline float Celsius(float fahrenheit)
{
return (fahrenheit - 32) * 0.55555555555; // 5.0 / 9.0 = 0.555...
}
inline float Kelvin(float celsius)
{
return celsius + 273.15;
}
// reference:
// [1] https://wahiduddin.net/calc/density_algorithms.htm
// [2] https://web.archive.org/web/20100528030817/https://www.colorado.edu/geography/weather_station/Geog_site/about.htm
// dewPoint function based on code of [2]
// calculation of the saturation vapour pressure part is based upon NOAA ESGG(temp)
float dewPoint(float celsius, float humidity)
{
// Calculate saturation vapour pressure
// ratio 100C and actual temp in Kelvin
float A0 = 373.15 / (273.15 + celsius);
// SVP = Saturation Vapor Pressure - based on ESGG() NOAA
float SVP = -7.90298 * (A0 - 1.0);
SVP += 5.02808 * log10(A0);
SVP += -1.3816e-7 * (pow(10, (11.344 * ( 1.0 - 1.0/A0))) - 1.0 );
SVP += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1.0 ))) - 1.0 ) ;
SVP += log10(1013.246);
// calculate actual vapour pressure VP;
// note to convert to KPa the -3 is used
float VP = pow(10, SVP - 3) * humidity;
float T = log( VP / 0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}
// dewPointFast() is > 5x faster than dewPoint() - run dewpoint_test.ino
// delta mdewPointFastax with dewPoint() - run dewpoint_test.ino ==> ~0.347
// (earlier version mentions ~0.6544 but that test code is gone :(
// http://en.wikipedia.org/wiki/Dew_point
float dewPointFast(float celsius, float humidity)
{
float a = 17.271;
float b = 237.7;
float temp = (a * celsius) / (b + celsius) + log(humidity/100);
float Td = (b * temp) / (a - temp);
return Td;
}
// https://en.wikipedia.org/wiki/Humidex
float humidex(float celsius, float dewPoint)
{
float e = 19.833625 - 5417.753 /(273.16 + dewPoint);
float h = celsius + 3.3941 * exp(e) - 5.555;
return h;
}
// https://en.wikipedia.org/wiki/Heat_index
// TODO add valid range for TF & R
// TF = temp in Fahrenheit
// R = humidity in %
float heatIndex(float TF, float R)
{
const float c1 = -42.379;
const float c2 = 2.04901523;
const float c3 = 10.14333127;
const float c4 = -0.22475541;
const float c5 = -0.00683783;
const float c6 = -0.05481717;
const float c7 = 0.00122874;
const float c8 = 0.00085282;
const float c9 = -0.00000199;
float A = (( c5 * TF) + c2) * TF + c1;
float B = (((c7 * TF) + c4) * TF + c3) * R;
float C = (((c9 * TF) + c8) * TF + c6) * R * R;
return A + B + C;
}
// https://en.wikipedia.org/wiki/Heat_index
// TODO add valid range for TF & R
float heatIndexC(float celcius, float humidity)
{
const float c1 = -8.78469475556;
const float c2 = 1.61139411;
const float c3 = 2.33854883889;
const float c4 = -0.14611605;
const float c5 = -0.012308094;
const float c6 = -0.0164248277778;
const float c7 = 0.002211732;
const float c8 = 0.00072546;
const float c9 = -0.000003582;
float A = (( c5 * celcius) + c2) * celcius + c1;
float B = (((c7 * celcius) + c4) * celcius + c3) * humidity;
float C = (((c9 * celcius) + c8) * celcius + c6) * humidity * humidity;
return A + B + C;
}
// https://en.wikipedia.org/wiki/Wind_chill
// US = Fahrenheit / miles
// METRIC = Celsius / meter/sec
// wind speed @ 10 meter,
// if convert is true => wind speed will be converted to 1.5 meter
// else ==> formula assumes wind speed @ 1.5 meter
// US
float WindChill_F_mph(const float fahrenheit, const float milesPerHour, const bool convert = true)
{
float windSpeed = milesPerHour;
if (convert) windSpeed = pow(milesPerHour, 0.16);
return 35.74 + 0.6125 * fahrenheit + (0.4275 * fahrenheit - 35.75) * windSpeed;
}
// METRIC
float WindChill_C_kmph(const float celcius, const float kilometerPerHour, const bool convert = true)
{
float windSpeed = kilometerPerHour;
if (convert) windSpeed = pow(kilometerPerHour, 0.16);
return 13.12 + 0.6215 * celcius + (0.3965 * celcius - 11.37) * windSpeed;
}
float WindChill_C_mps(const float celcius, const float meterPerSecond, const bool convert = true)
{
return WindChill_C_kmph(celcius, meterPerSecond * 3.6, convert);
}
// -- END OF FILE --

View File

@ -0,0 +1,89 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2021-01-01
// PURPOSE: unit tests for the temperature library
// https://github.com/RobTillaart/Temperature
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual); // a == b
// assertNotEqual(unwanted, actual); // a != b
// assertComparativeEquivalent(expected, actual); // abs(a - b) == 0 or (!(a > b) && !(a < b))
// assertComparativeNotEquivalent(unwanted, actual); // abs(a - b) > 0 or ((a > b) || (a < b))
// assertLess(upperBound, actual); // a < b
// assertMore(lowerBound, actual); // a > b
// assertLessOrEqual(upperBound, actual); // a <= b
// assertMoreOrEqual(lowerBound, actual); // a >= b
// assertTrue(actual);
// assertFalse(actual);
// assertNull(actual);
// // special cases for floats
// assertEqualFloat(expected, actual, epsilon); // fabs(a - b) <= epsilon
// assertNotEqualFloat(unwanted, actual, epsilon); // fabs(a - b) >= epsilon
// assertInfinity(actual); // isinf(a)
// assertNotInfinity(actual); // !isinf(a)
// assertNAN(arg); // isnan(a)
// assertNotNAN(arg); // !isnan(a)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "temperature.h"
unittest_setup()
{
fprintf(stderr, "TEMPERATURE_VERSION: %s\n", (char *) TEMPERATURE_VERSION);
}
unittest_teardown()
{
}
unittest(test_conversion)
{
assertEqualFloat(-40, Fahrenheit(-40), 0.001);
assertEqualFloat(-40, Celsius(-40), 0.001);
assertEqualFloat(273.15, Kelvin(0), 0.001);
}
unittest(test_dewpoint)
{
assertEqualFloat(9.27985, dewPoint(20, 50), 0.001);
assertEqualFloat(9.25489, dewPointFast(20, 50), 0.001);
assertEqualFloat(21.2829, humidex(20, 10), 0.001);
}
unittest(test_heatIndex)
{
assertEqualFloat(206.46, heatIndex(20, 50), 0.001);
assertEqualFloat(77.3509, heatIndex(68, 50), 0.001);
assertEqualFloat(25.1949, heatIndexC(20, 50), 0.001);
}
unittest(test_windChill)
{
assertEqualFloat(107.108, WindChill_F_mph (100, 10, true), 0.001);
assertEqualFloat(40.8862, WindChill_C_kmph(37, 10, true), 0.001);
assertEqualFloat(41.9713, WindChill_C_mps (37, 10, true), 0.001);
assertEqualFloat(166.99, WindChill_F_mph (100, 10, false), 0.001);
assertEqualFloat(69.1205, WindChill_C_kmph(37, 10, false), 0.001);
assertEqualFloat(154.934, WindChill_C_mps (37, 10, false), 0.001);
}
unittest_main()
// --------