Scaling number ranges

Often when dealing with numbers, it is desired to be able to scale them to a different range. This is especially the case when using sensor or motor values.

For a while I just always hacked together something that would work for what I needed. For example, if I needed to scale a 10-bit RAW ADC value into a percent, I would multiply by 100 and divide by 1023. That is a very basic case, but things can get to be a lot more complicated. Instead of figuring out a working algorithm every time that would support the values I needed, I decided to make an NXC function that supports every parameter I could need.

Here is the NXC function:

//Scales a range of numbers to a new range.
//Input value, lowest possible, highest possible, scale from this, to this. It returns the result.
float ScaleRange(float Value, float ValueMin, float ValueMax, float DesiredMin, float DesiredMax)
{
  float Result = (DesiredMax - DesiredMin) / (ValueMax - ValueMin) * (Value - ValueMin) + DesiredMin;
  return Result;
}

I haven’t done a lot of testing of it, but it seems to work fine.

Because of it allowing all parameters, you can do some pretty cool things. For example, if you take the RAW value from a PSP-Nx joystick (0-255), you can scale that directly into a motor speed. Take a look at this:
char speed = ScaleRange(PSP_Left_X, 0, 255, -100, 100);
OnFwd(OUT_A, speed);

and if the motor spins the wrong way, you can simply change it to this:
char speed = ScaleRange(PSP_Left_X, 0, 255, 100, -100);
OnFwd(OUT_A, speed);

It doesn’t care which of the values is higher or lower. That means you could scale 0 through 1023 to 200 through -200, and it should work just fine.

As Muntoo pointed out, it can be better to multiply then divide. Here is the updated function:

//Scales a range of numbers to a new range.
//Input value, lowest possible, highest possible, scale from this, to this. It returns the result.
float ScaleRange(float Value, float ValueMin, float ValueMax, float DesiredMin, float DesiredMax)
{
  return (DesiredMax - DesiredMin) * (Value - ValueMin) / (ValueMax - ValueMin) + DesiredMin;
}
Advertisements
This entry was posted in Mindstorms, NXC, NXT and tagged , , , . Bookmark the permalink.

4 Responses to Scaling number ranges

  1. timpattinson says:

    Nice.
    I must remember to use that 😉

  2. muntoo says:

    You should use:

    float ScaleRange(float val, float valmin, float valmax, float toMin, float toMax)
    {
    return((toMax – toMin) * (val – valmin) / (valmax – valmin) + toMin);
    }

    This way, it’s a lot more accurate.

    • mattallen37 says:

      There was a reason I used the extra variable, but it was probably just while testing.

      I don’t think your way is any more accurate. I see what you did, multiply then divide, but with floating point I don’t think it should ever be an issue.

      I will post the more efficient and “better” way, but I would like to keep my original variable names.

      • muntoo says:

        Depends on the range – when it’s 0 to 1024, maybe not. When it’s small ranges like 0.0125 to 0.25, it does matter. (Who knows – maybe someone will try to do that.)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s