Go Down

Topic: Class from map function  (Read 245 times) previous topic - next topic

robtillaart

Nov 01, 2014, 01:26 pm Last Edit: Nov 01, 2014, 01:47 pm by robtillaart
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.


Code: (the concept) [Select]

map.init(in_min, in_max, out_min, out_max)
{
  _in_min = in_min;
  _in_max = in_max;
  _out_min = out_min;
  _out_max = out_max;
  _factor = float(out_max - out_min)/(in_max - in_min);
}

map.map(value)
{
  return (value - _in_min) * factor;
}

map.constrainedMap(value)
{
  if (value <= _in_min) return _out_min;
  if (value >= _in_max) return _out_max;
  return (value - _in_min) * factor;
}

map.lowerConstrainedMap()...
map.upperConstrainedMap()...


- http://www.engblaze.com/faster-code-fridays-understand-division-and-speed-of-operations/ -

any thoughts what could also be in it?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

PaulS

Quote
any thoughts what could also be in it?
Some types for the variables?
Proper syntax for the function declaration (map::init()).
A return type?

An overloaded method that deals with floats?

 8)

robtillaart

#2
Nov 02, 2014, 04:31 pm Last Edit: Nov 02, 2014, 05:27 pm by robtillaart
The fastmap class can be found on GITHUB

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
Code: [Select]
//
//    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
//


OUTPUT:
Start fastmap demo
lib version: 0.1.02

572960
250 -> 15846.00

9512
250 -> 15845.55
Performance factor: 60


updated code + link
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

PaulS

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.

robtillaart

#4
Nov 02, 2014, 05:10 pm Last Edit: Nov 02, 2014, 05:28 pm by robtillaart
good point, will rename it a.s.a.p.
<done>

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#5
Nov 02, 2014, 05:32 pm Last Edit: Nov 02, 2014, 05:32 pm by robtillaart
a simple constrainedMap demo
Code: [Select]
//
//    FILE: constrainedMap.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.01
// PURPOSE: demo of FastMap class ==> merge map and constrain functions
//    DATE: 2014-11-02
//     URL:
//
// Released to the public domain
//

#include "FastMap.h"

FastMap mapper;

void setup()
{
  Serial.begin(115200);
  Serial.print("Start constrainedMap demo\nlib version: ");
  Serial.println(FASTMAP_LIB_VERSION);
  Serial.println();

  mapper.init(0, 10, 0, 300);

  Serial.println("I\tMAP\tLCM\tUCM\tCM");
  for (int i = -5; i < 20; i++)
  {
    float a = map(i, 0, 10, 0, 300);
    float b = mapper.lowerConstrainedMap(i);
    float c = mapper.upperConstrainedMap(i);
    float d = mapper.constrainedMap(i);
    Serial.print(i);
    Serial.print("\t");
    Serial.print(a);
    Serial.print("\t");
    Serial.print(b);
    Serial.print("\t");
    Serial.print(c);
    Serial.print("\t");
    Serial.println(d);
  }
  Serial.println("\ndone...");
}

void loop(){}


OUTPUT:
Start constrainedMap demo
lib version: 0.1.03

I   MAP   LCM   UCM   CM
-5   -150.00   0.00   -150.00   0.00
-4   -120.00   0.00   -120.00   0.00
-3   -90.00   0.00   -90.00   0.00
-2   -60.00   0.00   -60.00   0.00
-1   -30.00   0.00   -30.00   0.00
0   0.00   0.00   0.00   0.00
1   30.00   30.00   30.00   30.00
2   60.00   60.00   60.00   60.00
3   90.00   90.00   90.00   90.00
4   120.00   120.00   120.00   120.00
5   150.00   150.00   150.00   150.00
6   180.00   180.00   180.00   180.00
7   210.00   210.00   210.00   210.00
8   240.00   240.00   240.00   240.00
9   270.00   270.00   270.00   270.00
10   300.00   300.00   300.00   300.00
11   330.00   330.00   300.00   300.00
12   360.00   360.00   300.00   300.00
13   390.00   390.00   300.00   300.00
14   420.00   420.00   300.00   300.00
15   450.00   450.00   300.00   300.00
16   480.00   480.00   300.00   300.00
17   510.00   510.00   300.00   300.00
18   540.00   540.00   300.00   300.00
19   570.00   570.00   300.00   300.00

