繁体   English   中英

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

[英]Mapping a range of values to another

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

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

sensor_value = 256
actuator_value = translate(sensor_value, 1, 512, 5, 10)

在此示例中,我希望 output actuator_value7.5 ,因为sensor_value处于可能输入范围的中间。

一种解决方案是:

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)

您可能会使用代数来提高效率,但会降低可读性。

使用scipy.interpolate.interp1d

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

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

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

>>> float(m(256))
7.4951076320939336

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

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

另外,您可以从一个范围到另一个范围进行非均匀映射,例如,如果要映射[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

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

使用numpy.interp

〜unutbu所述numpy.interp也是一个选项(具有较少的依赖项):

>>> from numpy import interp
>>> interp(256,[1,512],[5,10])
7.4951076320939336

实际上,这对于创建闭包是一个很好的情况,即编写一个返回函数的函数。 由于您可能有很多这样的值,因此对于每个值计算和重新计算这些值的跨度和因数,或者就此而言,始终不超过最小/最大限制,就没有什么价值。

相反,请尝试以下操作:

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

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

# 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]
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

简单 map 范围 function:

def mapRange(value, inMin, inMax, outMin, outMax):
    return outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin))

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

我最终变得非常简单。

变量:

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

功能:

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

用法:

dyn111.goal_position=mapFromTo(pos111,0,300,0,1024)
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]

https://rosettacode.org/wiki/Map_range#Python_中找到

  • 不会将转换后的值限制在ab范围内(推断)
  • from_lower > from_upperto_lower > to_upper时也起作用

所有现有的答案都在 CC BY-SA 许可下。 这是我写的; 在法律允许的范围内,我放弃此代码的所有版权或相关和相邻权利。 知识共享 CC0 公共领域贡献)

def remap(number, from_min, from_max, to_min, to_max):                         
    number_s = number - from_min
    from_max_s = from_max - from_min
    to_max_s = to_max - to_min
    return ((number_s / from_max_s) * to_max_s) + to_min

您可以使用 lambda function

translate = lambda a, b, c, d, e: (a - b) * (e - d) / (c - b) + d
sensor_value = 256
translate(sensor_value, 1, 512, 5, 10)
>> 7.495107632093934

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM