c4dynamics 2.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- c4dynamics/__init__.py +240 -0
- c4dynamics/datasets/__init__.py +95 -0
- c4dynamics/datasets/_manager.py +596 -0
- c4dynamics/datasets/_registry.py +80 -0
- c4dynamics/detectors/__init__.py +37 -0
- c4dynamics/detectors/yolo3_opencv.py +686 -0
- c4dynamics/detectors/yolo3_tf.py +124 -0
- c4dynamics/eqm/__init__.py +324 -0
- c4dynamics/eqm/derivs.py +212 -0
- c4dynamics/eqm/integrate.py +359 -0
- c4dynamics/filters/__init__.py +1373 -0
- c4dynamics/filters/a.py +48 -0
- c4dynamics/filters/ekf.py +320 -0
- c4dynamics/filters/kalman.py +725 -0
- c4dynamics/filters/kalman_v0.py +1071 -0
- c4dynamics/filters/kalman_v1.py +821 -0
- c4dynamics/filters/lowpass.py +123 -0
- c4dynamics/filters/luenberger.py +97 -0
- c4dynamics/rotmat/__init__.py +141 -0
- c4dynamics/rotmat/animate.py +465 -0
- c4dynamics/rotmat/rotmat.py +351 -0
- c4dynamics/sensors/__init__.py +72 -0
- c4dynamics/sensors/lineofsight.py +78 -0
- c4dynamics/sensors/radar.py +740 -0
- c4dynamics/sensors/seeker.py +1030 -0
- c4dynamics/states/__init__.py +327 -0
- c4dynamics/states/lib/__init__.py +320 -0
- c4dynamics/states/lib/datapoint.py +660 -0
- c4dynamics/states/lib/pixelpoint.py +776 -0
- c4dynamics/states/lib/rigidbody.py +677 -0
- c4dynamics/states/state.py +1486 -0
- c4dynamics/utils/__init__.py +44 -0
- c4dynamics/utils/_struct.py +6 -0
- c4dynamics/utils/const.py +130 -0
- c4dynamics/utils/cprint.py +80 -0
- c4dynamics/utils/gen_gif.py +142 -0
- c4dynamics/utils/idx2keys.py +4 -0
- c4dynamics/utils/images_loader.py +63 -0
- c4dynamics/utils/math.py +136 -0
- c4dynamics/utils/plottools.py +140 -0
- c4dynamics/utils/plottracks.py +304 -0
- c4dynamics/utils/printpts.py +36 -0
- c4dynamics/utils/slides_gen.py +64 -0
- c4dynamics/utils/tictoc.py +167 -0
- c4dynamics/utils/video_gen.py +300 -0
- c4dynamics/utils/vidgen.py +182 -0
- c4dynamics-2.0.3.dist-info/METADATA +242 -0
- c4dynamics-2.0.3.dist-info/RECORD +50 -0
- c4dynamics-2.0.3.dist-info/WHEEL +5 -0
- c4dynamics-2.0.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import sys
|
|
3
|
+
sys.path.append('.')
|
|
4
|
+
# import c4dynamics as c4d
|
|
5
|
+
from c4dynamics.utils.const import *
|
|
6
|
+
from c4dynamics.utils.math import *
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def rotx(phi):
|
|
10
|
+
'''
|
|
11
|
+
Generate a 3x3 Direction Cosine Matrix for
|
|
12
|
+
a positive rotation about the x-axis by an angle :math:`\\phi` in radians.
|
|
13
|
+
|
|
14
|
+
A right-hand rotation matrix about `x` is given by:
|
|
15
|
+
|
|
16
|
+
.. math::
|
|
17
|
+
|
|
18
|
+
R = \\begin{bmatrix}
|
|
19
|
+
1 & 0 & 0 \\\\
|
|
20
|
+
0 & cos(\\varphi) & sin(\\varphi) \\\\
|
|
21
|
+
0 & -sin(\\varphi) & cos(\\varphi)
|
|
22
|
+
\\end{bmatrix}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
phi : float or int
|
|
29
|
+
The angle of rotation in radians.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
out : numpy.array
|
|
34
|
+
A 3x3 rotation matrix representing the rotation about the x-axis.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
|
|
40
|
+
>>> rotx(0) # doctest: +NUMPY_FORMAT
|
|
41
|
+
[[1 0 0]
|
|
42
|
+
[0 1 0]
|
|
43
|
+
[0 0 1]]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
>>> rotx(c4d.pi / 2) # doctest: +NUMPY_FORMAT
|
|
47
|
+
[[1 0 0]
|
|
48
|
+
[0 0 1]
|
|
49
|
+
[0 -1 0]]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
>>> v1 = [0, 0, 1]
|
|
53
|
+
>>> phi = 90 * c4d.d2r
|
|
54
|
+
>>> rotx(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
55
|
+
[0 1 0]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
>>> phi = 45 * c4d.d2r
|
|
59
|
+
>>> rotx(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
60
|
+
[0 0.707 0.707]
|
|
61
|
+
|
|
62
|
+
'''
|
|
63
|
+
return np.array([[1, 0, 0], [0, cos(phi), sin(phi)], [0, -sin(phi), cos(phi)]])
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def roty(theta):
|
|
67
|
+
'''
|
|
68
|
+
Generate a 3x3 Direction Cosine Matrix for
|
|
69
|
+
a positive rotation about the y-axis by an angle :math:`\\theta` in radians.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
A right-hand rotation matrix about `y` is given by:
|
|
74
|
+
|
|
75
|
+
.. math::
|
|
76
|
+
|
|
77
|
+
R = \\begin{bmatrix}
|
|
78
|
+
cos(\\theta) & 0& -sin(\\theta) \\\\
|
|
79
|
+
0 & 1 & 0 \\\\
|
|
80
|
+
sin(\\theta) & 0 & cos(\\theta)
|
|
81
|
+
\\end{bmatrix}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
theta : float or int
|
|
87
|
+
The angle of rotation in radians.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
out : numpy.array
|
|
92
|
+
A 3x3 rotation matrix representing the rotation about the y-axis.
|
|
93
|
+
|
|
94
|
+
Examples
|
|
95
|
+
--------
|
|
96
|
+
|
|
97
|
+
>>> roty(0) # doctest: +NUMPY_FORMAT
|
|
98
|
+
[[1 0 0]
|
|
99
|
+
[0 1 0]
|
|
100
|
+
[0 0 1]]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
>>> roty(c4d.pi / 2) # doctest: +NUMPY_FORMAT
|
|
104
|
+
[[0 0 -1]
|
|
105
|
+
[0 1 0]
|
|
106
|
+
[1 0 0]]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
>>> v1 = [0, 0, 1]
|
|
110
|
+
>>> phi = 90 * c4d.d2r
|
|
111
|
+
>>> roty(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
112
|
+
[-1 0 0]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
>>> phi = 45 * c4d.d2r
|
|
116
|
+
>>> roty(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
117
|
+
[-0.707 0 0.707]
|
|
118
|
+
|
|
119
|
+
'''
|
|
120
|
+
return np.array([[cos(theta), 0, -sin(theta)], [0, 1, 0], [sin(theta), 0, cos(theta)]])
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def rotz(psi):
|
|
124
|
+
'''
|
|
125
|
+
Generate a 3x3 Direction Cosine Matrix for
|
|
126
|
+
a positive rotation about the z-axis by an angle :math:`\\psi` in radians.
|
|
127
|
+
|
|
128
|
+
A right-hand rotation matrix about `y` is given by:
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
.. math::
|
|
132
|
+
|
|
133
|
+
R = \\begin{bmatrix}
|
|
134
|
+
cos(\\psi) & sin(\\psi) & 0 \\\\
|
|
135
|
+
-sin(\\psi) & cos(\\psi) & 0 \\\\
|
|
136
|
+
0 & 0 & 1
|
|
137
|
+
\\end{bmatrix}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
psi : float or int
|
|
144
|
+
The angle of rotation in radians.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
out : numpy.array
|
|
149
|
+
A 3x3 rotation matrix representing the rotation about the z-axis.
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
|
|
154
|
+
>>> rotz(0) # doctest: +NUMPY_FORMAT
|
|
155
|
+
[[1 0 0]
|
|
156
|
+
[0 1 0]
|
|
157
|
+
[0 0 1]]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
>>> rotz(c4d.pi / 2) # doctest: +NUMPY_FORMAT
|
|
161
|
+
[[0 1 0]
|
|
162
|
+
[-1 0 0]
|
|
163
|
+
[0 0 1]]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
>>> v1 = [0.707, 0.707, 0]
|
|
167
|
+
>>> phi = 90 * c4d.d2r
|
|
168
|
+
>>> rotz(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
169
|
+
[0.707 -0.707 0]
|
|
170
|
+
|
|
171
|
+
>>> phi = 45 * c4d.d2r
|
|
172
|
+
>>> rotz(phi) @ v1 # doctest: +NUMPY_FORMAT
|
|
173
|
+
[1 0 0]
|
|
174
|
+
|
|
175
|
+
'''
|
|
176
|
+
return np.array([[cos(psi), sin(psi), 0], [-sin(psi), cos(psi), 0], [0, 0, 1]])
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def dcm321(phi = 0.0, theta = 0.0, psi = 0.0):
|
|
180
|
+
'''
|
|
181
|
+
Generate a 3x3 Direction Cosine Matrix (DCM) for a sequence of
|
|
182
|
+
positive rotations around the axes in the following order:
|
|
183
|
+
:math:`z`, then :math:`y`, then :math:`x`.
|
|
184
|
+
|
|
185
|
+
The final form of the matrix is given by:
|
|
186
|
+
|
|
187
|
+
.. math::
|
|
188
|
+
|
|
189
|
+
R = \\begin{bmatrix}
|
|
190
|
+
c\\theta \\cdot c\\psi
|
|
191
|
+
& c\\theta \\cdot s\\psi
|
|
192
|
+
& -s\\theta \\\\
|
|
193
|
+
s\\varphi \\cdot s\\theta \\cdot c\\psi - c\\varphi \\cdot s\\psi
|
|
194
|
+
& s\\varphi \\cdot s\\theta \\cdot s\\psi + c\\varphi \\cdot c\\psi
|
|
195
|
+
& s\\varphi \\cdot c\\theta \\\\
|
|
196
|
+
c\\varphi \\cdot s\\theta \\cdot c\\psi + s\\varphi \\cdot s\\psi
|
|
197
|
+
& c\\varphi \\cdot s\\theta \\cdot s\\psi - s\\varphi \\cdot c\\psi
|
|
198
|
+
& c\\varphi \\cdot c\\theta
|
|
199
|
+
\\end{bmatrix}
|
|
200
|
+
|
|
201
|
+
where
|
|
202
|
+
|
|
203
|
+
- :math:`c\\varphi \\equiv cos(\\varphi)`
|
|
204
|
+
- :math:`s\\varphi \\equiv sin(\\varphi)`
|
|
205
|
+
- :math:`c\\theta \\equiv cos(\\theta)`
|
|
206
|
+
- :math:`s\\theta \\equiv sin(\\theta)`
|
|
207
|
+
- :math:`c\\psi \\equiv cos(\\psi)`
|
|
208
|
+
- :math:`s\\psi \\equiv sin(\\psi)`
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
phi : float or int
|
|
215
|
+
The angle in radian of rotation about `x`, default :math:`\\phi = 0`.
|
|
216
|
+
theta : float or int
|
|
217
|
+
The angle in radian of rotation about `y`, default :math:`\\theta = 0`.
|
|
218
|
+
psi : float or int
|
|
219
|
+
The angle in radian of rotation about `z`, default :math:`\\psi = 0`.
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
out : numpy.array
|
|
224
|
+
3x3 Direction Cosine Matrix representing the combined rotation.
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
Examples
|
|
228
|
+
--------
|
|
229
|
+
|
|
230
|
+
The inertial velocity vector of an aircraft expressed in an inertial earth frame is given by:
|
|
231
|
+
|
|
232
|
+
>>> v = [150, 0, 0]
|
|
233
|
+
|
|
234
|
+
The attitude of the aircraft with respect to the inertial earth frame is
|
|
235
|
+
given by the 3 Euler angles:
|
|
236
|
+
|
|
237
|
+
.. math::
|
|
238
|
+
|
|
239
|
+
\\phi = 0
|
|
240
|
+
|
|
241
|
+
\\theta = 30 \\cdot {\\pi \\over 180}
|
|
242
|
+
|
|
243
|
+
\\psi = 0
|
|
244
|
+
|
|
245
|
+
The velcoty expressed in body frame:
|
|
246
|
+
|
|
247
|
+
>>> dcm321(phi = 0, theta = 30 * c4d.d2r, psi = 0) @ v # doctest: +NUMPY_FORMAT
|
|
248
|
+
[129.9 0 75]
|
|
249
|
+
|
|
250
|
+
'''
|
|
251
|
+
return rotx(phi) @ roty(theta) @ rotz(psi)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def dcm321euler(dcm):
|
|
255
|
+
'''
|
|
256
|
+
Extract Euler angles (roll, pitch, yaw) from a Direction Cosine Matrix (DCM) of 3-2-1 order.
|
|
257
|
+
|
|
258
|
+
The form of a 3-2-1 rotation matrix:
|
|
259
|
+
|
|
260
|
+
.. math::
|
|
261
|
+
|
|
262
|
+
R = \\begin{bmatrix}
|
|
263
|
+
c\\theta \\cdot c\\psi
|
|
264
|
+
& c\\theta \\cdot s\\psi
|
|
265
|
+
& -s\\theta \\\\
|
|
266
|
+
s\\varphi \\cdot s\\theta \\cdot c\\psi - c\\varphi \\cdot s\\psi
|
|
267
|
+
& s\\varphi \\cdot s\\theta \\cdot s\\psi - c\\varphi \\cdot c\\psi
|
|
268
|
+
& s\\varphi \\cdot c\\theta \\\\
|
|
269
|
+
s\\varphi \\cdot s\\theta \\cdot s\\psi + s\\varphi \\cdot s\\psi
|
|
270
|
+
& s\\varphi \\cdot s\\theta \\cdot s\\psi - s\\varphi \\cdot c\\psi
|
|
271
|
+
& c\\varphi \\cdot c\\theta
|
|
272
|
+
\\end{bmatrix}
|
|
273
|
+
|
|
274
|
+
where
|
|
275
|
+
|
|
276
|
+
- :math:`c\\varphi \\equiv cos(\\varphi)`
|
|
277
|
+
- :math:`s\\varphi \\equiv sin(\\varphi)`
|
|
278
|
+
- :math:`c\\theta \\equiv cos(\\theta)`
|
|
279
|
+
- :math:`s\\theta \\equiv sin(\\theta)`
|
|
280
|
+
- :math:`c\\psi \\equiv cos(\\psi)`
|
|
281
|
+
- :math:`s\\psi \\equiv sin(\\psi)`
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
dcm : numpy.array
|
|
287
|
+
3x3 Direction Cosine Matrix representing a rotation.
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
out : tuple
|
|
292
|
+
A tuple containing Euler angles (yaw, pitch, roll) in degrees.
|
|
293
|
+
|
|
294
|
+
Notes
|
|
295
|
+
-----
|
|
296
|
+
Each set of Euler angles has a geometric singularity where
|
|
297
|
+
two angles are not uniquely defined.
|
|
298
|
+
It is always the second angle which defines this singular orientation:
|
|
299
|
+
|
|
300
|
+
- Symmetric Set: 2nd angle is 0 or 180 degrees. For example the 3-1-3 orbit angles with zero inclination.
|
|
301
|
+
- Asymmetric Set: 2nd angle is ±90 degrees. For example, the 3-2-1 angle of an aircraft with 90 degrees pitch.
|
|
302
|
+
|
|
303
|
+
Examples
|
|
304
|
+
--------
|
|
305
|
+
|
|
306
|
+
>>> dcm321euler(np.eye(3)) # doctest: +NUMPY_FORMAT
|
|
307
|
+
(0, 0, 0)
|
|
308
|
+
|
|
309
|
+
A rotation matrix that represents the attitude of an aircraft with respect to
|
|
310
|
+
an inertial earth frame is given by:
|
|
311
|
+
|
|
312
|
+
>>> BI = np.array([[ 0.866, 0, -0.5 ]
|
|
313
|
+
... , [ 0, 1, 0 ]
|
|
314
|
+
... , [ 0.5, 0, 0.866 ]])
|
|
315
|
+
>>> dcm321euler(BI) # doctest: +NUMPY_FORMAT
|
|
316
|
+
(0, 30, 0)
|
|
317
|
+
|
|
318
|
+
'''
|
|
319
|
+
|
|
320
|
+
psi = atan2(dcm[0, 1], dcm[0, 0]) * r2d
|
|
321
|
+
theta = -asin(dcm[0, 2]) * r2d
|
|
322
|
+
phi = atan2(dcm[1, 2], dcm[2, 2]) * r2d
|
|
323
|
+
|
|
324
|
+
return phi, theta, psi
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
if __name__ == "__main__":
|
|
329
|
+
|
|
330
|
+
import doctest, contextlib, os
|
|
331
|
+
from c4dynamics import IgnoreOutputChecker, cprint
|
|
332
|
+
|
|
333
|
+
# Register the custom OutputChecker
|
|
334
|
+
doctest.OutputChecker = IgnoreOutputChecker
|
|
335
|
+
|
|
336
|
+
tofile = False
|
|
337
|
+
optionflags = doctest.FAIL_FAST
|
|
338
|
+
|
|
339
|
+
if tofile:
|
|
340
|
+
with open(os.path.join('tests', '_out', 'output.txt'), 'w') as f:
|
|
341
|
+
with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f):
|
|
342
|
+
result = doctest.testmod(optionflags = optionflags)
|
|
343
|
+
else:
|
|
344
|
+
result = doctest.testmod(optionflags = optionflags)
|
|
345
|
+
|
|
346
|
+
if result.failed == 0:
|
|
347
|
+
cprint(os.path.basename(__file__) + ": all tests passed!", 'g')
|
|
348
|
+
else:
|
|
349
|
+
print(f"{result.failed}")
|
|
350
|
+
|
|
351
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'''
|
|
2
|
+
|
|
3
|
+
`c4dynamics` provides sensor models to simulate real world applications.
|
|
4
|
+
The models include the functionality and the errors model
|
|
5
|
+
of electro-optic, lasers, and electro-magnetic devices.
|
|
6
|
+
|
|
7
|
+
'''
|
|
8
|
+
#
|
|
9
|
+
# i think maybe to include also detectors in this module
|
|
10
|
+
# and rename it to something like perception \ source \ input
|
|
11
|
+
# measures \
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
sys.path.append('.')
|
|
16
|
+
|
|
17
|
+
from c4dynamics.sensors.radar import radar
|
|
18
|
+
from c4dynamics.sensors.lineofsight import lineofsight
|
|
19
|
+
from c4dynamics.sensors.seeker import seeker
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Background Material
|
|
23
|
+
# -------------------
|
|
24
|
+
|
|
25
|
+
# Introduction
|
|
26
|
+
# ^^^^^^^^^^^^
|
|
27
|
+
# '''
|
|
28
|
+
|
|
29
|
+
# seekers:
|
|
30
|
+
# matter:
|
|
31
|
+
# radar
|
|
32
|
+
# laser
|
|
33
|
+
# optic
|
|
34
|
+
# functionallity:
|
|
35
|
+
# altitude radar
|
|
36
|
+
# lineofsight seeker
|
|
37
|
+
|
|
38
|
+
# sensors:
|
|
39
|
+
# imu
|
|
40
|
+
# accelerometers
|
|
41
|
+
# roll gyro
|
|
42
|
+
# rate gyro
|
|
43
|
+
# gps
|
|
44
|
+
# lidar
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
|
|
50
|
+
import doctest, contextlib, os
|
|
51
|
+
from c4dynamics import IgnoreOutputChecker, cprint
|
|
52
|
+
|
|
53
|
+
# Register the custom OutputChecker
|
|
54
|
+
doctest.OutputChecker = IgnoreOutputChecker
|
|
55
|
+
|
|
56
|
+
tofile = False
|
|
57
|
+
optionflags = doctest.FAIL_FAST
|
|
58
|
+
|
|
59
|
+
if tofile:
|
|
60
|
+
with open(os.path.join('tests', '_out', 'output.txt'), 'w') as f:
|
|
61
|
+
with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f):
|
|
62
|
+
result = doctest.testmod(optionflags = optionflags)
|
|
63
|
+
else:
|
|
64
|
+
result = doctest.testmod(optionflags = optionflags)
|
|
65
|
+
|
|
66
|
+
if result.failed == 0:
|
|
67
|
+
cprint(os.path.basename(__file__) + ": all tests passed!", 'g')
|
|
68
|
+
else:
|
|
69
|
+
print(f"{result.failed}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
import c4dynamics as c4d
|
|
4
|
+
|
|
5
|
+
# np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning)
|
|
6
|
+
|
|
7
|
+
class lineofsight:
|
|
8
|
+
'''
|
|
9
|
+
Line of Sight seeker.
|
|
10
|
+
|
|
11
|
+
the lineofsight is measure line of sight vector rate
|
|
12
|
+
the seeker head lags the true angular rate.
|
|
13
|
+
this lag is represented by a first order transfer function with time constant tau1
|
|
14
|
+
there are assumed to be delays involved in processing the seeker head angular rate singal.
|
|
15
|
+
the filter delays are represented by a first order transfer function with time constant tau2
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
==========
|
|
19
|
+
TODO complete
|
|
20
|
+
|
|
21
|
+
Example
|
|
22
|
+
=======
|
|
23
|
+
TODO complete
|
|
24
|
+
|
|
25
|
+
'''
|
|
26
|
+
|
|
27
|
+
tau1 = 0
|
|
28
|
+
tau2 = 0
|
|
29
|
+
dt = 0
|
|
30
|
+
|
|
31
|
+
isideal = False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
omega = np.array([0, 0, 0]) # truth los rate
|
|
35
|
+
omega_ach = np.array([0, 0, 0]) # achieved los rate after first order filter
|
|
36
|
+
omega_f = np.array([0, 0, 0]) # filtered los rate after first order filter
|
|
37
|
+
|
|
38
|
+
_data = np.zeros((1, 7))
|
|
39
|
+
|
|
40
|
+
def __init__(obj, dt, tau1 = 0.05, tau2 = 0.05, isideal = False): #**kwargs):
|
|
41
|
+
# obj.__dict__.update(kwargs)
|
|
42
|
+
obj.dt = dt
|
|
43
|
+
obj.tau1 = tau1 # tracking loop time constant
|
|
44
|
+
obj.tau2 = tau2 # seeker signal processing time constant
|
|
45
|
+
obj.isideal = isideal
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def measure(obj, r, v):
|
|
49
|
+
# r: range to target (line of sight vector)
|
|
50
|
+
# v: relative velocity with target
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# true angular rate of the los vector
|
|
54
|
+
##
|
|
55
|
+
obj.omega = np.cross(r, v) / np.linalg.norm(r)**2
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# achieved seeker-head angular rate vector
|
|
59
|
+
##
|
|
60
|
+
obj.omega_ach = obj.omega_ach * np.exp(-obj.dt / obj.tau1) + obj.omega * (1 - np.exp(-obj.dt / obj.tau1)) # lag
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# final processed tracking rate signal vector
|
|
64
|
+
##
|
|
65
|
+
obj.omega_f = obj.omega_f * np.exp(-obj.dt / obj.tau2) + obj.omega_ach * (1 - np.exp(-obj.dt / obj.tau2)) # filter
|
|
66
|
+
|
|
67
|
+
if obj.isideal:
|
|
68
|
+
obj.omega_f = obj.omega_ach = obj.omega
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
return obj.omega_f
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def store(obj, t = -1):
|
|
75
|
+
obj._data = np.vstack((obj._data
|
|
76
|
+
, np.concatenate(([t], obj.omega, obj.omega_f)))).copy()
|
|
77
|
+
|
|
78
|
+
|