29
29
import copy
30
30
import numpy as np
31
31
from scipy .optimize import curve_fit
32
+ from scipy import __version__ as scipy_version
33
+
32
34
33
35
class Wave_position ():
34
36
def __init__ (self , frequency , time_range , refresh_time = 1 ):
35
37
# frequency: rate of acceleration reading
36
- # time range: readings aquired during this time window are used for predictions (idealy should be a few sea waves)
38
+ # time range: readings acquired during this time window are used for predictions
37
39
# refresh time: how often is prediction function re-trained on the most recent data
38
40
41
+ if ((int (scipy_version .split ('.' )[0 ]) == 0 ) and (int (scipy_version .split ('.' )[1 ]) < 17 )):
42
+ raise Exception ("Your scipy is outdated. Minimal required version is 0.17.0. Your are currently running " + scipy_version )
43
+
39
44
self .period = 1.0 / frequency # period in seconds between each two data points
40
45
# queue is updated every time update func is called.
41
46
self .time_range = time_range # time range captured (size of window for fitting the curve)
42
47
self .refresh_time = refresh_time # after this time new fit is performed
43
48
self .queue = deque ()
49
+ self .required_queue_length = frequency * time_range
44
50
# xdata & ydata are updated in time_range periods
45
51
self .xdata = np .array ([])
46
52
self .ydata = np .array ([])
47
- self .popt = np .array ([])
53
+ self .popt = np .array ([0 , 0 , 0 ])
48
54
self .initializing = True
49
55
self .last_refresh = 0 # time when last refresh occured
50
56
@@ -53,32 +59,37 @@ def update(self, data_point):
53
59
54
60
self .queue .append (data_point )
55
61
if (self .initializing ):
56
- now = time .time ()
57
- if (len (self .queue ) <= 1 ):
58
- self .last_refresh = now
59
- if ((now - self .last_refresh ) >= self .time_range ):
62
+ if (len (self .queue ) >= self .required_queue_length ):
60
63
self .initializing = False
61
64
else :
62
65
# Delete the oldest value to keep the queue size constant.
63
66
self .queue .popleft ()
64
67
now = time .time ()
65
68
if ((now - self .last_refresh ) >= self .refresh_time ):
66
- self .last_refresh = now
67
- # Copy current queue to self.ydata.
68
- self .process_queue ()
69
- # Fit model_func to the data.
70
- self .train ()
71
-
72
-
73
- def model_func (self , x , a , b , c , d ):
74
- return a * (np .cos (b * x + c )) + d
69
+ try :
70
+ # Copy current queue to self.ydata.
71
+ self .process_queue ()
72
+ # Fit model_func to the data.
73
+ self .train ()
74
+ self .last_refresh = now
75
+ except RuntimeError as e :
76
+ print (e )
77
+
78
+ def model_func (self , x , a , b , c ):
79
+ return a * (np .cos (b * x + c )) + np .mean (self .ydata )
75
80
76
81
def train (self ):
77
82
"""
78
83
Fits model_func to self.xdata & self.ydata and saves fit parameters
79
84
to self.popt.
80
85
"""
81
- self .popt , pcov = curve_fit (self .model_func , self .xdata , self .ydata )
86
+ guess_freq = 0.5
87
+ guess_amplitude = 3 * np .std (self .ydata )/ (2 ** 0.5 )
88
+ guess_phase = 0
89
+ p0 = [guess_amplitude , guess_freq , guess_phase ]
90
+
91
+ popt , pcov = curve_fit (f = self .model_func , xdata = self .xdata , ydata = self .ydata , p0 = p0 , bounds = ((0 , 0 , 0 ), (100. , 2. , np .pi )), maxfev = 2000 )
92
+ self .popt = popt
82
93
83
94
def process_queue (self ):
84
95
"""
@@ -100,12 +111,21 @@ def get_position(self):
100
111
(It is relative distance from the last crest.)
101
112
"""
102
113
if (not self .initializing ):
103
- a , b , c , d = self .popt
104
114
pi = np .pi
115
+ amplitude , frequency , phase = self .popt
116
+ last_refresh = self .last_refresh
105
117
now = time .time ()
106
- diff = float (now - self . refresh_time )
107
- cos_inner = float (b * diff + c )
118
+ diff = float (now - last_refresh )
119
+ cos_inner = float (frequency * diff + phase )
108
120
rel_distance = cos_inner / pi - int (cos_inner / pi )
121
+
122
+ # print("frequency: {}".format(frequency))
123
+ # print("diff: {}".format(diff))
124
+ # print("phase: {}".format(phase))
125
+ # print("cos_inner: {}".format(cos_inner))
126
+ # print("rel_distance: {}".format(rel_distance))
127
+ # print("\n")
128
+
109
129
return rel_distance
110
130
else :
111
131
return "initializing"
@@ -121,17 +141,26 @@ def get_position(self):
121
141
# np.random.seed(1729)
122
142
# y_noise = 0.2 * np.random.normal(size=self.xdata.size)
123
143
# self.ydata = y + y_noise
124
- #
125
- # def plot(self):
144
+
145
+ # def plot_all(self):
146
+ # import matplotlib.pyplot as plt
147
+ # plt.plot(self.xdata, self.ydata, 'b*', label='training data')
148
+ # plt.plot(self.xdata, self.model_func(self.xdata, *self.popt), 'r+', label='predicted')
149
+ # plt.legend(loc=0)
150
+ # plt.show()
151
+
152
+ # def plot_training_data(self):
126
153
# import matplotlib.pyplot as plt
127
- # plt.plot(self.xdata, self.ydata, 'b*', label='data')
128
- # plt.plot(self.xdata, self.model_func(self.xdata, *self.popt), 'r+')
154
+ # plt.plot(self.xdata, self.ydata, 'b*')
129
155
# plt.show()
130
- #
156
+
131
157
# def print_vars(self):
132
158
# print("period: {}\n".format(self.period))
133
159
# print("time_range: {}\n".format(self.time_range))
134
160
# print("refresh_time: {}\n".format(self.refresh_time))
161
+ # print("queue size: {}\n".format(len(self.queue)))
162
+ # print("xdata size: {}\n".format(len(self.xdata)))
163
+ # print("ydata size: {}\n".format(len(self.ydata)))
135
164
# print("queue: {}\n".format(self.queue))
136
165
# print("xdata: {}\n".format(self.xdata))
137
166
# print("ydata: {}\n".format(self.ydata))
0 commit comments