ubc-solar-physics 1.1.0__cp39-cp39-win_amd64.whl → 1.2.0__cp39-cp39-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.cp39-win_amd64.pyd CHANGED
Binary file
physics/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.1.0'
16
- __version_tuple__ = version_tuple = (1, 1, 0)
15
+ __version__ = version = '1.2.0'
16
+ __version_tuple__ = version_tuple = (1, 2, 0)
physics/lib.rs CHANGED
@@ -8,6 +8,7 @@ pub mod environment;
8
8
  pub mod models;
9
9
  use crate::environment::gis::gis::rust_closest_gis_indices_loop;
10
10
  use crate::environment::meteorology::meteorology::{rust_calculate_array_ghi_times, rust_closest_weather_indices_loop, rust_weather_in_time, rust_closest_timestamp_indices};
11
+ use crate::models::battery::battery::update_battery_array;
11
12
 
12
13
  fn constrain_speeds(speed_limits: ArrayViewD<f64>, speeds: ArrayViewD<f64>, tick: i32) -> Vec<f64> {
13
14
  let mut distance: f64 = 0.0;
@@ -94,5 +95,38 @@ fn rust_simulation(_py: Python, m: &PyModule) -> PyResult<()> {
94
95
  py_result
95
96
  }
96
97
 
98
+ #[pyfn(m)]
99
+ #[pyo3(name = "update_battery_array")]
100
+ fn update_battery_array_py<'py>(
101
+ py: Python<'py>,
102
+ python_delta_energy_array: PyReadwriteArrayDyn<'py, f64>,
103
+ time_step: f64,
104
+ initial_state_of_charge: f64,
105
+ initial_polarization_potential: f64,
106
+ polarization_resistance: f64,
107
+ python_internal_resistance_coeffs: PyReadwriteArrayDyn<'py, f64>,
108
+ python_open_circuit_voltage_coeffs: PyReadwriteArrayDyn<'py, f64>,
109
+ time_constant: f64,
110
+ nominal_charge_capacity: f64,
111
+ ) -> (&'py PyArrayDyn<f64>, &'py PyArrayDyn<f64>) {
112
+ let delta_energy_array = python_delta_energy_array.as_array();
113
+ let internal_resistance_coeffs = python_internal_resistance_coeffs.as_array();
114
+ let open_circuit_voltage_coeffs = python_open_circuit_voltage_coeffs.as_array();
115
+ let (soc_array, voltage_array): (Vec<f64>, Vec<f64>) = update_battery_array(
116
+ delta_energy_array,
117
+ time_step,
118
+ initial_state_of_charge,
119
+ initial_polarization_potential,
120
+ polarization_resistance,
121
+ internal_resistance_coeffs,
122
+ open_circuit_voltage_coeffs,
123
+ time_constant,
124
+ nominal_charge_capacity,
125
+ );
126
+ let py_soc_array = PyArray::from_vec(py, soc_array).to_dyn();
127
+ let py_voltage_array = PyArray::from_vec(py, voltage_array).to_dyn();
128
+ (py_soc_array, py_voltage_array)
129
+ }
130
+
97
131
  Ok(())
98
132
  }
@@ -1,7 +1,14 @@
1
1
  from .base_battery import BaseBattery
2
2
  from .basic_battery import BasicBattery
3
+ from .battery_model import BatteryModel
4
+ from .kalman_filter import EKF_SOC
5
+ from .battery_config import BatteryModelConfig, load_battery_config
3
6
 
4
7
  __all__ = [
5
8
  "BaseBattery",
6
- "BasicBattery"
9
+ "BasicBattery",
10
+ "BatteryModel",
11
+ "EKF_SOC",
12
+ "BatteryModelConfig",
13
+ "load_battery_config"
7
14
  ]
@@ -1,6 +1,5 @@
1
1
  import numpy as np
2
2
  from numpy.polynomial import Polynomial
3
-
4
3
  from physics.models.battery.base_battery import BaseBattery
5
4
 
6
5
 
