0.4.0 FastMap

This commit is contained in:
rob tillaart 2022-11-05 10:57:25 +01:00
parent 5e0c1b5641
commit 6c196e7c48
8 changed files with 234 additions and 84 deletions

View File

@ -1,3 +1,18 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
@ -9,6 +24,7 @@ compile:
- esp32
# - esp8266
# - mega2560
- rpipico
# Declaring Dependent Arduino Libraries (to be installed via the Arduino Library Manager)
libraries:

View File

@ -0,0 +1,72 @@
# Change Log FastMap
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.4.0] - 2022-11-02
- add changelog.md
- add rp2040 to build-CI
- update readme.md
- init() returns bool to indicate valid (non-zero) ranges.
- add range check in init()
----
## [0.3.3] - 2021-12-17
- update library.json
- update license
- minor edits
## [0.3.2] - 2020-12-21
- add Arduino-CI + unit test
## [0.3.1] - 2020-08-31
- update documentation
## [0.3.0] - 2020-07-04
- added fastMapDouble + test sketch.
----
## [0.2.1] - 2020-06-10
- fix library.json
- rename license
## [0.2.0] - 2020-03-21
- #pragma once
- readme.md
- license.md
----
## [0.1.8] - 2017-07-27
- revert double to float (issue 33)
## [0.1.7] - 2017-04-28
- clean up code
- get examples working again
## [0.1.06] - 2015-03-08
- replaced float by double (support ARM)
## [0.1.05] - 2014-11-02
- stripped of bit mask experimental code
## [0.1.04]
- add back() - the inverse map
- tested with bit mask for constrain code (Performance was killed)
## [0.1.03]
- proper name
## [0.1.02]
- squeezed the code (first public version)
## [0.1.01]
- refactor
## [0.1.00]
- initial version

View File

@ -1,51 +1,43 @@
//
// FILE: FastMap.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.3.3
// VERSION: 0.4.0
// PURPOSE: class with fast map function - library for Arduino
// URL: https://github.com/RobTillaart/FastMap
//
// HISTORY:
// 0.3.3 2021-12-17 update library.json, license, minor edits
// 0.3.2 2020-12-21 add Arduino-CI + unit test
// 0.3.1 2020-08-31 updated documentation
// 0.3.0 2020-07-04 added fastMapDouble + test sketch.
// 0.2.1 2020-06-10 fix library.json; rename license
// 0.2.0 2020-03-21 #pragma once; readme.md; license.md
//
// 0.1.8 2017-07-27 revert double to float (issue 33)
// 0.1.7 2017-04-28 cleaned up, get examples working again
// 0.1.06 2015-03-08 replaced float by double (support ARM)
// 0.1.05 2014-11-02 stripped of bit mask experimental code
// 0.1.04 add back() - the inverse map
// tested with bit mask for constrain code (Performance was killed)
// 0.1.03 proper name
// 0.1.02 squeezed the code (first public version)
// 0.1.01 refactor
// 0.1.00 initial version
// HISTORY: see changelog.md
#include "FastMap.h"
///////////////////////////////////////////////////////////////
//
// FASTMAP
//
FastMap::FastMap()
{
init(0, 1, 0, 1);
}
void FastMap::init(float in_min, float in_max, float out_min, float out_max)
bool FastMap::init(float in_min, float in_max, float out_min, float out_max)
{
float _inRange = in_max - in_min;
float _outRange = out_max - out_min;
if ((_inRange == 0.0 ) || (_outRange == 0.0)) return false;
_in_min = in_min;
_in_max = in_max;
_out_min = out_min;
_out_max = out_max;
_factor = (out_max - out_min)/(in_max - in_min);
_base = out_min - in_min * _factor;
_factor = _outRange/_inRange;
_base = _out_min - _in_min * _factor;
_backfactor = 1/_factor;
_backbase = in_min - out_min * _backfactor;
_backfactor = _inRange/_outRange;
_backbase = _in_min - _out_min * _backfactor;
return true;
}
@ -71,24 +63,33 @@ float FastMap::upperConstrainedMap(float value)
}
///////////////////////////////////////////////////////////////
//
// FASTMAP_DOUBLE
//
FastMapDouble::FastMapDouble()
{
init(0, 1, 0, 1);
}
void FastMapDouble::init(double in_min, double in_max, double out_min, double out_max)
bool FastMapDouble::init(double in_min, double in_max, double out_min, double out_max)
{
double _inRange = in_max - in_min;
double _outRange = out_max - out_min;
if ((_inRange == 0.0 ) || (_outRange == 0.0)) return false;
_in_min = in_min;
_in_max = in_max;
_out_min = out_min;
_out_max = out_max;
_factor = (out_max - out_min)/(in_max - in_min);
_base = out_min - in_min * _factor;
_factor = _outRange/_inRange;
_base = _out_min - _in_min * _factor;
_backfactor = 1/_factor;
_backbase = in_min - out_min * _backfactor;
_backfactor = _inRange/_outRange;
_backbase = _in_min - _out_min * _backfactor;
return true;
}

