Подтвердить что ты не робот

Отображение диапазона значений для другого

Я ищу идеи о том, как перевести значения одного диапазона в другой в Python. Я работаю над аппаратным проектом и считываю данные с датчика, который может возвращать диапазон значений. Затем я использую эти данные для управления приводом, для которого требуется другой диапазон значений.

Например, скажем, что датчик возвращает значения в диапазоне от 1 до 512, а привод управляется значениями в диапазоне от 5 до 10. Я хотел бы, чтобы функция могла передавать значение и два диапазона и получать верните значение, отображаемое во второй диапазон. Если такая функция была названа translate, ее можно было бы использовать следующим образом:

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

В этом примере я ожидал бы, что вывод actuator_value будет 7.5, так как sensor_value находится в середине возможного диапазона ввода.

4b9b3361

Ответ 1

Одно из решений:

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)

Вы могли бы использовать алгебру, чтобы сделать ее более эффективной, за счет удобочитаемости.

Ответ 2

Использование scipy.interpolate.interp1d

Вы также можете использовать пакет scipy.interpolate для выполнения таких преобразований (если вы не против зависимости от SciPy):

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

или преобразовать его обратно в обычный float из 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

Ответ 3

Это действительно хороший пример для создания замыкания, то есть запись функции, возвращающей функцию. Поскольку у вас, вероятно, есть многие из этих значений, мало что нужно для вычисления и пересчета этих значений и коэффициентов значения для каждого значения и, при этом, для ограничения этих пределов min/max все время.

Вместо этого попробуйте следующее:

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]

Ответ 4

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

Ответ 5

Я искал одно и то же в 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)

Ответ 6

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_

  • не привязывает преобразованные значения к указанному диапазону (экстраполирует)
  • также работает, когда from_lower > from_upper или to_lower > to_upper