@@ -0,0 +1,78 @@
1
+ use std::f64;
2
+ use numpy::ndarray::ArrayViewD;
3
+
4
+ /// Evaluate a polynomial given coefficients and an input value (x)
5
+ fn evaluate_polynomial(coefficients: &[f64], x: f64) -> f64 {
6
+ coefficients.iter().fold(0.0, |acc, &coeff| acc * x + coeff)
7
+ }
8
+
9
+ /// Evolve the battery state for a single step
10
+ fn battery_evolve(
11
+ power: f64, // Watts
12
+ tick: f64, // Seconds
13
+ state_of_charge: f64, // Dimensionless, 0 < SOC < 1
14
+ polarization_potential: f64, // Volts
15
+ polarization_resistance: f64, // Ohms
16
+ internal_resistance: f64, // Ohms
17
+ open_circuit_voltage: f64, // Volts
18
+ time_constant: f64, // Seconds
19
+ nominal_charge_capacity: f64, // Nominal charge capacity (Coulombs)
20
+ ) -> (f64, f64, f64) {
21
+ // Compute current (I) based on power input/output
22
+ let current: f64 = power / (open_circuit_voltage + polarization_potential + internal_resistance);
23
+
24
+ // Update state of charge and polarization potential
25
+ let new_state_of_charge: f64 = state_of_charge + (current * tick / nominal_charge_capacity);
26
+ let new_polarization_potential: f64 = f64::exp(-tick / time_constant) * polarization_potential
27
+ + current * polarization_resistance * (1.0 - f64::exp(-tick / time_constant));
28
+ let terminal_voltage: f64 = open_circuit_voltage + new_polarization_potential
29
+ + (current * internal_resistance); // Terminal voltage
30
+
31
+ (new_state_of_charge, new_polarization_potential, terminal_voltage)
32
+ }
33
+
34
+ pub fn update_battery_array(
35
+ delta_energy_array: ArrayViewD<'_, f64>, // W*s
36
+ tick: f64, // Seconds
37
+ initial_state_of_charge: f64, // dimensionless, 0 < SOC < 1
38
+ initial_polarization_potential: f64, // Volts
39
+ polarization_resistance: f64, // Ohms
40
+ internal_resistance_coeffs: ArrayViewD<'_, f64>, // Coefficients for internal resistance
41
+ open_circuit_voltage_coeffs: ArrayViewD<'_, f64>, // Coefficients for open-circuit voltage
42
+ time_constant: f64, // Seconds
43
+ nominal_charge_capacity: f64, // Coulombs
44
+ ) -> (Vec<f64>, Vec<f64>) {
45
+ let mut state_of_charge: f64 = initial_state_of_charge;
46
+ let mut polarization_potential: f64 = initial_polarization_potential;
47
+ let mut soc_array: Vec<f64> = Vec::with_capacity(delta_energy_array.len());
48
+ let mut voltage_array: Vec<f64> = Vec::with_capacity(delta_energy_array.len());
49
+
50
+ for &power in delta_energy_array.iter() {
51
+ // Interpolate values from coefficient
52
+ let open_circuit_voltage: f64 = evaluate_polynomial(open_circuit_voltage_coeffs.as_slice().unwrap(), state_of_charge);
53
+ let internal_resistance: f64 = evaluate_polynomial(internal_resistance_coeffs.as_slice().unwrap(), state_of_charge);
54
+
55
+ let (new_state_of_charge, new_polarization_potential, terminal_voltage) = battery_evolve(
56
+ power,
57
+ tick,
58
+ state_of_charge,
59
+ polarization_potential,
60
+ polarization_resistance,
61
+ internal_resistance,
62
+ open_circuit_voltage,
63
+ time_constant,
64
+ nominal_charge_capacity,
65
+ );
66
+
67
+ // Update state for the next iteration
68
+ state_of_charge = new_state_of_charge;
69
+ polarization_potential = new_polarization_potential;
70
+
71
+ // Store results
72
+ soc_array.push(new_state_of_charge);
73
+ voltage_array.push(terminal_voltage);
74
+ }
75
+
76
+ (soc_array, voltage_array)
77
+ }
78
+
@@ -0,0 +1,22 @@
1
+ import tomli
2
+ from pydantic import BaseModel
3
+ from typing import List
4
+ import os
5
+ import pathlib
6
+
7
+ class BatteryModelConfig(BaseModel):
8
+ R_0_data: List[float]
9
+ R_P: float
10
+ C_P: float
11
+ Q_total: float
12
+ SOC_data: List[float]
13
+ Uoc_data: List[float]
14
+ max_current_capacity: float
15
+ max_energy_capacity: float
16
+
17
+ def load_battery_config(absolute_path: str) -> BatteryModelConfig:
18
+ # Build the full path to the config file
19
+ full_path = pathlib.Path(absolute_path)
20
+ with open(full_path, 'rb') as f:
21
+ data = tomli.load(f)
22
+ return BatteryModelConfig.model_validate(data)
@@ -0,0 +1,135 @@
1
+ import numpy as np
2
+ import core
3
+ from scipy import optimize
4
+ from physics.models.battery.battery_config import BatteryModelConfig
5
+
6
+
7
+ class BatteryModel:
8
+ """
9
+ Class representing the Thevenin equivalent battery model with modular parameters.
10
+
11
+ Attributes:
12
+ R_P (float): Polarization resistance of the battery (Ohms).
13
+ C_P (float): Polarization capacitance of the battery (Farads).
14
+ max_current_capacity (float): Nominal capacity of the battery (Ah).
15
+ max_energy_capacity (float): Maximum energy capacity of the battery (Wh).
16
+ nominal_charge_capacity (float): Total charge capacity of the battery (Coulombs).
17
+ state_of_charge (float): Current state of charge (dimensionless, 0.0 to 1.0).
18
+ U_oc_coefficients (np.ndarray): Coefficients for the open-circuit voltage polynomial.
19
+ R_0_coefficients (np.ndarray): Coefficients for the ohmic resistance polynomial.
20
+ U_oc (callable): Function for open-circuit voltage as a function of state of charge (V).
21
+ R_0 (callable): Function for ohmic resistance as a function of state of charge (Ohms).
22
+ U_P (float): Current polarization potential (V).
23
+ U_L (float): Current terminal voltage (V).
24
+ tau (float): Time constant of the battery model (seconds).
25
+ """
26
+
27
+ def __init__(self, battery_config: BatteryModelConfig, state_of_charge=1):
28
+ """
29
+ Constructor for the BatteryModel class.
30
+
31
+ :param BatteryModelConfig battery_config: Configuration object containing the battery's parameters and data.
32
+ :param float state_of_charge: Initial state of charge of the battery (default is 1.0, fully charged).
33
+ """
34
+
35
+ # ----- Load Config -----
36
+
37
+ self.R_P = battery_config.R_P
38
+ self.C_P = battery_config.C_P
39
+ self.max_current_capacity = battery_config.max_current_capacity
40
+ self.max_energy_capacity = battery_config.max_energy_capacity
41
+ self.nominal_charge_capacity = battery_config.Q_total
42
+ Soc_data = battery_config.SOC_data
43
+ Uoc_data = battery_config.Uoc_data
44
+ R_0_data = battery_config.R_0_data
45
+
46
+ # ----- Initialize Parameters -----
47
+ def quintic_polynomial(x, x0, x1, x2, x3, x4):
48
+ return np.polyval(np.array([x0, x1, x2, x3, x4]), x)
49
+
50
+ self.U_oc_coefficients, _ = optimize.curve_fit(quintic_polynomial, Soc_data, Uoc_data)
51
+ self.R_0_coefficients, _ = optimize.curve_fit(quintic_polynomial, Soc_data, R_0_data)
52
+ self.U_oc = lambda soc: np.polyval(self.U_oc_coefficients, soc) # V
53
+ self.R_0 = lambda soc: np.polyval(self.R_0_coefficients, soc) # Ohms
54
+
55
+ self.U_P = 0.0 # V
56
+ self.U_L = 0.0 # V
57
+ self.state_of_charge = state_of_charge
58
+
59
+ self.tau = self.R_P * self.C_P # Characteristic Time (seconds)
60
+
61
+ # calculated the charging and discharging currents
62
+ self.discharge_current = lambda P, U_oc, U_P, R_0: ((U_oc - U_P) - np.sqrt(
63
+ np.power((U_oc - U_P), 2) - 4 * R_0 * P)) / (2 * R_0)
64
+ self.charge_current = lambda P, U_oc, U_P, R_0: (-(U_oc + U_P) + np.sqrt(
65
+ np.power((U_oc + U_P), 2) + 4 * R_0 * P)) / (2 * R_0)
66
+
67
+ def _evolve(self, power: float, tick: float) -> None:
68
+ """
69
+ Update the battery state given the power and time elapsed.
70
+
71
+ :param float power: Power applied to the battery (W). Positive for charging, negative for discharging.
72
+ :param float T: Time interval over which the power is applied (seconds).
73
+ """
74
+ soc = self.state_of_charge # State of Charge (dimensionless, 0 < soc < 1)
75
+ U_P = self.U_P # Polarization Potential (V)
76
+ R_P = self.R_P # Polarization Resistance (Ohms)
77
+ U_oc = self.U_oc(soc) # Open-Circuit Potential (V)
78
+ R_0 = self.R_0(soc) # Ohmic Resistance (Ohms)
79
+ Q = self.nominal_charge_capacity # Nominal Charge Capacity (C)
80
+
81
+ current = self.discharge_current(power, U_oc, U_P, R_0) if power <= 0 else self.charge_current(power, U_oc, U_P, R_0) # Current (A)
82
+
83
+ new_soc = soc + (current * tick / Q)
84
+ new_U_P = np.exp(-tick / self.tau) * U_P + current * R_P * (1 - np.exp(-tick / self.tau))
85
+
86
+ self.state_of_charge = new_soc
87
+ self.U_P = new_U_P
88
+ self.U_L = U_oc + U_P + (current * R_0)
89
+
90
+ def update_array(self, delta_energy_array, tick, rust=True):
91
+ """
92
+ Compute the battery's state of charge, voltage, and stored energy over time.
93
+ This function is a wrapper for the Rust-based and Python-based implementations.
94
+
95
+ :param np.ndarray delta_energy_array: Array of energy changes (J) at each time step.
96
+ :param float tick: Time interval for each step (seconds).
97
+ :param bool rust: If True, use Rust-based calculations (default is True).
98
+
99
+ :return: A tuple containing arrays for state-of-charge, voltage, and stored energy.
100
+ :rtype: tuple[np.ndarray, np.ndarray, np.ndarray]
101
+ """
102
+
103
+ if rust:
104
+ return core.update_battery_array(
105
+ delta_energy_array,
106
+ tick,
107
+ self.state_of_charge,
108
+ self.U_P,
109
+ self.R_P,
110
+ self.R_0_coefficients,
111
+ self.U_oc_coefficients,
112
+ self.tau,
113
+ self.nominal_charge_capacity
114
+ )
115
+ else:
116
+ return self._update_array_py(delta_energy_array, tick)
117
+
118
+ def _update_array_py(self, delta_energy_array, tick):
119
+ """
120
+ Perform energy calculations using Python (fallback method if Rust is disabled).
121
+
122
+ :param np.ndarray delta_energy_array: Array of energy changes (J) at each time step.
123
+ :param float tick: Time interval for each step (seconds).
124
+
125
+ :return: A tuple containing arrays for state-of-charge and voltage.
126
+ :rtype: tuple[np.ndarray, np.ndarray]
127
+ """
128
+ soc = np.empty_like(delta_energy_array, dtype=float)
129
+ voltage = np.empty_like(delta_energy_array, dtype=float)
130
+ for i, energy in enumerate(delta_energy_array):
131
+ self._evolve(energy, tick)
132
+ soc[i] = self.state_of_charge
133
+ voltage[i] = self.U_L
134
+
135
+ return soc, voltage
@@ -0,0 +1,180 @@
1
+ import numpy as np
2
+ from scipy import optimize
3
+ from filterpy.kalman import ExtendedKalmanFilter as EKF
4
+ from physics.models.battery.battery_config import BatteryModelConfig
5
+
6
+
7
+ class EKF_SOC:
8
+ def __init__(self, battery_config: BatteryModelConfig, initial_SOC=1, initial_Uc=0):
9
+ """
10
+ EKF_SOC represents the Kalman filter used for predicting state of charge.
11
+
12
+ :param BatteryModelConfig battery_config: Contains the HPPC parameters of the battery model.
13
+ :param float initial_SOC: Initial state of charge of the battery (ranges from 0 to 1 inclusive, default is 1).
14
+ :param float initial_Uc: Initial polarization voltage of the battery in volts (default is 0).
15
+ """
16
+ # Initial state
17
+ self.SOC = initial_SOC
18
+ self.Uc = initial_Uc # Polarization Voltage
19
+
20
+ # Covariance Matrices
21
+ self.Q_covariance = np.eye(2) * 0.0001
22
+ self.R_covariance = np.eye(1) * 0.5 # currently not really trusting the predicted state
23
+
24
+ # Load Config data
25
+ self.R_P = battery_config.R_P
26
+ self.C_P = battery_config.C_P
27
+ self.Q_total = battery_config.Q_total
28
+ SOC_data = battery_config.SOC_data
29
+ Uoc_data = battery_config.Uoc_data
30
+ R_0_data = battery_config.R_0_data
31
+
32
+ def quintic_polynomial(x, x0, x1, x2, x3, x4):
33
+ return np.polyval([x0, x1, x2, x3, x4], x)
34
+
35
+ U_oc_coefficients, _ = optimize.curve_fit(quintic_polynomial, SOC_data, Uoc_data)
36
+ R_0_coefficients, _ = optimize.curve_fit(quintic_polynomial, SOC_data, R_0_data)
37
+ self.U_oc = lambda soc: np.polyval(U_oc_coefficients, soc) # Open-circuit voltage as a function of SOC
38
+ self.R_0 = lambda soc: np.polyval(R_0_coefficients, soc) # Resistance as a function of SOC
39
+ self.Uoc_derivative = lambda soc: np.polyval(np.polyder(U_oc_coefficients), soc) # Derivative of Uoc wrt SOC
40
+
41
+ self.tau = self.R_P / self.C_P
42
+
43
+ # initializing the ekf object
44
+ self.ekf = EKF(dim_x=2, dim_z=1)
45
+ self.ekf.x = np.array([self.SOC, self.Uc])
46
+ self.ekf.P = np.diag([1e-6, 1e-6]) # I'm keeping low uncertainty in initial SOC and Uc
47
+ self.ekf.Q = self.Q_covariance
48
+ self.ekf.R = self.R_covariance
49
+
50
+ # For logs
51
+ self.predicted_measurement = 0
52
+
53
+ def get_SOC(self):
54
+ """
55
+ Return the current state of charge of the battery.
56
+
57
+ :return: The current state of charge.
58
+ :rtype: float
59
+ """
60
+ return self.SOC
61
+
62
+ def get_Uc(self):
63
+ """
64
+ Return the polarization voltage of the battery.
65
+
66
+ :return: The current polarization voltage.
67
+ :rtype: float
68
+ """
69
+ return self.Uc
70
+
71
+ def get_predicted_Ut(self):
72
+ """
73
+ Return the predicted terminal voltage for the last prediction step.
74
+
75
+ :return: The predicted terminal voltage.
76
+ :rtype: float
77
+ """
78
+ return self.predicted_measurement
79
+
80
+ def update_filter(self, measured_Ut, I):
81
+ """
82
+ Update the filter based on a new measurement and the predicted state.
83
+ This function should be called after `predict_state` in a typical predict-update workflow.
84
+
85
+ :param float measured_Ut: The actual voltage across the terminals of the battery.
86
+ :param float I: The current being sourced by the battery.
87
+ """
88
+ check_Terminal_V(measured_Ut)
89
+
90
+ h_jacobian = self._measurement_jacobian
91
+ Hx = self._measurement_function
92
+
93
+ self.ekf.update(z=measured_Ut, HJacobian=h_jacobian, Hx=Hx, hx_args=I)
94
+
95
+ self.SOC, self.Uc = self.ekf.x
96
+
97
+ def predict_state(self, I, time_step):
98
+ """
99
+ Predict the next evolution of the state vector (SOC, Uc).
100
+ This function should be called before updating the filter in a typical predict-update workflow.
101
+
102
+ :param float I: The current being sourced by the battery. Positive indicates current being drawn.
103
+ :param float time_step: Time elapsed between this prediction and the last updated state of the filter (seconds).
104
+ """
105
+ check_current(I)
106
+ # Control matrix B (for input current I_k)
107
+ self.ekf.B = np.array([-time_step / self.Q_total, self.R_P * (1 - np.exp(-time_step / self.tau))])
108
+ self.ekf.F = self._state_jacobian(time_step)
109
+
110
+ self.ekf.predict(u=I)
111
+ print(f'ekf prediction: {self.ekf.x_prior}')
112
+
113
+ def predict_then_update(self, measured_Ut, I, time_step):
114
+ """
115
+ Predict the next evolution of the state vector (SOC, Uc), then update the filter
116
+ based on this prediction and a measurement. Abstracts the full predict-update workflow of the EKF.
117
+
118
+ :param float measured_Ut: The actual voltage across the terminals of the battery.
119
+ :param float I: The current being sourced by the battery. Positive indicates current being drawn.
120
+ :param float time_step: Time elapsed between this prediction and the last updated state of the filter (seconds).
121
+ """
122
+ check_current(I)
123
+ check_Terminal_V(measured_Ut)
124
+
125
+ self.predict_state(I, time_step)
126
+ print(f'predicted: {self.ekf.x_prior}')
127
+
128
+ self.update_filter(measured_Ut, I)
129
+ print(f'SOC: {self.ekf.x[0]}, Uc: {self.ekf.x[1]}')
130
+
131
+ def _state_jacobian(self, time_step):
132
+ """
133
+ Return the state Jacobian matrix for the current time step.
134
+
135
+ :param float time_step: Time elapsed between this prediction and the last updated state of the filter (seconds).
136
+ :return: The state Jacobian matrix.
137
+ :rtype: np.ndarray
138
+ """
139
+ return np.array([[1, 0], [0, np.exp(-time_step / self.tau)]])
140
+
141
+ def _measurement_jacobian(self, x):
142
+ """
143
+ Return the measurement Jacobian matrix for the current state vector.
144
+
145
+ :param list[float, float] x: The state vector [SOC, Uc].
146
+ :return: The measurement Jacobian matrix.
147
+ :rtype: np.ndarray
148
+ """
149
+ SOC = x[0]
150
+ derivative = self.Uoc_derivative(SOC)
151
+ return np.array([[derivative, -1]])
152
+
153
+ def _measurement_function(self, x, I):
154
+ """
155
+ Return the measurement function relating terminal voltage to SOC and polarization voltage.
156
+
157
+ :param list[float, float] x: The state vector [SOC, Uc].
158
+ :param float I: The current being sourced by the battery.
159
+ :return: The predicted terminal voltage.
160
+ :rtype: float
161
+ """
162
+ SOC, Uc = x
163
+ R_0 = self.R_0(SOC)
164
+ Uoc = self.U_oc(SOC)
165
+ self.predicted_measurement = Uoc - Uc - R_0 * I
166
+ return self.predicted_measurement
167
+
168
+
169
+ def check_current(I):
170
+ if not isinstance(I, (float, int)):
171
+ raise TypeError(f"Invalid type for current I: {type(I)}. Expected float or int.")
172
+ if not (-45.0 <= I <= 45.0):
173
+ raise ValueError(f"Invalid value for current (I): {I}. Must be between -45.0A and 45.0A.")
174
+
175
+
176
+ def check_Terminal_V(Ut):
177
+ if not isinstance(Ut, (float, int)):
178
+ raise TypeError(f"Invalid type for measured_Ut: {type(Ut)}. Expected float or int.")
179
+ if not (0.0 <= Ut <= 5.0):
180
+ raise ValueError(f"Invalid value for terminal voltage (measured_Ut): {Ut}. Must be between 0.0 and 5.0 volts.")
physics/models/battery.rs CHANGED
@@ -1 +1 @@
1
- mod battery;
1
+ pub mod battery;
physics/models.rs CHANGED
@@ -1,5 +1,5 @@
1
1
  mod arrays;
