Skip to content

openstb.simulator.system.trajectory

Trajectory plugins for the openSTB simulator.

Classes:

Name Description
Linear

An ideal linear trajectory.

Linear

Linear(start_position, end_position, speed, start_time=None)

Bases: Trajectory

An ideal linear trajectory.

Parameters:

Name Type Description Default
start_position array-like of 3 floats

The start and end position of the trajectory in the global coordinate system.

required
end_position array-like of 3 floats

The start and end position of the trajectory in the global coordinate system.

required
speed float

The speed of the system in metres per second.

required
start_time (datetime, str, int)

The time at which the trajectory starts. If a datetime instance is given, it will be converted to UTC. An string in the ISO 8601 format "YYYY-MM-DDTHH:MM:SS+ZZ:ZZ", where the "+ZZ:ZZ" represents the offset of the timezone, can be given. If the timezone offset is not given, it will be assumed to be UTC. An integer representing a UTC POSIX timestamp (seconds since midnight on 1 January 1970) can be given. If no start time is given, it is set to the time the trajectory instance is initialised.

None
Source code in openstb/simulator/system/trajectory.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def __init__(
    self,
    start_position: ArrayLike,
    end_position: ArrayLike,
    speed: float,
    start_time: datetime | str | int | None = None,
):
    """
    Parameters
    ----------
    start_position, end_position : array-like of 3 floats
        The start and end position of the trajectory in the global coordinate
        system.
    speed : float
        The speed of the system in metres per second.
    start_time : datetime.datetime, str, int, optional
        The time at which the trajectory starts. If a datetime instance is given, it
        will be converted to UTC. An string in the ISO 8601 format
        "YYYY-MM-DDTHH:MM:SS+ZZ:ZZ", where the "+ZZ:ZZ" represents the offset of the
        timezone, can be given. If the timezone offset is not given, it will be
        assumed to be UTC. An integer representing a UTC POSIX timestamp (seconds
        since midnight on 1 January 1970) can be given. If no start time is given,
        it is set to the time the trajectory instance is initialised.

    """
    self.start_position = np.asarray(start_position)
    if self.start_position.shape != (3,):
        raise ValueError(
            _("3 element vector required for linear trajectory start position")
        )
    self.end_position = np.asarray(end_position)
    if self.end_position.shape != (3,):
        raise ValueError(
            _("3 element vector required for linear trajectory end position")
        )

    # Calculate the length, velocity and duration of the trajectory.
    if not speed > 0:
        raise ValueError(_("speed of linear trajectory must be positive"))
    diff = self.end_position - self.start_position
    self._length = float(np.linalg.norm(diff))
    self._velocity = speed * diff / self._length
    self._duration = float(self._length / speed)

    # Calculate the orientation of the system. The cross product will be zero for
    # trajectories parallel to the x axis hence the special cases. We store the
    # result as a NumPy array here as quaternionic arrays cannot be pickled for
    # transfer between workers.
    hvec = diff / self._length
    dp = np.dot([1, 0, 0], hvec)
    if np.isclose(dp, 1):
        self._ori = np.array([1.0, 0.0, 0.0, 0.0])
    elif np.isclose(dp, -1):
        self._ori = np.array([0.0, 0.0, 0.0, 1.0])
    else:
        angle = np.arccos(dp)
        axis = np.cross([1, 0, 0], hvec)
        axis /= np.linalg.norm(axis)
        c = np.cos(angle / 2)
        s = np.sin(angle / 2)
        self._ori = np.array([c, s * axis[0], s * axis[1], s * axis[2]])

    # Calculate or convert the start time as needed.
    if start_time is None:
        self._start_time = datetime.now(timezone.utc)
    elif isinstance(start_time, str):
        raw = datetime.fromisoformat(start_time)
        if raw.tzinfo is None:
            self._start_time = raw.replace(tzinfo=timezone.utc)
        else:
            self._start_time = raw.astimezone(timezone.utc)
    elif isinstance(start_time, int):
        self._start_time = datetime.fromtimestamp(start_time, timezone.utc)
    else:
        self._start_time = start_time.astimezone(timezone.utc)