[英]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_value
为7.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
包进行此类转换(如果您不介意对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
创建分段线性插值对象(可像函数一样调用)。
如〜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_中找到
a
或b
范围内(推断) from_lower > from_upper
或to_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.