{"id":20989776,"url":"https://github.com/robtillaart/multimap","last_synced_at":"2025-06-22T23:08:21.428Z","repository":{"id":45309720,"uuid":"254357706","full_name":"RobTillaart/MultiMap","owner":"RobTillaart","description":"Arduino library for fast non-linear mapping or interpolation of values","archived":false,"fork":false,"pushed_at":"2024-04-13T09:08:23.000Z","size":31,"stargazers_count":34,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T22:02:35.769Z","etag":null,"topics":["arduino","interpolation","linear","map","multimap","non-linear"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTillaart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"RobTillaart","custom":"https://www.paypal.me/robtillaart"}},"created_at":"2020-04-09T11:52:37.000Z","updated_at":"2025-03-27T14:37:08.000Z","dependencies_parsed_at":"2024-04-13T10:25:09.862Z","dependency_job_id":"ca47b4ed-90f5-4f90-a190-26a47a5c4e96","html_url":"https://github.com/RobTillaart/MultiMap","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/RobTillaart/MultiMap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FMultiMap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FMultiMap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FMultiMap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FMultiMap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTillaart","download_url":"https://codeload.github.com/RobTillaart/MultiMap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FMultiMap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261380910,"owners_count":23149966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","interpolation","linear","map","multimap","non-linear"],"created_at":"2024-11-19T06:26:08.160Z","updated_at":"2025-06-22T23:08:16.415Z","avatar_url":"https://github.com/RobTillaart.png","language":"C++","readme":"\n[![Arduino CI](https://github.com/RobTillaart/MultiMap/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)\n[![Arduino-lint](https://github.com/RobTillaart/MultiMap/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/MultiMap/actions/workflows/arduino-lint.yml)\n[![JSON check](https://github.com/RobTillaart/MultiMap/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/MultiMap/actions/workflows/jsoncheck.yml)\n[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/MultiMap.svg)](https://github.com/RobTillaart/MultiMap/issues)\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MultiMap/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/RobTillaart/MultiMap.svg?maxAge=3600)](https://github.com/RobTillaart/MultiMap/releases)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/MultiMap.svg)](https://registry.platformio.org/libraries/robtillaart/MultiMap)\n\n\n# MultiMap\n\nArduino library for fast non-linear mapping or interpolation of values.\n\n\n## Description\n\nIn Arduino applications often the 'raw' value of a sensor is mapped upon a more\nusable value. E.g. the value of analogRead() 0 .. 1023 is mapped onto 0 .. 5.0 Volt.\nThis is often done by the map function which does a linear interpolation.\n\nThis means in code:\n\n```cpp\n    output = C1 + input * C2\n```\n\nAs C1 and C2 are to be determined, Arduino has the **map()** function that calculates the \ntwo variables runtime from two given mapping points (I1, O1) and (I2, O2).\n\n```cpp\n    output = map(input, I1, I2, O1, O2):\n```\n\nIn many cases when there is no linear mapping possible as the 'points' are not on a single straight line.\nTo solve this one needs non-linear math to calculate the output.\n\nThe **multiMap()** function simulates this math by approximating the non-linear function with multiple\nlinear line segments. \nOf course this approximation introduces an error. \nBy increasing the number of points and choose their position strategically the average error will be reduced.\n\nNote: some functions are hard to approximate with multiMap as they go to infinity or have a singularity.\nThink of **tan(x)** around x = PI/2 (90°) or **sin(1/x)** around zero.\n\n\n#### Related\n\nOther mapping libraries \n\n- https://github.com/RobTillaart/FastMap\n- https://github.com/RobTillaart/Gamma\n- https://github.com/RobTillaart/map2colour\n- https://github.com/RobTillaart/moduloMap\n- https://github.com/RobTillaart/MultiMap\n\n\n## Interface\n\n```cpp\n#include \"MultiMap.h\"\n```\n\n\n#### Usage\n\nThe basic call for **multiMap()** is:\n\n```cpp\noutput = Multimap\u003cdatatype\u003e(input, inputArray, outputArray, size);\n```\n\n**multiMap()** needs two equally sized arrays representing the reference 'points' named \n**inputArray\\[\\]** and **outputArray\\[\\]** both of the **datatype**.\n\n**multiMap()** will do a lookup of the input value in the inputArray\\[\\].\nIf it cannot find the index of an exact point it will determine a weighted position between two points.\nThis optional weighted point is used to interpolate a value from data in the output\\[\\] array.\n\n- The **inputArray\\[\\]** must have increasing values, \nthere is no such restriction for the **output\\[\\]** array.\n- The values of the **inputArray\\[\\]** do not need to have the same distance (non-equidistant).\nE.g an array like { 1, 10, 100, 1000 } is valid.\n- **multiMap()** automatically constrains the output to the first and last value in the **output\\[\\]** array.\nThis is a explicit difference with the **map()** function.\nTherefore it is important to extend the range of the arrays to cover all possible values.\n\n\n## Performance\n\n**multiMap()** does a linear search for the inputValue in the inputArray.\nThis implies that usage of larger and more precise arrays will take more time.\nFurthermore \"low\" input values will be found faster than \"high\" values.\n\nAs every usage of multiMap() is unique one should always do a performance check to see\nif there is a substantial gain in the case at hand. In my experience there often is.\n\n\n#### MultiMapBS\n\nExperimental 0.1.7 =\u003e use with care.\n\n**multiMapBS()** MMBS for short, is a very similar function as **multiMap()**.\nThe main difference is that MMBS uses binary search instead of linear search.\n\nFirst performance tests indicate that for array sizes about 10 MMBS is on par\nwith **multiMap()**. This is expected as both need on average about 5 steps \nto find the right interval.\n\nBe sure to do your own tests to see if MMBS improves your performance.\n\n\n#### MultiMapCache\n\nExperimental 0.1.7 =\u003e use with care.\n\n**multiMapCache()** MMC for short, is a very similar function as **multiMap()**.\nThe main difference is that MMC caches the last input and output value.\nThe goal is to improve the performance by preventing searching the same \nvalue again and again.\n\nIf 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\nMMC will be able to return the value from cache often. \nOtherwise keeping cache is overhead.\n\nBe sure to do your own tests to see if MMC improves your performance.\n\nA possible variation is to cache the last interval - lower and upper index.\nIt would allow a to test that value and improve the linear search.\n(to be investigated).\n\n\n#### MultiMap two types\n\nExperimental 0.2.0 =\u003e use with care.\n\n**multiMap\u003cT1, T2\u003e()** MMTT for short, is a very similar function as **multiMap()**.\nThe main difference is that MMTT uses two different types, typical the input \nis an integer type and the output is a float or double type.\nIt is expected that there will be a gain if two different sized integer types are used.\nThis is not tested.\n\nSee the example **multimap_distance_two_types.ino**\n\n```cpp\n// for a sharp distance range finder\nfloat sharp2cm2(int val)\n{\n  // out[] holds the distances in cm\n  float out[] = {150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20};\n\n  // in[] holds the measured analogRead() values for that distance\n  int in[]  = { 90, 97, 105, 113, 124, 134, 147, 164, 185, 218, 255, 317, 408, 506};\n\n  float dist = multiMap\u003cint, float\u003e(val, in, out, 14);\n  return dist;\n}\n```\n\nA first test indicate that using the int type for the input in the example\nis substantial (~37%) faster per call. Test on UNO, time in micros per call.\n\n|  types  |  time us  |  call  |\n|:-------:|:---------:|:-------|\n|    1    |  194.93   |  ```float dist = multiMap\u003cfloat\u003e(val, in, out, 14);```       |\n|    2    |  121.97   |  ```float dist = multiMap\u003cint, float\u003e(val, in, out, 14);```  |\n\nFurthermore it is obvious that there is less need for RAM if the integer type is smaller\nin size than the float type.\n\nBe sure to do your own tests to see if MMTT improves your performance.\n\n\n## Operation\n\nSee examples\n\nPlease note the fail example as this shows that in the intern math overflow can happen.\n\n\n## Future\n\n#### Must\n\n- improve documentation\n\n#### Should\n\n- investigate multiMapCache behaviour\n  - determine overhead.\n- extend unit tests\n  - multi type versions\n\n#### Could\n\n- Investigate class implementation\n  - basic call ```out = mm.map(value);```\n  - runtime adjusting input and output array **begin(in[], out[])**\n  - performance / footprint\n  - less parameter passing\n  - **isInRange(value)**?\n  - caching last value / position / index (does that help?)\n  - flag if input value was \"IN_MIN\" \u003c  input \u003c \"IN_MAX\", \n    now it is constrained without user being informed.\n- Investigate a 2D multiMap e.g. for complex numbers?\n  - is it possible / feasible?\n\n#### Wont\n\n- should the lookup tables be merged into one array of pairs?\n  - you cannot reuse e.g. the input array or the output array then. \n    this would not improve the memory footprint.\n\n\n## Support\n\nIf you appreciate my libraries, you can support the development and maintenance.\nImprove the quality of the libraries by providing issues and Pull Requests, or\ndonate through PayPal or GitHub sponsors.\n\nThank you,\n\n","funding_links":["https://github.com/sponsors/RobTillaart","https://www.paypal.me/robtillaart"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fmultimap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobtillaart%2Fmultimap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fmultimap/lists"}