ubc-solar-physics 1.2.0__cp311-cp311-win_amd64.whl → 1.4.0__cp311-cp311-win_amd64.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.
core.cp311-win_amd64.pyd CHANGED
Binary file
physics/_version.py CHANGED
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '1.2.0'
16
- __version_tuple__ = version_tuple = (1, 2, 0)
20
+ __version__ = version = '1.4.0'
21
+ __version_tuple__ = version_tuple = (1, 4, 0)
@@ -0,0 +1,8 @@
1
+ R_0_data = [0.002564, 0.002541, 0.002541, 0.002558, 0.002549, 0.002574, 0.002596, 0.002626, 0.002676, 0.002789]
2
+ R_P = 0.000530
3
+ C_P = 14646
4
+ Q_total = 259200
5
+ SOC_data = [0.0752, 0.1705, 0.2677, 0.366, 0.4654, 0.5666, 0.6701, 0.7767, 0.8865, 1.0]
6
+ Uoc_data = [3.481, 3.557, 3.597, 3.623, 3.660, 3.750, 3.846, 3.946, 4.056, 4.183]
7
+ max_current_capacity = 40
8
+ max_energy_capacity = 500
@@ -178,3 +178,164 @@ def check_Terminal_V(Ut):
178
178
  raise TypeError(f"Invalid type for measured_Ut: {type(Ut)}. Expected float or int.")
179
179
  if not (0.0 <= Ut <= 5.0):
180
180
  raise ValueError(f"Invalid value for terminal voltage (measured_Ut): {Ut}. Must be between 0.0 and 5.0 volts.")
