map(value, fromLow, fromHigh, toLow, toHigh)
Description
Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a value of fromHigh to toHigh, values in-between to values in-between, etc.
Does not constrain values to within the range, because out-of-range values are sometimes intended and useful. The constrain() function may be used either before or after this function, if limits to the ranges are desired.
Note that the "lower bounds" of either range may be larger or smaller than the "upper bounds" so the map() function may be used to reverse a range of numbers, for example
y = map(x, 1, 50, 50, 1);
The function also handles negative numbers well, so that this example
y = map(x, 1, 50, 50, -100);
is also valid and works well.
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged.
Parameters
value: the number to map
fromLow: the lower bound of the value's current range
fromHigh: the upper bound of the value's current range
toLow: the lower bound of the value's target range
toHigh: the upper bound of the value's target range
Returns
The mapped value.
This is the equation that they use...
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
I tried this....
dim map, InMin, InMax, OutMin, OutMax as integer
Value = 1012
Value = map (Value, 0, 1023, 20, 255)
HSerPrint Value
function map (Value, InMin, InMax, OutMin, OutMax)
map = (Value - InMin) * (OutMax - OutMin) / (InMax - InMin) + OutMin
end function
But it crashes. Not sure why. Any ideas out there?
Last edit: viscomjim 2016-06-22
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It won't output anything. I am using the same setup for different projects using serial output so I am sure the set up is working fine. I just did a new program to try and test this function out and get nothing on the serial out. It did compile.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The integer values used the above attempts will overflow in the computations with anything but relatively small numbers.
Arduio MAP uses LONGS which with Arduino I think are actually capable of holdng very large negative and positive numbers. GCB Longs are positive only.
I think MAP was looked at last year and it was determined that it could not work unless\until GCB supported REAL numbers.
A limited verion of MAP could possibly be done using longs and where none of the values are negative.
The function below should work (within limits). If any calculation results in a negative number the results will be wrong.
Function MAP (in Value as word , in InMin as WORD, in InMax as WORD, in OutMin as WORD, in OutMax as WORD) as LONG
map = (Value - InMin) * (OutMax - OutMin)
map = map / (InMax - InMin) + OutMin
end function
Last edit: William Roth 2016-06-30
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi William, thanks for that example. I will give it a try and report back. As this will work well with the 10 bit ADC, I am using it with a MSGEQ7. The output from the MSEQ7 ranges from 0 to 255 on the 8 bit pic ADC, from about 0 to 70 or so is noise. I am driving some DMX RGB light units and want to remap the output from the MSGEQ7 from 70 to 255 to 0 to 255. I noticed a lot of arduino code that does this and it allows for a better range on the lights. Won't be using negative numbers here so hopefully this will be a good solution. Something like this...
EqValue(Zz) = Map (EqValue(Zz), 70, 255, 0, 255)
Last edit: viscomjim 2016-06-30
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Won't be using negative numbers here so hopefully this will be a good solution. Something like this... EqValue(Zz) = Map (EqValue(Zz), 70, 255, 0, 255)
You do not have to use a negative number to have an errant result.
For example: IF the starting "value" is 65 then ....
map = (65 - 70) * 255
Since the function does not handle negative numbers .... (65 - 70) will result in an underflow and return a value of "65531" instead of "-5". This will cause the function to return an unexpected value of 90,396
So the input value will need to be constrained to > or = to InMin to prevent this underflow. The Function then becomes:
Function MAP (in Value as word , in InMin as WORD, in InMax as WORD, in OutMin as WORD, in OutMax as WORD) as LONG
if value < InMin then value = InMin
map = (Value - InMin) * (OutMax - OutMin)
map = map / (InMax - InMin) + OutMin
end function
These maths take time that you may not have for fast response. This is why a lookup may be a better option.
Edit: The speed is not a bad as I thought it might be. It takes the function above about 218 microseconds to complete with a PIC operating at 32Mhz. I tested on a PIC16F1788
Last edit: William Roth 2016-07-03
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
After looking at a lot of arduino code, it seems like people use the "constrain" function quite a bit with the use of the map function. I made a "version" of this so I could do some testing to see if it solves some problems. This is what I came up with, although it probably could be done better. I'm not quite up to par yet with all the tricks yet so don't laugh...
Not sure how to make this prettier without the else if type statement. I will give your enhanced map function a whirl also. I appreciate your time William!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Lots of calculations being done with very little time to refresh the display from the MSGEQ7. Here are my thoughts:
1. Build a table with a spreadsheet based on the math required to remap the values.
2. Reading tables is kinda slow, so when initializing the code before main, read the table into a large buffer variable (i.e. SRAM).
Now you've got a super quick way to get from MSGEQ7 value to a DMX PWM value out. Extra points if you convert the logarithmic brightness perception of the eye to a linear scale. See gamma correction.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Kent, running the pic at 20Mhz I can read the 7 values of the MSGEQ7, do some stuff with that data and spit out 24 DMX values (8 x 3) to an 8 channel RGB decoder pretty quickly. I am pretty amazed at the speed of these little buggers. It seems like there is plenty of time to spare also. Great Cow Basic is quite amazing! I have a very limited setup right now as I am "babysitting" at my sister's house for a while to help her out. I put together a nice little breadboard setup with a laptop that I can transport back and forth easily. Innovation at it's best...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Is it possible to create a Map function in GCB?
From arduino...
This is the equation that they use...
I tried this....
dim map, InMin, InMax, OutMin, OutMax as integer
Value = 1012
Value = map (Value, 0, 1023, 20, 255)
HSerPrint Value
function map (Value, InMin, InMax, OutMin, OutMax)
map = (Value - InMin) * (OutMax - OutMin) / (InMax - InMin) + OutMin
end function
But it crashes. Not sure why. Any ideas out there?
Last edit: viscomjim 2016-06-22
You know the next question.
What version of Great Cow BASIC compiler?
Soooooo Sorrrry, latest one!
What is value defined as? A word? Is Value defined?
Last edit: Anobium 2016-06-22
I did not dim Value orginally so I just tried it using
still no luck....
When does it crash? During compiling?
It won't output anything. I am using the same setup for different projects using serial output so I am sure the set up is working fine. I just did a new program to try and test this function out and get nothing on the serial out. It did compile.
Expanding the function.
For me... this prints 20.
However, I am on very latest build.
I'm going to have to do a bit more research and experimentation on this. My math is not working correctly I think....
The integer values used the above attempts will overflow in the computations with anything but relatively small numbers.
Arduio MAP uses LONGS which with Arduino I think are actually capable of holdng very large negative and positive numbers. GCB Longs are positive only.
I think MAP was looked at last year and it was determined that it could not work unless\until GCB supported REAL numbers.
A limited verion of MAP could possibly be done using longs and where none of the values are negative.
The function below should work (within limits). If any calculation results in a negative number the results will be wrong.
Last edit: William Roth 2016-06-30
Looks to me like you may simply be trying to scale an ADC from 10 bits to 8 bits. Where a value of 0-1023 is scaled to a value of 0- 255.
If this is the case, just divide by the 10 bit ADC value by 4.
Last edit: William Roth 2016-06-30
Hi William, thanks for that example. I will give it a try and report back. As this will work well with the 10 bit ADC, I am using it with a MSGEQ7. The output from the MSEQ7 ranges from 0 to 255 on the 8 bit pic ADC, from about 0 to 70 or so is noise. I am driving some DMX RGB light units and want to remap the output from the MSGEQ7 from 70 to 255 to 0 to 255. I noticed a lot of arduino code that does this and it allows for a better range on the lights. Won't be using negative numbers here so hopefully this will be a good solution. Something like this...
EqValue(Zz) = Map (EqValue(Zz), 70, 255, 0, 255)
Last edit: viscomjim 2016-06-30
You do not have to use a negative number to have an errant result.
Consider the function math.
For example: IF the starting "value" is 65 then ....
Since the function does not handle negative numbers .... (65 - 70) will result in an underflow and return a value of "65531" instead of "-5". This will cause the function to return an unexpected value of 90,396
So the input value will need to be constrained to > or = to InMin to prevent this underflow. The Function then becomes:
These maths take time that you may not have for fast response. This is why a lookup may be a better option.
Edit: The speed is not a bad as I thought it might be. It takes the function above about 218 microseconds to complete with a PIC operating at 32Mhz. I tested on a PIC16F1788
Last edit: William Roth 2016-07-03
After looking at a lot of arduino code, it seems like people use the "constrain" function quite a bit with the use of the map function. I made a "version" of this so I could do some testing to see if it solves some problems. This is what I came up with, although it probably could be done better. I'm not quite up to par yet with all the tricks yet so don't laugh...
Not sure how to make this prettier without the else if type statement. I will give your enhanced map function a whirl also. I appreciate your time William!
Lots of calculations being done with very little time to refresh the display from the MSGEQ7. Here are my thoughts:
1. Build a table with a spreadsheet based on the math required to remap the values.
2. Reading tables is kinda slow, so when initializing the code before main, read the table into a large buffer variable (i.e. SRAM).
Now you've got a super quick way to get from MSGEQ7 value to a DMX PWM value out. Extra points if you convert the logarithmic brightness perception of the eye to a linear scale. See gamma correction.
Hi Kent, running the pic at 20Mhz I can read the 7 values of the MSGEQ7, do some stuff with that data and spit out 24 DMX values (8 x 3) to an 8 channel RGB decoder pretty quickly. I am pretty amazed at the speed of these little buggers. It seems like there is plenty of time to spare also. Great Cow Basic is quite amazing! I have a very limited setup right now as I am "babysitting" at my sister's house for a while to help her out. I put together a nice little breadboard setup with a laptop that I can transport back and forth easily. Innovation at it's best...