0.1.2 WaterMix

This commit is contained in:
Rob Tillaart 2023-09-10 16:48:02 +02:00
parent 4b4a52c7f3
commit 2038ff53d5
6 changed files with 172 additions and 119 deletions

View File

@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.2] - 2023-09-08
- add base class **LiquidMix** (moved functions up)
- made **WaterMix::density()** public
- update readme.md
- fix keywords.txt
## [0.1.1] - 2023-08-30
- add **void addExact(float volume, float temperature)** (works only for water).
- add **float mass()** (works only for water).
@ -15,7 +22,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- fix keywords.txt
- minor edits
## [0.1.0] - 2023-08-29
- initial version

View File

@ -18,48 +18,72 @@ Arduino library for mixing water with different temperatures.
**Warning: Experimental**
Experimental library for elementary math of mixing water with different temperatures.
Experimental library for elementary math of mixing certain amounts of water or other
(same) liquids with different temperatures.
The library provides math for mixing a volume of water with temperature T1
with a another volume with temperature temperature T2.
In fact the library will work for any single liquid (TODO: liquidMix class),
although some functions are **water specific**.
The library provides math **add()** for mixing a volume of a liquid with temperature T1
with another volume of the same liquid with temperature T2.
The **WaterMix** class of the library has **water specific** functions.
The library does not support mixing different liquids as that would need the density
function for every liquid involved. Furthermore not all liquids mix well with each other.
This library is useful e.g. by doing "water math" for aquaria or cooking.
The **add()** function can be called multiple times, e.g. to mix more than two amounts
of liquids. One can also mix an other LiquidMix object (same liquids).
Besides the **add()** the library supports:
- **div()** to "split the liquid in equal amounts" and a
- **mul()** to multiply it (magically) and
- **sub()** to remove part of the liquid.
This library is meant to be useful e.g. by doing "water math" for aquaria or cooking.
Also the library is well suited for basic educational purposes.
Since version 0.1.2, the library has a base class, named **LiquidMix** which can do
the basic math. The extended math like in **WaterMix** needs a **density()** function
and cannot be done as the liquid is unknown.
For now the library is experimental and refactoring is expected.
If you have requests, questions or ideas, let me know by opening an issue.
By adding the LiquidMix base class the library allows easy derived classes
like the WaterMix.
#### Limitations
The library uses a generic volume parameter instead of gallons or liters as
The **LiquidMix** uses a generic volume parameter instead of gallons or liters as
this way any user selected unit can be used.
However you must use the chosen units consistently as the library cannot handle
different units simultaneously.
different units simultaneously.
To use different units for volume you can convert them with the library named
**VolumeConverter**.
The temperature unit can also be chosen by the user and can be Kelvin, Celsius,
Fahrenheit or other.
For the **LiquidMix** the temperature unit can also be chosen by the user and
can be Kelvin, Celsius, Fahrenheit or other.
However you must use the chosen units consistently as the library cannot handle
different units simultaneously. Check **Temperature** library below for conversion.
The **WaterMix** class must use the **Celsius** scale as the **density()** function
used is defined in degrees Celsius.
#### Accuracy
The working range for temperature is not tested with real water.
The working range for temperature is not tested e.g. with real water.
It is expected to work quite well for water with a range from 5°C to 80°C.
In the basic math the **add()** function assumes there is no expansion so
the density is identical for "both volumes of waters".
the density is identical for both volumes of waters.
Of course this is incorrect, therefore it is expected to have a difference
Of course this assumption is incorrect, therefore there will be a difference
between the theoretical values and doing the mixing in practice.
However the delta's are expected to be small, less than 1% in many cases.
Given the accuracy of volume measurement and temperature measurement,
this delta is often acceptable.
However these delta's are expected to be small, less than 1% in many cases.
Given the accuracy of volume measurement and temperature measurement, this
delta of 1% will often be acceptable.
If one wants a more exact answer, one should use the **addExact()** function
as this compensates for the density of the water at a given temperature.
If one wants a more exact answer, one could use **WaterMix** class.
This class supports the **addExact()** function which compensates for
the density of the water at a given temperature.
This function is much slower but will provide a more exact answer.
#### Related
@ -75,68 +99,77 @@ as this compensates for the density of the water at a given temperature.
#include "WaterMix.h"
```
#### Constructor
#### LiquidMix (base class)
- **WaterMix()** constructor, starts with no water of 0°
To be used with any liquid.
- **LiquidMix()** constructor, starts with no liquid of 0°
- **void begin(float volume = 0, float temperature = 0)**
sets initial values, default no water of 0°.
#### Math
- **void add(float volume, float temperature)** add an amount of water
with temperature to the "WaterMix".
- **void addExact(float volume, float temperature)** Water only!
add an amount of water with temperature to the "WaterMix".
The math is calculated including using the density of the water.
This is slower as **add()** but more exact.
Note the temperature must be in °C.
- **void sub(float volume)** subtract a volume from the "WaterMix".
sets initial values, default no liquid of 0°.
- **void add(float volume, float temperature)** add an amount of liquid
with temperature to the "LiquidMix".
- **void sub(float volume)** subtract a volume from the "LiquidMix".
Temperature won't change.
- **void div(float nr)** divide the amount of liquid, same temperature.
- **void mul(float nr)** multiply the amount of liquid, same temperature.
#### Getters
- **float volume()** get the current volume.
- **float temperature()** get the current temperature.
#### WaterMix
WaterMix is specific for water and has the following additional functions:
- **WaterMix()** constructor, starts with no water of 0°
- **void addExact(float volume, float temperature)**
add an amount of water with temperature to the "WaterMix".
The math uses the **density** of the water at the given temperature.
This is slower as **add()** but more exact.
Note the temperature must be in °C.
- **float mass()** get the mass of the current volume. Water only!
#### Converters
- **float volume2mass(float volume, float temperature)** idem, Water only!
Use volume == 1 to get the density at a certain temperature.
Use volume == 1 to get the density of water at the given temperature.
Assumption is no pressure.
- **float mass2volume(float mass, float temperature)** idem, Water only!
## Performance
Most functions are just fast, the only that do the core math are add()
and addExact().
The WaterMix_exact.ino sketch provides some performance figures shown
here.
Most functions are minimal and fast, the ones that do the core math
are **add()** and **addExact()**.
The WaterMix_exact.ino sketch provides performance figures shown here.
Note that the **addExact()** differs in runtime as it uses a linear lookup
for the density so the numbers below are indicative.
| Function | time (us) | Notes |
|:------------:|:-----------:|:--------|
| add() | 72 |
| addExact() | 576 | most accurate |
Tested on UNO, 16 MHz.
Note it is possible to tune the linear lookup of the density by reducing
the amount of interpolation points in the tables (at your own risk).
This will reduce the accuracy however still be better than the fast **add()**.
| Version | Function | time (us) | Notes |
|:-----------:|:------------:|:-----------:|:--------|
| 0.1.1 | add() | 72 |
| 0.1.1 | addExact() | 576 | most accurate |
Note it is possible to improve the performance of the lookup of the density
by reducing the amount of interpolation points in the tables (at your own risk).
This will reduce the accuracy however still be better than the faster **add()**.
Performance of **addExact()** can be improved by caching the mass of the water.
As this is needed for every next **addExact()**. As the volume can be manipulated
by **div()** et al, there must be additional code and/or a "dirty" flag.
To be investigated.
Finally the lookup can be improved by a binary search, however previous experience
indicate that this only improves above a certain number of elements (~20).
## Volumetric Coefficient of Expansion
The VCE is not supported in the library.
The VCE is related to density and not supported in the library.
Math needs to be understood / investigated.
(0.1.1 supports an **addExact()** for water only, temperature in °C)
The VCE is useful as background information as the theoretical volumes calculated
in this library will differ from reality due to the VCE effect.
The VCE is useful as background information as the theoretical volumes
calculated in this library will differ from reality due to the VCE effect.
This difference depends on the liquid used and the delta temperature.
@ -204,37 +237,26 @@ Source: - https://www.engineeringtoolbox.com/cubical-expansion-coefficients-d_12
- update documentation
- library can be used for water and salinity and other linear related things.
- investigate linear expansion
- VCE as parameter.
#### Should
- create base class **LiquidMix** and derive a specific **WaterMix** from it.
- code is quite identical, easy to split/strip water specific functions
- **WaterMix** can include specific heat, density, VCE etc.
- 0.2.0
- **WaterMixF()** Fahrenheit, as derived class too.
- **WaterMixK()** Kelvin?
- investigate linear expansion
- VCE as parameter.
- do not make the library too complex (see could below).
- extend unit tests
- investigate the caching of the mass of the water.
- add Exact only, 4 bytes..
#### Could
- cool(time) == depends on many factors
- add **void cool(time)** == depends on many factors
- need to configure curve constant (only option).
- must use defined liquid and temp scale.
- catch temperature below zero?
- must use defined liquid and temp scale.
- user responsibility for now.
- **void AddEnergy(float joule)** to raise temperature (joule)
- must use defined liquid and temp scale.
- specific heat needed. (Water only?)
- specific heat needed. (WaterMix only?)
- replace div and mul with operators \* and \/
- use double iso float?
- investigate injection of density function to make LiquidMix generic?
#### Wont (or on special request)
@ -244,6 +266,16 @@ Source: - https://www.engineeringtoolbox.com/cubical-expansion-coefficients-d_12
- energy functions to calculate how hot an amount of water
should be to reach a certain temperature.
- Think Aquaria or cooking.
- investigate how to mix different liquids?
- gives too much params
- use double instead of float?
- weight and temperature are not that accurate (assumption)
- investigate the caching of the mass of the water.
- **addExact()** only, 4 bytes only for WaterMix class
- it is so far no performance issue.
- catch temperature below zero?
- must use defined liquid and temp scale.
- user responsibility for now.
## Support

View File

@ -3,33 +3,35 @@
// FILE: WaterMix.h
// AUTHOR: Rob Tillaart
// PURPOSE: Arduino library for mixing water with different temperatures.
// VERSION: 0.1.1
// VERSION: 0.1.2
// URL: https://github.com/RobTillaart/WaterMix
#include "Arduino.h"
#define WATERMIX_LIB_VERSION (F("0.1.1"))
#define WATERMIX_LIB_VERSION (F("0.1.2"))
class WaterMix
////////////////////////////////////////////
//
// LIQUIDMIX
//
class LiquidMix
{
public:
WaterMix()
LiquidMix()
{
_volume = 0;
_temperature = 0;
}
void begin(float volume = 0, float temperature = 0)
{
_volume = volume;
_temperature = temperature;
}
void add(float volume, float temperature)
{
if (volume <= 0) return; // false ?
@ -38,31 +40,11 @@ public:
_volume = vol;
}
void addExact(float volume, float temperature)
void add(LiquidMix &lm)
{
if (volume <= 0) return; // false
float mass0 = _volume * _density(_temperature);
float mass1 = volume * _density(temperature);
float totalMass = mass0 + mass1;
_temperature = (mass0 * _temperature + mass1 * temperature) / totalMass;
_volume = totalMass / _density(_temperature);
add(lm.volume(), lm.temperature());
}
void add(WaterMix &wm)
{
add(wm.volume(), wm.temperature());
}
void addExact(WaterMix &wm)
{
addExact(wm.volume(), wm.temperature());
}
void sub(float volume)
{
_volume -= volume;
@ -70,58 +52,90 @@ public:
// temperature does not change.
}
void div(float nr)
{
_volume /= nr;
// temperature does not change.
}
void mul(float nr)
{
_volume *= nr;
// temperature does not change.
}
float volume()
{
return _volume;
}
float temperature()
{
return _temperature;
}
float mass()
protected:
float _volume;
float _temperature;
};
////////////////////////////////////////////
//
// WATERMIX
//
class WaterMix : public LiquidMix
{
public:
WaterMix() : LiquidMix()
{
return _volume * _density(_temperature);
}
void add(float volume, float temperature)
{
LiquidMix::add(volume, temperature);
}
void addExact(float volume, float temperature)
{
if (volume <= 0) return; // false
float mass0 = _volume * density(_temperature);
float mass1 = volume * density(temperature);
float totalMass = mass0 + mass1;
_temperature = (mass0 * _temperature + mass1 * temperature) / totalMass;
_volume = totalMass / density(_temperature);
}
void add(WaterMix &wm)
{
LiquidMix::add(wm.volume(), wm.temperature());
}
void addExact(WaterMix &wm)
{
addExact(wm.volume(), wm.temperature());
}
float mass()
{
return _volume * density(_temperature);
}
float volume2mass(float volume, float temperature)
{
return volume * _density(temperature);
return volume * density(temperature);
}
float mass2volume(float mass, float temperature)
{
return mass / _density(temperature);
return mass / density(temperature);
}
private:
float _volume;
float _temperature;
// _density is in fact multiMap code
float _density(float temperature)
// density is in fact multiMap code
float density(float temperature)
{
// strip table size?
uint8_t size = 22;
@ -134,7 +148,6 @@ private:
0.9618900, 0.9583500
};
// take care the temperature is within range
// temperature = constrain(temperature, _in[0], _in[size-1]);
if (temperature <= _in[0]) return _out[0];

View File

@ -1,6 +1,7 @@
# Syntax Colouring Map For WaterMix
# Data types (KEYWORD1)
LiquidMix KEYWORD1
WaterMix KEYWORD1
@ -19,6 +20,7 @@ mass KEYWORD2
volume2mass KEYWORD2
mass2volume KEYWORD2
density KEYWORD2
# Constants (LITERAL1)

View File

@ -1,6 +1,6 @@
{
"name": "WaterMix",
"keywords": "water, mix, liters, temperature",
"keywords": "water, mix, liters, temperature, LiquidMix, density",
"description": "Arduino library for mixing water with different temperatures.",
"authors":
[
@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/WaterMix.git"
},
"version": "0.1.1",
"version": "0.1.2",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=WaterMix
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for mixing water with different temperatures.