181
+
182
+ import numpy as np
183
+ from filterpy.kalman import ExtendedKalmanFilter as EKF
184
+ from physics.models.battery.battery_config import BatteryModelConfig
185
+ import numpy as np
186
+
187
+ class EKF_SOC():
188
+ def __init__(self, battery_config: BatteryModelConfig, initial_SOC = 1, initial_Uc = 0):
189
+ """
190
+ EKF_SOC represents the kalman filter used for predicting state of charge.
191
+
192
+ Attributes:
193
+ battery_model_config (BatteryModelConfig): This contains the HPPC parameters of the battery model
194
+ initial_SOC (float/int): Ranges from 0 to 1 inclusive. The initial state of charge of the battery.
195
+ initial_Uc (float/int): The initial polarization volatge of the battery. (V)
196
+ """
197
+ # Inital state
198
+ self.SOC = initial_SOC
199
+ self.Uc = initial_Uc # Polarization Volatge
200
+
201
+ # Covariance Matrices
202
+ self.Q_covariance = np.eye(2) * 0.0001
203
+ self.R_covariance = np.eye(1) * 0.5 # currently not really trusting the predicted state
204
+
205
+ # Load Config data
206
+ self.R_P = battery_config.R_P
207
+ self.C_P = battery_config.C_P
208
+ self.Q_total = battery_config.Q_total
209
+ SOC_data = np.array(battery_config.SOC_data)
210
+ Uoc_data = np.array(battery_config.Uoc_data)
211
+ R_0_data = np.array(battery_config.R_0_data)
212
+
213
+ # polynomial interpolation
214
+ self.Uoc_coefficients = np.polyfit(SOC_data, Uoc_data, 7)
215
+ self.R_0_coefficients = np.polyfit(SOC_data, R_0_data, 7)
216
+ self.Uoc_derivative_coefficients = np.polyder(self.Uoc_coefficients)
217
+
218
+ self.tau = self.R_P / self.C_P
219
+
220
+ # initializing the ekf object
221
+ self.ekf = EKF(dim_x=2, dim_z=1)
222
+ self.ekf.x = np.array([self.SOC, self.Uc])
223
+ self.ekf.P = np.diag([1e-6, 1e-6]) # I'm keeping low uncertainty in initial SOC and Uc
224
+ self.ekf.Q = self.Q_covariance
225
+ self.ekf.R = self.R_covariance
226
+
227
+ # For logs
228
+ self.predicted_measurment = 0
229
+
230
+ def get_SOC(self):
231
+ """ Return the state of charge of the battery """
232
+ return self.SOC
233
+
234
+ def get_Uc(self):
235
+ """ Return the polarization voltage of the battery """
236
+ return self.Uc
237
+
238
+ def get_predicted_Ut(self):
239
+ """ Return the predicted terminal voltage for the last prediction step """
240
+ return self.predicted_measurment
241
+
242
+ def update_filter(self, measured_Ut, I):
243
+ """
244
+ Update the filter based on a new measurment, and the predicted state.
245
+ This function should be called after predict_state in a typical predict update workflow.
246
+
247
+ Attributes:
248
+ measured_Ut (float/integer): The actual voltage across the terminals of the battery.
249
+ I (float/integer): The current being sourced by the battery
250
+ """
251
+ check_Terminal_V(measured_Ut)
252
+
253
+ h_jacobian = self._measurement_jacobian
254
+ Hx = self._measurement_function
255
+
256
+ self.ekf.update(z=measured_Ut, HJacobian=h_jacobian, Hx=Hx, hx_args=I)
257
+
258
+ self.SOC, self.Uc = self.ekf.x
259
+
260
+ def predict_state(self, I, time_step):
261
+ """
262
+ Predicts the next evolution of the state vector (SOC, Uc).
263
+ This function should be called before updating the filter in a typical predict update workflow.
264
+
265
+ Attributes:
266
+ I (float/integer): The current being sourced by the battery. Positive indicated current being drawn.
267
+ time_step (float/integer): Time elapsed between this prediction and the last updated state of filter. (Seconds)
268
+ """
269
+ check_current(I)
270
+ # Control matrix B (for input current I_k)
271
+ self.ekf.B = np.array([-time_step / self.Q_total, self.R_P * (1 - np.exp(-time_step / self.tau))])
272
+ self.ekf.F = self._state_jacobian(time_step)
273
+
274
+ self.ekf.predict(u=I)
275
+ print(f'ekf prediction: {self.ekf.x_prior}')
276
+
277
+ def predict_then_update(self, measured_Ut, I, time_step):
278
+ """
279
+ Predicts the next evolution of the state vector (SOC, Uc), then updates the filter
280
+ based on this prediction and a measurement.
281
+ This function abstracts the full predict update workflow of the EKF.
282
+
283
+ Attributes:
284
+ measured_Ut (float/integer): The actual voltage across the terminals of the battery.
285
+ I (float/integer): The current being sourced by the battery. Positive indicated current being drawn.
286
+ time_step (float/integer): Time elapsed between this prediction and the last updated state of filter. (Seconds)
287
+ """
288
+ check_current(I)
289
+ check_Terminal_V(measured_Ut)
290
+
291
+ self.predict_state(I, time_step)
292
+ print(f'predicted: {self.ekf.x_prior}')
293
+
294
+ self.update_filter(measured_Ut, I)
295
+ print(f'SOC: {self.ekf.x[0]}, Uc: {self.ekf.x[1]}')
296
+
297
+ def _state_jacobian(self, time_step):
298
+ """
299
+ Returns the state jacobian for the current time
300
+
301
+ Attributes:
302
+ time_step (float/integer): Time elapsed between this prediction and the last updated state of filter. (Seconds)
303
+ """
304
+ return np.array([[1, 0], [0, np.exp(-time_step / self.tau)]])
305
+
306
+ def _measurement_jacobian(self, x):
307
+ """
308
+ Returns the measurement jacobian for the current time
309
+
310
+ Attributes:
311
+ x [float, float]: The state vector [SOC, Uc], where both values are floats or integers.
312
+ """
313
+ SOC = x[0]
314
+ derivative = np.polyval(self.Uoc_derivative_coefficients, SOC)
315
+ return np.array([[derivative, -1]])
316
+
317
+ def _measurement_function(self, x, I):
318
+ """
319
+ The customized measurement equation relating Ut to SOC and Uc
320
+
321
+ Attributes:
322
+ x [float, float]: The state vector [SOC, Uc], where both values are floats or integers.
323
+ I (float/integer): The current being sourced by the battery. Positive indicated current being drawn.
324
+ """
325
+ SOC, Uc = x
326
+ R_0 = np.polyval(self.R_0_coefficients, SOC)
327
+ Uoc = np.polyval(self.Uoc_coefficients, SOC)
328
+ self.predicted_measurment = Uoc - Uc - R_0*I
329
+ return self.predicted_measurment
330
+
331
+ def check_current(I):
332
+ if not isinstance(I, (float, int)):
333
+ raise TypeError(f"Invalid type for current I: {type(I)}. Expected float or int.")
334
+ if not (-45.0 <= I <= 45.0):
335
+ raise ValueError(f"Invalid value for current (I): {I}. Must be between -45.0A and 45.0A.")
336
+
337
+ def check_Terminal_V(Ut):
338
+ if not isinstance(Ut, (float, int)):
339
+ raise TypeError(f"Invalid type for measured_Ut: {type(Ut)}. Expected float or int.")
340
+ if not (0.0 <= Ut <= 5.0):
341
+ raise ValueError(f"Invalid value for terminal voltage (measured_Ut): {Ut}. Must be between 0.0 and 5.0 volts.")
@@ -12,6 +12,18 @@ class BasicRegen(BaseRegen):
12
12
  self.vehicle_mass = vehicle_mass