2
- mod battery;
2
+ pub mod battery;
3
3
  mod lvs;
4
4
  mod motor;
5
5
  mod regen;
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: ubc-solar-physics
3
- Version: 1.1.0
3
+ Version: 1.2.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>
@@ -39,34 +39,40 @@ Classifier: Topic :: Scientific/Engineering :: Physics
39
39
  Requires-Python: >=3.9
40
40
  Description-Content-Type: text/markdown
41
41
  License-File: LICENSE
42
- Requires-Dist: backports.tarfile ==1.2.0
43
- Requires-Dist: certifi ==2024.7.4
44
- Requires-Dist: charset-normalizer ==3.3.2
45
- Requires-Dist: dill ==0.3.8
46
- Requires-Dist: haversine ==2.8.1
47
- Requires-Dist: idna ==3.7
48
- Requires-Dist: importlib-metadata ==8.2.0
49
- Requires-Dist: jaraco.classes ==3.4.0
50
- Requires-Dist: jaraco.context ==5.3.0
51
- Requires-Dist: jaraco.functools ==4.0.2
52
- Requires-Dist: keyring ==25.3.0
53
- Requires-Dist: llvmlite ==0.43.0
54
- Requires-Dist: markdown-it-py ==3.0.0
55
- Requires-Dist: mdurl ==0.1.2
56
- Requires-Dist: more-itertools ==10.4.0
57
- Requires-Dist: nh3 ==0.2.18
58
- Requires-Dist: numba ==0.60.0
59
- Requires-Dist: numpy ==2.0.1
60
- Requires-Dist: pkginfo ==1.10.0
61
- Requires-Dist: Pygments ==2.18.0
62
- Requires-Dist: readme-renderer ==44.0
63
- Requires-Dist: requests ==2.32.3
64
- Requires-Dist: requests-toolbelt ==1.0.0
65
- Requires-Dist: rfc3986 ==2.0.0
66
- Requires-Dist: rich ==13.7.1
67
- Requires-Dist: tqdm ==4.66.5
68
- Requires-Dist: urllib3 ==2.2.2
69
- Requires-Dist: zipp ==3.20.0
42
+ Requires-Dist: backports.tarfile==1.2.0
43
+ Requires-Dist: certifi==2024.7.4
44
+ Requires-Dist: charset-normalizer==3.3.2
45
+ Requires-Dist: dill==0.3.8
46
+ Requires-Dist: haversine==2.8.1
47
+ Requires-Dist: idna==3.7
48
+ Requires-Dist: importlib_metadata==8.2.0
49
+ Requires-Dist: jaraco.classes==3.4.0
50
+ Requires-Dist: jaraco.context==5.3.0
51
+ Requires-Dist: jaraco.functools==4.0.2
52
+ Requires-Dist: keyring==25.3.0
53
+ Requires-Dist: llvmlite==0.43.0
54
+ Requires-Dist: markdown-it-py==3.0.0
55
+ Requires-Dist: mdurl==0.1.2
56
+ Requires-Dist: more-itertools==10.4.0
57
+ Requires-Dist: nh3==0.2.18
58
+ Requires-Dist: numba==0.60.0
59
+ Requires-Dist: numpy==2.0.1
60
+ Requires-Dist: pkginfo==1.10.0
61
+ Requires-Dist: Pygments==2.18.0
62
+ Requires-Dist: readme_renderer==44.0
63
+ Requires-Dist: requests==2.32.3
64
+ Requires-Dist: requests-toolbelt==1.0.0
65
+ Requires-Dist: rfc3986==2.0.0
66
+ Requires-Dist: rich==13.7.1
67
+ Requires-Dist: tqdm==4.66.5
68
+ Requires-Dist: urllib3==2.2.2
69
+ Requires-Dist: zipp==3.20.0
70
+ Requires-Dist: filterpy==1.4.5
71
+ Requires-Dist: toml==0.10.2
72
+ Requires-Dist: pandas
73
+ Requires-Dist: pydantic==2.9.2
74
+ Requires-Dist: scipy
75
+ Requires-Dist: tomli
70
76
 
