causalchamber 0.0.1__tar.gz

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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Juan L Gamella
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: causalchamber
3
+ Version: 0.0.1
4
+ Summary: Access the datasets and models from the causal chambers.
5
+ Author-email: Juan L Gamella <juangamella@gmail.com>
6
+ Project-URL: Homepage, https://causalchamber.org
7
+ Project-URL: Repository, https://github.com/juangamella/causal-chamber
8
+ Project-URL: Issues, https://github.com/juangamella/causal-chamber/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # `causalchamber` package
17
+
18
+ TODO.
@@ -0,0 +1,139 @@
1
+ # The Causal Chambers: Dataset Repository
2
+
3
+ ![The Causal Chambers: (left) the wind tunnel, and (right) the light tunnel with the front panel removed to show its interior.](the_chambers.jpg)
4
+
5
+ This repository contains datasets collected from the _causal chambers_, the two devices described in the 2024 paper [*The Causal Chambers: Real Physical Systems as a Testbed for AI Methodology*](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>) by Juan L. Gamella, Jonas Peters and Peter Bühlmann. The repository is updated as we collect new datasets from the chambers.
6
+
7
+ The datasets are publicly available through a permissive [CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0/). This means you are free to use, share and modify the datasets as long as you give appropriate credit and communicate changes. If you use the datasets in your scientific work, please consider citing:
8
+
9
+ ```
10
+ @article{gamella2024chamber,
11
+ title={The Causal Chambers: Real Physical Systems as a Testbed for AI Methodology},
12
+ author={Gamella, Juan L. and B\"uhlmann, Peter and Peters, Jonas},
13
+ journal={arXiv preprint arXiv:TODO},
14
+ year={2024}
15
+ }
16
+ ```
17
+
18
+ This repository also contains the source code for the `causalchamber` [package](<https://placehold.co/600x400?text=Placeholder:\nPyPi link!>) to directly [import the datasets into your Python code](#downloading-the-datasets). The package also provides Python implementations of the [mechanistic models](#mechanistic-models) described in appendix [XX] of the original [paper](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>).
19
+
20
+ Here you can also find the resources to [build the chambers](#building-the-chambers), and the datasheets for all chamber components (see [`hardware/`](hardware/)).
21
+
22
+ The code to reproduce the case studies in the original paper can be found in the separate [paper repository](https://github.com/juangamella/causal-chamber-paper).
23
+
24
+ ## Available datasets
25
+
26
+ <!-- ![Examples of data collected from the chambers. See Fig. TODO of the manuscript for more details.](chamber_data.png) -->
27
+
28
+ Each dataset is described in detail in its corresponding page (click the dataset name). The chamber configurations are described in Fig. 3 of the manuscript.
29
+
30
+ | Dataset name | Notes | Chamber | Config. |
31
+ |--------:|:--------------------------------|:--------:|:--------:|
32
+ | [lt_camera_walks_v1](datasets/lt_camera_walks_v1/) | Image data for the ICA case study (task d3, Fig. 6). | Light tunnel | camera |
33
+ | [lt_color_regression_v1](datasets/lt_color_regression_v1/) | Image data for task b2 in the OOD case study (Fig. 5) | Light tunnel | camera |
34
+ | [lt_interventions_standard_v1](datasets/lt_interventions_standard_v1/) | Observational and interventional data from the light tunnel, used for the causal discovery case study in Fig. 5. | Light tunnel | standard |
35
+ | [lt_walks_v1](datasets/lt_walks_v1/) | Random and deterministic walks of the light-tunnel actuators. Used in the ICA case study (task d1), Fig. 6. | Light tunnel | standard |
36
+ | [wt_walks_v1](datasets/wt_walks_v1/) | Random and deterministic walks of the wind-tunnel actuators. Used in the causal discovery (task a3) and ICA (task d2) case studies. | Wind tunnel | standard |
37
+ | [lt_malus_v1](datasets/lt_malus_v1/) | Measurements of light intensity displaying Malus' law, used in the symbolic regression task in Fig. XX. | Light tunnel | standard |
38
+ | [wt_bernoulli_v1](datasets/wt_bernoulli_v1/) | Measurements of air pressure displaying Bernoulli's principle, used in the symbolic regression task in Fig. XX. | Wind tunnel | standard |
39
+ | [wt_changepoints_v1](datasets/wt_changepoints_v1/) | Used for the change point detection case study in Fig. 5. | Wind tunnel | standard |
40
+ | [wt_intake_impulse_v1](datasets/wt_intake_impulse_v1/) | Barometric pressure curves used in task 2c, Fig. 5. | Wind tunnel | standard |
41
+ | [wt_pressure_control_v1](datasets/wt_pressure_control_v1/) | Data from the pressure-control configuration of the wind tunnel. | Wind tunnel | pressure-control |
42
+ | [lt_test_v1](datasets/lt_test_v1/) | Experiments to characterize some of the physical effects of the light tunnel. Shown in figures XX-XX of the manuscript. | Light tunnel | standard |
43
+ | [wt_test_v1](datasets/wt_test_v1/) | Experiments to characterize some of the physical effects of the wind tunnel. Shown in figures XX-XX of the manuscript. | Wind tunnel | standard |
44
+ | [lt_camera_test_v1](datasets/lt_camera_test_v1/) | Experiments to characterize some of the physical effects of the camera system in the light tunnel. | Light tunnel | camera |
45
+ | [wt_validate_v1](datasets/wt_validate_v1/) | Randomized control experiments to validate the causal ground-truth graph of the wind tunnel in its _standard_ configuration (appendix XX of the manuscript). | Wind tunnel | standard |
46
+ | [wt_pc_validate_v1](datasets/wt_validate_v1/) | Randomized control experiments to validate the causal ground-truth graph of the wind tunnel in its _pressure-control_ configuration (appendix XX of the manuscript). | Wind tunnel | pressure-control |
47
+ | [lt_validate_v1](datasets/lt_validate_v1/) | Randomized control experiments to validate the causal ground-truth graphs of the light tunnel in its _standard_ configuration (appendix XX of the manuscript). | Light tunnel | standard |
48
+ | [lt_camera_validate_v1](datasets/lt_validate_v1/) | Randomized control experiments to validate the causal ground-truth graphs of the light tunnel in its _camera_ configuration (appendix XX of the manuscript). | Light tunnel | standard |
49
+
50
+ ## Downloading the datasets
51
+
52
+ For each dataset, you can simply download a `.zip` file with all the data, including the images at different resolutions. The link and checksum (to verify integrity) are available on the page of each dataset (click on the dataset name in the table above).
53
+
54
+ If you use Python, you can directly import a dataset into your code through the `causalchamber` [package](<https://placehold.co/600x400?text=Placeholder:\nPyPi link!>). You can install it using pip, e.g. by typing
55
+
56
+ ```
57
+ pip install causalchamber
58
+ ```
59
+
60
+ in an appropriate shell. Datasets can then be accessed directly from your Python code. For example, you can access the image data from task d3 of the ICA case study ([Fig. 6](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>)) as follows:
61
+
62
+ ```python
63
+ from causalchamber.datasets import Dataset
64
+
65
+ # Download the dataset and store in e.g. /tmp
66
+ dataset = Dataset(name='lt_camera_walks_v1',
67
+ root='/tmp')
68
+
69
+ # Load the observations and images (at 50x50 pixels)
70
+ experiment = dataset.get_experiment(name='actuator_mix')
71
+
72
+ observations = experiment.as_pandas_dataframe()
73
+ images = experiment.as_image_array(size='50')
74
+ ```
75
+
76
+ For the available experiment names, see the page for each dataset (click on the dataset name in the table above) or run
77
+ ```python
78
+ dataset.available_experiments()
79
+
80
+ # Output:
81
+ # ['actuator_mix',
82
+ # 'color_mix']
83
+ ```
84
+
85
+ To force-download a fresh copy of a dataset, can call `Dataset(...)` above with the flag `force_download=True`. Update the `causalchamber` [package](<https://placehold.co/600x400?text=Placeholder:\nPyPi link!>) for access to the latest datasets.
86
+
87
+
88
+ ## Mechanistic models
89
+
90
+ The `causalchamber` [package](<https://placehold.co/600x400?text=Placeholder:\nPyPi link!>) also contains Python implementations of the mechanistic models described in appendix [XX] of the original [paper](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>). The models follow the same nomenclature as in the paper, e.g., to import and run model A1 of the steady-state fan speed:
91
+ ```Python
92
+ from causalchamber.models import model_a1
93
+ model_a1(L=np.linspace(0,1,10), L_min=0.1, omega_max=314.15)
94
+
95
+ # Output:
96
+
97
+ # array([ 31.415 , 34.90555556, 69.81111111, 104.71666667,
98
+ # 139.62222222, 174.52777778, 209.43333333, 244.33888889,
99
+ # 279.24444444, 314.15 ])
100
+ ```
101
+
102
+ The implementations can be found in the [`src/causalchamber/models`](src/causalchamber/models) directory. You can find examples of using the models in the (case_studies/mechanistic_models.ipynb)[XX] notebook in the separate [paper repository](https://github.com/juangamella/causal-chamber-paper).
103
+
104
+ ## Causal ground-truth graphs
105
+
106
+ The graphs for the causal ground truths given in Fig. 3 of the original [paper](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>) can be found as adjacency matrices in the `ground_truths/` directory. The adjacencies can also be loaded through the `causalchamber` [package](<https://placehold.co/600x400?text=Placeholder:\nPyPi link!>), e.g.,
107
+ ```python
108
+ from causalchamber.ground_truth import graph
109
+ graph(chamber="lt", configuration="standard")
110
+
111
+ # Output:
112
+
113
+ # red green blue osr_c v_c current pol_1 pol_2 osr_angle_1 \
114
+ # red 0 0 0 0 0 1 0 0 0
115
+ # green 0 0 0 0 0 1 0 0 0
116
+ # blue 0 0 0 0 0 1 0 0 0
117
+ # osr_c 0 0 0 0 0 1 0 0 0
118
+ ```
119
+
120
+ To make it easier to plot graphs and reference them back to the original paper, the latex representation of each variable can be obtained by calling the `latex_name` function. For example, to obtain the latex representation $\theta_1$ of the `pol_1` variable, you can run
121
+ ```python
122
+ from causalchamber.ground_truth import latex_name
123
+ latex_name('pol_1', enclose=True)
124
+
125
+ # Output:
126
+
127
+ # '$\\theta_1$'
128
+ ```
129
+
130
+ ## Building the chambers
131
+
132
+ You can find the resources to build the chambers in [`hardware/`](hardware/), together with the datasheets for all physical components (see appendix [XX]) of the original [paper](<https://placehold.co/600x400?text=Placeholder:\nArxiv link!>).
133
+
134
+ ## Licenses
135
+
136
+ All images and `.csv` files in the datasets are licensed under a [CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0/). A copy of the license can be found in [LICENSE_DATASETS.txt](LICENSE_DATASETS.txt).
137
+
138
+ The code, e.g., for the `causalchamber` package and mechanistic models, is shared under the [MIT license](https://opensource.org/license/mit/). A copy of the license can also be found in [LICENSE_SOFTWARE.txt](LICENSE_SOFTWARE.txt).
139
+
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "causalchamber"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Juan L Gamella", email="juangamella@gmail.com" },
10
+ ]
11
+ description = "Access the datasets and models from the causal chambers."
12
+ readme = "src/README.md"
13
+ requires-python = ">=3.8"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ dependencies = [
20
+ "numpy>=1.17.0",
21
+ "pandas>=1.2.1"
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://causalchamber.org"
26
+ Repository = "https://github.com/juangamella/causal-chamber"
27
+ Issues = "https://github.com/juangamella/causal-chamber/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ # `causalchamber` package
2
+
3
+ TODO.
File without changes
@@ -0,0 +1 @@
1
+ from .main import *
@@ -0,0 +1,345 @@
1
+ # MIT License
2
+
3
+ # Copyright (c) 2023 Juan L. Gamella
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ import causalchamber.datasets.utils as utils
24
+ from pathlib import Path
25
+ import pandas as pd
26
+ import yaml
27
+ from PIL import Image
28
+ import numpy as np
29
+ import os
30
+
31
+
32
+ # Maybe have this as a downloadable YAML file
33
+ directory_path = Path(Path(__file__).parents[0], "directory.yaml")
34
+ with open(directory_path, "r") as f:
35
+ directory = yaml.load(f, Loader=yaml.Loader)
36
+ f.close()
37
+
38
+ # --------------------------------------------------------------------
39
+ # Base Dataset and Experiment classes
40
+
41
+ citation = """
42
+ @article{gamella2024chamber,
43
+ title={The Causal Chambers: Real Physical Systems as a Testbed for AI Methodology},
44
+ author={Gamella, Juan L. and B\"uhlmann, Peter and Peters, Jonas},
45
+ journal={(work in progress)},
46
+ year={2023}
47
+ }
48
+ """
49
+
50
+ print(f"If you use our datasets for your work please consider citing:\n{citation}")
51
+
52
+
53
+ class Dataset:
54
+ def __init__(self, name, root, download=True):
55
+ available_datasets = directory["datasets"].keys()
56
+ if name not in available_datasets:
57
+ string = ""
58
+ for d in available_datasets:
59
+ string += ' "' + d + '"\n'
60
+ raise ValueError(
61
+ f'Dataset "{name}" is not available. Available datasets:\n{string}'
62
+ )
63
+ # Store attributes
64
+ self.name = name
65
+ self.root = root
66
+ self.image = directory["datasets"][name]["image"]
67
+ # Check if dataset has already been downloaded to root
68
+ dataset_dir = Path(self.root, self.name)
69
+ if os.path.isdir(dataset_dir):
70
+ print(f'Dataset {self.name} found in "{dataset_dir}".')
71
+ else:
72
+ if download:
73
+ # Download, verify and extract
74
+ self.url = directory["datasets"][name]["url"]
75
+ self.checksum = directory["datasets"][name]["md5"]
76
+ utils.download_and_extract(self.url, self.root, self.checksum)
77
+ else:
78
+ raise FileNotFoundError(
79
+ f'Could not find dataset directory "{dataset_dir}". Set download=True or choose another root directory (root).'
80
+ )
81
+ # Load available experiments
82
+ # If not an image dataset, experiments are just .csv files in the dataset directory
83
+ # If an image dataset, each experiment is a folder
84
+ # containing the .csv file with measurements and a subfolder
85
+ # with the images
86
+
87
+ if self.image:
88
+ experiment_names = [p.name for p in Path(self.root).glob(f"{self.name}/*")]
89
+ csv_paths = [
90
+ Path(self.root, self.name, e, f"{e}.csv") for e in experiment_names
91
+ ]
92
+ experiments = [ImageExperiment(self.name, path) for path in csv_paths]
93
+ else:
94
+ csv_paths = [p for p in Path(self.root).glob(f"{self.name}/*.csv")]
95
+ experiments = [Experiment(self.name, path) for path in csv_paths]
96
+ # Store experiment dictionary
97
+ assert len(experiments) > 0
98
+ self.__experiments = dict((e.name, e) for e in experiments)
99
+
100
+ def available_experiments(self):
101
+ return list(self.__experiments.keys())
102
+
103
+ def get_experiment(self, name):
104
+ return self.__experiments[name]
105
+
106
+
107
+ class Experiment:
108
+ def __init__(self, dataset_name, csv_path):
109
+ self.dataset = dataset_name
110
+ self.csv_path = csv_path
111
+ self.name = csv_path.stem
112
+ self.columns = pd.read_csv(self.csv_path, nrows=0).columns.tolist()
113
+
114
+ def as_pandas_dataframe(self):
115
+ """Returns a pandas dataframe with the experiment data (excl. images)"""
116
+ return pd.read_csv(self.csv_path)
117
+
118
+ def as_image_array(self):
119
+ raise NotImplementedError("This is not an image dataset!")
120
+
121
+
122
+ class ImageExperiment(Experiment):
123
+ def __init__(self, dataset_name, csv_path):
124
+ super().__init__(dataset_name, csv_path)
125
+ self.image_folders = {}
126
+ for path in [p for p in Path(csv_path.parents[0]).glob("images_*")]:
127
+ size = path.stem.split("_")[1]
128
+ self.image_folders[size] = path
129
+
130
+ def available_sizes(self):
131
+ return list(self.image_folders.keys())
132
+
133
+ def as_image_array(self, size):
134
+ """Returns a numpy array with all the images along the first dimension (axis-0)"""
135
+ if size not in self.image_folders.keys():
136
+ raise ValueError(
137
+ f" Size {size} not available; available image sizes: {list(self.image_folders.keys())}."
138
+ )
139
+ image_filenames = pd.read_csv(self.csv_path).image_file
140
+ image_folder = self.image_folders[size]
141
+ image_paths = [Path(image_folder, f) for f in image_filenames]
142
+ return np.array([np.array(Image.open(f)) for f in image_paths])
143
+
144
+
145
+ latex_names = {
146
+ # Light tunnel variables
147
+ "red": r"R",
148
+ "green": r"G",
149
+ "blue": r"B",
150
+ "osr_c": r"O_C",
151
+ "v_c": r"R_C",
152
+ "current": r"\tilde{C}",
153
+ "pol_1": r"\theta_1",
154
+ "pol_2": r"\theta_2",
155
+ "osr_angle_1": r"O_1",
156
+ "osr_angle_2": r"O_2",
157
+ "v_angle_1": r"R_1",
158
+ "v_angle_2": r"R_2",
159
+ "angle_1": r"\tilde{\theta}_1",
160
+ "angle_2": r"\tilde{\theta}_2",
161
+ "ir_1": r"\tilde{I}_1",
162
+ "vis_1": r"\tilde{V}_1",
163
+ "ir_2": r"\tilde{I}_2",
164
+ "vis_2": r"\tilde{V}_2",
165
+ "ir_3": r"\tilde{I}_3",
166
+ "vis_3": r"\tilde{V}_3",
167
+ "l_11": r"L_{11}",
168
+ "l_12": r"L_{12}",
169
+ "l_21": r"L_{21}",
170
+ "l_22": r"L_{22}",
171
+ "l_31": r"L_{31}",
172
+ "l_32": r"L_{32}",
173
+ "diode_ir_1": r"D^I_1",
174
+ "diode_vis_1": r"D^V_1",
175
+ "diode_ir_2": r"D^I_2",
176
+ "diode_vis_2": r"D^V_2",
177
+ "diode_ir_3": r"D^I_3",
178
+ "diode_vis_3": r"D^V_3",
179
+ "t_ir_1": r"T^I_1",
180
+ "t_vis_1": r"T^V_1",
181
+ "t_ir_2": r"T^I_2",
182
+ "t_vis_2": r"T^V_2",
183
+ "t_ir_3": r"T^I_3",
184
+ "t_vis_3": r"T^V_3",
185
+ "im": r"\tilde{\text{I}}\text{m}",
186
+ "shutter_speed": r"T_\text{Im}",
187
+ "aperture": r"\text{Ap}",
188
+ "iso": r"\text{ISO}",
189
+ # Wind tunnel variables
190
+ "hatch": r"H",
191
+ "pot_1": r"A_1",
192
+ "pot_2": r"A_2",
193
+ "osr_1": r"O_1",
194
+ "osr_2": r"O_2",
195
+ "osr_mic": r"O_M",
196
+ "osr_in": r"O_\text{in}",
197
+ "osr_out": r"O_\text{out}",
198
+ "osr_upwind": r"O_\text{up}",
199
+ "osr_downwind": r"O_\text{dw}",
200
+ "osr_ambient": r"O_\text{amb}",
201
+ "osr_intake": r"O_\text{int}",
202
+ "v_1": r"R_1",
203
+ "v_2": r"R_2",
204
+ "v_mic": r"R_M",
205
+ "v_in": r"R_\text{in}",
206
+ "v_out": r"R_\text{out}",
207
+ "load_in": r"L_\text{in}",
208
+ "load_out": r"L_\text{out}",
209
+ "current_in": r"\tilde{C}_\text{in}",
210
+ "current_out": r"\tilde{C}_\text{out}",
211
+ "res_in": r"T_\text{in}",
212
+ "res_out": r"T_\text{out}",
213
+ "rpm_in": r"\tilde{\omega}_\text{in}",
214
+ "rpm_out": r"\tilde{\omega}_\text{out}",
215
+ "pressure_upwind": r"\tilde{P}_\text{up}",
216
+ "pressure_downwind": r"\tilde{P}_\text{dw}",
217
+ "pressure_ambient": r"\tilde{P}_\text{amb}",
218
+ "pressure_intake": r"\tilde{P}_\text{int}",
219
+ "mic": r"\tilde{M}",
220
+ "signal_1": r"\tilde{S}_1",
221
+ "signal_2": r"\tilde{S}_2",
222
+ }
223
+
224
+
225
+ def latex_name(var, enclose=True):
226
+ """Translate from machine variable name to latex name."""
227
+ if var not in latex_names:
228
+ return var
229
+ else:
230
+ name = latex_names[var]
231
+ return "$" + name + "$" if enclose else name
232
+
233
+
234
+ lt_standard_edges = [
235
+ ("red", "ir_1"),
236
+ ("green", "ir_1"),
237
+ ("blue", "ir_1"),
238
+ ("red", "ir_2"),
239
+ ("green", "ir_2"),
240
+ ("blue", "ir_2"),
241
+ ("red", "ir_3"),
242
+ ("green", "ir_3"),
243
+ ("blue", "ir_3"),
244
+ ("red", "vis_1"),
245
+ ("green", "vis_1"),
246
+ ("blue", "vis_1"),
247
+ ("red", "vis_2"),
248
+ ("green", "vis_2"),
249
+ ("blue", "vis_2"),
250
+ ("red", "vis_3"),
251
+ ("green", "vis_3"),
252
+ ("blue", "vis_3"),
253
+ ("red", "current"),
254
+ ("green", "current"),
255
+ ("blue", "current"),
256
+ ("pol_1", "ir_3"),
257
+ ("pol_2", "ir_3"),
258
+ ("pol_1", "vis_3"),
259
+ ("pol_2", "vis_3"),
260
+ ("pol_1", "angle_1"),
261
+ ("pol_2", "angle_2"),
262
+ ("v_angle_1", "angle_1"),
263
+ ("osr_angle_1", "angle_1"),
264
+ ("v_angle_2", "angle_2"),
265
+ ("osr_angle_2", "angle_2"),
266
+ ("v_c", "current"),
267
+ ("osr_c", "current"),
268
+ ("l_11", "ir_1"),
269
+ ("l_12", "ir_1"),
270
+ ("l_11", "vis_1"),
271
+ ("l_12", "vis_1"),
272
+ ("t_ir_1", "ir_1"),
273
+ ("diode_ir_1", "ir_1"),
274
+ ("t_vis_1", "vis_1"),
275
+ ("diode_vis_1", "vis_1"),
276
+ ("l_21", "ir_2"),
277
+ ("l_22", "ir_2"),
278
+ ("l_21", "vis_2"),
279
+ ("l_22", "vis_2"),
280
+ ("t_ir_2", "ir_2"),
281
+ ("diode_ir_2", "ir_2"),
282
+ ("t_vis_2", "vis_2"),
283
+ ("diode_vis_2", "vis_2"),
284
+ ("l_31", "ir_3"),
285
+ ("l_32", "ir_3"),
286
+ ("l_31", "vis_3"),
287
+ ("l_32", "vis_3"),
288
+ ("t_ir_3", "ir_3"),
289
+ ("diode_ir_3", "ir_3"),
290
+ ("t_vis_3", "vis_3"),
291
+ ("diode_vis_3", "vis_3"),
292
+ ("pol_1", "im"),
293
+ ("pol_2", "im"),
294
+ ("red", "im"),
295
+ ("green", "im"),
296
+ ("blue", "im"),
297
+ ("shutter_speed", "im"),
298
+ ("aperture", "im"),
299
+ ("iso", "im"),
300
+ ]
301
+
302
+ wt_standard_edges = [
303
+ ("load_in", "rpm_in"),
304
+ ("res_in", "rpm_in"),
305
+ ("load_in", "rpm_out"),
306
+ ("load_in", "current_in"),
307
+ ("load_in", "current_out"),
308
+ ("load_out", "rpm_in"),
309
+ ("load_out", "rpm_out"),
310
+ ("res_out", "rpm_out"),
311
+ ("load_out", "current_out"),
312
+ ("load_out", "current_in"),
313
+ ("hatch", "rpm_in"),
314
+ ("hatch", "rpm_out"),
315
+ ("load_in", "pressure_intake"),
316
+ ("hatch", "pressure_intake"),
317
+ ("load_out", "pressure_intake"),
318
+ ("osr_intake", "pressure_intake"),
319
+ ("load_in", "pressure_upwind"),
320
+ ("hatch", "pressure_upwind"),
321
+ ("load_out", "pressure_upwind"),
322
+ ("osr_up", "pressure_upwind"),
323
+ ("load_in", "pressure_downwind"),
324
+ ("hatch", "pressure_downwind"),
325
+ ("load_out", "pressure_downwind"),
326
+ ("osr_downwind", "pressure_downwind"),
327
+ ("osr_ambient", "pressure_ambient"),
328
+ ("osr_in", "current_in"),
329
+ ("v_in", "current_in"),
330
+ ("osr_out", "current_out"),
331
+ ("v_out", "current_out"),
332
+ ("pot_1", "signal_1"),
333
+ ("osr_1", "signal_1"),
334
+ ("v_1", "signal_1"),
335
+ ("pot_1", "signal_2"),
336
+ ("pot_2", "signal_2"),
337
+ ("osr_2", "signal_2"),
338
+ ("v_2", "signal_2"),
339
+ ("pot_1", "mic"),
340
+ ("load_in", "mic"),
341
+ ("load_out", "mic"),
342
+ ("hatch", "mic"),
343
+ ("osr_mic", "mic"),
344
+ ("v_mic", "mic"),
345
+ ]
@@ -0,0 +1,76 @@
1
+ # MIT License
2
+
3
+ # Copyright (c) 2023 Juan L. Gamella
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ """
24
+ Functions for general sampling.
25
+ """
26
+
27
+ import numpy as np
28
+
29
+
30
+ def random_walk(n, step_size=1, step_resolution=1, random_state=None):
31
+ rng = np.random.default_rng(random_state)
32
+ possible_transitions = np.arange(
33
+ -step_size, step_size + step_resolution, step_resolution
34
+ )
35
+ steps = rng.choice(possible_transitions, size=n, replace=True)
36
+ return np.cumsum(steps)
37
+
38
+
39
+ def random_walk_mirrored(
40
+ n, minn, maxx, step_size=1, step_resolution=1, random_state=None
41
+ ):
42
+ rng = np.random.default_rng(random_state - 1)
43
+ init = rng.choice(np.arange(minn, maxx + step_resolution, step_resolution))
44
+ walk = init + random_walk(
45
+ n,
46
+ step_size=step_size,
47
+ step_resolution=step_resolution,
48
+ random_state=random_state,
49
+ )
50
+ # As long as walk is out of bounds
51
+ while (
52
+ maxx is not None
53
+ and (walk > maxx).any()
54
+ or minn is not None
55
+ and (walk < minn).any()
56
+ ):
57
+ walk = np.minimum(walk, maxx) - np.maximum(walk, maxx) + maxx
58
+ walk = np.maximum(walk, minn) - np.minimum(walk, minn) + minn
59
+ return walk
60
+
61
+
62
+ # Deprecatedx
63
+ def discrete_rw(n, minn, maxx, step_sizes=[-1, 0, 1], p=None, seed=42):
64
+ rng = np.random.default_rng(seed)
65
+ walk = np.zeros(n)
66
+ walk[0] = rng.integers(minn, maxx + 1)
67
+ steps = rng.choice(step_sizes, p=p, size=n - 1, replace=True)
68
+ for i, s in enumerate(steps):
69
+ walk[i + 1] = min(max(walk[i] + s, minn), maxx)
70
+ return walk
71
+
72
+
73
+ def smooth_discrete_rw(n, minn, maxx, step_sizes=[-1, 0, 1], p=None, lags=0, seed=42):
74
+ walk = discrete_rw(n + lags, minn, maxx, step_sizes, p, seed)
75
+ walk = pd.DataFrame(walk).rolling(lags).mean()[lags:]
76
+ return walk.values