done...


LCM = lowerConstrainedMap() - only constrain lower side
UCM = upperConstrainedMap() - only constrain upper side
CM = constrainedMap() - constrain both ends
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

some remarks wrt the constrain functions

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...

c = temperature.map(f);
f = temperature.back(c);

or mapping between voltage and RPM and back.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Another example, using 2 mappers side by side (and the one that inspired the "back" function above)

Code: [Select]
//
//    FILE: fastMapDemo2.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"

FastMap CtoF;
FastMap FtoC;

void setup()
{
  Serial.begin(115200);
  Serial.print("Start fastMapDemo2\nlib version: ");
  Serial.println(FASTMAP_LIB_VERSION);
  Serial.println();

  CtoF.init(0, 100, 32, 212);
  FtoC.init(32, 212, 0, 100);

  float f = FtoC.map(163);
  Serial.print(f);
  Serial.print(char(176));
  Serial.println('C');

  float c = CtoF.map(f);
  Serial.print(c);
  Serial.print(char(176)); // degree symbol
  Serial.println('F');
}

void loop()
{
}
//
// END OF FILE
//
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

implemented the back function. Works like a charm (code will be asap on github)
Code: [Select]
//    FILE: fastMapDemo3.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo of FastMap class ==> a faster map function
//    DATE: 2014-11-02
//     URL:
//
// Released to the public domain
//

#include "FastMap.h"

FastMap CtoF;

void setup()
{
  Serial.begin(115200);
  Serial.print("Start fastMapDemo3\nlib version: ");
  Serial.println(FASTMAP_LIB_VERSION);
  Serial.println();

  CtoF.init(0, 100, 32, 212);

  float f = CtoF.map(163);
  Serial.print(f);
  Serial.print(char(176));
  Serial.println('F');

  float c = CtoF.back(f);
  Serial.print(c);
  Serial.print(char(176));
  Serial.println('C');
}

void loop()
{
}
//
// END OF FILE
//


OUTPUT:

Start fastMapDemo3
lib version: 0.1.04

325.40°F
163.00°C


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#9
Nov 02, 2014, 09:52 pm Last Edit: Nov 02, 2014, 09:53 pm by robtillaart
draft implementation of the constrain bit mask demo
Code: [Select]
//    FILE: fastMapDemo3.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo of FastMap class ==> a faster map function
//    DATE: 2014-11-02
//     URL: http://forum.arduino.cc/index.php?topic=276194
//
// Released to the public domain
//

#include "FastMap.h"

FastMap CtoF;

void setup()
{
  Serial.begin(115200);
  Serial.print("Start fastMapDemo3\nlib version: ");
  Serial.println(FASTMAP_LIB_VERSION);
  Serial.println();

  CtoF.init(0, 100, 32, 212);

  float f = CtoF.map(163);
  Serial.print(f);
  Serial.print(char(176));
  Serial.println('F');

  float c = CtoF.back(f);
  Serial.print(c);
  Serial.print(char(176));
  Serial.println('C');

  f = CtoF.map(163, CONSTRAIN_UPPER);
  Serial.print(f);
  Serial.print(char(176));
  Serial.println('F');

  c = CtoF.back(f, CONSTRAIN_BOTH);
  Serial.print(c);
  Serial.print(char(176));
  Serial.println('C');

}

void loop()
{
}
//
// END OF FILE
//


OUTPUT:
Start fastMapDemo3
lib version: 0.1.04

325.40°F
163.00°C
212.00°F
100.00°C

so the draft 0.1.04 works quite well,

tomorrow investigate speed and footprint ...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

perfomance is decreased extremely, so this 0.1.04 version will not come out of the labs soon ;)


Start fastMapDemo
lib version: 0.1.04

572956
255 -> 15763.00

233340
255 -> 15762.46
Performance factor: 2
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Created an 0.1.05 version that supports the back() function. (bit-mask experiment removed)
See post #8 for demo code.

Posted the 0.1.05 version on - https://github.com/RobTillaart/Arduino/tree/master/libraries/FastMap -


As always remarks and comments are welcome.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up