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.
- pybatteryse/__init__.py +1 -0
- pybatteryse/coefficient.py +97 -0
- pybatteryse/filters/__init__.py +3 -0
- pybatteryse/filters/ekf.py +938 -0
- pybatteryse/filters/pf.py +261 -0
- pybatteryse/plotter.py +32 -0
- pybatteryse/statespace.py +93 -0
- pybatteryse-1.0.0.dist-info/METADATA +128 -0
- pybatteryse-1.0.0.dist-info/RECORD +12 -0
- pybatteryse-1.0.0.dist-info/WHEEL +5 -0
- pybatteryse-1.0.0.dist-info/licenses/LICENSE.txt +29 -0
- pybatteryse-1.0.0.dist-info/top_level.txt +1 -0
pybatteryse/__init__.py
ADDED
|
@@ -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
|