Skip to content

Commit 710b6ce

Browse files
committed
Fix ctrlutil.unwrap
New implementation of unwrap() that is faster and better. Also simplify implementation of issys()
1 parent 51536bf commit 710b6ce

2 files changed

Lines changed: 22 additions & 38 deletions

File tree

control/ctrlutil.py

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -42,61 +42,39 @@
4242

4343
# Packages that we need access to
4444
from . import lti
45-
46-
# Specific functions that we use
45+
import numpy as np
4746
from numpy import pi
4847

4948
# Utility function to unwrap an angle measurement
50-
5149
def unwrap(angle, period=2*pi):
5250
"""Unwrap a phase angle to give a continuous curve
5351
5452
Parameters
5553
----------
56-
X : array_like
57-
Input array
58-
period : number
59-
Input period (usually either 2``*``pi or 360)
54+
angle : array_like
55+
Array of angles to be unwrapped
56+
period : float, optional
57+
Period (defaults to `2*pi`)
6058
6159
Returns
6260
-------
63-
Y : array_like
61+
angle_out : array_like
6462
Output array, with jumps of period/2 eliminated
6563
6664
Examples
6765
--------
6866
>>> import numpy as np
69-
>>> X = [5.74, 5.97, 6.19, 0.13, 0.35, 0.57]
70-
>>> unwrap(X, period=2 * np.pi)
67+
>>> theta = [5.74, 5.97, 6.19, 0.13, 0.35, 0.57]
68+
>>> unwrap(theta, period=2 * np.pi)
7169
[5.74, 5.97, 6.19, 6.413185307179586, 6.633185307179586, 6.8531853071795865]
7270
7371
"""
74-
wrap = 0;
75-
last = angle[0];
76-
77-
for k in range(len(angle)):
78-
# See if we need to account for angle wrapping
79-
if (angle[k] - last > period/2):
80-
wrap -= period
81-
elif (last - angle[k] > period/2):
82-
wrap += period
83-
84-
# Update the last value we have sene
85-
last = angle[k]
86-
87-
# Add in the wrap angle if nonzer
88-
if (wrap != 0):
89-
angle[k] += wrap;
90-
91-
# return the updated list
72+
dangle = np.diff(angle)
73+
dangle_desired = (dangle + period/2.) % period - period/2.
74+
correction = np.cumsum(dangle_desired - dangle)
75+
angle[1:] += correction
9276
return angle
9377

94-
# Determine if an object is a system
95-
def issys(object):
96-
# Check for a member of one of the classes that we define here
97-
#! TODO: this should probably look for an LTI object instead??
98-
if (isinstance(object, lti.Lti)):
99-
return True
100-
101-
# Didn't find anything that matched
102-
return False
78+
def issys(obj):
79+
"""Return True if an object is a system, otherwise False"""
80+
return isinstance(obj, lti.Lti)

control/tests/ctrlutil_test.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
class TestUtils(unittest.TestCase):
66
def setUp(self):
77
self.mag = np.array([1, 10, 100, 2, 0.1, 0.01])
8-
self.db = np.array([0, 20, 40, 6.0206, -20, -40])
8+
self.db = np.array([0, 20, 40, 6.0205999, -20, -40])
99

1010
def check_unwrap_array(self, angle, period=None):
1111
if period is None:
@@ -36,6 +36,12 @@ def test_unwrap_large_skips(self):
3636
angle = np.array([0., 4 * np.pi, -2 * np.pi])
3737
np.testing.assert_array_almost_equal(unwrap(angle), [0., 0., 0.])
3838

39+
def test_unwrap_list(self):
40+
angle = [0, 2.2, 5.4, -0.4]
41+
angle_unwrapped = [0, 0.2, 0.4, 0.6]
42+
np.testing.assert_array_almost_equal(unwrap(angle, 1.0), angle_unwrapped)
43+
44+
3945
def test_suite():
4046
return unittest.TestLoader().loadTestsFromTestCase(TestUtils)
4147

0 commit comments

Comments
 (0)