View File

@ -2,15 +2,14 @@
//
// FILE: FastMap.h
// AUTHOR: Rob Tillaart
// VERSION: 0.3.3
// VERSION: 0.4.0
// PURPOSE: class with fast map function - library for Arduino
// URL: https://github.com/RobTillaart/FastMap
#include "Arduino.h"
#define FASTMAP_LIB_VERSION (F("0.3.3"))
#define FASTMAP_LIB_VERSION (F("0.4.0"))
class FastMap
@ -18,7 +17,7 @@ class FastMap
public:
FastMap();
void init(const float in_min, const float in_max, const float out_min, const float out_max);
bool init(float in_min, float in_max, float out_min, float out_max);
float inline map (const float value) { return _base + value * _factor; }
float inline back (const float value) { return _backbase + value * _backfactor; }
@ -38,7 +37,7 @@ class FastMapDouble
{
public:
FastMapDouble();
void init(const double in_min, const double in_max, const double out_min, const double out_max);
bool init(double in_min, double in_max, double out_min, double out_max);
double inline map (const double value) { return _base + value * _factor; }
double inline back (const double value) { return _backbase + value * _backfactor; }

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/FastMap"
},
"version": "0.3.3",
"version": "0.4.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=FastMap
version=0.3.3
version=0.4.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with fast map function for Arduino.

View File

