0.1.5 MultiMap

This commit is contained in:
rob tillaart 2021-12-22 12:10:05 +01:00
parent 0e5434fb5f
commit af5b9e99b1
14 changed files with 109 additions and 52 deletions

View File

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

View File

@ -4,10 +4,14 @@ name: Arduino CI
on: [push, pull_request]
jobs:
arduino_ci:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: Arduino-CI/action@master
# Arduino-CI/action@v0.1.1
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2011-2021 Rob Tillaart
Copyright (c) 2011-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

View File

@ -2,7 +2,7 @@
//
// FILE: MultiMap.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.4
// VERSION: 0.1.5
// DATE: 2011-01-26
// PURPOSE: Arduino library for fast non-linear mapping or interpolation of values
// URL: https://github.com/RobTillaart/MultiMap
@ -10,37 +10,39 @@
//
// HISTORY:
// 0.0.1 2011-01-26 initial version (see forum)
// .....
// ..... eons passed ...
// 0.1.0 2015-03-29
// 0.1.1 2020-04-09
// 0.1.2 2020-06-19 fix library.json
// 0.1.3 2021-01-02 add arduino-CI
// 0.1.4 2021-05-27 fix arduino-lint
// 0.1.3 2021-01-02 add Arduino-CI
// 0.1.4 2021-05-27 fix Arduino-lint
// 0.1.5 2021-12-22 update library.json, readme, license, minor edits
#define MULTIMAP_LIB_VERSION (F("0.1.4"))
#define MULTIMAP_LIB_VERSION (F("0.1.5"))
#include "Arduino.h"
// note: the in array should have increasing values
template<typename T>
T multiMap(T val, T* _in, T* _out, uint8_t size)
T multiMap(T value, T* _in, T* _out, uint8_t size)
{
// take care the value is within range
// val = constrain(val, _in[0], _in[size-1]);
if (val <= _in[0]) return _out[0];
if (val >= _in[size-1]) return _out[size-1];
// value = constrain(value, _in[0], _in[size-1]);
if (value <= _in[0]) return _out[0];
if (value >= _in[size-1]) return _out[size-1];
// search right interval
uint8_t pos = 1; // _in[0] allready tested
while(val > _in[pos]) pos++;
uint8_t pos = 1; // _in[0] already tested
while(value > _in[pos]) pos++;
// this will handle all exact "points" in the _in array
if (val == _in[pos]) return _out[pos];
if (value == _in[pos]) return _out[pos];
// interpolate in the right segment for the rest
return (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
return (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}
@ -50,24 +52,24 @@ T multiMap(T val, T* _in, T* _out, uint8_t size)
// note: the in array should have increasing values
template<typename T>
T multiMap(T val, T* _in, T* _out, uint8_t size)
T multiMap(T value, T* _in, T* _out, uint8_t size)
{
static T lastvalue = -1;
static T cache = -1;
if (val == lastvalue)
if (value == lastvalue)
{
return cache;
}
lastvalue = val;
lastvalue = value;
// take care the value is within range
// val = constrain(val, _in[0], _in[size-1]);
if (val <= _in[0])
// value = constrain(value, _in[0], _in[size-1]);
if (value <= _in[0])
{
cache = _out[0];
}
else if (val >= _in[size-1])
else if (value >= _in[size-1])
{
cache = _out[size-1];
}
@ -75,17 +77,17 @@ T multiMap(T val, T* _in, T* _out, uint8_t size)
{
// search right interval; index 0 _in[0] already tested
uint8_t pos = 1;
while(val > _in[pos]) pos++;
while(value > _in[pos]) pos++;
// this will handle all exact "points" in the _in array
if (val == _in[pos])
if (value == _in[pos])
{
cache = _out[pos];
}
else
{
// interpolate in the right segment for the rest
cache = (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}
}
return cache;
@ -94,3 +96,4 @@ T multiMap(T val, T* _in, T* _out, uint8_t size)
// -- END OF FILE --

View File

@ -1,8 +1,11 @@
[![Arduino CI](https://github.com/RobTillaart/MultiMap/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/MultiMap/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/MultiMap/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/MultiMap/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/MultiMap/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MultiMap/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/MultiMap.svg?maxAge=3600)](https://github.com/RobTillaart/MultiMap/releases)
# MultiMap
Arduino library for fast non-linear mapping or interpolation of values
@ -12,7 +15,8 @@ Arduino library for fast non-linear mapping or interpolation of values
In Arduino applications often the value of a sensor is mapped upon a more
usable value. E.g. the value of analogRead() is mapped onto 0 .. 5.0 Volt.
This is done by the map function which does a linear interpolation. This means
This is done by the map function which does a linear interpolation.
This means in code:
```cpp
output = C1 + input * C2
@ -25,14 +29,15 @@ two variables runtime from two given mappings.
output = map(input, I1, I2, O1, O2):
```
In many cases when there is no linear mapping possible, as the 'points' are not on a single line.
One needs non-linear math to calculate the output, **Multimap()** just does that.
In many cases when there is no linear mapping possible, as the 'points' are not on a single straight line.
One needs non-linear math to calculate the output, **Multimap()** just simulates that.
**out = Multimap(value, input, output, size)** needs two equal sized arrays of reference 'points', **input\[\]** and **output\[\]**, it looks up the
**out = Multimap(value, input, output, size)** needs two equal sized arrays of reference 'points',
**input\[\]** and **output\[\]**, it looks up the
input value in the input\[\] array and if needed it linear interpolates between two
points of the output\[\] array.
- The **input\[\]** array must have increasing values,
- The **input\[\]** array must have increasing values,
there is no such restriction for the **output\[\]** array.
- **Multimap()** automatically constrains the output to the first and last value in the **output\[\]** array.
@ -44,6 +49,15 @@ See examples
Please note the fail example as this shows that in the intern math overflow can happen.
## TODO
## Future
- Investigate class implementation for performance / footprint
- flag if input value was "IN_MIN" < input < "IN_MAX",
now it is constrained without user being informed.
- extend unit tests
**wont**
- should the lookup tables be merged into one array of pairs?
- you cannot reuse e.g. the input array then. (memory footprint)
Investigate class implementation for performance.

View File

@ -1,11 +1,11 @@
//
// FILE: multimap_NTC.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo
// DATE: 2020-04-09
// (c) : MIT
//
// example uses multiMap to calculate the temperature from an 10K NTC.
#include "MultiMap.h"
@ -22,11 +22,13 @@ volatile float x, y, z;
float in[] = {
0, 1, 3, 8, 13, 20, 25, 32, 50, 60, 72, 85, 100, 145, 200, 250, 300, 400, 500, 600, 650, 700, 753, 800, 830, 870, 900, 936, 964, 985, 1000, 1017, 1023
};
float out[] = {
-273.15, -71.65, -60.69, -49.81, -43.97, -38.50, -35.54, -32.16, -25.72, -22.95, -20.08, -17.37, -14.62, -7.90, -1.43, 3.57,
8.08, 16.34, 24.30, 32.64, 37.17, 42.13, 48.05, 54.19, 58.75, 66.03, 72.87, 83.85, 96.51, 111.46, 129.49, 182.82, 301.82
};
int sz = 33;
@ -87,3 +89,4 @@ float val(int sensorValueA1)
// -- END OF FILE --

View File

@ -1,16 +1,15 @@
//
// FILE: multimap_NTC_int_FAIL.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo of faulty optimizing
// DATE: 2020-04-09
// (c) : MIT
//
//
// NOTE:
// use integers instead of floats to minimize RAM. uses ~320 bytes PROGMEM ~120 bytes RAM less on UNO than float version
//
// this example is added to show how to reduce memory but also how it can FAIL due to math overflow
// this example is added to show how to reduce memory but also how it can FAIL due to math overflow
// E.g. see around 196-200; 340-400
// to prevent this one must have more values which increases the memory usage again.
//
@ -27,6 +26,7 @@ volatile float x, y, z;
int in[] = {
0, 1, 3, 8, 13, 20, 25, 32, 50, 60, 72, 85, 100, 145, 200, 250, 300, 400, 500, 600, 650, 700, 753, 800, 830, 870, 900, 936, 964, 985, 1000, 1017, 1023
};
int out[] = {
-27315, -7165, -6069, -4981, -4397, -3850, -3554, -3216, -2572, -2295, -2008, -1737, -1462, -790, -143, 357, 808, 1634, 2430, 3264,
3717, 4213, 4805, 5419, 5875, 6603, 7287, 8385, 9651, 11146, 12949, 18282, 30182
@ -91,3 +91,4 @@ float val(int sensorValueA1)
// -- END OF FILE --

View File

@ -1,10 +1,10 @@
//
// FILE: multimap_distance.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo
// DATE: 2020-04-09
//
// example simulates the lookup graph of a distance sensor
#include "MultiMap.h"
@ -48,3 +48,4 @@ float sharp2cm(int val)
// -- END OF FILE --

View File

@ -1,11 +1,12 @@
//
// FILE: multimap_functions.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo (use serial plotter)...
// DATE: 2020-04-09
// (c) : MIT
//
// example show use of multiMap to approximate some well known functions.
#include "MultiMap.h"
@ -53,7 +54,7 @@ void test_normal_distribution()
void test_sinus()
{
// one sinus wave, amplitudo 1023
// one sinus wave, amplitude 1023
long sinus[] = {0, 316, 601, 827, 972, 1023, 972, 827, 601, 316, 0, -316, -601, -827, -972, -1023, -972, -827, -601, -316, 0 }; //21
long in[21];
for (int i = 0; i < 21; i++) in[i] = round(i * 1000.0 / 20);
@ -136,3 +137,4 @@ void test_sawtooth()
// -- END OF FILE --

View File

@ -1,11 +1,11 @@
//
// FILE: multimap_timing.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo
// DATE: 2020-04-09
// (c) : MIT
//
// example measures the performance of multiMap <int> vs <float>
#include "MultiMap.h"
@ -30,6 +30,7 @@ void setup()
start = micros();
float x = multiMap<int>(12, in, out, 3);
stop = micros();
Serial.print("time <int>: \t");
Serial.println(stop - start);
Serial.println(x, 4);
delay(10); // make sure print has ended
@ -37,8 +38,12 @@ void setup()
start = micros();
float y = multiMap<float>(12, fin, fout, 3);
stop = micros();
Serial.print("time <float>: \t");
Serial.println(stop - start);
Serial.println(y, 4);
delay(10); // make sure print has ended
Serial.println("\ndone...");
}
@ -48,3 +53,4 @@ void loop()
// -- END OF FILE --

View File

@ -1,6 +1,6 @@
# Syntax Coloring Map For multiMap
# Syntax Colouring Map For multiMap
# Datatypes (KEYWORD1)
# Data types (KEYWORD1)
# Methods and Functions (KEYWORD2)

View File

@ -15,8 +15,9 @@
"type": "git",
"url": "https://github.com/RobTillaart/MultiMap.git"
},
"version": "0.1.4",
"version": "0.1.5",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
"platforms": "*",
"headers": "MultiMap.h"
}

View File

@ -1,5 +1,5 @@
name=MultiMap
version=0.1.4
version=0.1.5
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for fast non-linear interpolation by means of two arrays.

View File

@ -37,6 +37,7 @@
unittest_setup()
{
fprintf(stderr, "MULTIMAP_LIB_VERSION: %s\n", (char *) MULTIMAP_LIB_VERSION);
}
@ -58,10 +59,8 @@ unittest(test_new_operator)
*/
unittest(test_all)
unittest(test_float)
{
fprintf(stderr, "VERSION: %s\n", MULTIMAP_LIB_VERSION);
// based on the distance example
// out[] holds the distances in cm
float out[] = {150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20};
@ -78,6 +77,25 @@ unittest(test_all)
}
/* todo
unittest(test_uint32_t)
{
// based on the distance example
// out[] holds the distances in cm
uint32_t out[] = {150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20};
// in[] holds the measured analogRead() values for that distance
uint32_t in[] = { 90, 97, 105, 113, 124, 134, 147, 164, 185, 218, 255, 317, 408, 506};
assertEqual(150, multiMap<uint32_t>(80, in, out, 14) );
assertEqual(136, multiMap<uint32_t>(100, in, out, 14) );
assertEqual( 65, multiMap<uint32_t>(200, in, out, 14) );
assertEqual( 42, multiMap<uint32_t>(300, in, out, 14) );
assertEqual( 30, multiMap<uint32_t>(400, in, out, 14) );
assertEqual( 20, multiMap<uint32_t>(500, in, out, 14) );
assertEqual( 20, multiMap<uint32_t>(600, in, out, 14) );
}
*/
unittest_main()