Mapping a range of values to another

前端 未结 6 2211
谎友^
谎友^ 2020-11-28 02:39

I am looking for ideas on how to translate one range values to another in Python. I am working on hardware project and am reading data from a sensor that can return a range

相关标签:
6条回答
  • 2020-11-28 02:54
    def translate(sensor_val, in_from, in_to, out_from, out_to):
        out_range = out_to - out_from
        in_range = in_to - in_from
        in_val = sensor_val - in_from
        val=(float(in_val)/in_range)*out_range
        out_val = out_from+val
        return out_val
    
    0 讨论(0)
  • 2020-11-28 02:55

    One solution would be:

    def translate(value, leftMin, leftMax, rightMin, rightMax):
        # Figure out how 'wide' each range is
        leftSpan = leftMax - leftMin
        rightSpan = rightMax - rightMin
    
        # Convert the left range into a 0-1 range (float)
        valueScaled = float(value - leftMin) / float(leftSpan)
    
        # Convert the 0-1 range into a value in the right range.
        return rightMin + (valueScaled * rightSpan)
    

    You could possibly use algebra to make it more efficient, at the expense of readability.

    0 讨论(0)
  • 2020-11-28 02:55

    This would actually be a good case for creating a closure, that is write a function that returns a function. Since you probably have many of these values, there is little value in calculating and recalculating these value spans and factors for every value, nor for that matter, in passing those min/max limits around all the time.

    Instead, try this:

    def make_interpolater(left_min, left_max, right_min, right_max): 
        # Figure out how 'wide' each range is  
        leftSpan = left_max - left_min  
        rightSpan = right_max - right_min  
    
        # Compute the scale factor between left and right values 
        scaleFactor = float(rightSpan) / float(leftSpan) 
    
        # create interpolation function using pre-calculated scaleFactor
        def interp_fn(value):
            return right_min + (value-left_min)*scaleFactor
    
        return interp_fn
    

    Now you can write your processor as:

    # create function for doing interpolation of the desired
    # ranges
    scaler = make_interpolater(1, 512, 5, 10)
    
    # receive list of raw values from sensor, assign to data_list
    
    # now convert to scaled values using map 
    scaled_data = map(scaler, data_list)
    
    # or a list comprehension, if you prefer
    scaled_data = [scaler(x) for x in data_list]
    
    0 讨论(0)
  • 2020-11-28 03:02

    I was looking for the same thing in python to map angles 0-300deg to raw dynamixel values 0-1023, or 1023-0 depending on the actuator orientations.

    I ended up going very simple.

    Variables:

    x:input value; 
    a,b:input range
    c,d:output range
    y:return value
    

    Function:

    def mapFromTo(x,a,b,c,d):
       y=(x-a)/(b-a)*(d-c)+c
       return y
    

    Usage:

    dyn111.goal_position=mapFromTo(pos111,0,300,0,1024)
    
    0 讨论(0)
  • 2020-11-28 03:04

    Using scipy.interpolate.interp1d

    You can also use scipy.interpolate package to do such conversions (if you don't mind dependency on SciPy):

    >>> from scipy.interpolate import interp1d
    >>> m = interp1d([1,512],[5,10])
    >>> m(256)
    array(7.4951076320939336)
    

    or to convert it back to normal float from 0-rank scipy array:

    >>> float(m(256))
    7.4951076320939336
    

    You can do also multiple conversions in one command easily:

    >>> m([100,200,300])
    array([ 5.96868885,  6.94716243,  7.92563601])
    

    As a bonus, you can do non-uniform mappings from one range to another, for intance if you want to map [1,128] to [1,10], [128,256] to [10,90] and [256,512] to [90,100] you can do it like this:

    >>> m = interp1d([1,128,256,512],[1,10,90,100])
    >>> float(m(400))
    95.625
    

    interp1d creates piecewise linear interpolation objects (which are callable just like functions).

    Using numpy.interp

    As noted by ~unutbu, numpy.interp is also an option (with less dependencies):

    >>> from numpy import interp
    >>> interp(256,[1,512],[5,10])
    7.4951076320939336
    
    0 讨论(0)
  • 2020-11-28 03:12
    def maprange(a, b, s):
        (a1, a2), (b1, b2) = a, b
        return  b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
    
    
    a = [from_lower, from_upper]
    b = [to_lower, to_upper]
    

    found at https://rosettacode.org/wiki/Map_range#Python_

    • does not clamp the transformed values to the ranges a or b (it extrapolates)
    • also works when from_lower > from_upper or to_lower > to_upper
    0 讨论(0)
提交回复
热议问题