Circular interpolation in Python -


i have 2 systems, each of has direction sensor (0-360 degrees), sensors can provide wildly different values depending on orientation of each system , linearity of each sensor. have mechanical reference can use generate table of each system pointing. yields table 3 columns:

physical  systema  systemb --------  -------  -------  000.0     005.7    182.3  005.0     009.8    178.4  ...       ...      ... 

from data shown, can see systema isn't far physical reference, systemb 180 degrees off, , goes in opposite direction (imagine mounted upside-down).

i need able map , forth between 3 values: if systema reports @ 105.7, need tell user physical direction is, tell systemb point same location. same if systemb makes initial report. , user can request both systems point desired physical direction, systema , systemb need told point.

linear interpolation isn't hard, i'm having trouble when data going in opposite directions, , modular/cyclical.

is there pythonic way these mappings?


edit: let's focus on difficult case, have 2 paired lists of values:

a        b -----    -----   0.0    182.5  10.0    172.3  20.0    161.4  ...      ... 170.0      9.7 180.0    359.1 190.0    348.2  ...      ... 340.0    163.6 350.0    171.8 

let's lists come 2 different radars pointers aren't aligned north or else, did manually take above data moving target around , seeing each radar had point see it.

when radar says "i have target @ 123.4!", need aim radar b see it? if radar b finds target, tell radar point?

list wraps between last , first elements, list b wraps nearer middle of list. list increases monotonically, while list b decreases monotonically. notice size of degree on not same size degree on b.

is there simple interpolator wrap correctly when:

  1. interpolating list list b.

  2. interpolating list b list a.

it ok use 2 separate interpolator instantiations, 1 going in each direction. i'll assume linear (first-order) interpolator ok, may want use higher-order or spline interpolation in future.

some test cases:

  • a = 356.7, b = ?

  • a = 179.2, b = ?

this works me. use clean-up.

class interpolatedarray(object):     """ array-like object provides interpolated values between set points.     """     points = none     wrap_value = none     offset = none      def _mod_delta(self, a, b):         """ perform difference within modular domain.             return value in range +/- wrap_value/2.         """         limit = self.wrap_value / 2.         val = - b         if val < -limit: val += self.wrap_value         elif val > limit: val -= self.wrap_value         return val      def __init__(self, points, wrap_value=none):         """initialization of interpolatedarray instance.          parameter 'points' list of two-element tuples, each of maps         input value output value.  list not need sorted.          optional parameter 'wrap_value' used when domain closed,         indicate both input , output domains wrap.  example,         table of degree values provide 'wrap_value' of 360.0.          after sorting, wrapped domain's output values must monotonic         in either positive or negative direction.          tables don't wrap, attempts interpolate values outside         input range cause valueerror exception.         """         if wrap_value none:             points.sort()   # sort in-place on first element of each tuple         else:   # force values positive modular range             points = sorted([(p[0]%wrap_value, p[1]%wrap_value) p in points])             # wrapped domains must monotonic, positive or negative             monotonic = [points[x][1] < points[x+1][1] x in xrange(0,len(points)-1)]             num_pos_steps = monotonic.count(true)             num_neg_steps = monotonic.count(false)             if num_pos_steps > 1 , num_neg_steps > 1: # allow 1 wrap point                 raise valueerror("table wrapped domains must monotonic.")         self.wrap_value = wrap_value         # pre-compute inter-value slopes         self.x_list, self.y_list = zip(*points)         if wrap_value none:             intervals = zip(self.x_list, self.x_list[1:], self.y_list, self.y_list[1:])             self.slopes = [(y2 - y1)/(x2 - x1) x1, x2, y1, y2 in intervals]         else:   # create modular slopes, including wrap element             x_rot = list(self.x_list[1:]); x_rot.append(self.x_list[0])             y_rot = list(self.y_list[1:]); y_rot.append(self.y_list[0])             intervals = zip(self.x_list, x_rot, self.y_list, y_rot)             self.slopes = [self._mod_delta(y2, y1)/self._mod_delta(x2, x1) x1, x2, y1, y2 in intervals]      def __getitem__(self, x):       # works indexing operator []         result = none         if self.wrap_value none:             if x < self.x_list[0] or x > self.x_list[-1]:                 raise valueerror('input value out-of-range: %s'%str(x))             = bisect.bisect_left(self.x_list, x) - 1             result = self.y_list[i] + self.slopes[i] * (x - self.x_list[i])         else:             x %= self.wrap_value             = bisect.bisect_left(self.x_list, x) - 1             result = self.y_list[i] + self.slopes[i] * self._mod_delta(x, self.x_list[i])             result %= self.wrap_value         return result 

and test:

import nose  def xfrange(start, stop, step=1.):     """ floating point equivalent xrange()."""     while start < stop:         yield start         start += step  # test simple inverted mapping non-wrapped domain pts = [(x,-x) x in xfrange(1.,16., 1.)] = interpolatedarray(pts) in xfrange(1., 15., 0.1):     nose.tools.assert_almost_equal(a[i], -i) # cause expected over/under range errors result = false  # assume failure try: x = a[0.5] except valueerror: result = true assert result result = false try: x = a[15.5] except valueerror: result = true assert result  # test simple wrapped domain wrap = 360. offset = 1.234 pts = [(x,((wrap/2.) - x)) x in xfrange(offset, wrap+offset, 10.)] = interpolatedarray(pts, wrap) in xfrange(0.5, wrap, 0.1):     nose.tools.assert_almost_equal(a[i], (((wrap/2.) - i)%wrap)) 

Comments

Popular posts from this blog

android - getbluetoothservice() called with no bluetoothmanagercallback -

sql - ASP.NET SqlDataSource, like on SelectCommand -

ios - Undefined symbols for architecture armv7: "_OBJC_CLASS_$_SSZipArchive" -