I've been thinking to make a class of the map() function. Goal is to perform substantial faster as a big part of the map() function is often constant but includes an expensive division.
The fastmap class minimizes the time to do a mapping by doing most math in advance. The code "removes" three subtractions and one division from the map formula. The code is using float as that gave the fastest performance and is usable for all datatypes. Using floats results in slightly different values as the map() function truncates its math.
The test application fastmapper.ino does a first order timing in which the - float based - fastMap class is approx 60 times faster than the - long based - map() function. The price for this is 24 bytes RAM. Note that 16 bytes of RAM are used for three constrainedMap() methods that are also part of the class.
The three constrainedMap() methods do mapping with a constrain on the lower input, upper input or both. These are not in the sample sketch below.
test application
//
// FILE: fastMapDemo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.02
// PURPOSE: demo of FastMap class ==> a faster map function
// DATE: 2014-11-02
// URL:
//
// Released to the public domain
//
#include "FastMap.h"
uint32_t start;
uint32_t stop;
uint32_t reference;
volatile long zz = 3000, yy = 20000;
volatile float x;
FastMap mapper;
void setup()
{
Serial.begin(115200);
Serial.print("Start fastMapDemo\nlib version: ");
Serial.println(FASTMAP_LIB_VERSION);
Serial.println();
// Get a non optimizable value;
int z = analogRead(A0);
// REFERENCE
start = micros();
for (int i = 0; i < 10000; i++)
{
x = map(z, 0, 1023, yy, zz);
}
stop = micros();
reference = stop-start;
Serial.println(reference);
Serial.print(z);
Serial.print(" -> ");
Serial.println(x);
Serial.println();
// FASTMAP
mapper.init(0, 1023, yy, zz);
start = micros();
for (int i = 0; i < 10000; i++)
{
x = mapper.map(z);
}
stop = micros();
Serial.println(stop-start);
Serial.print(z);
Serial.print(" -> ");
Serial.println(x);
// GAIN
Serial.print("Performance factor: ");
Serial.println(reference/(stop-start));
}
void loop()
{
}
//
// END OF FILE
//
One final comment on the name of the class. The Arduino (and many other systems) convention is that class names start with capital letters, and all words are capitalized. So, your class should be FastMap, not fastmap.
LCM = lowerConstrainedMap() - only constrain lower side
UCM = upperConstrainedMap() - only constrain upper side
CM = constrainedMap() - constrain both ends
the lowerConstrainMap() can be used to prevent the result go below a certain value.
E.g mapping some sensors on the speed of a motor that cannot go below zero.
the upperConstrainMap() can be used to prevent the result go above a certain value.
E.g. preventing that a frequency goes beyond 20000Hz (human limit)
the constrainMap() can be used to keep the result between certain values.
E.g. to keep a PWM signal between 0 and 255;
I think the names are well descriptive but a bit long.
Thinking about this class gave me several ideas how to continue with this class.
create a single map function with constrain parameters -> bit mask...
y = map(x); // default is no constrain
y = map(x, CONSTRAIN_NONE); // CONSTRAIN_NONE = 0; default
y = map(x, CONSTRAIN_LOWER); // CONSTRAIN_LOWER = 1
y = map(x, CONSTRAIN_UPPER); // CONSTRAIN_UPPER = 2
y = map(x, CONSTRAIN_BOTH); // CONSTRAIN_BOTH = 3 = CONSTRAIN_LOWER | CONSTRAIN_UPPER
strong point is that one function supports all constrain types.
the FastMap class can at the cost of 2 floats RAM (and a bit of flash) create an inverse method, which is very similar to map itself. It allows to "map the other way, in reverse". e.g. one instance of FastMap can do both Celsius2Fahrenheit or Fahrenheit2Celsius...