71
77
  # UBC Solar Physics
72
78
 
@@ -1,9 +1,9 @@
1
- core.cp39-win_amd64.pyd,sha256=58iQkLjDBIx5NLa4kpI_Nz5eEyg8Ynxg1tuZN99P5lc,365568
1
+ core.cp39-win_amd64.pyd,sha256=kdWR551aw-H-qoXz6vJoE104KevwzuO_WJpKzy8Ta3c,382976
2
2
  physics/__init__.py,sha256=jRV9J_eGh0vNXEfFrILqcM6xxVjyqm3XwKAg1B1IPBs,183
3
- physics/_version.py,sha256=mLrG-mC5i2vs5IEM3ZgT5S9ZdaqM1wQHESPk1-Rj79o,427
3
+ physics/_version.py,sha256=DnUqy-xWN4z1XWOsowoRN4Vz2GPuDm_18GEJc3VGkWg,427
4
4
  physics/environment.rs,sha256=OghmBkvHLZvzzuVsXUmV2lR3X_tEwuB9sT2TGZLQC6E,36
5
- physics/lib.rs,sha256=lH7bim9AIVvn58XmwzLk5RqhcotvX6l0IezT6Rm41zY,4246
6
- physics/models.rs,sha256=iyhO-vQsAYrIQJHYONUvtuTqQ3HtlaTeOIZqCOH3JkU,59
5
+ physics/lib.rs,sha256=FqnhKkotYKJCu8v1vbov2QW9s0apay7-BnEcUgxOakU,5798
6
+ physics/models.rs,sha256=747ABP-D1XKxA6X_MNh1PbmST0zsxpxhP_pEWjbR46c,63
7
7
  physics/environment/__init__.py,sha256=se_LVo4aWZKcZgbbK1KwwhHG8SH2zS1g6TEPw0GOZSs,225
