将一系列值映射到另一个值

Ten*_*she 55 python algorithm

我正在寻找有关如何在Python中将一个范围值转换为另一个范围值的想法.我正在研究硬件项目,并且正在从可以返回一系列值的传感器读取数据,然后我使用该数据来驱动需要不同范围值的执行器.

例如,假设传感器返回1到512范围内的值,并且执行器由5到10范围内的值驱动.我想要一个函数,我可以传递一个值和两个范围并获取值映射到第二个范围.如果这样的函数被命名,translate它可以像这样使用:

sensor_value = 256
actuator_value = translate(sensor_value, 1, 512, 5, 10)
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我希望输出actuator_value7.5因为sensor_value它位于可能的输入范围的中间.

Ada*_*ers 82

一个解决方案是:

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)
Run Code Online (Sandbox Code Playgroud)

您可以使用代数来提高效率,但会牺牲可读性.

  • 好的解决方案 一个建议是在代码中使用'to'和'from'而不是'left'和'right',这可能令人困惑. (3认同)
  • 简单,有据可查,紧凑,多数民众赞成在一个很好的答案! (2认同)

sas*_*nin 72

使用scipy.interpolate.interp1d

您也可以使用scipy.interpolate包进行此类转换(如果您不介意依赖SciPy):

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

或者从0级scipy数组转换回普通浮点数:

>>> float(m(256))
7.4951076320939336
Run Code Online (Sandbox Code Playgroud)

您还可以轻松地在一个命令中执行多次转换:

>>> m([100,200,300])
array([ 5.96868885,  6.94716243,  7.92563601])
Run Code Online (Sandbox Code Playgroud)

作为奖励,如果要将[1,128]映射到[1,10],[128,256]到[10,90]和[256,512]到[90,100],可以进行从一个范围到另一个范围的非均匀映射.你可以这样做:

>>> m = interp1d([1,128,256,512],[1,10,90,100])
>>> float(m(400))
95.625
Run Code Online (Sandbox Code Playgroud)

interp1d 创建分段线性插值对象(可以像函数一样调用).

使用numpy.interp

正如~unutbu所指出的,numpy.interp也是一个选项(具有较少的依赖性):

>>> from numpy import interp
>>> interp(256,[1,512],[5,10])
7.4951076320939336
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用`numpy.interp(256,[1,512],[5,10])`来减少对numpy的依赖. (24认同)
  • 要将 `array([ 5.96868885, 6.94716243, 7.92563601])` 转换为列表,请使用 `m([100,200,300]).tolist()`。 (2认同)

Pau*_*McG 18

这实际上是创建闭包的一个好例子,即编写一个返回函数的函数.由于您可能拥有许多这些值,因此在计算和重新计算每个值的这些值跨度和因子时几乎没有价值,也无论如何都在一直传递这些最小/最大限制.

相反,试试这个:

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
Run Code Online (Sandbox Code Playgroud)

现在您可以将处理器编写为:

# 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]
Run Code Online (Sandbox Code Playgroud)


小智 10

我在 python 中寻找相同的东西来将角度 0-300deg 映射到原始 dynamixel 值 0-1023 或 1023-0,具体取决于执行器的方向。

我最终变得非常简单。

变量:

x:input value; 
a,b:input range
c,d:output range
y:return value
Run Code Online (Sandbox Code Playgroud)

功能:

def mapFromTo(x,a,b,c,d):
   y=(x-a)/(b-a)*(d-c)+c
   return y
Run Code Online (Sandbox Code Playgroud)

用法:

dyn111.goal_position=mapFromTo(pos111,0,300,0,1024)
Run Code Online (Sandbox Code Playgroud)


Har*_*har 7

简单的地图范围函数:

def mapRange(value, inMin, inMax, outMin, outMax):
    return outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin))
Run Code Online (Sandbox Code Playgroud)


ins*_*get 5

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
Run Code Online (Sandbox Code Playgroud)