@ -14,53 +14,64 @@ Fast mapping and constraining.
## Description
FastMap is an object that pre-calculates (internal) floats to make a mapping function especially for floats.
The Fastmap also provides a **back()** function to reverse the mapping.
This only works well with floats, so use with care.
The FastMap also provides a **back()** function to reverse the mapping.
This only works well with floats, and less with integers, so use with care.
An important difference with the traditional **map()** function is that both **init()** and **map()**
accepts floats as parameters, allowing mapping that would be hard to achieve with the normal **map()**
function.
accepts floats as parameters.
This allows mapping that would be hard to achieve with the normal **map()** function.
Since 0.4.0 the **init()** function will not accept zero range defining input or output parameters.
## Performance notes
(based upon tests https://github.com/RobTillaart/FastMap/issues/4 )
- On AVR (UNO and MEGA) no gain is made mapping integers with fastMap, 130% slower = substantial
- On AVR the gain for float is limited, 10% faster
- On ESP32 the gain for integers and float is both in the order of 25%
- On AVR (UNO and MEGA) no gain is made mapping integers with fastMap, 130% slower = substantial.
- On AVR the gain for float is limited, 10% faster.
- On ESP32 the gain for integers and float is both in the order of 25%.
To see the actual gain in your project on your hardware you should test and compare.
FastMap is faster when mapping floats as it uses less float operations than the standard map formula does.
The performance results from pre-calculating values in the **init()** function so actual mapping needs only
one multiply and add, where the standard **map()** function uses four adds, a multiplication and a division.
The performance results from pre-calculating values in the **init()** function.
An actual mapping therefore needs only one multiply and one add operation where the standard **map()** function
uses four adds, a multiplication and a division.
The pre-calculation in **init()** should be taken in account and if every **map()** call needs an **init()**
there will be no gain, on contrary.
## Precision notes
The implementation of **fastMap()** uses floats (typical 32 bits) which might result in more memory usage
and loss of precision for mapping of larger values, especially 32 and 64 bit integers.
This is caused by the limits of the mantissa (~23 bits) of the standard 4 byte float.
To solve this a **FastMapDouble** class is added which uses the **double** type for the platforms
that support 8 byte floats.
If your platform does not support double it will often be mapped to float, so no gain.
Furthermore using double might imply a performance penalty on some platforms.
## Interface
- **void init(float in_min, float in_max, float out_min, float out_max);** defines the linear mapping parameters.
- **bool init(float in_min, float in_max, float out_min, float out_max)** defines the linear mapping parameters.
The **init()** function calculates all needed values for the **map()**, the **back()** call and the **constrainXX()** functions.
The **init()** function can be called again with new values when needed to do other mapping,
although it will give less overhead if you create an fastMap object per conversion needed.
Note: **init()** does not check for a divide by zero (out_max == out_min) or (in_max == in_min)
Returns false if (out_max == out_min) or (in_max == in_min). (breaking change in 0.4.0).
- **float map(float value)** maps the parameter.
- **float back(float value)** does the inverse mapping
- **float back(float value)** does the inverse mapping.
### Constrains
FastMap supports three versions of constraining the map function, based upon the parameters of **init()**
- **float constrainedMap(float value);** returns a value between outMin .. outMax
- **float lowerConstrainedMap(float value);** returns a value between outMin .. inf (No upper limit)
- **float upperConstrainedMap(float value);** returns a value between -inf .. outMax
FastMap supports three versions of constraining the map function, based upon the parameters of **init()**.
To change the constrain values call **init()** with new limits, or call **constrain()**
- **float constrainedMap(float value);** returns a value between outMin .. outMax
- **float lowerConstrainedMap(float value);** returns a value between outMin .. infinity, ==> no upper limit.
- **float upperConstrainedMap(float value);** returns a value between -infinity .. outMax ==> no lower limit.
To change the constrain values call **init()** with new limits, or use the standard **constrain()**.
Note there are **NO** constrain-versions for **back(value)** function.
@ -72,6 +83,34 @@ This class is meant to support 8 bytes doubles in their native accuracy and prec
To display doubles one might need the **sci()** function of my **printHelpers** class.
https://github.com/RobTillaart/printHelpers
Note that on most embedded platforms the performance of doubles is less than floats.
#### boards supporting double
| board | float | double |
|:---------------|:-------:|:--------:|
| UNO | yes | no |
| ATMEGA | yes | no |
| MKR1000 | yes | yes |
| Zero | yes | yes |
| Teensy | yes | ? |
| ESP32 | yes | yes |
| RP2040 | yes | ? |
to elaborate table. (if someone has a good link, please let me know).
test code.
```cpp
void setup() {
Serial.begin(115200);
Serial.print("size of double:\t");
Serial.println(sizeof(double));
Serial.print("size of float: \t");
Serial.println(sizeof(float));
}
void loop() {}
```
## Usage
@ -80,9 +119,15 @@ See examples.
## Future
#### must
#### should
- update documentation
- test performance fastMapDouble on ESP32.
#### could
- investigate map function for complex numbers? / coordinates?
- can fastMap and fastMapDouble be in a class hierarchy? gain?
- Template class?
- test performance fastMapDouble on ESP32.

View File

@ -39,6 +39,23 @@ unittest_teardown()
}
unittest(test_init)
{
FastMap fm;
FastMapDouble fmd;
assertTrue(fm.init(-2, 12, 17, 42));
assertFalse(fm.init(12, 12, 17, 42));
assertFalse(fm.init(-2, 12, 17, 17));
assertFalse(fm.init(12, 12, 17, 17));
assertTrue(fmd.init(-2, 12, 17, 42));
assertFalse(fmd.init(12, 12, 17, 42));
assertFalse(fmd.init(-2, 12, 17, 17));
assertFalse(fmd.init(12, 12, 17, 17));
}
unittest(test_map)
{
FastMap fm;