8
8
  physics/environment/environment.rs,sha256=-VztdV2_GSlRbyIV_Pt6gKPVxpuNXpjLgAmoervonLg,34
9
9
  physics/environment/gis.rs,sha256=9R7G0cjf5PxQAz-CSryA6-KGfrh1eSwRhJ6qF8KfjDE,12
@@ -19,7 +19,7 @@ physics/environment/meteorology/irradiant_meteorology.py,sha256=BNuINbPfNQO5dB9A
19
19
  physics/environment/meteorology/meteorology.rs,sha256=a5XlYhb34xvPKuGp1etTQZlSqm9qTd7UXuN6H0-jXfY,5142
20
20
  physics/models/__init__.py,sha256=YgSvt4iBbcoH55XskiK9uE3VXxqCh-ZoIbAWogNUK7U,268
21
21
  physics/models/arrays.rs,sha256=rtthXq7PDjL30lIt8y9L2xFAPJE5o_ltmCbOGzzOxrc,11
22
- physics/models/battery.rs,sha256=GzPA7uaF5FdewEFZL2eOt9ZeA1GzfRDQ9db_qkEpLR8,12
22
+ physics/models/battery.rs,sha256=fTL9O20fQarT_CFsmMSqVEZNe_sTejWMaAR8Fc-z_ak,16
23
23
  physics/models/constants.py,sha256=GMD4hYO1FKoni3MNPvcyYg2EKGrgKxvOnxVKlEapUEc,839
