Parking Finder
The Parking Finder system is a smart parking solution designed to help drivers efficiently locate available
Loading...
Searching...
No Matches
test_ekf.py
1
7import numpy as np
8
9class EKF:
10 def __init__(self):
11 self.dt = 0
12 """
13 Define state vector [x, y, v, psi]
14 [x-position, y-position, speed (scalar), yaw (heading)]
15 Speed used instead of velocity since it can be assumed that a car will be traveling in the forward or backward direction in relation to its
16 orientation. For example, a car is not going to travel sideways.
17 """
18 self.x = np.zeros((4, 1))
19
20 """
21 State covariance P matrix
22 How uncertain the filter is about each part of the state
23 Diagonals contain covariances of each measurement, off-diagonals show uncertainty in correlation between measurements
24 So for example, if speed is wrong, then position is probably wrong as well.
25 Small values in P mean the filter is more confident, large values in P mean more uncertainty
26 """
27 self.P = np.diag([10, 10, 1, 0.1])
28
29 """
30 Process noise Q matrix
31 Represents uncertainty in the model
32 Increase if motion is unpredictable or filter is too "confident"
33 Slow/unresponsive filter? Increase Q values
34
35 This Q matrix controls acceleration and yaw rate
36 """
37 self.Q = np.diag([1.0, 0.05])
38
39 """
40 Measurement noise R matrix
41 Based on sensor specs, increase if measurements are noisy
42 Noisy output? Increase R values
43 """
44 self.R_gps = np.diag([25, 25]) # GPS variance, 5m std dev
45 self.R_yaw = np.array([[0.05]]) # magenetometer variance (from IMU)
46
47 def predict(self, u, dt):
48 a, omega = u.flatten()
49 x, y, v, psi = self.x.flatten()
50
51 # Nonlinear motion model: velocity + heading
52 # x_pred = x_prev + v_prev * cos(psi_prev) * dt
53 # y_pred = y_prev + v_prev * sin(psi_prev) * dt
54 # v_pred = v_prev + a * dt
55 # psi_pred = psi_prev + omega * dt
56 # where a is forward acceleration from IMU and omega is yaw rate from gyro (also on IMU)
57 x_new = x + v * np.cos(psi) * dt
58 y_new = y + v * np.sin(psi) * dt
59 v_new = v + a * dt
60 psi_new = self.normalize_angle(psi + omega * dt)
61
62 self.x = np.array([[x_new], [y_new], [v_new], [psi_new]])
63
64 """
65 Computing Jacobians
66 State Transition Jacobian F captures how turning affects position
67 Control Jacobian B captures how acceleration and yaw rate affect state
68 """
69 F = np.array([
70 [1, 0, np.cos(psi) * dt, -v * np.sin(psi) * dt],
71 [0, 1, np.sin(psi) * dt, v * np.cos(psi) * dt],
72 [0, 0, 1, 0],
73 [0, 0, 0, 1]
74 ])
75
76 B = np.array([
77 [0, 0],
78 [0, 0],
79 [dt, 0],
80 [0, dt]
81 ])
82
83 # Predict state covariance
84 # P_pred = F * P * F^T + B * Q * B^T
85 self.P = F @ self.P @ F.T + B @ (self.Q * dt) @ B.T
86
87 def update_gps(self, z):
88 # z = [x_meas, y_meas]
89 H = np.array([
90 [1, 0, 0, 0],
91 [0, 1, 0, 0]
92 ])
93
94 z = z.reshape((2,1))
95 y = z - H @ self.x
96
97 S = H @ self.P @ H.T + self.R_gps
98 K = self.P @ H.T @ np.linalg.inv(S)
99
100 self.x = self.x + K @ y
101 I = np.eye(4)
102 self.P = (I - K @ H) @ self.P @ (I - K @ H).T + K @ self.R_gps @ K.T
103
104 def update_yaw(self, yaw_meas):
105 H = np.array([[0, 0, 0, 1]])
106
107 z = np.array([[yaw_meas]])
108 y = z - H @ self.x
109
110 y[0,0] = self.normalize_angle(y[0,0])
111
112 S = H @ self.P @ H.T + self.R_yaw
113 K = self.P @ H.T @ np.linalg.inv(S)
114
115 self.x = self.x + K @ y
116 I = np.eye(4)
117 self.P = (I - K @ H) @ self.P @ (I - K @ H).T + K @ self.R_yaw @ K.T
118
119 self.x[3,0] = self.normalize_angle(self.x[3,0])
120
121 def normalize_angle(self, angle):
122 return (angle + np.pi) % (2 * np.pi) - np.pi
normalize_angle(self, angle)
Definition test_ekf.py:121