Giter VIP home page Giter VIP logo

multimap's Introduction

Arduino CI Arduino-lint JSON check GitHub issues

License: MIT GitHub release PlatformIO Registry

MultiMap

Arduino library for fast non-linear mapping or interpolation of values.

Description

In Arduino applications often the 'raw' value of a sensor is mapped upon a more usable value. E.g. the value of analogRead() 0 .. 1023 is mapped onto 0 .. 5.0 Volt. This is often done by the map function which does a linear interpolation.

This means in code:

    output = C1 + input * C2

As C1 and C2 are to be determined, Arduino has the map() function that calculates the two variables runtime from two given mapping points (I1, O1) and (I2, O2).

    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 straight line. To solve this one needs non-linear math to calculate the output.

The multiMap() function simulates this math by approximating the non-linear function with multiple linear line segments. Of course this approximation introduces an error. By increasing the number of points and choose their position strategically the average error will be reduced.

Note: some functions are hard to approximate with multiMap as they go to infinity or have a singularity. Think of tan(x) around x = PI/2 (90°) or sin(1/x) around zero.

Related

Other mapping libraries

Interface

#include "MultiMap.h"

Usage

The basic call for multiMap() is:

output = Multimap<datatype>(input, inputArray, outputArray, size);

multiMap() needs two equally sized arrays representing the reference 'points' named inputArray[] and outputArray[] both of the datatype.

multiMap() will do a lookup of the input value in the inputArray[]. If it cannot find the index of an exact point it will determine a weighted position between two points. This optional weighted point is used to interpolate a value from data in the output[] array.

  • The inputArray[] must have increasing values, there is no such restriction for the output[] array.
  • The values of the inputArray[] do not need to have the same distance (non-equidistant). E.g an array like { 1, 10, 100, 1000 } is valid.
  • multiMap() automatically constrains the output to the first and last value in the output[] array. This is a explicit difference with the map() function. Therefore it is important to extend the range of the arrays to cover all possible values.

Performance

multiMap() does a linear search for the inputValue in the inputArray. This implies that usage of larger and more precise arrays will take more time. Furthermore "low" input values will be found faster than "high" values.

As every usage of multiMap() is unique one should always do a performance check to see if there is a substantial gain in the case at hand. In my experience there often is.

MultiMapBS

Experimental 0.1.7 => use with care.

multiMapBS() MMBS for short, is a very similar function as multiMap(). The main difference is that MMBS uses binary search instead of linear search.

First performance tests indicate that for array sizes about 10 MMBS is on par with multiMap(). This is expected as both need on average about 5 steps to find the right interval.

Be sure to do your own tests to see if MMBS improves your performance.

MultiMapCache

Experimental 0.1.7 => use with care.

multiMapCache() MMC for short, is a very similar function as multiMap(). The main difference is that MMC caches the last input and output value. The goal is to improve the performance by preventing searching the same value again and again.

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 MMC will be able to return the value from cache often. Otherwise keeping cache is overhead.

Be sure to do your own tests to see if MMC improves your performance.

A possible variation is to cache the last interval - lower and upper index. It would allow a to test that value and improve the linear search. (to be investigated).

MultiMap two types

Experimental 0.2.0 => use with care.

multiMap<T1, T2>() MMTT for short, is a very similar function as multiMap(). The main difference is that MMTT uses two different types, typical the input is an integer type and the output is a float or double type. It is expected that there will be a gain if two different sized integer types are used. This is not tested.

See the example multimap_distance_two_types.ino

// for a sharp distance range finder
float sharp2cm2(int val)
{
  // out[] holds the distances in cm
  float out[] = {150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20};

  // in[] holds the measured analogRead() values for that distance
  int in[]  = { 90, 97, 105, 113, 124, 134, 147, 164, 185, 218, 255, 317, 408, 506};

  float dist = multiMap<int, float>(val, in, out, 14);
  return dist;
}

A first test indicate that using the int type for the input in the example is substantial (~37%) faster per call. Test on UNO, time in micros per call.

types time us call
1 194.93 float dist = multiMap<float>(val, in, out, 14);
2 121.97 float dist = multiMap<int, float>(val, in, out, 14);

Furthermore it is obvious that there is less need for RAM if the integer type is smaller in size than the float type.

Be sure to do your own tests to see if MMTT improves your performance.

Operation

See examples