24
24
  physics/models/lvs.rs,sha256=uyJ1ZZ1Phq8cWCzr2aevCWzt8MlhCw9DO5ObUvEs8ds,8
25
25
  physics/models/motor.rs,sha256=Iya1C_YF09KMy-9N-Mt-rBf1EIAs2Bf3Q4eDvyFuAoc,10
@@ -28,10 +28,13 @@ physics/models/arrays/__init__.py,sha256=Ds36SXwtCBnoq1xDOVlqA4kMBcOqS1wa9gLTn7T
28
28
  physics/models/arrays/arrays.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  physics/models/arrays/base_array.py,sha256=KjTX_0MCvWSEf4irXd3P1ITsgjhFUqK1Cf0MbSQwLuk,101
30
30
  physics/models/arrays/basic_array.py,sha256=-6yj85XkuySrjnLVmLnU35A4EOatiw4QpkLcC7n1WXU,1371
31
- physics/models/battery/__init__.py,sha256=y0sM5d4aUdpHnrcx4fNRLnThOHofCcCSAxDh7OIDGTY,138
31
+ physics/models/battery/__init__.py,sha256=huRYMnfw035kqHyWeApAvdCaSf9yAQZMcQMnPutIXLE,376
32
32
  physics/models/battery/base_battery.py,sha256=yU-QopEEQ83kw4CUvJ2MEhYyj3AM3LYY_hvdZ2wwW7c,1232
