programing tip

값 범위를 다른 값에 매핑

itbloger 2021. 1. 5. 07:48
반응형

값 범위를 다른 값에 매핑


Python에서 한 범위 값을 다른 범위 값으로 변환하는 방법에 대한 아이디어를 찾고 있습니다. 저는 하드웨어 프로젝트를 진행 중이며 값 범위를 반환 할 수있는 센서에서 데이터를 읽고 있습니다. 그런 다음 해당 데이터를 사용하여 다른 값 범위가 필요한 액추에이터를 구동합니다.

예를 들어 센서가 1 ~ 512 범위의 값을 반환하고 액추에이터는 5 ~ 10 범위의 값에 의해 구동된다고 가정 해 보겠습니다. 값과 두 범위를 전달하고 값을 반환 할 수있는 함수를 원합니다. 두 번째 범위에 매핑됩니다. 이러한 함수의 이름이 지정되면 다음과 translate같이 사용할 수 있습니다.

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

이 예에서는가 가능한 입력 범위의 중간에 있기 때문에 출력 actuator_value이 될 것으로 예상합니다 .7.5sensor_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로 다시 변환하려면 :

>>> 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에 매핑하려는 경우 intance에 대해 한 범위에서 다른 범위로 불균일 한 매핑을 수행 할 수 있습니다. ] 다음과 같이 할 수 있습니다.

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

액추에이터 방향에 따라 0-300deg 각도를 원시 다이나믹 셀 값 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

ReferenceURL : https://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another

반응형