13
13
  self.kmh_to_mps = 0.278
14
14
 
15
+ def get_regen_efficiency(self, speed_array):
16
+ """
17
+ Returns a numpy array of regen efficiency percentage based on the vehicle speed in m/s.
18
+
19
+ :param speed_array: a numpy array of speeds in m/s
20
+ :returns: numpy array of regen efficiency percentage
21
+ """
22
+ # Efficiency polynomial, more details can be found in regen_analysis folder located in data_analysis
23
+ efficiency_poly = [0.022288416685942, 0.026545396753597]
24
+
25
+ return np.polyval(efficiency_poly, speed_array)
26
+
15
27
  def calculate_produced_energy(self, speed_kmh, gis_route_elevations, min_regen_speed, max_power):
16
28
  """
17
29
  Returns a numpy array containing the energy produced by regen
@@ -29,7 +41,8 @@ class BasicRegen(BaseRegen):
29
41
 
30
42
  # create regen energy produced array
31
43
  # if delta_energy is negative, we regen that energy back at the set efficiency rate; else 0 energy regen
32
- produced_energy = np.where(delta_energy < 0, abs(delta_energy) * self.EFFICIENCY, 0)
44
+ efficiencies = self.get_regen_efficiency(speed_ms)
45
+ produced_energy = np.where(delta_energy < 0, abs(delta_energy) * efficiencies, 0)
33
46
 
34
47
  # Regen does not occur below a certain speed
35
48
  produced_energy = np.where(speed_ms >= min_regen_speed, produced_energy, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ubc-solar-physics
3
- Version: 1.2.0
3
+ Version: 1.4.0
4
4
  Summary: UBC Solar's Simulation Environment
5
5
  Author: Fisher Xue, Mihir Nimgade, Chris Chang, David Widjaja, Justin Hua, Ilya Veksler, Renu Rajamagesh, Ritchie Xia, Erik Langille, Chris Aung, Nicolas Ric, Ishaan Trivedi, Jason Liang, Felix Toft, Mack Wilson, Jonah Lee, Tamzeed Quazi, Joshua Riefman
6
6
  Author-email: UBC Solar <strategy@ubcsolar.com>
@@ -42,7 +42,7 @@ License-File: LICENSE
42
42
  Requires-Dist: backports.tarfile==1.2.0
43
43
  Requires-Dist: certifi==2024.7.4
44
44
  Requires-Dist: charset-normalizer==3.3.2
45
- Requires-Dist: dill==0.3.8
45
+ Requires-Dist: dill>=0.3.8
46
46
  Requires-Dist: haversine==2.8.1
47
47
  Requires-Dist: idna==3.7
48
48
  Requires-Dist: importlib_metadata==8.2.0
@@ -1,6 +1,6 @@
1
- core.cp311-win_amd64.pyd,sha256=WyxeKn8ggdsv_5r8z62OLFhDH1bKIlQW7iwmfKyytEA,382464
1
+ core.cp311-win_amd64.pyd,sha256=gzsvsGUwCk5pL0ldFHYGQNZDfbX2F_xYdn3q4_GexbY,382464
2
2
  physics/__init__.py,sha256=jRV9J_eGh0vNXEfFrILqcM6xxVjyqm3XwKAg1B1IPBs,183
3
- physics/_version.py,sha256=DnUqy-xWN4z1XWOsowoRN4Vz2GPuDm_18GEJc3VGkWg,427
3
+ physics/_version.py,sha256=mQpvfIn8roT-O8LS07P1pK-7O17jWuq_vL-TTh8VVvs,532
4
4
  physics/environment.rs,sha256=OghmBkvHLZvzzuVsXUmV2lR3X_tEwuB9sT2TGZLQC6E,36
5
5
  physics/lib.rs,sha256=FqnhKkotYKJCu8v1vbov2QW9s0apay7-BnEcUgxOakU,5798
6
6
  physics/models.rs,sha256=747ABP-D1XKxA6X_MNh1PbmST0zsxpxhP_pEWjbR46c,63
@@ -33,8 +33,9 @@ physics/models/battery/base_battery.py,sha256=yU-QopEEQ83kw4CUvJ2MEhYyj3AM3LYY_h
33
33
  physics/models/battery/basic_battery.py,sha256=5o-7g5xflhNLKuJyeqOY-1rLIOSIy_CJ0U4GEqeQO1E,5894
34
34
  physics/models/battery/battery.rs,sha256=0wIQVli7UOWgKXT96cQLWisLQKo5UE08X4B9dl09USI,3649
35
35
  physics/models/battery/battery_config.py,sha256=Dsi7cXR8SL0v7aSTuihhB6il9-8h1a2P8qrGbdvlf8Q,617
36
+ physics/models/battery/battery_config.toml,sha256=J8jzmhg1mdfFqiHreiRfbbb_5byJklgVBEXKsn3sSUI,393
36
37
  physics/models/battery/battery_model.py,sha256=kHn-xOyFBzWycpd-9Wn75fzHYZ512wXOi1dUrlt3a5M,6313
37
- physics/models/battery/kalman_filter.py,sha256=Lr7J2vwO1HwN6miNFAYCfhZiZ2j72bwmUt-vubpo0Ks,7371
38
+ physics/models/battery/kalman_filter.py,sha256=axDzXTpAmJVE_AcOv3nk8nhJJSztyaAwXQ6qC2Y0hj4,14231
38
39
  physics/models/lvs/__init__.py,sha256=ZBips6zW4Lot7SkQZMZt_OGRNUqgOfUlDtBA5lfUkM4,114
39
40
  physics/models/lvs/base_lvs.py,sha256=kVLfGd9Qwql4-6u86uwHbJoFCgYpG07r0cAR2Ngsq38,116
40
41
  physics/models/lvs/basic_lvs.py,sha256=xNXeN6RGSZkJLhtcW0n2xZU6YIOT4bKUIbOFdmh4zc0,621
@@ -45,10 +46,10 @@ physics/models/motor/basic_motor.py,sha256=hHGngG5lvZNzw7qgU3-c_3KFMKQ9siZCm471R
45
46
  physics/models/motor/motor.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
47
  physics/models/regen/__init__.py,sha256=JzyRYKwT89FQ6_p9ofCqusl2fnWGHulyiK4P4f8Lakc,126
47
48
  physics/models/regen/base_regen.py,sha256=lY44jrTSHEo8Xv7hKCjo4C3Jx0PUgilyITHwQchT2bM,101
48
- physics/models/regen/basic_regen.py,sha256=RY730lQLJ_gKkm2wJ68t1OPTmcz9xxGmu0yBLwHCGoQ,1811
49
+ physics/models/regen/basic_regen.py,sha256=SZl7nj75w-3uczfNfaZAMtcC4WO8M2mTmwbnB0HmrtU,2402
49
50
  physics/models/regen/regen.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- ubc_solar_physics-1.2.0.dist-info/LICENSE,sha256=1Vq7OikLHh7N0xsmTPHCmPkOxk1AXrMK9k1a1icQFlk,1087
51
- ubc_solar_physics-1.2.0.dist-info/METADATA,sha256=nPuG2LtB0tkAdyZqiH_xYFiVCR4DmG0aFDQwPj-zBEU,5107
52
- ubc_solar_physics-1.2.0.dist-info/WHEEL,sha256=yNnHoQL2GZYIUXm9YvoaBpFjGlUoK9qq9oqYeudrWlE,101
53
- ubc_solar_physics-1.2.0.dist-info/top_level.txt,sha256=aws060Zz-1h0Kx76JzcE1gLA_AfS1lrRtTCsyUYwDvM,8
54
- ubc_solar_physics-1.2.0.dist-info/RECORD,,
51
+ ubc_solar_physics-1.4.0.dist-info/LICENSE,sha256=1Vq7OikLHh7N0xsmTPHCmPkOxk1AXrMK9k1a1icQFlk,1087
52
+ ubc_solar_physics-1.4.0.dist-info/METADATA,sha256=d_AzqplNDIwtWaZWavMufkFT6QdwjlxwvFCPherV6MA,5107
53
+ ubc_solar_physics-1.4.0.dist-info/WHEEL,sha256=lPxm9M09dVYWZ0wAh0Zu0ADFguuSXLRXmaW8X9Lg2rA,101
54
+ ubc_solar_physics-1.4.0.dist-info/top_level.txt,sha256=aws060Zz-1h0Kx76JzcE1gLA_AfS1lrRtTCsyUYwDvM,8
55
+ ubc_solar_physics-1.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp311-cp311-win_amd64
5
5