33
- physics/models/battery/basic_battery.py,sha256=yFgFIXdTuNrp6E0jDYERowY9-pkTSWyoIs_Ksad2fyI,5896
34
- physics/models/battery/battery.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ physics/models/battery/basic_battery.py,sha256=5o-7g5xflhNLKuJyeqOY-1rLIOSIy_CJ0U4GEqeQO1E,5894
34
+ physics/models/battery/battery.rs,sha256=0wIQVli7UOWgKXT96cQLWisLQKo5UE08X4B9dl09USI,3649
35
+ physics/models/battery/battery_config.py,sha256=Dsi7cXR8SL0v7aSTuihhB6il9-8h1a2P8qrGbdvlf8Q,617
36
+ physics/models/battery/battery_model.py,sha256=kHn-xOyFBzWycpd-9Wn75fzHYZ512wXOi1dUrlt3a5M,6313
37
+ physics/models/battery/kalman_filter.py,sha256=Lr7J2vwO1HwN6miNFAYCfhZiZ2j72bwmUt-vubpo0Ks,7371
35
38
  physics/models/lvs/__init__.py,sha256=ZBips6zW4Lot7SkQZMZt_OGRNUqgOfUlDtBA5lfUkM4,114
36
39
  physics/models/lvs/base_lvs.py,sha256=kVLfGd9Qwql4-6u86uwHbJoFCgYpG07r0cAR2Ngsq38,116