Please note the fail example as this shows that in the intern math overflow can happen.

Future

Must

  • improve documentation

Should

  • investigate multiMapCache behaviour
    • determine overhead.
  • extend unit tests
    • multi type versions

Could

  • Investigate class implementation
    • basic call out = mm.map(value);
    • runtime adjusting input and output array begin(in[], out[])
    • performance / footprint
    • less parameter passing
    • isInRange(value)?
    • caching last value / position / index (does that help?)
    • flag if input value was "IN_MIN" < input < "IN_MAX", now it is constrained without user being informed.
  • Investigate a 2D multiMap e.g. for complex numbers?
    • is it possible / feasible?

Wont

  • should the lookup tables be merged into one array of pairs?
    • you cannot reuse e.g. the input array or the output array then. this would not improve the memory footprint.

Support

If you appreciate my libraries, you can support the development and maintenance. Improve the quality of the libraries by providing issues and Pull Requests, or donate through PayPal or GitHub sponsors.

Thank you,

multimap's People

Contributors

robtillaart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

multimap's Issues

Use for 10k thermistor? (Closed/Solved)

This is not really an issue. Feel free to label as solved right away, I just do not know how to simply message author of this library otherwise?? LOL
Is it possible to use multimap with an NTC thermistor as long as I have made a table of known raw analog values and resistances (my IN[]) matching associated temperatures (my OUT[])?
Only reason I ask is cause i have used multimap before for flow sensors with success but Im not a coder by any means and the NTC example provided is confusing the hell out of me!! LOL

thanks

Bug: Unexpected values when using Arduino Leonardo

I don't get it. Used Multimap several times before with great success, but now with an Arduino Leonardo I get unexpected results.

I've made an example to the bear minimum:

#include "MultiMap.h"
int In[]   = { 0  ,   512};
int Out[]  = { 0  ,   255};

void setup() {
  Serial.begin(9600);
}

void loop() {
  for (int i = 0; i <= 512; i++) {
    int mapValue = multiMap<int>(i, In, Out, 2);
    Serial.println(String(i) + ": " + String (mapValue));
  }
  delay(10000);
}

And this is the result:

