tracinginsights commited on
Commit
666d174
·
1 Parent(s): f6a40e3

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +170 -0
main.py CHANGED
@@ -1,6 +1,8 @@
1
  import datetime
2
  import os
3
  import streamlit as st
 
 
4
  import fastf1
5
  import pandas as pd
6
  from fastapi import FastAPI
@@ -20,6 +22,153 @@ app.add_middleware(
20
  allow_headers=["*"],
21
  )
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  @st.cache_data
24
  @app.get("/", response_model=None)
25
  async def root():
@@ -150,6 +299,11 @@ def telemetry_data(year: int, event: str | int, session: str, driver: str, lap_n
150
  selected_lap = driver_laps[driver_laps.LapNumber == lap_number]
151
 
152
  telemetry = selected_lap.get_telemetry()
 
 
 
 
 
153
  telemetry['Time'] = telemetry['Time'].dt.total_seconds()
154
 
155
  laptime = selected_lap.LapTime.values[0]
@@ -165,6 +319,8 @@ def telemetry_data(year: int, event: str | int, session: str, driver: str, lap_n
165
  throttle_tel = []
166
  time_tel = []
167
  track_map = []
 
 
168
 
169
  for _, row in telemetry.iterrows():
170
 
@@ -202,11 +358,23 @@ def telemetry_data(year: int, event: str | int, session: str, driver: str, lap_n
202
  "y": row['Time'],
203
  }
204
  time_tel.append(time)
 
 
 
 
 
 
 
 
 
 
205
 
206
  track = {"x": row['X'],
207
  "y": row['Y'],
208
  }
209
  track_map.append(track)
 
 
210
 
211
  telemetry_data = {
212
  "telemetryData":{
@@ -218,6 +386,8 @@ def telemetry_data(year: int, event: str | int, session: str, driver: str, lap_n
218
  "speed": speed_tel,
219
  "throttle": throttle_tel,
220
  "time": time_tel,
 
 
221
  "trackMap": track_map,
222
  }
223
  }
 
1
  import datetime
2
  import os
3
  import streamlit as st
4
+ import numpy as np
5
+ import math
6
  import fastf1
7
  import pandas as pd
8
  from fastapi import FastAPI
 
22
  allow_headers=["*"],
23
  )
24
 
25
+ import math
26
+ import numpy as np
27
+ def smooth_derivative(t_in, v_in):
28
+
29
+ #
30
+ # Function to compute a smooth estimation of a derivative.
31
+ # [REF: http://holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/]
32
+ #
33
+
34
+ # Configuration
35
+ #
36
+ # Derivative method: two options: 'smooth' or 'centered'. Smooth is more conservative
37
+ # but helps to supress the very noisy signals. 'centered' is more agressive but more noisy
38
+ method = "smooth"
39
+
40
+ t = t_in.copy()
41
+ v = v_in.copy()
42
+
43
+ # (0) Prepare inputs
44
+
45
+ # (0.1) Time needs to be transformed to seconds
46
+ try:
47
+ for i in range(0, t.size):
48
+ t.iloc[i] = t.iloc[i].total_seconds()
49
+ except:
50
+ pass
51
+
52
+ t = np.array(t)
53
+ v = np.array(v)
54
+
55
+ # (0.1) Assert they have the same size
56
+ assert t.size == v.size
57
+
58
+ # (0.2) Initialize output
59
+ dvdt = np.zeros(t.size)
60
+
61
+ # (1) Manually compute points out of the stencil
62
+
63
+ # (1.1) First point
64
+ dvdt[0] = (v[1] - v[0]) / (t[1] - t[0])
65
+
66
+ # (1.2) Second point
67
+ dvdt[1] = (v[2] - v[0]) / (t[2] - t[0])
68
+
69
+ # (1.3) Third point
70
+ dvdt[2] = (v[3] - v[1]) / (t[3] - t[1])
71
+
72
+ # (1.4) Last points
73
+ n = t.size
74
+ dvdt[n - 1] = (v[n - 1] - v[n - 2]) / (t[n - 1] - t[n - 2])
75
+ dvdt[n - 2] = (v[n - 1] - v[n - 3]) / (t[n - 1] - t[n - 3])
76
+ dvdt[n - 3] = (v[n - 2] - v[n - 4]) / (t[n - 2] - t[n - 4])
77
+
78
+ # (2) Compute the rest of the points
79
+ if method == "smooth":
80
+ c = [5.0 / 32.0, 4.0 / 32.0, 1.0 / 32.0]
81
+ for i in range(3, t.size - 3):
82
+ for j in range(1, 4):
83
+ dvdt[i] += (
84
+ 2 * j * c[j - 1] * (v[i + j] - v[i - j]) /
85
+ (t[i + j] - t[i - j])
86
+ )
87
+ elif method == "centered":
88
+ for i in range(3, t.size - 2):
89
+ for j in range(1, 4):
90
+ dvdt[i] = (v[i + 1] - v[i - 1]) / (t[i + 1] - t[i - 1])
91
+
92
+ return dvdt
93
+
94
+
95
+ def truncated_remainder(dividend, divisor):
96
+ divided_number = dividend / divisor
97
+ divided_number = (
98
+ -int(-divided_number) if divided_number < 0 else int(divided_number)
99
+ )
100
+
101
+ remainder = dividend - divisor * divided_number
102
+
103
+ return remainder
104
+
105
+
106
+ def transform_to_pipi(input_angle):
107
+ pi = math.pi
108
+ revolutions = int((input_angle + np.sign(input_angle) * pi) / (2 * pi))
109
+
110
+ p1 = truncated_remainder(input_angle + np.sign(input_angle) * pi, 2 * pi)
111
+ p2 = (
112
+ np.sign(
113
+ np.sign(input_angle)
114
+ + 2
115
+ * (
116
+ np.sign(
117
+ math.fabs(
118
+ (truncated_remainder(input_angle + pi, 2 * pi)) / (2 * pi)
119
+ )
120
+ )
121
+ - 1
122
+ )
123
+ )
124
+ ) * pi
125
+
126
+ output_angle = p1 - p2
127
+
128
+ return output_angle, revolutions
129
+
130
+
131
+ def remove_acceleration_outliers(acc):
132
+
133
+ acc_threshold_g = 7.5
134
+ if math.fabs(acc[0]) > acc_threshold_g:
135
+ acc[0] = 0.0
136
+
137
+ for i in range(1, acc.size - 1):
138
+ if math.fabs(acc[i]) > acc_threshold_g:
139
+ acc[i] = acc[i - 1]
140
+
141
+ if math.fabs(acc[-1]) > acc_threshold_g:
142
+ acc[-1] = acc[-2]
143
+
144
+ return acc
145
+
146
+
147
+ def compute_accelerations(telemetry):
148
+
149
+ v = np.array(telemetry["Speed"]) / 3.6
150
+ lon_acc = smooth_derivative(telemetry["Time"], v) / 9.81
151
+
152
+ dx = smooth_derivative(telemetry["Distance"], telemetry["X"])
153
+ dy = smooth_derivative(telemetry["Distance"], telemetry["Y"])
154
+
155
+ theta = np.zeros(dx.size)
156
+ theta[0] = math.atan2(dy[0], dx[0])
157
+ for i in range(0, dx.size):
158
+ theta[i] = (
159
+ theta[i - 1] +
160
+ transform_to_pipi(math.atan2(dy[i], dx[i]) - theta[i - 1])[0]
161
+ )
162
+
163
+ kappa = smooth_derivative(telemetry["Distance"], theta)
164
+ lat_acc = v * v * kappa / 9.81
165
+
166
+ # Remove outliers
167
+ lon_acc = remove_acceleration_outliers(lon_acc)
168
+ lat_acc = remove_acceleration_outliers(lat_acc)
169
+
170
+ return lon_acc, lat_acc
171
+
172
  @st.cache_data
173
  @app.get("/", response_model=None)
174
  async def root():
 
299
  selected_lap = driver_laps[driver_laps.LapNumber == lap_number]
300
 
301
  telemetry = selected_lap.get_telemetry()
302
+
303
+ lon_acc, lat_acc = compute_accelerations(telemetry)
304
+ telemetry["lon_acc"] = lon_acc
305
+ telemetry["lat_acc"] = lat_acc
306
+
307
  telemetry['Time'] = telemetry['Time'].dt.total_seconds()
308
 
309
  laptime = selected_lap.LapTime.values[0]
 
319
  throttle_tel = []
320
  time_tel = []
321
  track_map = []
322
+ lon_acc_tel = []
323
+ lat_acc_tel = []
324
 
325
  for _, row in telemetry.iterrows():
326
 
 
358
  "y": row['Time'],
359
  }
360
  time_tel.append(time)
361
+
362
+ lon_acc = {"x": row['Distance'],
363
+ "y": row['lon_acc'],
364
+ }
365
+ lon_acc_tel.append(lon_acc)
366
+
367
+ lat_acc = {"x": row['Distance'],
368
+ "y": row['lat_acc'],
369
+ }
370
+ lat_acc_tel.append(lat_acc)
371
 
372
  track = {"x": row['X'],
373
  "y": row['Y'],
374
  }
375
  track_map.append(track)
376
+
377
+
378
 
379
  telemetry_data = {
380
  "telemetryData":{
 
386
  "speed": speed_tel,
387
  "throttle": throttle_tel,
388
  "time": time_tel,
389
+ "lon_acc": lon_acc_tel,
390
+ "lat_acc": lat_acc_tel
391
  "trackMap": track_map,
392
  }
393
  }