nnodely 1.5.0__tar.gz → 1.5.2__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.
- {nnodely-1.5.0/nnodely.egg-info → nnodely-1.5.2}/PKG-INFO +25 -8
- {nnodely-1.5.0 → nnodely-1.5.2}/README.md +25 -8
- {nnodely-1.5.0 → nnodely-1.5.2}/mplplots/plots.py +66 -22
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/__init__.py +5 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/model.py +6 -7
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/modeldef.py +43 -32
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/relation.py +2 -2
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/exporter/export.py +23 -10
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/exporter/reporter.py +4 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/arithmetic.py +2 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/fir.py +7 -6
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/fuzzify.py +0 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/input.py +8 -8
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/interpolation.py +0 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/output.py +1 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/parameter.py +1 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/part.py +2 -1
- nnodely-1.5.2/nnodely/layers/rungekutta.py +143 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/timeoperation.py +6 -6
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/nnodely.py +9 -10
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/composer.py +36 -30
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/exporter.py +15 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/loader.py +25 -8
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/network.py +44 -22
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/trainer.py +21 -12
- nnodely-1.5.2/nnodely/operators/validator.py +304 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/jsonutils.py +20 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/utils.py +3 -4
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/dynamicmpl/resultsplot.py +7 -2
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/dynamicmpl/trainingplot.py +6 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/mplnotebookvisualizer.py +23 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/mplvisualizer.py +28 -16
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/textvisualizer.py +4 -4
- {nnodely-1.5.0 → nnodely-1.5.2/nnodely.egg-info}/PKG-INFO +25 -8
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely.egg-info/SOURCES.txt +1 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/pyproject.toml +1 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_dataset.py +94 -13
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_export_recurrent.py +35 -3
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_json.py +25 -1
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_model_predict.py +12 -11
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_model_predict_recurrent.py +207 -53
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_network_element.py +38 -2
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_parameters_of_train.py +118 -61
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_results.py +31 -16
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_train.py +2 -2
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_train_recurrent.py +131 -57
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_visualizer.py +53 -6
- nnodely-1.5.0/nnodely/operators/validator.py +0 -176
- {nnodely-1.5.0 → nnodely-1.5.2}/LICENSE +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/mplplots/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/loss.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/basic/optimizer.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/exporter/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/exporter/emptyexporter.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/exporter/standardexporter.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/activation.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/equationlearner.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/linear.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/localmodel.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/parametricfunction.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/layers/trigonometric.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/operators/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/earlystopping.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/fixstepsolver.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/initializer.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/logger.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/support/mathutils.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/__init__.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/dynamicmpl/functionplot.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/dynamicmpl/fuzzyplot.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely/visualizer/emptyvisualizer.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely.egg-info/dependency_links.txt +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely.egg-info/requires.txt +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/nnodely.egg-info/top_level.txt +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/setup.cfg +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/setup.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_documentation.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_export.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_input_dimensions.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_losses.py +0 -0
- {nnodely-1.5.0 → nnodely-1.5.2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nnodely
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.2
|
|
4
4
|
Summary: Model-structured neural network framework for the modeling and control of physical systems
|
|
5
5
|
Author-email: Gastone Pietro Rosati Papini <tonegas@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -138,7 +138,6 @@ Download the source code and install the dependencies using the following comman
|
|
|
138
138
|
To contribute to the nnodely framework, you can:
|
|
139
139
|
- Open a pull request, if you have a new feature or bug fix.
|
|
140
140
|
- Open an issue, if you have a question or suggestion.
|
|
141
|
-
- Contact us via email at [gastone.rosatipapini@unitn.it](mailto:gastone.rosatipapini@unitn.it) or [mattia.piccinini@tum.de](mailto:mattia.piccinini@tum.de) to directly **collaborate** with us **on your project**!
|
|
142
141
|
|
|
143
142
|
We are very happy to collaborate with you!
|
|
144
143
|
|
|
@@ -190,7 +189,7 @@ where $x[1]$ is the next position of the mass, $F[0]$ is the last sample of the
|
|
|
190
189
|
|
|
191
190
|
For the input variable `x`, we are using a time window $T_w = 1$ second, which means that we are using the last $N_x$ samples of the variable `x` to estimate the next position of the mass. The value of $N_x$ is equal to $T_w/T_s$, where $T_s$ is the sampling time used to sample the input variable `x`.
|
|
192
191
|
|
|
193
|
-
In a particular case, our MS-NN formulation becomes equivalent to the discrete-time response of the mass-spring-damper system. This happens when we choose the following values: $N_x = 3$, $h_x$ equal to the characteristic polynomial of the system, and $h_f = T_s^2/m$, where $T_s$ is the sampling time and $m$ is the mass of the system.
|
|
192
|
+
In a particular case, our MS-NN formulation becomes equivalent to the discrete-time response (discretize with Forward-Euler) of the mass-spring-damper system. This happens when we choose the following values: $N_x = 3$, $h_x$ equal to the characteristic polynomial of the system, and $h_f = T_s^2/m$, where $T_s$ is the sampling time and $m$ is the mass of the system.
|
|
194
193
|
|
|
195
194
|
However, our formulation is more general and can take better adapt to model mismatches and noise levels in the measured variables. This improved learning potential can be achieved by using a larger number of samples $N_x$ in the time window of the input variable `x`.
|
|
196
195
|
|
|
@@ -286,11 +285,29 @@ print(results)
|
|
|
286
285
|
### nnodely Folder
|
|
287
286
|
This folder contains all the nnodely library files with relative references.
|
|
288
287
|
|
|
289
|
-
The
|
|
290
|
-
1.
|
|
291
|
-
2.
|
|
292
|
-
|
|
293
|
-
|
|
288
|
+
The `Moldey` main class defined in __nnodely.py__, it contains all the main properties of the nnodely object and it derives from five main operators:
|
|
289
|
+
1. __composer.py__ contains all the functions to build the networks: `addModel`, `neuralizeModel`, `addConnection`, `addClosedLool` etc..
|
|
290
|
+
2. __loader.py__ contains the function for managing the dataset, the main function is `dataLoad`.
|
|
291
|
+
3. __trainer.py__ contains the function for train the network as the `trainModel`.
|
|
292
|
+
4. __exporter.py__ contains all the function for import and export: `saveModel`, `loadModel`, `exportONNX` etc..
|
|
293
|
+
5. __validator.py__ contains all the function for validate the model ad the `resultsAnalysis`.
|
|
294
|
+
All the operators derive from `Network`defined in __network.py__, that contains the shared support functions for all the operators.
|
|
295
|
+
|
|
296
|
+
The folder basic contatins the main classes for the low level functionalities:
|
|
297
|
+
1. __model.py__ containts the pytorch template model for the structured network.
|
|
298
|
+
2. __modeldef.py__ containts the operation for work with the json model definition.
|
|
299
|
+
3. __loss.py__ contatins the loss functions.
|
|
300
|
+
4. __optimizer.py__ contains the optimizer calss.
|
|
301
|
+
6. __relation.py__ contains all the main classes from which all the layers are derived.
|
|
302
|
+
|
|
303
|
+
The other folders are:
|
|
304
|
+
1. exporter that contains the classes for the export functions.
|
|
305
|
+
2. support for the support functions.
|
|
306
|
+
3. visualizer that contains all the classes related to the visualization.
|
|
307
|
+
4. And finally the layers folder.
|
|
308
|
+
|
|
309
|
+
The layers folder contains all the layers that can be used in the MSNN.
|
|
310
|
+
In particular, the model structured NN is defined by `Inputs`, `Outputs` and `Parameters`:
|
|
294
311
|
1. __input.py__ contains the Input class used for create an input for the network.
|
|
295
312
|
2. __ouptut.py__ contains the Output class used for create an output for the network.
|
|
296
313
|
3. __parameter.py__ contains the logic for create a generic parameters and constants.
|
|
@@ -92,7 +92,6 @@ Download the source code and install the dependencies using the following comman
|
|
|
92
92
|
To contribute to the nnodely framework, you can:
|
|
93
93
|
- Open a pull request, if you have a new feature or bug fix.
|
|
94
94
|
- Open an issue, if you have a question or suggestion.
|
|
95
|
-
- Contact us via email at [gastone.rosatipapini@unitn.it](mailto:gastone.rosatipapini@unitn.it) or [mattia.piccinini@tum.de](mailto:mattia.piccinini@tum.de) to directly **collaborate** with us **on your project**!
|
|
96
95
|
|
|
97
96
|
We are very happy to collaborate with you!
|
|
98
97
|
|
|
@@ -144,7 +143,7 @@ where $x[1]$ is the next position of the mass, $F[0]$ is the last sample of the
|
|
|
144
143
|
|
|
145
144
|
For the input variable `x`, we are using a time window $T_w = 1$ second, which means that we are using the last $N_x$ samples of the variable `x` to estimate the next position of the mass. The value of $N_x$ is equal to $T_w/T_s$, where $T_s$ is the sampling time used to sample the input variable `x`.
|
|
146
145
|
|
|
147
|
-
In a particular case, our MS-NN formulation becomes equivalent to the discrete-time response of the mass-spring-damper system. This happens when we choose the following values: $N_x = 3$, $h_x$ equal to the characteristic polynomial of the system, and $h_f = T_s^2/m$, where $T_s$ is the sampling time and $m$ is the mass of the system.
|
|
146
|
+
In a particular case, our MS-NN formulation becomes equivalent to the discrete-time response (discretize with Forward-Euler) of the mass-spring-damper system. This happens when we choose the following values: $N_x = 3$, $h_x$ equal to the characteristic polynomial of the system, and $h_f = T_s^2/m$, where $T_s$ is the sampling time and $m$ is the mass of the system.
|
|
148
147
|
|
|
149
148
|
However, our formulation is more general and can take better adapt to model mismatches and noise levels in the measured variables. This improved learning potential can be achieved by using a larger number of samples $N_x$ in the time window of the input variable `x`.
|
|
150
149
|
|
|
@@ -240,11 +239,29 @@ print(results)
|
|
|
240
239
|
### nnodely Folder
|
|
241
240
|
This folder contains all the nnodely library files with relative references.
|
|
242
241
|
|
|
243
|
-
The
|
|
244
|
-
1.
|
|
245
|
-
2.
|
|
246
|
-
|
|
247
|
-
|
|
242
|
+
The `Moldey` main class defined in __nnodely.py__, it contains all the main properties of the nnodely object and it derives from five main operators:
|
|
243
|
+
1. __composer.py__ contains all the functions to build the networks: `addModel`, `neuralizeModel`, `addConnection`, `addClosedLool` etc..
|
|
244
|
+
2. __loader.py__ contains the function for managing the dataset, the main function is `dataLoad`.
|
|
245
|
+
3. __trainer.py__ contains the function for train the network as the `trainModel`.
|
|
246
|
+
4. __exporter.py__ contains all the function for import and export: `saveModel`, `loadModel`, `exportONNX` etc..
|
|
247
|
+
5. __validator.py__ contains all the function for validate the model ad the `resultsAnalysis`.
|
|
248
|
+
All the operators derive from `Network`defined in __network.py__, that contains the shared support functions for all the operators.
|
|
249
|
+
|
|
250
|
+
The folder basic contatins the main classes for the low level functionalities:
|
|
251
|
+
1. __model.py__ containts the pytorch template model for the structured network.
|
|
252
|
+
2. __modeldef.py__ containts the operation for work with the json model definition.
|
|
253
|
+
3. __loss.py__ contatins the loss functions.
|
|
254
|
+
4. __optimizer.py__ contains the optimizer calss.
|
|
255
|
+
6. __relation.py__ contains all the main classes from which all the layers are derived.
|
|
256
|
+
|
|
257
|
+
The other folders are:
|
|
258
|
+
1. exporter that contains the classes for the export functions.
|
|
259
|
+
2. support for the support functions.
|
|
260
|
+
3. visualizer that contains all the classes related to the visualization.
|
|
261
|
+
4. And finally the layers folder.
|
|
262
|
+
|
|
263
|
+
The layers folder contains all the layers that can be used in the MSNN.
|
|
264
|
+
In particular, the model structured NN is defined by `Inputs`, `Outputs` and `Parameters`:
|
|
248
265
|
1. __input.py__ contains the Input class used for create an input for the network.
|
|
249
266
|
2. __ouptut.py__ contains the Output class used for create an output for the network.
|
|
250
267
|
3. __parameter.py__ contains the logic for create a generic parameters and constants.
|
|
@@ -340,4 +357,4 @@ Robust and Sample-Efficient Estimation of Vehicle Lateral Velocity Using Neural
|
|
|
340
357
|
IEEE Transactions on Intelligent Transportation Systems. https://doi.org/10.1109/TITS.2023.3303776
|
|
341
358
|
|
|
342
359
|
|
|
343
|
-
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
360
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
@@ -30,36 +30,80 @@ def plot_training(ax, title, key, data_train, data_val = None, last = None):
|
|
|
30
30
|
ax.set_ylim(min_val - min_val / 10, max_val + max_val / 10)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def plot_results(ax, name_data, key, A, B, sample_time):
|
|
33
|
+
def plot_results(ax, name_data, key, A, B, data_idxs, sample_time):
|
|
34
34
|
# Plot data
|
|
35
35
|
ax.set_title(f'{key} on the dataset {name_data}')
|
|
36
36
|
A_t = np.transpose(np.array(A))
|
|
37
37
|
B_t = np.transpose(np.array(B))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
idxs_t = np.transpose(np.array(data_idxs))
|
|
39
|
+
color_A = 'tab:blue'
|
|
40
|
+
rgb_A = mcolors.to_rgb(color_A)
|
|
41
|
+
color_B = 'tab:orange'
|
|
42
|
+
rgb_B = mcolors.to_rgb(color_B)
|
|
43
|
+
delta = 0.1
|
|
44
|
+
|
|
45
|
+
if len(A_t.shape) == 3:
|
|
46
|
+
# Print without prediction samples
|
|
47
|
+
time_array = []
|
|
48
|
+
num_samples = A_t.shape[2]
|
|
49
|
+
for o in range(A_t.shape[1]):
|
|
50
|
+
time_array.append(np.linspace(0, (num_samples - 1) * sample_time, num_samples) + sample_time * o)
|
|
51
|
+
time_array = np.array(time_array)
|
|
52
|
+
for ind_dim in range(A_t.shape[0]):
|
|
53
|
+
# Print the marker only if the output have a time window
|
|
54
|
+
ax.plot(time_array[0,:], A_t[ind_dim, 0, :],
|
|
55
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_A),
|
|
56
|
+
marker='s' if A_t.shape[1] > 1 else None, markersize=2,
|
|
57
|
+
label=f'A_{ind_dim}')
|
|
58
|
+
ax.plot(time_array[0,:], B_t[ind_dim, 0, :], '-.',
|
|
59
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_B),
|
|
60
|
+
marker='o' if A_t.shape[1] > 1 else None, markersize=2,
|
|
61
|
+
label=f'B_{ind_dim}')
|
|
62
|
+
if A_t.shape[1] > 1 :
|
|
63
|
+
correlation = np.empty((A_t.shape[0],A_t.shape[2]))
|
|
64
|
+
for ind_el in range(A_t.shape[2]):
|
|
65
|
+
ax.plot(time_array[:,ind_el], A_t[ind_dim,:,ind_el], color=tuple((x + delta*ind_dim)%1.0001 for x in rgb_A))
|
|
66
|
+
ax.plot(time_array[:,ind_el], B_t[ind_dim,:,ind_el], '-.', color=tuple((x + delta*ind_dim)%1.0001 for x in rgb_B))
|
|
67
|
+
correlation[ind_dim, ind_el] = np.corrcoef(A_t[ind_dim,:,ind_el], B_t[ind_dim,:,ind_el])[0, 1]
|
|
68
|
+
ax.text(0.05, 0.95 - 0.05 * ind_dim,
|
|
69
|
+
f'Correlation A_{ind_dim} - B_{ind_dim}: {np.mean(correlation, axis=1)[ind_dim]:.2f}',
|
|
70
|
+
transform=ax.transAxes, verticalalignment='top')
|
|
49
71
|
else:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
correlation = np.empty((A_t.shape[0],))
|
|
73
|
+
correlation[ind_dim] = np.corrcoef(A_t[ind_dim, 0], B_t[ind_dim, 0])[0, 1]
|
|
74
|
+
ax.text(0.05, 0.95-0.05*ind_dim, f'Correlation A_{ind_dim} - B_{ind_dim}: {correlation[ind_dim]:.2f}', transform=ax.transAxes, verticalalignment='top')
|
|
75
|
+
else:
|
|
76
|
+
correlation = np.empty(A_t.shape)
|
|
77
|
+
for ind_dim in range(A_t.shape[0]):
|
|
78
|
+
first = True
|
|
79
|
+
ax.scatter(idxs_t[:,0] * sample_time, A_t[ind_dim, 0, :, 0], marker='s', s=6,
|
|
80
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_A))
|
|
81
|
+
ax.scatter(idxs_t[:,0] * sample_time, B_t[ind_dim, 0, :, 0], marker='o', s=6,
|
|
82
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_B))
|
|
83
|
+
for ind_el in range(A_t.shape[2]):
|
|
84
|
+
time_array = idxs_t[ind_el] * sample_time
|
|
85
|
+
# Print the marker only if the output have a time window
|
|
86
|
+
ax.plot(time_array, A_t[ind_dim, 0, ind_el], marker = 's' if A_t.shape[1] > 1 else None, markersize=2,
|
|
87
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_A),
|
|
88
|
+
label=f'A_{ind_dim}' if first else None)
|
|
89
|
+
ax.plot(time_array, B_t[ind_dim, 0, ind_el], '-.', marker = 'o' if A_t.shape[1] > 1 else None, markersize=2,
|
|
90
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_B),
|
|
91
|
+
label=f'B_{ind_dim}' if first else None)
|
|
92
|
+
for ind_pred in range(A_t.shape[3]):
|
|
93
|
+
time_array = idxs_t[ind_el,ind_pred] * sample_time + np.linspace(0, (A_t.shape[1] - 1) * sample_time, A_t.shape[1])
|
|
94
|
+
ax.plot(time_array, A_t[ind_dim, :, ind_el,ind_pred],
|
|
95
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_A))
|
|
96
|
+
ax.plot(time_array, B_t[ind_dim, :, ind_el,ind_pred], '-.',
|
|
97
|
+
color=tuple((x + delta * ind_dim) % 1.0001 for x in rgb_B))
|
|
98
|
+
first = False
|
|
99
|
+
for ind_win in range(A_t.shape[1]):
|
|
100
|
+
correlation[ind_dim,ind_win,ind_el] = np.corrcoef(A_t[ind_dim,ind_win,ind_el], B_t[ind_dim,ind_win,ind_el])[0, 1]
|
|
101
|
+
ax.text(0.05, 0.95-0.05*ind_dim, f'Correlation A_{ind_dim} - B_{ind_dim}: {np.mean(correlation, axis=(1, 2, 3))[ind_dim]:.2f}', transform=ax.transAxes, verticalalignment='top')
|
|
102
|
+
|
|
59
103
|
|
|
60
104
|
ax.grid(True)
|
|
61
105
|
ax.legend(loc='best')
|
|
62
|
-
ax.set_xlabel('Time
|
|
106
|
+
ax.set_xlabel('Time [s]')
|
|
63
107
|
ax.set_ylabel(f'Value {key}')
|
|
64
108
|
|
|
65
109
|
# min_val = min([min(A), min(B)])
|
|
@@ -17,8 +17,9 @@ from nnodely.layers.fuzzify import Fuzzify
|
|
|
17
17
|
from nnodely.layers.part import Part, Select, Concatenate, SamplePart, SampleSelect, TimePart, TimeConcatenate
|
|
18
18
|
from nnodely.layers.localmodel import LocalModel
|
|
19
19
|
from nnodely.layers.equationlearner import EquationLearner
|
|
20
|
-
from nnodely.layers.timeoperation import Integrate,
|
|
20
|
+
from nnodely.layers.timeoperation import Integrate, Differentiate
|
|
21
21
|
from nnodely.layers.interpolation import Interpolation
|
|
22
|
+
from nnodely.layers.rungekutta import ForwardEuler, RK2, RK4
|
|
22
23
|
|
|
23
24
|
# Main nnodely classes
|
|
24
25
|
from nnodely.nnodely import nnodely, Modely, clearNames
|
|
@@ -35,7 +36,7 @@ from nnodely.support import logger
|
|
|
35
36
|
major, minor = sys.version_info.major, sys.version_info.minor
|
|
36
37
|
logger.LOG_LEVEL = logging.INFO
|
|
37
38
|
|
|
38
|
-
__version__ = '1.5.
|
|
39
|
+
__version__ = '1.5.2'
|
|
39
40
|
|
|
40
41
|
if major < 3:
|
|
41
42
|
sys.exit("Sorry, Python 2 is not supported. You need Python >= 3.10 for "+__package__+".")
|
|
@@ -64,8 +65,9 @@ __all__ = [
|
|
|
64
65
|
'TimePart', 'TimeConcatenate',
|
|
65
66
|
'LocalModel',
|
|
66
67
|
'EquationLearner',
|
|
67
|
-
'Integrate', '
|
|
68
|
+
'Integrate', 'Differentiate',
|
|
68
69
|
'Interpolation',
|
|
70
|
+
'ForwardEuler', 'RK2', 'RK4',
|
|
69
71
|
'TextVisualizer', 'MPLVisualizer', 'MPLNotebookVisualizer',
|
|
70
72
|
'StandardExporter',
|
|
71
73
|
'SGD', 'Adam', 'Optimizer',
|
|
@@ -9,14 +9,13 @@ from itertools import product
|
|
|
9
9
|
from nnodely.support.utils import TORCH_DTYPE
|
|
10
10
|
from nnodely.support import initializer
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
12
|
@torch.fx.wrap
|
|
15
|
-
def
|
|
16
|
-
virtual = torch.roll(data_in, shifts=-1, dims=1)
|
|
13
|
+
def update_state(data_in, rel):
|
|
14
|
+
#virtual = torch.roll(data_in, shifts=-1, dims=1)
|
|
17
15
|
max_dim = min(rel.size(1), data_in.size(1))
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
data_out = data_in.clone()
|
|
17
|
+
data_out[:, -max_dim:, :] = rel[:, -max_dim:, :]
|
|
18
|
+
return data_out
|
|
20
19
|
|
|
21
20
|
class Model(nn.Module):
|
|
22
21
|
def __init__(self, model_def):
|
|
@@ -184,7 +183,7 @@ class Model(nn.Module):
|
|
|
184
183
|
## Check if the relation is inside the connect
|
|
185
184
|
for connect_input, connect_rel in self.connect_update.items():
|
|
186
185
|
if relation == connect_rel:
|
|
187
|
-
result_dict[connect_input] =
|
|
186
|
+
result_dict[connect_input] = update_state(kwargs[connect_input], result_dict[relation])
|
|
188
187
|
available_keys.add(connect_input)
|
|
189
188
|
|
|
190
189
|
## Return a dictionary with all the connected inputs
|
|
@@ -3,9 +3,10 @@ import copy
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
5
|
from nnodely.support.utils import check, check_and_get_list
|
|
6
|
-
from nnodely.support.jsonutils import merge, subjson_from_model,
|
|
6
|
+
from nnodely.support.jsonutils import merge, subjson_from_model, subjson_from_minimize, check_model, get_models_json
|
|
7
7
|
from nnodely.basic.relation import MAIN_JSON, Stream, check_names
|
|
8
8
|
from nnodely.layers.output import Output
|
|
9
|
+
from nnodely.layers.input import Input
|
|
9
10
|
|
|
10
11
|
from nnodely.support.logger import logging, nnLogger
|
|
11
12
|
log = nnLogger(__name__, logging.INFO)
|
|
@@ -36,17 +37,11 @@ class ModelDef:
|
|
|
36
37
|
self.__json[key] = value
|
|
37
38
|
|
|
38
39
|
def __rebuild_json(self, models_names, minimizers):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
relations_name = set(rel_A) | set(rel_B)
|
|
45
|
-
if len(relations_name) != 0:
|
|
46
|
-
minimizers_json = subjson_from_relation(self.__json, list(relations_name))
|
|
47
|
-
new_json = merge(new_json, minimizers_json)
|
|
48
|
-
|
|
49
|
-
return copy.deepcopy(new_json)
|
|
40
|
+
models_json = subjson_from_model(self.__json, list(models_names))
|
|
41
|
+
if 'Minimizers' in self.__json and len(minimizers) > 0:
|
|
42
|
+
minimizers_json = subjson_from_minimize(self.__json, list(minimizers))
|
|
43
|
+
models_json = merge(models_json, minimizers_json)
|
|
44
|
+
return copy.deepcopy(models_json)
|
|
50
45
|
|
|
51
46
|
def recurrentInputs(self):
|
|
52
47
|
return {key:value for key, value in self.__json['Inputs'].items() if ('closedLoop' in value.keys() or 'connect' in value.keys())}
|
|
@@ -66,24 +61,30 @@ class ModelDef:
|
|
|
66
61
|
def isDefined(self):
|
|
67
62
|
return self.__json is not None
|
|
68
63
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
def addConnection(self, stream_out:str|Output|Stream, input_in:str|Input, type:str, local:bool = False):
|
|
65
|
+
outputs = self.__json['Outputs']
|
|
66
|
+
|
|
67
|
+
if isinstance(stream_out, (Output, Stream)):
|
|
68
|
+
stream_name = outputs[stream_out.name] if stream_out.name in outputs.keys() else stream_out.name
|
|
69
|
+
else:
|
|
70
|
+
output_name = check_and_get_list(stream_out, set(outputs.keys()),
|
|
71
|
+
lambda name: f"The name {name} is not part of the available Outputs")[0]
|
|
72
|
+
stream_name = outputs[output_name]
|
|
73
|
+
|
|
74
|
+
if isinstance(input_in, Input):
|
|
75
|
+
input_name = input_in.name
|
|
76
|
+
else:
|
|
77
|
+
input_name = input_in #TODO Add tests
|
|
76
78
|
|
|
77
|
-
def addClosedLoop(self, stream_name:str, input_name:str, local:bool = False):
|
|
78
79
|
input_name = check_and_get_list(input_name, set(self.__json['Inputs'].keys()),
|
|
79
|
-
lambda name: f"The name {name} is not part of the available
|
|
80
|
+
lambda name: f"The name {name} is not part of the available Inputs")[0]
|
|
80
81
|
stream_name = check_and_get_list(stream_name, set(self.__json['Relations'].keys()),
|
|
81
|
-
lambda name: f"The name {name} is not part of the available
|
|
82
|
-
self.__json['Inputs'][input_name][
|
|
82
|
+
lambda name: f"The name {name} is not part of the available Relations")[0]
|
|
83
|
+
self.__json['Inputs'][input_name][type] = stream_name
|
|
83
84
|
self.__json['Inputs'][input_name]['local'] = int(local)
|
|
84
85
|
|
|
85
86
|
def removeConnection(self, name_list:str|list[str]):
|
|
86
|
-
name_list = check_and_get_list(name_list, set(self.__json['Inputs'].keys()), lambda name: f"The name {name} is not part of the available
|
|
87
|
+
name_list = check_and_get_list(name_list, set(self.__json['Inputs'].keys()), lambda name: f"The name {name} is not part of the available Inputs")
|
|
87
88
|
for input_in in name_list:
|
|
88
89
|
if 'closedLoop' in self.__json['Inputs'][input_in].keys():
|
|
89
90
|
del self.__json['Inputs'][input_in]['closedLoop']
|
|
@@ -124,17 +125,25 @@ class ModelDef:
|
|
|
124
125
|
self.__json = self.__rebuild_json(models_names, minimizers)
|
|
125
126
|
|
|
126
127
|
def addMinimize(self, name, streamA, streamB, loss_function='mse'):
|
|
127
|
-
check(isinstance(streamA, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
|
|
128
|
-
check(isinstance(streamB, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
|
|
129
|
-
# check(streamA.dim == streamB.dim, ValueError, f'Dimension of streamA={streamA.dim} and streamB={streamB.dim} are not equal.')
|
|
130
128
|
if 'Minimizers' not in self.__json:
|
|
131
129
|
self.__json['Minimizers'] = {}
|
|
132
|
-
|
|
133
130
|
check_names(name, set(self.__json['Minimizers'].keys()), 'Minimizers')
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
|
|
132
|
+
if isinstance(streamA, str):
|
|
133
|
+
streamA_name = streamA
|
|
134
|
+
else:
|
|
135
|
+
check(isinstance(streamA, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
|
|
136
|
+
streamA_name = streamA.json['Outputs'][streamA.name] if isinstance(streamA, Output) else streamA.name
|
|
137
|
+
self.__json = merge(self.__json, streamA.json)
|
|
138
|
+
|
|
139
|
+
if isinstance(streamB, str):
|
|
140
|
+
streamB_name = streamB
|
|
141
|
+
else:
|
|
142
|
+
check(isinstance(streamB, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
|
|
143
|
+
streamB_name = streamB.json['Outputs'][streamB.name] if isinstance(streamB, Output) else streamB.name
|
|
144
|
+
self.__json = merge(self.__json, streamB.json)
|
|
145
|
+
#check(streamA.dim == streamB.dim, ValueError, f'Dimension of streamA={streamA.dim} and streamB={streamB.dim} are not equal.')
|
|
146
|
+
|
|
138
147
|
self.__json['Minimizers'][name] = {}
|
|
139
148
|
self.__json['Minimizers'][name]['A'] = streamA_name
|
|
140
149
|
self.__json['Minimizers'][name]['B'] = streamB_name
|
|
@@ -158,6 +167,8 @@ class ModelDef:
|
|
|
158
167
|
self.__sample_time = 1
|
|
159
168
|
|
|
160
169
|
self.__json['Info'] = {"SampleTime": self.__sample_time}
|
|
170
|
+
if 'SampleTime' in self.__json['Constants']:
|
|
171
|
+
self.__json['Constants']['SampleTime'] = {'dim': 1, 'values': self.__sample_time}
|
|
161
172
|
|
|
162
173
|
check(self.__json['Inputs'] != {}, RuntimeError, "No model is defined!")
|
|
163
174
|
json_inputs = self.__json['Inputs']
|
|
@@ -261,11 +261,11 @@ class Stream(Relation):
|
|
|
261
261
|
Stream
|
|
262
262
|
A Stream of the signal represents the integral or derivation operation.
|
|
263
263
|
"""
|
|
264
|
-
from nnodely.layers.timeoperation import
|
|
264
|
+
from nnodely.layers.timeoperation import Differentiate, Integrate
|
|
265
265
|
check(order != 0, ValueError, "The order must be a positive or negative integer not a zero")
|
|
266
266
|
if order > 0:
|
|
267
267
|
for i in range(order):
|
|
268
|
-
o =
|
|
268
|
+
o = Differentiate(self, der_name = der_name, int_name = int_name, method = method)
|
|
269
269
|
elif order < 0:
|
|
270
270
|
for i in range(-order):
|
|
271
271
|
o = Integrate(self, der_name = der_name, int_name = int_name, method = method)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import sys, os, torch, importlib
|
|
1
|
+
import sys, os, torch, importlib, json
|
|
2
2
|
|
|
3
3
|
from torch.fx import symbolic_trace
|
|
4
4
|
|
|
@@ -54,11 +54,19 @@ def export_python_model(model_def, model, model_path):
|
|
|
54
54
|
file.write("import torch\n\n")
|
|
55
55
|
|
|
56
56
|
## write the connect wrap function
|
|
57
|
-
file.write(f"def {package_name}
|
|
58
|
-
file.write(" virtual = torch.cat((data_in[:, 1:, :], data_in[:, :1, :]), dim=1)\n")
|
|
57
|
+
# file.write(f"def {package_name}_basic_model_update_state(data_in, rel):\n")
|
|
58
|
+
# file.write(" virtual = torch.cat((data_in[:, 1:, :], data_in[:, :1, :]), dim=1)\n")
|
|
59
|
+
# file.write(" max_dim = min(rel.size(1), data_in.size(1))\n")
|
|
60
|
+
# file.write(" virtual[:, -max_dim:, :] = rel[:, -max_dim:, :]\n")
|
|
61
|
+
# file.write(" return virtual\n\n")
|
|
62
|
+
file.write(f"def {package_name}_basic_model_update_state(data_in, rel):\n")
|
|
63
|
+
file.write(" data_out = data_in.clone()\n")
|
|
59
64
|
file.write(" max_dim = min(rel.size(1), data_in.size(1))\n")
|
|
60
|
-
file.write("
|
|
61
|
-
file.write(" return
|
|
65
|
+
file.write(" data_out[:, -max_dim:, :] = rel[:, -max_dim:, :]\n")
|
|
66
|
+
file.write(" return data_out\n\n")
|
|
67
|
+
|
|
68
|
+
file.write(f"def {package_name}_basic_model_timeshift(data_in):\n")
|
|
69
|
+
file.write(" return torch.cat((data_in[:, 1:, :], data_in[:, :1, :]), dim=1)\n\n")
|
|
62
70
|
|
|
63
71
|
for name in model_def['Functions'].keys():
|
|
64
72
|
if 'Fuzzify' in name:
|
|
@@ -126,8 +134,8 @@ def export_python_model(model_def, model, model_path):
|
|
|
126
134
|
# file.write(f" self.all_parameters[\"{param}\"] = torch.nn.Parameter(torch.{value}, requires_grad=True)\n")
|
|
127
135
|
elif 'Part' in key or 'Select' in key: # any(element in key for element in ['Part', 'Select']):
|
|
128
136
|
value = model.relation_forward[key].W
|
|
129
|
-
temp_value =
|
|
130
|
-
file.write(f" self.all_constants[\"{key}\"] = torch.{temp_value}\n")
|
|
137
|
+
temp_value = json.dumps(value.tolist())
|
|
138
|
+
file.write(f" self.all_constants[\"{key}\"] = torch.tensor({temp_value}, requires_grad=True)\n")
|
|
131
139
|
elif 'all_parameters' in attr:
|
|
132
140
|
key = attr.split('.')[-1]
|
|
133
141
|
file.write(f" self.all_parameters[\"{key}\"] = torch.nn.Parameter(torch.tensor({model.all_parameters[key].tolist()}), requires_grad=True)\n")
|
|
@@ -194,7 +202,10 @@ def export_python_model(model_def, model, model_path):
|
|
|
194
202
|
file.write(" for key, value in results.items():\n")
|
|
195
203
|
file.write(" results[key].append(out[key])\n")
|
|
196
204
|
file.write(" for key, val in closed_loop.items():\n")
|
|
197
|
-
file.write(" self.states[key] =
|
|
205
|
+
file.write(" self.states[key] = nnodely_basic_model_timeshift(self.states[key])\n")
|
|
206
|
+
file.write(" self.states[key] = nnodely_basic_model_update_state(self.states[key], val)\n")
|
|
207
|
+
file.write(" for key, val in connect.items():\n")
|
|
208
|
+
file.write(" self.states[key] = nnodely_basic_model_timeshift(val)\n")
|
|
198
209
|
file.write(" return results\n")
|
|
199
210
|
|
|
200
211
|
def export_pythononnx_model(model_def, model_path, model_onnx_path, input_order=None, outputs_order=None):
|
|
@@ -289,9 +300,11 @@ def export_pythononnx_model(model_def, model_path, model_onnx_path, input_order=
|
|
|
289
300
|
for idx, key in enumerate(model_outputs):
|
|
290
301
|
file.write(f" results_{key}.append(out[{idx}])\n")
|
|
291
302
|
for idx, key in enumerate(closed_loop_states):
|
|
292
|
-
file.write(f" {key} =
|
|
303
|
+
file.write(f" {key} = nnodely_basic_model_timeshift({key})\n")
|
|
304
|
+
file.write(f" {key} = nnodely_basic_model_update_state({key}, closed_loop[{idx}])\n")
|
|
293
305
|
for idx, key in enumerate(connect_states):
|
|
294
|
-
file.write(f" {key} = connect[{idx}]\n")
|
|
306
|
+
file.write(f" {key} = nnodely_basic_model_timeshift(connect[{idx}])\n")
|
|
307
|
+
#file.write(f" {key} = connect[{idx}]\n")
|
|
295
308
|
for idx, key in enumerate(model_outputs):
|
|
296
309
|
file.write(f" results_{key} = torch.stack(results_{key}, dim=0)\n")
|
|
297
310
|
return_str = " return "
|
|
@@ -38,8 +38,11 @@ class Reporter:
|
|
|
38
38
|
for ind, name_data in enumerate(self.modely.prediction.keys()):
|
|
39
39
|
fig = plt.figure(figsize=(10, 5))
|
|
40
40
|
ax = fig.add_subplot(111)
|
|
41
|
+
idxs = None
|
|
42
|
+
if 'idxs' in self.modely.prediction[name_data]:
|
|
43
|
+
idxs = self.modely.prediction[name_data]['idxs']
|
|
41
44
|
plots.plot_results(ax, name_data, key, self.modely.prediction[name_data][key]['A'],
|
|
42
|
-
self.modely.prediction[name_data][key]['B'], self.modely._model_def['Info']["SampleTime"])
|
|
45
|
+
self.modely.prediction[name_data][key]['B'], idxs, self.modely._model_def['Info']["SampleTime"])
|
|
43
46
|
# Add a text box with correlation coefficient
|
|
44
47
|
results = io.BytesIO()
|
|
45
48
|
plt.savefig(results, format='png')
|
|
@@ -178,6 +178,7 @@ class Sum(Stream, ToStream):
|
|
|
178
178
|
obj = toStream(obj)
|
|
179
179
|
check(type(obj) is Stream, TypeError,
|
|
180
180
|
f"The type of {obj} is {type(obj)} and is not supported for sum operation.")
|
|
181
|
+
obj.dim['dim'] = 1
|
|
181
182
|
super().__init__(sum_relation_name + str(Stream.count),obj.json,obj.dim)
|
|
182
183
|
self.json['Relations'][self.name] = [sum_relation_name,[obj.name]]
|
|
183
184
|
|
|
@@ -313,7 +314,7 @@ class Sum_Layer(nn.Module):
|
|
|
313
314
|
super(Sum_Layer, self).__init__()
|
|
314
315
|
|
|
315
316
|
def forward(self, inputs):
|
|
316
|
-
return torch.sum(inputs, dim = 2)
|
|
317
|
+
return torch.sum(inputs, dim = 2, keepdim = True)
|
|
317
318
|
|
|
318
319
|
def createSum(name, *inputs):
|
|
319
320
|
"""
|
|
@@ -29,11 +29,11 @@ class Fir(NeuObj, AutoToStream):
|
|
|
29
29
|
----------
|
|
30
30
|
output_dimension : int, optional
|
|
31
31
|
The output dimension of the FIR relation.
|
|
32
|
-
W_init : Callable, optional
|
|
32
|
+
W_init : Callable, str, optional
|
|
33
33
|
A callable for initializing the parameters.
|
|
34
34
|
W_init_params : dict, optional
|
|
35
35
|
A dictionary of parameters for the parameter initializer.
|
|
36
|
-
b_init : Callable, optional
|
|
36
|
+
b_init : Callable, str, optional
|
|
37
37
|
A callable for initializing the bias.
|
|
38
38
|
b_init_params : dict, optional
|
|
39
39
|
A dictionary of parameters for the bias initializer.
|
|
@@ -83,14 +83,14 @@ class Fir(NeuObj, AutoToStream):
|
|
|
83
83
|
|
|
84
84
|
Example - passing a parameter:
|
|
85
85
|
>>> input = Input('in')
|
|
86
|
-
>>> par = Parameter('par', dimensions=3, sw=2, init=init_constant)
|
|
86
|
+
>>> par = Parameter('par', dimensions=3, sw=2, init='init_constant')
|
|
87
87
|
>>> relation = Fir(W=par)(input.sw(2))
|
|
88
88
|
|
|
89
89
|
Example - parameters initialization:
|
|
90
90
|
>>> x = Input('x')
|
|
91
91
|
>>> F = Input('F')
|
|
92
|
-
>>> fir_x = Fir(W_init=init_negexp)(x.tw(0.2))
|
|
93
|
-
>>> fir_F = Fir(W_init=init_constant, W_init_params={'value':1})(F.last())
|
|
92
|
+
>>> fir_x = Fir(W_init='init_negexp')(x.tw(0.2))
|
|
93
|
+
>>> fir_F = Fir(W_init='init_constant', W_init_params={'value':1})(F.last())
|
|
94
94
|
|
|
95
95
|
"""
|
|
96
96
|
@enforce_types
|
|
@@ -112,7 +112,8 @@ class Fir(NeuObj, AutoToStream):
|
|
|
112
112
|
super().__init__('P'+fir_relation_name + str(NeuObj.count))
|
|
113
113
|
|
|
114
114
|
if type(self.W) is Parameter:
|
|
115
|
-
check(
|
|
115
|
+
check('tw' in self.W.dim or 'sw' in self.W.dim, TypeError, f'The "W" Parameter must have a time dimension or a sample dimension but got {self.W.dim}.')
|
|
116
|
+
#check(len(self.W.dim) == 2,ValueError,f"The values of the parameters must have two dimensions [tw/sample_rate,output_dimension] or [sw,output_dimension].")
|
|
116
117
|
if output_dimension is None:
|
|
117
118
|
check(type(self.W.dim['dim']) is int, TypeError, 'Dimension of the parameter must be an integer for the Fir')
|
|
118
119
|
self.output_dimension = self.W.dim['dim']
|
|
@@ -10,9 +10,6 @@ from nnodely.basic.model import Model
|
|
|
10
10
|
from nnodely.support.utils import check, enforce_types
|
|
11
11
|
from nnodely.support.jsonutils import merge
|
|
12
12
|
|
|
13
|
-
from nnodely.support.logger import logging, nnLogger
|
|
14
|
-
log = nnLogger(__name__, logging.CRITICAL)
|
|
15
|
-
|
|
16
13
|
fuzzify_relation_name = 'Fuzzify'
|
|
17
14
|
|
|
18
15
|
class Fuzzify(NeuObj):
|
|
@@ -4,7 +4,7 @@ from nnodely.basic.relation import NeuObj, Stream, ToStream
|
|
|
4
4
|
from nnodely.support.utils import check, enforce_types
|
|
5
5
|
from nnodely.support.jsonutils import merge, stream_to_str
|
|
6
6
|
from nnodely.layers.part import SamplePart, TimePart
|
|
7
|
-
from nnodely.layers.timeoperation import
|
|
7
|
+
from nnodely.layers.timeoperation import Differentiate, Integrate
|
|
8
8
|
|
|
9
9
|
class Input(NeuObj):
|
|
10
10
|
"""
|
|
@@ -119,16 +119,16 @@ class Input(NeuObj):
|
|
|
119
119
|
Examples
|
|
120
120
|
--------
|
|
121
121
|
Select a sample window considering a signal T = [-3,-2,-1,0,1,2] where the time vector 0 represent the last passed instant. If sw is an integer #1 represent the number of step in the past
|
|
122
|
-
>>> T.
|
|
122
|
+
>>> T.sw(2) #= [-1, 0] represents two sample step in the past
|
|
123
123
|
|
|
124
124
|
If sw is a list [#1,#2] the numbers represent the sample indexes in the vector with the second element excluded
|
|
125
|
-
>>> T.
|
|
126
|
-
>>> T.
|
|
127
|
-
>>> T.
|
|
125
|
+
>>> T.sw([-2,0]) #= [-1, 0] represents two time step in the past zero in the future
|
|
126
|
+
>>> T.sw([0,1]) #= [1] the first time in the future
|
|
127
|
+
>>> T.sw([-4,-2]) #= [-3,-2]
|
|
128
128
|
|
|
129
129
|
The total number of samples can be computed #2-#1. The offset represent the index of the vector that need to be used to offset the window
|
|
130
|
-
>>> T.
|
|
131
|
-
>>> T.
|
|
130
|
+
>>> T.sw(2,offset=-2) #= [0, 1] the value of the window is [-1,0]
|
|
131
|
+
>>> T.sw([-2,2],offset=-1) #= [-1,0,1,2] the value of the window is [-1,0,1,2]
|
|
132
132
|
"""
|
|
133
133
|
dim = copy.deepcopy(self.dim)
|
|
134
134
|
json = copy.deepcopy(self.json)
|
|
@@ -224,7 +224,7 @@ class Input(NeuObj):
|
|
|
224
224
|
if order > 0:
|
|
225
225
|
o = self.last()
|
|
226
226
|
for i in range(order):
|
|
227
|
-
o =
|
|
227
|
+
o = Differentiate(o, der_name = der_name, int_name = int_name, method = method)
|
|
228
228
|
elif order < 0:
|
|
229
229
|
o = self.last()
|
|
230
230
|
for i in range(-order):
|
|
@@ -7,9 +7,6 @@ from nnodely.basic.model import Model
|
|
|
7
7
|
from nnodely.support.utils import check, enforce_types
|
|
8
8
|
from nnodely.support.jsonutils import merge
|
|
9
9
|
|
|
10
|
-
from nnodely.support.logger import logging, nnLogger
|
|
11
|
-
log = nnLogger(__name__, logging.CRITICAL)
|
|
12
|
-
|
|
13
10
|
interpolation_relation_name = 'Interpolation'
|
|
14
11
|
class Interpolation(NeuObj):
|
|
15
12
|
"""
|