88
99# MultiMap
1010
11- Arduino library for fast non-linear mapping or interpolation of values
11+ Arduino library for fast non-linear mapping or interpolation of values.
1212
1313
1414## Description
1515
16- In Arduino applications often the value of a sensor is mapped upon a more
17- usable value. E.g. the value of analogRead() is mapped onto 0 .. 5.0 Volt.
18- This is done by the map function which does a linear interpolation.
16+ In Arduino applications often the 'raw' value of a sensor is mapped upon a more
17+ usable value. E.g. the value of analogRead() 0 .. 1023 is mapped onto 0 .. 5.0 Volt.
18+ This is often done by the map function which does a linear interpolation.
19+
1920This means in code:
2021
2122``` cpp
2223 output = C1 + input * C2
2324```
2425
25- As C1 and C2 are to be calculated Arduino has the ** map()** that calculates the
26- two variables runtime from two given mappings .
26+ As C1 and C2 are to be determined, Arduino has the ** map()** function that calculates the
27+ two variables runtime from two given mapping points (I1, O1) and (I2, O2) .
2728
2829``` cpp
2930 output = map(input, I1, I2, O1, O2):
3031```
3132
32- In many cases when there is no linear mapping possible, as the 'points' are not on a single straight line.
33- One needs non-linear math to calculate the output, ** Multimap()** just simulates that.
33+ In many cases when there is no linear mapping possible as the 'points' are not on a single straight line.
34+ To solve this one needs non-linear math to calculate the output.
35+
36+ The ** multiMap()** function simulates this math by approximating the non-linear function with multiple
37+ linear line segments.
38+ Of course this approximation introduces an error.
39+ By increasing the number of points and choose their position strategically the average error will be reduced.
40+
41+ Note: some functions are hard to approximate with multiMap as they go to infinity or have a singularity.
42+ Think of ** tan(x)** around x = PI/2 (90°) or ** sin(1/x)** around zero.
43+
44+
45+ #### Usage
46+
47+ The basic call for ** multiMap()** is:
48+
49+ ``` cpp
50+ output = Multimap<datatype>(input, inputArray, outputArray, size);
51+ ```
52+
53+ ** multiMap()** needs two equally sized arrays representing the reference 'points' named
54+ ** inputArray\[\] ** and ** outputArray\[\] ** both of the ** datatype** .
3455
35- ** out = Multimap(value, input, output, size)** needs two equal sized arrays of reference 'points',
36- ** input\[\] ** and ** output\[\] ** , it looks up the
37- input value in the input\[\] array and if needed it linear interpolates between two
38- points of the output\[\] array.
56+ ** multiMap()** will do a lookup of the input value in the inputArray\[\] .
57+ If it cannot find the index of an exact point it will determine a weighted position between two points.
58+ This optional weighted point is used to interpolate a value from data in the output\[\] array.
3959
40- - The ** input \[\] ** array must have increasing values,
60+ - The ** inputArray \[\] ** must have increasing values,
4161there is no such restriction for the ** output\[\] ** array.
42- - ** Multimap()** automatically constrains the output to the first and last value in the ** output\[\] ** array.
62+ - The values of the ** inputArray\[\] ** do not need to have the same distance (non-equidistant).
63+ E.g an array like { 1, 10, 100, 1000 } is valid.
64+ - ** multiMap()** automatically constrains the output to the first and last value in the ** output\[\] ** array.
65+ This is a explicit difference with the ** map()** function.
66+ Therefore it is important to extend the range of the arrays to cover all possible values.
67+
68+
69+ #### Performance
70+
71+ ** multiMap()** does a linear search for the inputValue in the inputArray.
72+ This implies that usage of larger and more precise arrays will take more time.
73+ Furthermore "low" input values will be found faster than "high" values.
74+
75+ As every usage of multiMap() is unique one should always do a performance check to see
76+ if there is a substantial gain in the case at hand. In my experience there often is.
77+
78+
79+ #### MultiMapBS
80+
81+ Experimental 0.1.7 => use with care.
82+
83+ ** multiMapBS()** MMBS for short, is a very similar function as ** multiMap()** .
84+ The main difference is that MMBS uses binary search instead of linear search.
85+
86+ First performance tests indicate that for array sizes about 10 MMBS is on par
87+ with ** multiMap()** . This is expected as both need on average about 5 steps
88+ to find the right interval.
89+
90+ Be sure to do your own tests to see if MMBS improves your performance.
91+
92+
93+ #### MultiMapCache
94+
95+ Experimental 0.1.7 => use with care.
96+
97+ ** multiMapCache()** MMC for short, is a very similar function as ** multiMap()** .
98+ The main difference is that MMC caches the last input and output value.
99+ The goal is to improve the performance by preventing
100+
101+ If the input sequence has a lot of repeating values e.g. 2 2 2 2 2 2 5 5 5 5 5 4 4 4 4 2 2 2 2 2 2
102+ MMC will be able to return the value from cache often.
103+ Otherwise keeping cache is overhead.
104+
105+ Be sure to do your own tests to see if MMC improves your performance.
106+
107+
108+ #### Related
109+
110+ Other mapping libraries
111+
112+ - https://github.com/RobTillaart/FastMap
113+ - https://github.com/RobTillaart/Gamma
114+ - https://github.com/RobTillaart/map2colour
115+ - https://github.com/RobTillaart/moduloMap
116+ - https://github.com/RobTillaart/MultiMap
43117
44118
45119## Operation
@@ -51,20 +125,43 @@ Please note the fail example as this shows that in the intern math overflow can
51125
52126## Future
53127
54- #### must
128+ #### Must
129+
55130- improve documentation
56131
57- #### should
58- - Investigate class implementation
132+
133+ #### Should
134+
135+ - investigate multiMapCache behaviour
136+ - determine overhead.
137+ - investigate binary search multiMapBS behaviour
138+ - expect a constant time
139+ - where is the tipping point between linear and binary search.
140+ (expect around size = 8)
141+ - extend unit tests
142+
143+
144+ #### Could
145+
146+ - Investigate class implementation
147+ - basic call out = mm.map(value);
148+ - runtime adjusting input and output array ** begin(in[ ] , out[ ] )**
59149 - performance / footprint
60150 - less parameter passing
61-
62- #### could
63- - flag if input value was "IN_MIN" < input < "IN_MAX",
64- now it is constrained without user being informed.
65- - extend unit tests
151+ - ** isInRange(value)** ?
152+ - caching last value / position / index (does that help?)
153+ - flag if input value was "IN_MIN" < input < "IN_MAX",
154+ now it is constrained without user being informed.
155+ - Investigate a 2D multiMap e.g. for complex numbers?
156+ - is it possible / feasible?
157+ - data type input array does not need to be equal to the output array.
158+ - template<typename T1, typename T2>
159+ ``` T2 multiMapBS(T1 value, T1* _in, T2* _out, uint16_t size) ```
160+
161+
162+ #### Wont
66163
67- #### wont
68164- should the lookup tables be merged into one array of pairs?
69- - you cannot reuse e.g. the input array then. (memory footprint)
165+ - you cannot reuse e.g. the input array or the output array then.
166+ this would not improve the memory footprint.
70167
0 commit comments