0: 0
1: 0
2: 0
3: 1
4: 1
5: 2
6: 2
7: 3
8: 3
9: 4
10: 4
11: 5
12: 5
13: 6
14: 6
15: 7
16: 7
17: 8
18: 8
19: 9
20: 9
21: 10
22: 10
23: 11
24: 11
25: 12
26: 12
27: 13
28: 13
29: 14
30: 14
31: 15
32: 15
33: 16
34: 16
35: 17
36: 17
37: 18
38: 18
39: 19
40: 19
41: 20
42: 20
43: 21
44: 21
45: 22
46: 22
47: 23
48: 23
49: 24
50: 24
51: 25
52: 25
53: 26
54: 26
55: 27
56: 27
57: 28
58: 28
59: 29
60: 29
61: 30
62: 30
63: 31
64: 31
65: 32
66: 32
67: 33
68: 33
69: 34
70: 34
71: 35
72: 35
73: 36
74: 36
75: 37
76: 37
77: 38
78: 38
79: 39
80: 39
81: 40
82: 40
83: 41
84: 41
85: 42
86: 42
87: 43
88: 43
89: 44
90: 44
91: 45
92: 45
93: 46
94: 46
95: 47
96: 47
97: 48
98: 48
99: 49
100: 49
101: 50
102: 50
103: 51
104: 51
105: 52
106: 52
107: 53
108: 53
109: 54
110: 54
111: 55
112: 55
113: 56
114: 56
115: 57
116: 57
117: 58
118: 58
119: 59
120: 59
121: 60
122: 60
123: 61
124: 61
125: 62
126: 62
127: 63
128: 63
129: -63
130: -63
131: -62
132: -62
133: -61
134: -61
135: -60
136: -60
137: -59
138: -59
139: -58
140: -58
141: -57
142: -57
143: -56
144: -56
145: -55
146: -55
147: -54
148: -54
149: -53
150: -53
151: -52
152: -52
153: -51
154: -51
155: -50
156: -50
157: -49
158: -49
159: -48
160: -48
161: -47
162: -47
163: -46
164: -46
165: -45
166: -45
167: -44
168: -44
169: -43
170: -43
171: -42
172: -42
173: -41
174: -41
175: -40
176: -40
177: -39
178: -39
179: -38
180: -38
181: -37
182: -37
183: -36
184: -36
185: -35
186: -35
187: -34
188: -34
189: -33
190: -33
191: -32
192: -32
193: -31
194: -31
195: -30
196: -30
197: -29
198: -29
199: -28
200: -28
201: -27
202: -27
203: -26
204: -26
205: -25
206: -25
207: -24
208: -24
209: -23
210: -23
211: -22
212: -22
213: -21
214: -21
215: -20
216: -20
217: -19
218: -19
219: -18
220: -18
221: -17
222: -17
223: -16
224: -16
225: -15
226: -15
227: -14
228: -14
229: -13
230: -13
231: -12
232: -12
233: -11
234: -11
235: -10
236: -10
237: -9
238: -9
239: -8
240: -8
241: -7
242: -7
243: -6
244: -6
245: -5
246: -5
247: -4
248: -4
249: -3
250: -3
251: -2
252: -2
253: -1
254: -1
255: 0
256: 0
257: 0
258: 0
259: 0
260: 1
261: 1
262: 2
263: 2
264: 3
265: 3
266: 4
267: 4
268: 5
269: 5
270: 6
271: 6
272: 7
273: 7
274: 8
275: 8
276: 9
277: 9
278: 10
279: 10
280: 11
281: 11
282: 12
283: 12
284: 13
285: 13
286: 14
287: 14
288: 15
289: 15
290: 16
291: 16
292: 17
293: 17
294: 18
295: 18
296: 19
297: 19
298: 20
299: 20
300: 21
301: 21
302: 22
303: 22
304: 23
305: 23
306: 24
307: 24
308: 25
309: 25
310: 26
311: 26
312: 27
313: 27
314: 28
315: 28
316: 29
317: 29
318: 30
319: 30
320: 31
321: 31
322: 32
323: 32
324: 33
325: 33
326: 34
327: 34
328: 35
329: 35
330: 36
331: 36
332: 37
333: 37
334: 38
335: 38
336: 39
337: 39
338: 40
339: 40
340: 41
341: 41
342: 42
343: 42
344: 43
345: 43
346: 44
347: 44
348: 45
349: 45
350: 46
351: 46
352: 47
353: 47
354: 48
355: 48
356: 49
357: 49
358: 50
359: 50
360: 51
361: 51
362: 52
363: 52
364: 53
365: 53
366: 54
367: 54
368: 55
369: 55
370: 56
371: 56
372: 57
373: 57
374: 58
375: 58
376: 59
377: 59
378: 60
379: 60
380: 61
381: 61
382: 62
383: 62
384: 63
385: 63
386: -63
387: -63
388: -62
389: -62
390: -61
391: -61
392: -60
393: -60
394: -59
395: -59
396: -58
397: -58
398: -57
399: -57
400: -56
401: -56
402: -55
403: -55
404: -54
405: -54
406: -53
407: -53
408: -52
409: -52
410: -51
411: -51
412: -50
413: -50
414: -49
415: -49
416: -48
417: -48
418: -47
419: -47
420: -46
421: -46
422: -45
423: -45
424: -44
425: -44
426: -43
427: -43
428: -42
429: -42
430: -41
431: -41
432: -40
433: -40
434: -39
435: -39
436: -38
437: -38
438: -37
439: -37
440: -36
441: -36
442: -35
443: -35
444: -34
445: -34
446: -33
447: -33
448: -32
449: -32
450: -31
451: -31
452: -30
453: -30
454: -29
455: -29
456: -28
457: -28
458: -27
459: -27
460: -26
461: -26
462: -25
463: -25
464: -24
465: -24
466: -23
467: -23
468: -22
469: -22
470: -21
471: -21
472: -20
473: -20
474: -19
475: -19
476: -18
477: -18
478: -17
479: -17
480: -16
481: -16
482: -15
483: -15
484: -14
485: -14
486: -13
487: -13
488: -12
489: -12
490: -11
491: -11
492: -10
493: -10
494: -9
495: -9
496: -8
497: -8
498: -7
499: -7
500: -6
501: -6
502: -5
503: -5
504: -4
505: -4
506: -3
507: -3
508: -2
509: -2
510: -1
511: -1
512: 255

Any idea why the output does not met the expectation?


added cpp in the code block markup for syntax highlighting

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.