pybatteryse 1.0.0__py3-none-any.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.
@@ -0,0 +1 @@
1
+ """Load"""
@@ -0,0 +1,97 @@
1
+ """Utilities concerning model state-space representation."""
2
+
3
+ import re
4
+ from dataclasses import dataclass
5
+
6
+ import numpy as np
7
+
8
+
9
+ @dataclass
10
+ class CoefficientTerm:
11
+ """
12
+ Represents a term in the model coefficient. Note that the
13
+ coefficient is made up of several terms, e.g.,
14
+ b_0(k) = 2 * s(k) × log[s](k) + 4 * T(k) × 1/s(k) is made up
15
+ of two terms.
16
+ """
17
+ parameter: float
18
+ basis_function_strings: list[str]
19
+
20
+
21
+ Coefficients = dict[str, list[CoefficientTerm]]
22
+
23
+
24
+ def extract_model_coefficients(model_terms, model_estimate, output_symbol='v', input_symbol='i'):
25
+ """Extract p-dependent model coefficients."""
26
+
27
+ coefficients: dict[str, list[CoefficientTerm]] = {}
28
+
29
+ for term, parameter in zip(model_terms, model_estimate):
30
+ result = re.search(f'({output_symbol}|{input_symbol})\\(k(-(\\d+))?\\)', term)
31
+ if result is None:
32
+ raise ValueError('Invalid model terms.')
33
+
34
+ # Define coefficient
35
+ result_groups = result.groups()
36
+ coefficient_variable = 'a' if result_groups[0] == output_symbol else 'b'
37
+ coefficient_delay = result_groups[2] if result_groups[2] is not None else 0
38
+
39
+ # Remove input/output terms plus the time indices
40
+ coefficient_term = re.sub(f'({output_symbol}|{input_symbol})?\\(k(-(\\d+))?\\)', '', term)
41
+ # We split the term into a list of individual
42
+ # basis function strings
43
+ coefficient_term_bfs = coefficient_term.strip('×').split('×')
44
+
45
+ # Define coefficient key, e.g., b_0, b_1, ...
46
+ coefficient_key = f'{coefficient_variable}_{coefficient_delay}'
47
+ if coefficient_key not in coefficients:
48
+ coefficients[coefficient_key] = []
49
+ #
50
+ coefficient_parameter = -parameter if coefficient_variable == 'a' else parameter
51
+ coefficients[coefficient_key].append(CoefficientTerm(coefficient_parameter,
52
+ coefficient_term_bfs))
53
+
54
+ return coefficients
55
+
56
+
57
+ def evaluate_coefficient(coefficient_terms: list[CoefficientTerm],
58
+ signal_trajectories: dict,
59
+ time_instant: int):
60
+ """Evaluate a coefficient at a certain time instant."""
61
+
62
+ result = []
63
+ for coefficient_term in coefficient_terms:
64
+ #
65
+ term_value = coefficient_term.parameter
66
+ for bf_string in coefficient_term.basis_function_strings:
67
+ if bf_string == '':
68
+ continue
69
+ #
70
+ term_value *= signal_trajectories[f'{bf_string}(k)'][time_instant]
71
+ result.append(term_value)
72
+
73
+ return np.sum(result)
74
+
75
+
76
+ def update_model_parameters(coefficients: Coefficients, model_estimate: list[float]) -> None:
77
+ """Update coefficient parameters in-place from a flat model_estimate vector.
78
+
79
+ Iterates coefficients.items() in insertion order (a_1, a_2, ..., b_0, b_1, ...)
80
+ which matches the canonical parameter order guaranteed by extract_model_coefficients.
81
+ a-term parameters are stored with negated sign (convention from extract_model_coefficients).
82
+
83
+ Raises:
84
+ ValueError: If len(model_estimate) does not match the total subterm count.
85
+ """
86
+ all_keyed_subterms = [
87
+ (subterm, coefficient_key.startswith('a'))
88
+ for coefficient_key, subterms in coefficients.items()
89
+ for subterm in subterms
90
+ ]
91
+ if len(model_estimate) != len(all_keyed_subterms):
92
+ raise ValueError(
93
+ f"Parameter count mismatch: expected {len(all_keyed_subterms)} parameters "
94
+ f"but got {len(model_estimate)}."
95
+ )
96
+ for (subterm, is_a_coefficient), new_parameter in zip(all_keyed_subterms, model_estimate):
97
+ subterm.parameter = -new_parameter if is_a_coefficient else new_parameter
@@ -0,0 +1,3 @@
1
+ """Load"""
2
+ from .ekf import ExtendedKalmanFilter
3
+ from .pf import ParticleFilter