<div align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/utils/C4dynamics.png">
</div>
# Tsipor Dynamics
## Algorithms Engineering and Development
****
C4Dynamics (read Tsipor (bird) Dynamics) is the open-source framework of algorithms development for objects in space and time.
[![My Skills](https://skillicons.dev/icons?i=python)](https://skillicons.dev)
## Table of contents
- [Motivation](https://github.com/C4dynamics/C4dynamics/tree/main/#motivation)
- [Installation](https://github.com/C4dynamics/C4dynamics/tree/main/#installation)
- [Quickstart](https://github.com/C4dynamics/C4dynamics/tree/main/#quickstart)
- [Architecture](https://github.com/C4dynamics/C4dynamics/tree/main/#architecture)
- [Contributors ✨](https://github.com/C4dynamics/C4dynamics/tree/main/#contributors-✨)
- [Quickstart for Contributors](https://github.com/C4dynamics/C4dynamics/tree/main/#quickstart-for-contributors)
- [Getting Started 1: Objects Detection and Tracking Example](https://github.com/C4dynamics/C4dynamics/tree/main/#getting-started-1-objects-detection-and-tracking-example)
- [Getting Started 2: Missile Guidance Example](https://github.com/C4dynamics/C4dynamics/tree/main/#getting-started-2-missile-guidance-example)
## Motivation
C4dynamics provides two basic entities for developing and analyzing algorithms of objects in space and time:
* datapoint: a class defining a point in space: position, velocity, acceleration, and mass.
* rigidbody: a class defining a rigid body in space, i.e. an object with length and angular position.
You can develop and analyze algorithms by operating on these objects with one of the internal systems or algorithms of C4dynamics:
* ODE Solver (4th order Runge-Kutta)
* Kalman Filter
* Extended Kalman Filter
* Luenberger Observer
* Radar System
* Altitude Radar
* IMU Model
* GPS Model
* Line Of Sight Seeker
Or one of the 3rd party libraries integrated with C4dynamics:
* NumPy
* Matplotlib
* OpenCV
* YOLO
Whether you're a seasoned algorithm engineer or just getting started, this framework has something to offer. Its modular design allows you to easily pick and choose the components you need, and its active community of contributors is always working to improve and expand its capabilities.
So why wait? Start using C4dynamics today and take your algorithms engineering to the next level!
## Installation
* Download C4dynamics: https://github.com/C4dynamics/C4dynamics
* Install the required packages:
```
pip install -r requirements.txt
```
* Alternatively, run the preinstalled conda environment (see conda_installation.md):
```
conda env create -f c4dynamics_env.yaml
```
## Quickstart
Import the framework:
```
import C4dynamics as c4d
```
Define a point in space with some initial conditions:
```
pt = c4d.datapoint(x = 1000, vx = 100)
```
Define a body in space with some initial conditions:
```
body = c4d.rigidbody(theta = 15 * 3.14 / 180)
```
Load an object detection module (YOLO):
```
yolodet = c4d.detectors.yolo(height = height, width = width)
```
Define a linear Kalman Filter, perform a prediction and an update:
```
pt.filter = c4d.filters.kalman(np.hstack((z, np.zeros(2))), P, A, H, Q, R)
pt.filter.predict()
pt.filter.correct(measure)
```
Store the current state of the datapoint (at time t):
```
pt.store(t)
```
Store other variables added to the datapoint object:
```
pt.storevar('kalman_state', t)
```
Define errors to a general-purpose seeker with C4dynamics:
```
rdr = c4d.seekers.radar(sf = 0.9, bias = 0, noisestd = 1)
```
## Architecture
For Architecture & Roadmap, see the Wiki page.
## Contributors ✨
[//]: contributor-faces
<a href="https://www.linkedin.com/in/ziv-meri/"> <img src="https://github.com/C4dynamics/C4dynamics/raw/main/utils/ziv_noa2.png" title="Ziv Meri" width="80" height="80"></a>
<a href="https://www.linkedin.com/in/aviva-shneor-simhon-17b733b/"> <img src="https://github.com/C4dynamics/C4dynamics/blob/main/utils/aviva2.png" title="Aviva Shneor Simhon" width="80" height="80"></a>
<a href="https://www.linkedin.com/in/amit-elbaz-54301382/"> <img src="https://github.com/C4dynamics/C4dynamics/blob/main/utils/amit2.png" title="Amit Elbaz" width="80" height="80"></a>
<a href="https://www.linkedin.com/in/avraham-ohana-computer-vision/"> <img src="https://github.com/C4dynamics/C4dynamics/blob/main/utils/avraham2.png" title="Avraham Ohana" width="80" height="80"></a>
<a href="https://chat.openai.com/chat"> <img src="https://github.com/C4dynamics/C4dynamics/blob/main/utils/openai-featured.png" title="Chat GPT" width="80" height="80"></a>
[//]: contributor-faces
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## Quickstart for Contributors
* See the page contributing.md
* In any case, it's a good advise to start with the example dof6sim.ipynb and change the missile-target conditions to gain some experience with the framework. This example appears also down here in the README
## Getting Started 1: Objects Detection and Tracking Example
### Car Detection and Tracking with YOLO and Kalman Filter using C4dynamics
see the notebook: examples\cars_tracker.ipynb
This is an example of detecting vehicles in images using YOLO, and then tracking those detected cars using a Kalman filter.
For the demonstration, we will be using a dataset of traffic surveillance videos. The dataset contains video sequences recorded from a traffic camera, capturing various vehicles including cars.
#### Let's start!
* Load 3rd party modules:
```
import numpy as np
import cv2
from sklearn.neighbors import NearestNeighbors
from matplotlib import pyplot as plt
from matplotlib import image as mpimg
```
* Load the vidoes:
```
videoin = os.path.join(os.getcwd(), 'examples', 'cars1.mp4')
videoout = os.path.join(os.getcwd(), 'examples', 'out', 'cars1.mp4')
```
* Video preprocessing:
```
video = cv2.VideoCapture(videoin)
dt = 1 / video.get(cv2.CAP_PROP_FPS)
_, frame1 = video.read()
height, width, _ = frame1.shape
result = cv2.VideoWriter(videoout, cv2.VideoWriter_fourcc(*'mp4v')
, int(video.get(cv2.CAP_PROP_FPS)), [width, height])
```
```
plt.imshow(mpimg.imread(os.path.join(os.getcwd(), 'examples', 'out', 'before.png')))
plt.axis('off')
plt.show()
```
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars1.png?raw=true" width="325" height="260"/>
</p>
* Load a detector:
```
yolodet = c4d.detectors.yolo(height = height, width = width)
```
* Define Kalman parameters:
```
# x(t) = A(t) * x(t-1) + e(t) || e(t) ~ N(0,Q(t))
# z(t) = H(t) * x(t) + r(t) || r(t) ~ N(0,R(t))
# x(t) = [x1 y1 x2 y2 vx vy]
A = np.array([[1, 0, 0, 0, dt, 0 ]
, [0, 1, 0, 0, 0, dt]
, [0, 0, 1, 0, dt, 0 ]
, [0, 0, 0, 1, 0, dt]
, [0, 0, 0, 0, 1, 0 ]
, [0, 0, 0, 0, 0, 1 ]])
H = np.array([[1, 0, 0, 0, 0, 0]
, [0, 1, 0, 0, 0, 0]
, [0, 0, 1, 0, 0, 0]
, [0, 0, 0, 1, 0, 0]])
P = np.eye(A.shape[1])
Q = np.array([[25, 0, 0, 0, 0, 0]
, [0, 25, 0, 0, 0, 0]
, [0, 0, 25, 0, 0, 0]
, [0, 0, 0, 25, 0, 0]
, [0, 0, 0, 0, 49, 0]
, [0, 0, 0, 0, 0, 49]])
R = dt * np.eye(4)
```
* Define data-point object
Tracker = data-point + Kalman Filter
```
class tracker(c4d.datapoint):
# a datapoint
# kalman filter
# display color
##
def __init__(obj, z):
super().__init__() # Call the constructor of c4d.datapoint
obj.filter = c4d.filters.kalman(np.hstack((z, np.zeros(2))), P, A, H, Q, R)
obj.counterSame = 0
obj.counterEscaped = 0
obj.appear = 0
obj.color = [np.random.randint(0, 255)
, np.random.randint(0, 255)
, np.random.randint(0, 255)]
```
* Define trackers manager:
(a dictionary of trackers and methods to add and remove elements)
```
# trackers manager:
# list of active trackers
# add or remove tracks methods
class mTracks:
def __init__(obj):
obj.trackers = {}
obj.removelist = []
obj.neigh = NearestNeighbors(n_neighbors = 1)
obj.thresh = 100 # threshold of 100 pixels to verify the measure is close enough to the object.
```
* Main loop:
```
def run(tf = 1):
mtracks = mTracks()
cov = 25 * np.eye(4)
t = 0
while video.isOpened():
ret, frame = video.read()
# frame = frame.astype(np.uint8)
# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Assuming input frames are in BGR format
if not ret:
break
#
# the update function runs the main trackers loop.
##
zList = yolodet.getMeasurements(frame) # retrieves object measurements from the current frame using the object detector (YoloDetector).
# updates the trackers dictionary by adding or removing tracks.
# creates new trackers if there are more
# measurements than trackers and removes duplicate trackers if
# there are more trackers than measurements.
kfNumber = len(mtracks.trackers.keys())
zNumber = zList.shape[0]
if kfNumber < zNumber:
# more measurements than trackers
mtracks.trackerMaker(zList, cov)
elif kfNumber > zNumber and zNumber > 0:
# more trackers than measurements
mtracks.RemoveDoubles()
# fits the Nearest Neighbors algorithm to the object
# measurements for association purposes.
if zList.shape[0] >= 2:
mtracks.neigh.fit(zList)
mtracks.refresh(zList, frame, t)
mtracks.remove()
cv2.imshow('image', frame)
result.write(frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q') or t >= tf:
break
t += dt
cv2.destroyAllWindows()
result.release()
return mtracks
```
* Run for two seconds:
```
ltrk = run(tf = 2)
```
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_objected_tracked.gif?raw=true" width="325" height="260"/>
</p>
* Results analysis:
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_id.png?raw=true" width="325" height="260"/>
</p>
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_trajectories.png?raw=true" width="325" height="260"/>
</p>
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_velocity.png?raw=true" width="325" height="260"/>
</p>
## Getting Started 2: Missile Guidance Example
### 6 DOF simulation of a missile employing proportional navigation guidance to pursue a target.
#### Let's start:
* Load third party modules
```
import sys, os
import numpy as np
from matplotlib import pyplot as plt
```
* Add C4dynamics to the python path and load it
```
sys.path.append(os.path.join(os.getcwd(), '..', '..'))
import C4dynamics as c4d
```
* Load other modules that developed for the demonstration of current example
```
import control_system as mcontrol_system
import engine as mengine
import aerodynamics as maerodynamics
```
* Configure figure properties
```
plt.rcParams['figure.figsize'] = (5.0, 4.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
```
* Simulation setup
```
t = 0
dt = 5e-3
tf = 10
```
* Objects definition
```
target = c4d.datapoint(x = 4000, y = 1000, z = -3000
, vx = -250, vy = 0, vz = 0)\n
```
The target is a datapoint object which means it has all the attributes of a mass in space:
Position: target.x, target.y, target.z
Velocity: target.vx, target.vy, target.vz
Acceleration: target.ax, target.ay, target.az
It also has mass: target.m (necessary for solving the equations of motion in the case of accelerating motion)
The target object in the example is initialized with initial position conditions in 3 axes and velocity conditions in the x-axis only. Acceleration is not initialized which is equivalent to zero initialization (default).
As the target in the example is non-accelerating it is not necessary to provide the mass with its instantiation.
```
missile = c4d.rigidbody(m = 85, iyy = 61, izz = 61, xcm = 1.55)
m0 = missile.m
xcm0 = missile.xcm
i0 = missile.iyy
```
The missile is a rigid-body object which means that it has all the attributes of a datapoint but in addition:
Body angles: missile.phi, missile.theta, missile.psi (Euler)
Angular rates: missile.p, missile.q, missile.r (rotation about x-body, y-body, and z-body, respectively)
Angular accelerations: missile.p_dot, missile.q_dot, missile.r_dot (about x-body, y-body, and z-body, respectively)
As a rigid-body object it has also inertia attributes (necessary for solving the equations of motion in the case of accelerating motion):
Moment of inertia: missile.ixx, missile.iyy, missile.izz (about x-body, y-body, and z-body, respectively)
Distance from nose to center of mass: missile.xcm
The missile kinematic attributes in this example have not initialized with any initial conditions which mean that all its attributes are zero. But the mass properties provided as necessary.
However, we will immediately see that the missile has initial kinematic conditions which are loaded through direct assignment and not by the class constructor (c4d.rigidbody()).
As the dynamics in this example involves a combustion of fuel of the rocket engine the missile’s mass attributes varying as function of time. To recalculate the mass during the run time it's a good advice to save these initial conditions. As iyy and izz are equal here it's enough to save just one of them.
In any way the initial position and attitude of anybody object (datapoint and rigid-body) is always saved with its instantiation
The dimensions in this example are SI (i.e. seconds, meters, kilograms), but the objects and functions in the framework in general are independent of system of units.
The example uses a line-of-sight seeker object from the c4dynamics' seekers module and controller, engine, and aerodynamics objects that developed for the purpose of this example:
```
seeker = c4d.seekers.lineofsight(dt, tau1 = 0.01, tau2 = 0.01)
ctrl = mcontrol_system.control_system(dt)
eng = mengine.engine()
aero = maerodynamics.aerodynamics()
```
* User input data:
```
#
# missile total initial velocity
##
vm = 30
#
# atmospheric properties up to 2000m
##
pressure = 101325 # pressure pascals
rho = 1.225 # density kg/m^3
vs = 340.29 # speed of sound m/s
mach = 0.8
#
# combustion properties
##
mbo = 57 # burnout mass, kg
xcmbo = 1.35 # nose to cm after burnout, m
ibo = 47 # iyy izz at burnout
```
* Preliminary calculations
The initial missile pointing direction and angular rates are calculated in the fire-control block.
For the example simulation, a simple algorithm is employed in which the missile is pointed directly at the target at the instant of launch, and missile angular rates at launch are assumed to be negligible.
The unit vector in the direction from the missile to the target is calculated by normalizing the range vector.
```
rTM = target.pos() - missile.pos()
ucl = rTM / np.linalg.norm(rTM) # center line unit vector
missile.vx, missile.vy, missile.vz = vm * ucl
missile.psi = np.arctan(ucl[1] / ucl[0])
missile.theta = np.arctan(-ucl[2] / np.sqrt(ucl[0]**2 + ucl[1]**2))
missile.phi = 0
alpha = 0
beta = 0
alpha_total = 0
h = -missile.z
```
The function missile.BI() is bounded method of the rigid-body class.
The function generates a Body from Inertial DCM (Direction Cosine Matrix) matrix in 3-2-1 order.
Using this matrix, the missile velocity vector in the inertial frame of coordinates is rotated to represent the velocity in the body frame of coordinates.
The inertial frame is determined by the frame that the initial Euler angles refer to.
In this example the Euler angles are with respect the x parallel to flat earth in the direction of the missile centerline, z positive downward, and y such that z completes a right-hand system.
The velocity vector is also produced by a bounded method of the class. The methods datapoint.pos(), datapoint.vel(), datapoint.acc() read the current state of the object and return a three entries array composed of the coordinates of position, velocity, and acceleration, respectively.
Similarly, the functions datapoint.P(), datapoint.V(), datapoint.A() return the object squared norm of the position, velocity, and acceleration, respectively.
```
u, v, w = missile.BI() @ missile.vel()
```
* Main loop
The main loop includes the following steps:
* Estimation of missile-target line-of-sight angular rate
* Production of missile's wings-deflection commands
* Calculation of missile's forces and moments
* Integration of missile's equations of motion
* Integration of target's equations of motion
* Simulation update
The simulation runs until one of the following conditions:
* The missile hits the ground
* The simulation time is over
Comments are introduced inline.
The missile.run() function and the target.run() function perform integration of the equations of motion.
The integration is performed by running Runge-Kutta of fourth order.
For a datapoint, the equations are composed of translational equations, while for a datapoint they also include the rotational equations.
Therefore, for a datapoint object, like the target in this example, a force vector is necessary for the evaluation of the derivatives. The force must be given in the inertial frame of reference. As the target in this example is not maneuvering, the force vector is [0, 0, 0].
For a rigid-body object, like the missile in this example, a force vector and moment vector are necessary for the evaluation of the derivatives. The force vector must be given in the inertial frame of reference. Therefore, the propulsion, and the aerodynamic forces are rotated to the inertial frame using the DCM321 missile.IB() function. The gravity forces are already given in the inertial frame and therefore remain intact.
Forces and moments in the inertial frame are introduced to provide an estimation of the derivatives that represent the equations of motion. The integration method, 4th order Runge-Kutta is performed manually and independent on any third-party framework (such as scipy), therefore, currently, they may be non-optimal in terms of step-size variation.
The choice of this is due to a feature which this framework desires to satisfy in which derivatives of two objects (such as missile and target) could be integrated simultaneously, with reciprocal dependent.
Hopefully, later the function will be also optimized in terms of run-time and step-size variation.
```
while t <= tf and h >= 0:
#
# atmospheric calculations
##
mach = missile.V() / vs # mach number
Q = 1 / 2 * rho * missile.V()**2 # dynamic pressure
#
# relative position
##
vTM = target.vel() - missile.vel() # missile-target relative velocity
rTM = target.pos() - missile.pos() # relative position
uR = rTM / np.linalg.norm(rTM) # unit range vector
vc = -uR * vTM # closing velocity
#
# seeker
##
wf = seeker.measure(rTM, vTM) # filtered los vector
#
# guidance and control
##
Gs = 4 * missile.V() # guidance gain
acmd = Gs * np.cross(wf, ucl) # acceleration command
ab_cmd = missile.BI() @ acmd # acc. command in body frame
afp, afy = ctrl.update(ab_cmd, Q) # acchived pithc, yaw fins deflections
d_pitch = afp - alpha # effecive pitch deflection
d_yaw = afy - beta # effective yaw deflection
#
# missile dynamics
##
#
# aerodynamic forces
##
cL, cD = aero.f_coef(alpha_total)
L = Q * aero.s * cL
D = Q * aero.s * cD
A = D * np.cos(alpha_total) - L * np.sin(alpha_total) # aero axial force
N = D * np.sin(alpha_total) + L * np.cos(alpha_total) # aero normal force
fAb = np.array([ -A
, N * (-v / np.sqrt(v**2 + w**2))
, N * (-w / np.sqrt(v**2 + w**2))])
fAe = missile.IB() @ fAb
#
# aerodynamic moments
##
cM, cN = aero.m_coef(alpha, beta, d_pitch, d_yaw
, missile.xcm, Q, missile.V(), fAb[1], fAb[2]
, missile.q, missile.r)
mA = np.array([0 # aerodynamic moemnt in roll
, Q * cM * aero.s * aero.d # aerodynamic moment in pitch
, Q * cN * aero.s * aero.d]) # aerodynamic moment in yaw
#
# propulsion
##
thrust, thref = eng.update(t, pressure)
fPb = np.array([thrust, 0, 0])
fPe = missile.IB() @ fPb
#
# gravity
##
fGe = np.array([0, 0, missile.m * c4d.params.g])
#
# total forces
##
forces = np.array([fAe[0] + fPe[0] + fGe[0]
, fAe[1] + fPe[1] + fGe[1]
, fAe[2] + fPe[2] + fGe[2]])
#
# missile motion integration
##
missile.run(dt, forces, mA)
u, v, w = missile.BI() @ np.array([missile.vx, missile.vy, missile.vz])
#
# target dynmaics
##
target.run(dt, np.array([0, 0, 0]))
#
# update
##
t += dt
missile.store(t)
target.store(t)
missile.m -= thref * dt / eng.Isp
missile.xcm = xcm0 - (xcm0 - xcmbo) * (m0 - missile.m) / (m0 - mbo)
missile.izz = missile.iyy = i0 - (i0 - ibo) * (m0 - missile.m) / (m0 - mbo)
alpha = np.arctan2(w, u)
beta = np.arctan2(-v, u)
uvm = missile.vel() / missile.V()
ucl = np.array([np.cos(missile.theta) * np.cos(missile.psi)
, np.cos(missile.theta) * np.sin(missile.psi)
, np.sin(-missile.theta)])
alpha_total = np.arccos(uvm @ ucl)
h = -missile.z
```
* Results Analysis
<!-- <p align="center">
<img src="" width="325" height="260"/>
</p>
-->
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/trajectories.png" width="325" height="260"/>
</p>
```
missile.draw('theta')
```
</p>
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/theta.png?raw=true" width="325" height="260"/>
</p>
```
target.draw('vx')
```
<p align="center">
<img src="https://github.com/C4dynamics/C4dynamics/blob/main/examples/vx.png?raw=true" width="325" height="260"/>
</p>
Raw data
{
"_id": null,
"home_page": "",
"name": "C4dynamics",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "python,dynamics,physics,algorithms,computer vision,navigation",
"author": "C4dynamics",
"author_email": "zivmeri@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/62/7a/e2a6a260f792bc810575dcdb2a6cffb670df32abb6633469dc1a465fdfa5/C4dynamics-0.0.15.tar.gz",
"platform": null,
"description": "\r\n<div align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/utils/C4dynamics.png\">\r\n\r\n</div>\r\n\r\n\r\n\r\n# Tsipor Dynamics\r\n\r\n## Algorithms Engineering and Development\r\n\r\n****\r\n\r\n\r\n\r\n\r\n\r\nC4Dynamics (read Tsipor (bird) Dynamics) is the open-source framework of algorithms development for objects in space and time.\r\n\r\n\r\n\r\n[![My Skills](https://skillicons.dev/icons?i=python)](https://skillicons.dev) \r\n\r\n\r\n\r\n\r\n\r\n## Table of contents\r\n\r\n- [Motivation](https://github.com/C4dynamics/C4dynamics/tree/main/#motivation)\r\n\r\n- [Installation](https://github.com/C4dynamics/C4dynamics/tree/main/#installation)\r\n\r\n- [Quickstart](https://github.com/C4dynamics/C4dynamics/tree/main/#quickstart)\r\n\r\n- [Architecture](https://github.com/C4dynamics/C4dynamics/tree/main/#architecture)\r\n\r\n- [Contributors \u2728](https://github.com/C4dynamics/C4dynamics/tree/main/#contributors-\u2728)\r\n\r\n- [Quickstart for Contributors](https://github.com/C4dynamics/C4dynamics/tree/main/#quickstart-for-contributors)\r\n\r\n- [Getting Started 1: Objects Detection and Tracking Example](https://github.com/C4dynamics/C4dynamics/tree/main/#getting-started-1-objects-detection-and-tracking-example)\r\n\r\n- [Getting Started 2: Missile Guidance Example](https://github.com/C4dynamics/C4dynamics/tree/main/#getting-started-2-missile-guidance-example)\r\n\r\n\r\n\r\n\r\n\r\n## Motivation\r\n\r\nC4dynamics provides two basic entities for developing and analyzing algorithms of objects in space and time:\r\n\r\n* datapoint: a class defining a point in space: position, velocity, acceleration, and mass. \r\n\r\n* rigidbody: a class defining a rigid body in space, i.e. an object with length and angular position. \r\n\r\n\r\n\r\nYou can develop and analyze algorithms by operating on these objects with one of the internal systems or algorithms of C4dynamics: \r\n\r\n* ODE Solver (4th order Runge-Kutta) \r\n\r\n* Kalman Filter \r\n\r\n* Extended Kalman Filter \r\n\r\n* Luenberger Observer \r\n\r\n* Radar System \r\n\r\n* Altitude Radar \r\n\r\n* IMU Model \r\n\r\n* GPS Model \r\n\r\n* Line Of Sight Seeker \r\n\r\n \r\n\r\nOr one of the 3rd party libraries integrated with C4dynamics: \r\n\r\n* NumPy \r\n\r\n* Matplotlib \r\n\r\n* OpenCV \r\n\r\n* YOLO \r\n\r\n \r\n\r\nWhether you're a seasoned algorithm engineer or just getting started, this framework has something to offer. Its modular design allows you to easily pick and choose the components you need, and its active community of contributors is always working to improve and expand its capabilities.\r\n\r\n \r\n\r\nSo why wait? Start using C4dynamics today and take your algorithms engineering to the next level!\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Installation \r\n\r\n* Download C4dynamics: https://github.com/C4dynamics/C4dynamics\r\n\r\n\r\n\r\n* Install the required packages:\r\n\r\n```\r\n\r\npip install -r requirements.txt\r\n\r\n```\r\n\r\n\r\n\r\n* Alternatively, run the preinstalled conda environment (see conda_installation.md):\r\n\r\n```\r\n\r\nconda env create -f c4dynamics_env.yaml\r\n\r\n```\r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n\r\n\r\n## Quickstart\r\n\r\nImport the framework:\r\n\r\n```\r\n\r\nimport C4dynamics as c4d\r\n\r\n```\r\n\r\n\r\n\r\nDefine a point in space with some initial conditions: \r\n\r\n```\r\n\r\npt = c4d.datapoint(x = 1000, vx = 100)\r\n\r\n```\r\n\r\n\r\n\r\nDefine a body in space with some initial conditions: \r\n\r\n```\r\n\r\nbody = c4d.rigidbody(theta = 15 * 3.14 / 180)\r\n\r\n```\r\n\r\n\r\n\r\nLoad an object detection module (YOLO):\r\n\r\n```\r\n\r\nyolodet = c4d.detectors.yolo(height = height, width = width)\r\n\r\n```\r\n\r\n\r\n\r\nDefine a linear Kalman Filter, perform a prediction and an update: \r\n\r\n```\r\n\r\npt.filter = c4d.filters.kalman(np.hstack((z, np.zeros(2))), P, A, H, Q, R)\r\n\r\npt.filter.predict()\r\n\r\npt.filter.correct(measure)\r\n\r\n```\r\n\r\n\r\n\r\nStore the current state of the datapoint (at time t):\r\n\r\n```\r\n\r\npt.store(t)\r\n\r\n```\r\n\r\n\r\n\r\nStore other variables added to the datapoint object:\r\n\r\n```\r\n\r\npt.storevar('kalman_state', t)\r\n\r\n```\r\n\r\n\r\n\r\nDefine errors to a general-purpose seeker with C4dynamics: \r\n\r\n```\r\n\r\nrdr = c4d.seekers.radar(sf = 0.9, bias = 0, noisestd = 1)\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Architecture\r\n\r\nFor Architecture & Roadmap, see the Wiki page. \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Contributors \u2728\r\n\r\n\r\n\r\n[//]: contributor-faces\r\n\r\n<a href=\"https://www.linkedin.com/in/ziv-meri/\"> <img src=\"https://github.com/C4dynamics/C4dynamics/raw/main/utils/ziv_noa2.png\" title=\"Ziv Meri\" width=\"80\" height=\"80\"></a>\r\n\r\n<a href=\"https://www.linkedin.com/in/aviva-shneor-simhon-17b733b/\"> <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/utils/aviva2.png\" title=\"Aviva Shneor Simhon\" width=\"80\" height=\"80\"></a>\r\n\r\n<a href=\"https://www.linkedin.com/in/amit-elbaz-54301382/\"> <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/utils/amit2.png\" title=\"Amit Elbaz\" width=\"80\" height=\"80\"></a>\r\n\r\n<a href=\"https://www.linkedin.com/in/avraham-ohana-computer-vision/\"> <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/utils/avraham2.png\" title=\"Avraham Ohana\" width=\"80\" height=\"80\"></a>\r\n\r\n<a href=\"https://chat.openai.com/chat\"> <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/utils/openai-featured.png\" title=\"Chat GPT\" width=\"80\" height=\"80\"></a>\r\n\r\n\r\n\r\n[//]: contributor-faces\r\n\r\n\r\n\r\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Quickstart for Contributors\r\n\r\n* See the page contributing.md\r\n\r\n* In any case, it's a good advise to start with the example dof6sim.ipynb and change the missile-target conditions to gain some experience with the framework. This example appears also down here in the README\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Getting Started 1: Objects Detection and Tracking Example\r\n\r\n### Car Detection and Tracking with YOLO and Kalman Filter using C4dynamics\r\n\r\n\r\n\r\nsee the notebook: examples\\cars_tracker.ipynb\r\n\r\n\r\n\r\nThis is an example of detecting vehicles in images using YOLO, and then tracking those detected cars using a Kalman filter. \r\n\r\n\r\n\r\nFor the demonstration, we will be using a dataset of traffic surveillance videos. The dataset contains video sequences recorded from a traffic camera, capturing various vehicles including cars.\r\n\r\n\r\n\r\n#### Let's start!\r\n\r\n\r\n\r\n* Load 3rd party modules:\r\n\r\n```\r\n\r\nimport numpy as np\r\n\r\nimport cv2\r\n\r\nfrom sklearn.neighbors import NearestNeighbors\r\n\r\nfrom matplotlib import pyplot as plt\r\n\r\nfrom matplotlib import image as mpimg\r\n\r\n```\r\n\r\n\r\n\r\n* Load the vidoes:\r\n\r\n```\r\n\r\nvideoin = os.path.join(os.getcwd(), 'examples', 'cars1.mp4')\r\n\r\nvideoout = os.path.join(os.getcwd(), 'examples', 'out', 'cars1.mp4')\r\n\r\n```\r\n\r\n\r\n\r\n* Video preprocessing:\r\n\r\n```\r\n\r\nvideo = cv2.VideoCapture(videoin)\r\n\r\ndt = 1 / video.get(cv2.CAP_PROP_FPS)\r\n\r\n_, frame1 = video.read()\r\n\r\nheight, width, _ = frame1.shape\r\n\r\nresult = cv2.VideoWriter(videoout, cv2.VideoWriter_fourcc(*'mp4v')\r\n\r\n , int(video.get(cv2.CAP_PROP_FPS)), [width, height])\r\n\r\n```\r\n\r\n\r\n\r\n```\r\n\r\nplt.imshow(mpimg.imread(os.path.join(os.getcwd(), 'examples', 'out', 'before.png')))\r\n\r\nplt.axis('off')\r\n\r\nplt.show()\r\n\r\n```\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars1.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n* Load a detector:\r\n\r\n```\r\n\r\nyolodet = c4d.detectors.yolo(height = height, width = width)\r\n\r\n```\r\n\r\n\r\n\r\n* Define Kalman parameters:\r\n\r\n```\r\n\r\n# x(t) = A(t) * x(t-1) + e(t) || e(t) ~ N(0,Q(t))\r\n\r\n# z(t) = H(t) * x(t) + r(t) || r(t) ~ N(0,R(t))\r\n\r\n\r\n\r\n# x(t) = [x1 y1 x2 y2 vx vy]\r\n\r\n\r\n\r\nA = np.array([[1, 0, 0, 0, dt, 0 ]\r\n\r\n , [0, 1, 0, 0, 0, dt]\r\n\r\n , [0, 0, 1, 0, dt, 0 ]\r\n\r\n , [0, 0, 0, 1, 0, dt]\r\n\r\n , [0, 0, 0, 0, 1, 0 ]\r\n\r\n , [0, 0, 0, 0, 0, 1 ]])\r\n\r\n\r\n\r\nH = np.array([[1, 0, 0, 0, 0, 0]\r\n\r\n , [0, 1, 0, 0, 0, 0]\r\n\r\n , [0, 0, 1, 0, 0, 0]\r\n\r\n , [0, 0, 0, 1, 0, 0]])\r\n\r\n\r\n\r\nP = np.eye(A.shape[1])\r\n\r\n\r\n\r\nQ = np.array([[25, 0, 0, 0, 0, 0]\r\n\r\n , [0, 25, 0, 0, 0, 0]\r\n\r\n , [0, 0, 25, 0, 0, 0]\r\n\r\n , [0, 0, 0, 25, 0, 0]\r\n\r\n , [0, 0, 0, 0, 49, 0]\r\n\r\n , [0, 0, 0, 0, 0, 49]])\r\n\r\n\r\n\r\nR = dt * np.eye(4)\r\n\r\n```\r\n\r\n\r\n\r\n* Define data-point object\r\n\r\nTracker = data-point + Kalman Filter\r\n\r\n\r\n\r\n```\r\n\r\nclass tracker(c4d.datapoint):\r\n\r\n # a datapoint \r\n\r\n # kalman filter \r\n\r\n # display color\r\n\r\n ## \r\n\r\n \r\n\r\n def __init__(obj, z):\r\n\r\n\r\n\r\n super().__init__() # Call the constructor of c4d.datapoint\r\n\r\n \r\n\r\n obj.filter = c4d.filters.kalman(np.hstack((z, np.zeros(2))), P, A, H, Q, R)\r\n\r\n \r\n\r\n obj.counterSame = 0\r\n\r\n obj.counterEscaped = 0\r\n\r\n obj.appear = 0\r\n\r\n\r\n\r\n obj.color = [np.random.randint(0, 255)\r\n\r\n , np.random.randint(0, 255)\r\n\r\n , np.random.randint(0, 255)]\r\n\r\n```\r\n\r\n\r\n\r\n* Define trackers manager:\r\n\r\n(a dictionary of trackers and methods to add and remove elements)\r\n\r\n\r\n\r\n```\r\n\r\n# trackers manager:\r\n\r\n# list of active trackers\r\n\r\n# add or remove tracks methods\r\n\r\nclass mTracks:\r\n\r\n def __init__(obj):\r\n\r\n obj.trackers = {}\r\n\r\n obj.removelist = []\r\n\r\n obj.neigh = NearestNeighbors(n_neighbors = 1)\r\n\r\n obj.thresh = 100 # threshold of 100 pixels to verify the measure is close enough to the object. \r\n\r\n```\r\n\r\n\r\n\r\n* Main loop:\r\n\r\n```\r\n\r\ndef run(tf = 1):\r\n\r\n \r\n\r\n mtracks = mTracks()\r\n\r\n \r\n\r\n cov = 25 * np.eye(4)\r\n\r\n t = 0\r\n\r\n \r\n\r\n while video.isOpened():\r\n\r\n \r\n\r\n ret, frame = video.read()\r\n\r\n # frame = frame.astype(np.uint8)\r\n\r\n # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Assuming input frames are in BGR format\r\n\r\n \r\n\r\n if not ret: \r\n\r\n break\r\n\r\n #\r\n\r\n # the update function runs the main trackers loop. \r\n\r\n ##\r\n\r\n zList = yolodet.getMeasurements(frame) # retrieves object measurements from the current frame using the object detector (YoloDetector).\r\n\r\n \r\n\r\n \r\n\r\n # updates the trackers dictionary by adding or removing tracks. \r\n\r\n # creates new trackers if there are more \r\n\r\n # measurements than trackers and removes duplicate trackers if \r\n\r\n # there are more trackers than measurements.\r\n\r\n kfNumber = len(mtracks.trackers.keys())\r\n\r\n zNumber = zList.shape[0]\r\n\r\n \r\n\r\n if kfNumber < zNumber:\r\n\r\n # more measurements than trackers\r\n\r\n mtracks.trackerMaker(zList, cov)\r\n\r\n \r\n\r\n elif kfNumber > zNumber and zNumber > 0:\r\n\r\n # more trackers than measurements\r\n\r\n mtracks.RemoveDoubles()\r\n\r\n \r\n\r\n \r\n\r\n # fits the Nearest Neighbors algorithm to the object \r\n\r\n # measurements for association purposes.\r\n\r\n if zList.shape[0] >= 2:\r\n\r\n mtracks.neigh.fit(zList)\r\n\r\n\r\n\r\n\r\n\r\n mtracks.refresh(zList, frame, t)\r\n\r\n mtracks.remove()\r\n\r\n\r\n\r\n cv2.imshow('image', frame)\r\n\r\n result.write(frame)\r\n\r\n \r\n\r\n key = cv2.waitKey(1) & 0xFF\r\n\r\n if key == ord('q') or t >= tf:\r\n\r\n break\r\n\r\n \r\n\r\n t += dt\r\n\r\n \r\n\r\n cv2.destroyAllWindows()\r\n\r\n result.release()\r\n\r\n return mtracks\r\n\r\n```\r\n\r\n\r\n\r\n* Run for two seconds:\r\n\r\n```\r\n\r\nltrk = run(tf = 2)\r\n\r\n```\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_objected_tracked.gif?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n\r\n\r\n* Results analysis:\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_id.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_trajectories.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/cars_velocity.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n## Getting Started 2: Missile Guidance Example\r\n\r\n### 6 DOF simulation of a missile employing proportional navigation guidance to pursue a target.\r\n\r\n\r\n\r\n#### Let's start: \r\n\r\n\r\n\r\n\r\n\r\n* Load third party modules \r\n\r\n\r\n\r\n```\r\n\r\nimport sys, os\r\n\r\nimport numpy as np\r\n\r\nfrom matplotlib import pyplot as plt\r\n\r\n```\r\n\r\n\r\n\r\n* Add C4dynamics to the python path and load it\r\n\r\n\r\n\r\n```\r\n\r\nsys.path.append(os.path.join(os.getcwd(), '..', '..'))\r\n\r\nimport C4dynamics as c4d\r\n\r\n```\r\n\r\n\r\n\r\n* Load other modules that developed for the demonstration of current example \r\n\r\n\r\n\r\n```\r\n\r\nimport control_system as mcontrol_system \r\n\r\nimport engine as mengine \r\n\r\nimport aerodynamics as maerodynamics\r\n\r\n```\r\n\r\n\r\n\r\n* Configure figure properties \r\n\r\n\r\n\r\n\r\n\r\n```\r\n\r\nplt.rcParams['figure.figsize'] = (5.0, 4.0) \r\n\r\nplt.rcParams['image.interpolation'] = 'nearest'\r\n\r\nplt.rcParams['image.cmap'] = 'gray'\r\n\r\n```\r\n\r\n\r\n\r\n* Simulation setup\r\n\r\n\r\n\r\n```\r\n\r\nt = 0\r\n\r\ndt = 5e-3\r\n\r\ntf = 10 \r\n\r\n```\r\n\r\n\r\n\r\n* Objects definition \r\n\r\n\r\n\r\n\r\n\r\n```\r\n\r\ntarget = c4d.datapoint(x = 4000, y = 1000, z = -3000\r\n\r\n , vx = -250, vy = 0, vz = 0)\\n\r\n\r\n\r\n\r\n```\r\n\r\n\r\n\r\nThe target is a datapoint object which means it has all the attributes of a mass in space:\r\n\r\n\r\n\r\nPosition: target.x, target.y, target.z\r\n\r\n\r\n\r\nVelocity: target.vx, target.vy, target.vz\r\n\r\n\r\n\r\nAcceleration: target.ax, target.ay, target.az\r\n\r\n\r\n\r\nIt also has mass: target.m (necessary for solving the equations of motion in the case of accelerating motion)\r\n\r\n\r\n\r\n\r\n\r\nThe target object in the example is initialized with initial position conditions in 3 axes and velocity conditions in the x-axis only. Acceleration is not initialized which is equivalent to zero initialization (default).\r\n\r\nAs the target in the example is non-accelerating it is not necessary to provide the mass with its instantiation.\r\n\r\n\r\n\r\n```\r\n\r\nmissile = c4d.rigidbody(m = 85, iyy = 61, izz = 61, xcm = 1.55)\r\n\r\n\r\n\r\nm0 = missile.m\r\n\r\nxcm0 = missile.xcm\r\n\r\ni0 = missile.iyy\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\nThe missile is a rigid-body object which means that it has all the attributes of a datapoint but in addition:\r\n\r\n\r\n\r\nBody angles: missile.phi, missile.theta, missile.psi (Euler)\r\n\r\n\r\n\r\nAngular rates: missile.p, missile.q, missile.r (rotation about x-body, y-body, and z-body, respectively)\r\n\r\n\r\n\r\nAngular accelerations: missile.p_dot, missile.q_dot, missile.r_dot (about x-body, y-body, and z-body, respectively)\r\n\r\n\r\n\r\n\r\n\r\nAs a rigid-body object it has also inertia attributes (necessary for solving the equations of motion in the case of accelerating motion):\r\n\r\n\r\n\r\nMoment of inertia: missile.ixx, missile.iyy, missile.izz (about x-body, y-body, and z-body, respectively)\r\n\r\n\r\n\r\nDistance from nose to center of mass: missile.xcm\r\n\r\n\r\n\r\n\r\n\r\nThe missile kinematic attributes in this example have not initialized with any initial conditions which mean that all its attributes are zero. But the mass properties provided as necessary. \r\n\r\n\r\n\r\nHowever, we will immediately see that the missile has initial kinematic conditions which are loaded through direct assignment and not by the class constructor (c4d.rigidbody()).\r\n\r\n\r\n\r\n\r\n\r\nAs the dynamics in this example involves a combustion of fuel of the rocket engine the missile\u2019s mass attributes varying as function of time. To recalculate the mass during the run time it's a good advice to save these initial conditions. As iyy and izz are equal here it's enough to save just one of them.\r\n\r\n\r\n\r\nIn any way the initial position and attitude of anybody object (datapoint and rigid-body) is always saved with its instantiation \r\n\r\n\r\n\r\nThe dimensions in this example are SI (i.e. seconds, meters, kilograms), but the objects and functions in the framework in general are independent of system of units. \r\n\r\n\r\n\r\nThe example uses a line-of-sight seeker object from the c4dynamics' seekers module and controller, engine, and aerodynamics objects that developed for the purpose of this example:\r\n\r\n\r\n\r\n```\r\n\r\nseeker = c4d.seekers.lineofsight(dt, tau1 = 0.01, tau2 = 0.01)\r\n\r\nctrl = mcontrol_system.control_system(dt)\r\n\r\neng = mengine.engine()\r\n\r\naero = maerodynamics.aerodynamics()\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n* User input data:\r\n\r\n\r\n\r\n```\r\n\r\n# \r\n\r\n# missile total initial velocity \r\n\r\n##\r\n\r\nvm = 30 \r\n\r\n\r\n\r\n# \r\n\r\n# atmospheric properties up to 2000m\r\n\r\n##\r\n\r\npressure = 101325 # pressure pascals\r\n\r\nrho = 1.225 # density kg/m^3\r\n\r\nvs = 340.29 # speed of sound m/s\r\n\r\nmach = 0.8\r\n\r\n\r\n\r\n# \r\n\r\n# combustion properties \r\n\r\n## \r\n\r\nmbo = 57 # burnout mass, kg \r\n\r\nxcmbo = 1.35 # nose to cm after burnout, m\r\n\r\nibo = 47 # iyy izz at burnout \r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n* Preliminary calculations \r\n\r\n\r\n\r\n\r\n\r\nThe initial missile pointing direction and angular rates are calculated in the fire-control block. \r\n\r\n\r\n\r\nFor the example simulation, a simple algorithm is employed in which the missile is pointed directly at the target at the instant of launch, and missile angular rates at launch are assumed to be negligible.\r\n\r\n\r\n\r\n\r\n\r\nThe unit vector in the direction from the missile to the target is calculated by normalizing the range vector.\r\n\r\n\r\n\r\n \r\n\r\n```\r\n\r\nrTM = target.pos() - missile.pos()\r\n\r\nucl = rTM / np.linalg.norm(rTM) # center line unit vector \r\n\r\nmissile.vx, missile.vy, missile.vz = vm * ucl \r\n\r\nmissile.psi = np.arctan(ucl[1] / ucl[0])\r\n\r\nmissile.theta = np.arctan(-ucl[2] / np.sqrt(ucl[0]**2 + ucl[1]**2))\r\n\r\nmissile.phi = 0\r\n\r\nalpha = 0\r\n\r\nbeta = 0\r\n\r\nalpha_total = 0\r\n\r\nh = -missile.z\r\n\r\n```\r\n\r\n\r\n\r\nThe function missile.BI() is bounded method of the rigid-body class.\r\n\r\n\r\n\r\nThe function generates a Body from Inertial DCM (Direction Cosine Matrix) matrix in 3-2-1 order.\r\n\r\n\r\n\r\nUsing this matrix, the missile velocity vector in the inertial frame of coordinates is rotated to represent the velocity in the body frame of coordinates.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nThe inertial frame is determined by the frame that the initial Euler angles refer to.\r\n\r\n\r\n\r\nIn this example the Euler angles are with respect the x parallel to flat earth in the direction of the missile centerline, z positive downward, and y such that z completes a right-hand system.\r\n\r\n\r\n\r\nThe velocity vector is also produced by a bounded method of the class. The methods datapoint.pos(), datapoint.vel(), datapoint.acc() read the current state of the object and return a three entries array composed of the coordinates of position, velocity, and acceleration, respectively. \r\n\r\n\r\n\r\nSimilarly, the functions datapoint.P(), datapoint.V(), datapoint.A() return the object squared norm of the position, velocity, and acceleration, respectively.\r\n\r\n\r\n\r\n```\r\n\r\nu, v, w = missile.BI() @ missile.vel()\r\n\r\n```\r\n\r\n\r\n\r\n* Main loop\r\n\r\n\r\n\r\n\r\n\r\nThe main loop includes the following steps: \r\n\r\n\r\n\r\n* Estimation of missile-target line-of-sight angular rate \r\n\r\n\t\r\n\r\n* Production of missile's wings-deflection commands \r\n\r\n\t\r\n\r\n* Calculation of missile's forces and moments \r\n\r\n\t\r\n\r\n* Integration of missile's equations of motion \r\n\r\n\t\r\n\r\n* Integration of target's equations of motion \r\n\r\n\t\r\n\r\n* Simulation update \r\n\r\n\r\n\r\n\r\n\r\nThe simulation runs until one of the following conditions:\r\n\r\n\r\n\r\n* The missile hits the ground\r\n\r\n\t\r\n\r\n* The simulation time is over \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\nComments are introduced inline.\r\n\r\n\r\n\r\nThe missile.run() function and the target.run() function perform integration of the equations of motion. \r\n\r\n\r\n\r\nThe integration is performed by running Runge-Kutta of fourth order. \r\n\r\n\r\n\r\nFor a datapoint, the equations are composed of translational equations, while for a datapoint they also include the rotational equations. \r\n\r\n\r\n\r\n\r\n\r\nTherefore, for a datapoint object, like the target in this example, a force vector is necessary for the evaluation of the derivatives. The force must be given in the inertial frame of reference. As the target in this example is not maneuvering, the force vector is [0, 0, 0].\r\n\r\n\r\n\r\n\r\n\r\nFor a rigid-body object, like the missile in this example, a force vector and moment vector are necessary for the evaluation of the derivatives. The force vector must be given in the inertial frame of reference. Therefore, the propulsion, and the aerodynamic forces are rotated to the inertial frame using the DCM321 missile.IB() function. The gravity forces are already given in the inertial frame and therefore remain intact. \r\n\r\n\r\n\r\n\r\n\r\nForces and moments in the inertial frame are introduced to provide an estimation of the derivatives that represent the equations of motion. The integration method, 4th order Runge-Kutta is performed manually and independent on any third-party framework (such as scipy), therefore, currently, they may be non-optimal in terms of step-size variation. \r\n\r\n\r\n\r\nThe choice of this is due to a feature which this framework desires to satisfy in which derivatives of two objects (such as missile and target) could be integrated simultaneously, with reciprocal dependent. \r\n\r\n\r\n\r\nHopefully, later the function will be also optimized in terms of run-time and step-size variation.\r\n\r\n\r\n\r\n```\r\n\r\nwhile t <= tf and h >= 0:\r\n\r\n\r\n\r\n #\r\n\r\n # atmospheric calculations \r\n\r\n ##\r\n\r\n mach = missile.V() / vs # mach number \r\n\r\n Q = 1 / 2 * rho * missile.V()**2 # dynamic pressure \r\n\r\n \r\n\r\n # \r\n\r\n # relative position\r\n\r\n ##\r\n\r\n vTM = target.vel() - missile.vel() # missile-target relative velocity \r\n\r\n rTM = target.pos() - missile.pos() # relative position \r\n\r\n uR = rTM / np.linalg.norm(rTM) # unit range vector \r\n\r\n vc = -uR * vTM # closing velocity \r\n\r\n\r\n\r\n # \r\n\r\n # seeker \r\n\r\n ## \r\n\r\n wf = seeker.measure(rTM, vTM) # filtered los vector \r\n\r\n \r\n\r\n # \r\n\r\n # guidance and control \r\n\r\n ##\r\n\r\n Gs = 4 * missile.V() # guidance gain\r\n\r\n acmd = Gs * np.cross(wf, ucl) # acceleration command\r\n\r\n ab_cmd = missile.BI() @ acmd # acc. command in body frame \r\n\r\n afp, afy = ctrl.update(ab_cmd, Q) # acchived pithc, yaw fins deflections \r\n\r\n d_pitch = afp - alpha # effecive pitch deflection\r\n\r\n d_yaw = afy - beta # effective yaw deflection \r\n\r\n\r\n\r\n\r\n\r\n # \r\n\r\n # missile dynamics \r\n\r\n ##\r\n\r\n \r\n\r\n #\r\n\r\n # aerodynamic forces \r\n\r\n ## \r\n\r\n cL, cD = aero.f_coef(alpha_total)\r\n\r\n L = Q * aero.s * cL\r\n\r\n D = Q * aero.s * cD\r\n\r\n \r\n\r\n A = D * np.cos(alpha_total) - L * np.sin(alpha_total) # aero axial force \r\n\r\n N = D * np.sin(alpha_total) + L * np.cos(alpha_total) # aero normal force \r\n\r\n \r\n\r\n fAb = np.array([ -A\r\n\r\n , N * (-v / np.sqrt(v**2 + w**2))\r\n\r\n , N * (-w / np.sqrt(v**2 + w**2))])\r\n\r\n fAe = missile.IB() @ fAb\r\n\r\n \r\n\r\n # \r\n\r\n # aerodynamic moments \r\n\r\n ##\r\n\r\n cM, cN = aero.m_coef(alpha, beta, d_pitch, d_yaw \r\n\r\n , missile.xcm, Q, missile.V(), fAb[1], fAb[2]\r\n\r\n , missile.q, missile.r)\r\n\r\n \r\n\r\n mA = np.array([0 # aerodynamic moemnt in roll\r\n\r\n , Q * cM * aero.s * aero.d # aerodynamic moment in pitch\r\n\r\n , Q * cN * aero.s * aero.d]) # aerodynamic moment in yaw \r\n\r\n\r\n\r\n # \r\n\r\n # propulsion \r\n\r\n ##\r\n\r\n thrust, thref = eng.update(t, pressure)\r\n\r\n fPb = np.array([thrust, 0, 0]) \r\n\r\n fPe = missile.IB() @ fPb\r\n\r\n\r\n\r\n # \r\n\r\n # gravity\r\n\r\n ## \r\n\r\n fGe = np.array([0, 0, missile.m * c4d.params.g])\r\n\r\n\r\n\r\n # \r\n\r\n # total forces\r\n\r\n ## \r\n\r\n forces = np.array([fAe[0] + fPe[0] + fGe[0]\r\n\r\n , fAe[1] + fPe[1] + fGe[1]\r\n\r\n , fAe[2] + fPe[2] + fGe[2]])\r\n\r\n \r\n\r\n # \r\n\r\n # missile motion integration\r\n\r\n ##\r\n\r\n missile.run(dt, forces, mA)\r\n\r\n u, v, w = missile.BI() @ np.array([missile.vx, missile.vy, missile.vz])\r\n\r\n \r\n\r\n \r\n\r\n # \r\n\r\n # target dynmaics \r\n\r\n ##\r\n\r\n target.run(dt, np.array([0, 0, 0]))\r\n\r\n\r\n\r\n\r\n\r\n # \r\n\r\n # update \r\n\r\n ##\r\n\r\n t += dt\r\n\r\n missile.store(t)\r\n\r\n target.store(t)\r\n\r\n\r\n\r\n \r\n\r\n missile.m -= thref * dt / eng.Isp \r\n\r\n missile.xcm = xcm0 - (xcm0 - xcmbo) * (m0 - missile.m) / (m0 - mbo)\r\n\r\n missile.izz = missile.iyy = i0 - (i0 - ibo) * (m0 - missile.m) / (m0 - mbo)\r\n\r\n\r\n\r\n alpha = np.arctan2(w, u)\r\n\r\n beta = np.arctan2(-v, u)\r\n\r\n \r\n\r\n uvm = missile.vel() / missile.V()\r\n\r\n ucl = np.array([np.cos(missile.theta) * np.cos(missile.psi)\r\n\r\n , np.cos(missile.theta) * np.sin(missile.psi)\r\n\r\n , np.sin(-missile.theta)])\r\n\r\n alpha_total = np.arccos(uvm @ ucl)\r\n\r\n \r\n\r\n h = -missile.z \r\n\r\n```\r\n\r\n\r\n\r\n* Results Analysis \r\n\r\n\r\n\r\n<!-- <p align=\"center\">\r\n\r\n <img src=\"\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n -->\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/trajectories.png\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n\r\n\r\n```\r\n\r\nmissile.draw('theta')\r\n\r\n```\r\n\r\n</p>\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/theta.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n```\r\n\r\ntarget.draw('vx')\r\n\r\n```\r\n\r\n<p align=\"center\">\r\n\r\n <img src=\"https://github.com/C4dynamics/C4dynamics/blob/main/examples/vx.png?raw=true\" width=\"325\" height=\"260\"/>\r\n\r\n</p>\r\n\r\n\r\n\r\n\r\n\r\n",
"bugtrack_url": null,
"license": "",
"summary": "The framework for algorithms engineering with Python.",
"version": "0.0.15",
"project_urls": null,
"split_keywords": [
"python",
"dynamics",
"physics",
"algorithms",
"computer vision",
"navigation"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5190a6c3b22681afea8179b5c7e67ac5dbfc4b411e15f77868cd3fad4d815516",
"md5": "d181f13d41395613afa3dc440182d265",
"sha256": "4070f83ad1d75b7adc184bb2ea2fb50575e73c027886596862a3e09511979431"
},
"downloads": -1,
"filename": "C4dynamics-0.0.15-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d181f13d41395613afa3dc440182d265",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 34479,
"upload_time": "2023-11-08T17:08:58",
"upload_time_iso_8601": "2023-11-08T17:08:58.224186Z",
"url": "https://files.pythonhosted.org/packages/51/90/a6c3b22681afea8179b5c7e67ac5dbfc4b411e15f77868cd3fad4d815516/C4dynamics-0.0.15-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "627ae2a6a260f792bc810575dcdb2a6cffb670df32abb6633469dc1a465fdfa5",
"md5": "db6814a6510e2a24d78bc9410dd68dc2",
"sha256": "0e895c4c22d4f1357f0afdeb830e64fea854a6b1a86c9917055e2f63e8ff75d9"
},
"downloads": -1,
"filename": "C4dynamics-0.0.15.tar.gz",
"has_sig": false,
"md5_digest": "db6814a6510e2a24d78bc9410dd68dc2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 34387,
"upload_time": "2023-11-08T17:09:00",
"upload_time_iso_8601": "2023-11-08T17:09:00.020603Z",
"url": "https://files.pythonhosted.org/packages/62/7a/e2a6a260f792bc810575dcdb2a6cffb670df32abb6633469dc1a465fdfa5/C4dynamics-0.0.15.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-11-08 17:09:00",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "c4dynamics"
}