37
40
  physics/models/lvs/basic_lvs.py,sha256=xNXeN6RGSZkJLhtcW0n2xZU6YIOT4bKUIbOFdmh4zc0,621
@@ -44,8 +47,8 @@ physics/models/regen/__init__.py,sha256=JzyRYKwT89FQ6_p9ofCqusl2fnWGHulyiK4P4f8L
44
47
  physics/models/regen/base_regen.py,sha256=lY44jrTSHEo8Xv7hKCjo4C3Jx0PUgilyITHwQchT2bM,101
45
48
  physics/models/regen/basic_regen.py,sha256=RY730lQLJ_gKkm2wJ68t1OPTmcz9xxGmu0yBLwHCGoQ,1811
46
49
  physics/models/regen/regen.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- ubc_solar_physics-1.1.0.dist-info/LICENSE,sha256=1Vq7OikLHh7N0xsmTPHCmPkOxk1AXrMK9k1a1icQFlk,1087
48
- ubc_solar_physics-1.1.0.dist-info/METADATA,sha256=vvGaNhRnUCt6oAfnbaWYqrXdJG_oyhFwmUhSLuilFZ0,4975
49
- ubc_solar_physics-1.1.0.dist-info/WHEEL,sha256=vq7bX_I37ZJK2gZz_HGA8eCPjBDKQSfb_9FNjesTNkk,99
50
- ubc_solar_physics-1.1.0.dist-info/top_level.txt,sha256=aws060Zz-1h0Kx76JzcE1gLA_AfS1lrRtTCsyUYwDvM,8
51
- ubc_solar_physics-1.1.0.dist-info/RECORD,,
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=agy-BJge3afXwWznUXANATmKFW4eqelqRR0uf608A_0,99
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp39-cp39-win_amd64
5
5