diff --git a/doc/rtd/content/02_basic_functions/mlpro_bf/sub/layer3_application_support/04_control.rst b/doc/rtd/content/02_basic_functions/mlpro_bf/sub/layer3_application_support/04_control.rst new file mode 100644 index 000000000..6a39a797e --- /dev/null +++ b/doc/rtd/content/02_basic_functions/mlpro_bf/sub/layer3_application_support/04_control.rst @@ -0,0 +1,20 @@ +.. _target_bf_control: +Closed-loop Control +=================== + +... + +**Learn more** + +.. toctree:: + :maxdepth: 2 + :glob: + + control/* + + +**Cross Reference** + +- :ref:`API Reference BF-Control ` +- :ref:`API Reference BF-Control Pool Objects ` +- :ref:`BF-Systems - Basics of State-based Systems ` diff --git a/doc/rtd/content/02_basic_functions/mlpro_bf/sub/layer3_application_support/control/.gitkeep b/doc/rtd/content/02_basic_functions/mlpro_bf/sub/layer3_application_support/control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/03_machine_learning/mlpro_oa/sub/05_oa_control.rst b/doc/rtd/content/03_machine_learning/mlpro_oa/sub/05_oa_control.rst new file mode 100644 index 000000000..914e1ee06 --- /dev/null +++ b/doc/rtd/content/03_machine_learning/mlpro_oa/sub/05_oa_control.rst @@ -0,0 +1,22 @@ +.. _target_oa_control: +Online Adaptive Control +======================= + +Further descriptions coming soon... + + +**Learn more** + +.. toctree:: + :maxdepth: 2 + :glob: + + oa_control/* + + +**Cross Reference** + +- :ref:`Howtos OA-Control ` +- :ref:`API Reference OA-Control ` +- :ref:`API Reference OA-Control Pool Objects ` +- :ref:`BF-Control - Basics of Closed-loop Control ` diff --git a/doc/rtd/content/03_machine_learning/mlpro_oa/sub/oa_control/.gitkeep b/doc/rtd/content/03_machine_learning/mlpro_oa/sub/oa_control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix1/sub/mlpro_bf/layer3_application_support/04_control.rst b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_bf/layer3_application_support/04_control.rst new file mode 100644 index 000000000..820e5cc6a --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_bf/layer3_application_support/04_control.rst @@ -0,0 +1,8 @@ +Closed-loop Control +=================== + +.. toctree:: + :maxdepth: 1 + :glob: + + control/* diff --git a/doc/rtd/content/99_appendices/appendix1/sub/mlpro_bf/layer3_application_support/control/.gitkeep b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_bf/layer3_application_support/control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix1/sub/mlpro_oa/03_control.rst b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_oa/03_control.rst new file mode 100644 index 000000000..36e13baaf --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_oa/03_control.rst @@ -0,0 +1,9 @@ +.. _target_howto_oa_control: +Online Adaptive Control +======================= + +.. toctree:: + :maxdepth: 1 + :glob: + + control/* diff --git a/doc/rtd/content/99_appendices/appendix1/sub/mlpro_oa/control/.gitkeep b/doc/rtd/content/99_appendices/appendix1/sub/mlpro_oa/control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math-Geometry_class_diagram.drawio.bkp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math-Geometry_class_diagram.drawio.bkp deleted file mode 100644 index dcaf36aa1..000000000 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math-Geometry_class_diagram.drawio.bkp +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.bkp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.bkp deleted file mode 100644 index 283ce4ee4..000000000 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.bkp +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.dtmp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.dtmp deleted file mode 100644 index 86c7e93ab..000000000 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/.$MLPro-BF-Math_class_diagram.drawio.dtmp +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio index 8f46c6f03..ee1e48938 100644 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio.png b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio.png index 4bb8b23c1..13e6e1fab 100644 Binary files a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio.png and b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer2_mathematics/images/MLPro-BF-Math-Geometry_class_diagram.drawio.png differ diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/05_control.rst b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/05_control.rst new file mode 100644 index 000000000..8f8901218 --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/05_control.rst @@ -0,0 +1,12 @@ +.. _target_api_bf_control: +BF-CONTROL - Closed-loop Control +================================ + +.. image:: images/MLPro-BF-Control_class_diagram.drawio.png + :scale: 50% + +.. automodule:: mlpro.bf.control.basics + :members: + :undoc-members: + :private-members: + :show-inheritance: \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio new file mode 100644 index 000000000..4b6cef9f1 --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio.png b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio.png new file mode 100644 index 000000000..82373cc38 Binary files /dev/null and b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Control_class_diagram.drawio.png differ diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio index 2aff1e498..e03c75d13 100644 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio @@ -1 +1 @@ -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 \ No newline at end of file +7V3rd5pME/9rctrnPSceQED8aExs0+Z+a9Mvng2uSoNgAGPSv/7dBVaBHRUjF6Pk6dMGBFn2NzM7t505qLdHb98cNB6e2z1sHkhC7+2gfnwgSZIsSuQfeuY9OCMKdSE4M3CMXnhufuLW+IfZheHZidHDbuxCz7ZNzxjHT+q2ZWHdi51DjmNP45f1bTP+1DEaYO7ErY5M/uwvo+cNwxer19X5B9+xMRiyR6uKHHwyQuzq8FXcIerZ08ip+slBve3Ythf8NnprY5NOH5uYX6fvv8yzZ/Xbj2v3Bd0f/by7eDgMvqyzzi2zd3Cw5X34q2+61uBt+PLaPLx/frx2fpyf/70/ZDC53jubMdwjExge2o43tAe2hcyT+dkjx55YPUy/ViBH82vObHtMTork5F/see8hNaCJZ5NTQ29khp9iq9ei2JLDJ9PWn4NTHcOcX+A577/pA2oKO3yMfnb8Fj49OHpnR2+GF7mNHD1GPpnfRA/YPSknNwTBtSeOHs7Un5eJ0G08u0Nh9PMYD39Pm+3+bEY95Axw+IXmlXPy/eK35JxO/71Ou7L967p3KIbfSOc7QqsheN+wPcLk1cgFDjaRZ7zGCRqFfDGYXRfeSiYWvUcuGNuG5bmRb76iJ8gFjMeFcMAhhzeUBBmtdz35JRgBO4q8yvyUT5rrkKlckWlJZCp8SipVpXypdOmcviJzEs5DR/du7xxkkVcTvj71a6/IMeyJWzuzB/9xJO1OjZGJLEq7fdvyGHXXyTEyjYFFftcJ+tghJ16x4xlkmWuFH3iUpo/0oWH2ztC7PaGQuh7Sn9nR0dB2jH/kaxGjXvKx44XEL6mxK27pnSHhOdgl11wxwhNnp86Q64XX6LZporFrPPkDppeMCF0Z1pHtefaIfVGMH2eraTAUx36eLdD0TJ9wWds2bcefmnoPYa2vz66MfKLqGn7q00/C2evE7+z7P+TzgYN6BnmHyGcd/2dt5qJzj9+WckP4qRKnQo1RyHSuitQZZQ+jWkhDWMFAo7cboi4ha0BmfM4l9fjzRJl/nqgCz5PU+OOQSajMQh4+opi5CdbJhllEjlna3bvHqxNyzj8UvhDmIf8E/POF4xYCgRfhDBP3vYV84Y6RbliDM/+aY3l+5iacA3rKJvf2TZ8mh0avhy2fZj3koYCsKdWGcooMQDkif8hUtqkQV8iA2uRYnB+TP/Ryh9CbRYgWGT5lYcIzU0z5BqC55UJlNdG9x8FcRWRJ0KM0FkN7bWglDloOPdPw5VxkteVlwApoRwQkf6EPsbzzl/VDkcO7zuNdB7A10RM2r2zX8Aybfr8TXJvAvDRYFSkdrNrmqJ7fH+vC4fPDb+9NV1Bbsh9ap4f84tbtGpbhdbtf6Qt3TXtAJP5gxr5kiau1u2eX37qts7ODtnTQEvglr2LiBWirKVeKLOB+ObPflJ9y/595Or0R/z2Yknx9KHNwu8ZoQnQ83HUw0imPBLgTNcIjV7Ru/X/JDFLVi4iWuuirrT7w9NwW/DLuBgMno20Fv0jCf4dktIMASyF8h4pI0xGppqUjUqaGbEKkTet3/9+Pl9un6UTGty+PA/RnfKjxMunzU6k/XoBQyf+7T6vU8Ilo6AL5WaChZ0TDolQgEbdVdHTxw3au/r7/+HF/cXYuCNZhCm1pQGyn8YZGyszHGgJ3EPViQsaLODMf3uMzEJkpuQmtSVIGUyUct391Wo/n3snDj4v+jx8Pwzv7kLcZCEOYjG78V2Sko75M7IBTfCKiiM5PCS5zVLNzYvRjxmPBVz/FsGBX0QceBl/TIheI8viN/4ozPMBWz78i/C4n+e1kHp6Ac8H7JAbC3ZzmzKqZIcZxbGZWvakKvejS94PehUgaC3xaOE76JGfw9NUXi764jvz23+IBhG+78i1AuMi/aEQlo/XkjoPp4E8teq3YZaf05caOPXCw66b62kxP+Y8nXGL0ULB6FDqAG4x6VI54Nvlr4uLInAWwr0egcdZdhNSa9LceV2TBh7EzscEjz3OMpwldzQUqHyWBSMuh3fv6X5YoXeAppcnJk2noVDbPH9oJHscQe6LjMEZjE4+ot7G3tlTKEtAPwgc9Yuk0R4TS7Enku5rxoSQuyAYbH5iOYQ2xY/jTvQqkIaLvbrhJmMgi7ODFsGTLCbFX6HJzmyma0BC66/FISP1EcyUakD9ZbD470bFvDwPwUyp85JXjdBV5/W0grQXzkJWQTTtY2ISKuCZTWVPTIZnlW2JA0a+ZOoiei4c8ONtGVQU/FJKMaYRzkwiS9BcENni7YKmZsdoyiur3WrPWjP7IRar7vGV0jMfYD0gIVKtJhoT5eG0ExEXuXYbmWeLzmXs5rRs6Hhv2I3iBlSFKa6O0MtwaIngoqlK9JhI7jP1oMZPtUBI13mpTxJogi+r8B0BVWQIqHHMVhZokaAJZNDX/Pzk+FFESaoJQF0RFa5C/VSERIw5C1uF3LgntKgqhSEFTJKlB/xMlZa3HBAHv1Y9pJhyrdr/v4tgt68aw60JN5QebYJLNwtIgF9U5LjoN1gTKRn3HHm0vIwkVIwGMVJdqdU1WhbrYoH/L+fDR8qesy0bvERCWMVVWRM+HLzgqr9ItFqZb9DUd62C6xZOmyAr9QiCdYqaRrErFyFxjiTFOnf1ISpz4IP+lUJtfT394/k1S/qdOxQB5RVnNK3sUrl8qTjZJwkhBaxkEc8Hhq5U03EQa9vsSLA176pOqqNsqDUWpJjXn2klDrqRhCl5pVNJwlTRUU5PiVkpDPmugkoaZpuJuozQkMqdWb8RtnEoEwgzSrETgKhGopaa/skXgsl0dEYTDdKJoVhTdsEDmCKORWzsls4UsPUydIh/Q7XG1kyBCsFVbGWRhi+Rn/UPyc5OtDFAYgqfpbLY3yI24TEubtKpKjR0SoeCONd7i8pOlDUTvDFJQnmzb5Bjns+fv8aS2VP6kFp8A1LltaoC3a/KAuhNd99N7KkDXB1QtcJcKOGKJB/SJCmSrwvMjeDal4vAEJS5vt3c9Y4SpxlAB+gFARTFlYnRuiALZ/WTdHhlWtYh+EFJZLlno8rFoDrw9siwzQrWRUjfKy5jkY63xnYH+3puu69skjG/PAxOFWpPZ7sIZL9CzBX9kQgeZbj6PXSCacn8urIXm/lhQV8p/ksEVPefH/u9/4+7zFDkDOsn7sIc1K7mUUoEQRXFzyQRqELyba4A9JiC+JnfUVbrEOv5MrVmyeshb5G4EXH/lWbAUVDycFuW6qJSsMfLJKZSFw0WvYuGNwJXFksHlvaRuBNxAeYTVm4qFU6OsNkpGmffMUBYOFMiKgzfCtlkvGVveR+POsfUZGDYUKv5NHfkQy1a0eE855d/QFKsYeCNw5QL1KxBc3iPnRsD1OXiB0V2xcGqUGwUqWiDKvIvOZ+HQZVXx8EboNgtUsEB0eRvJjaJbMXEWMCtSgbrW95+938rp6e195xLffRu0UdO6WeDN6mPkTRzc7ZEJ5Rg5TNCqQE4LslygsgWCDHu1YiD7/Bw9M2PqGdyEr0MfdgV8OuAbBSpiIPC8lq3b43eOo3ez7FtesM62f5eXN8bzYCGl6z9YmX5VyXseqLRl6Jc2QVjdLSHEJ7s69JuhyotpVqhx/fTpM8PdshRq+WCfU6jXo/EPV4Ovp83bEFOUEPg86dIwP/GrH8cQ+54YJKYnuJl3KR2B5ZUYJPLOpXhmUFDlNpEadIsDK5VcLlzYVj6JJGhAJrtLRs+eJOTyGP/N3fjr7E0p9IyoOG3hezk3Moa9Z4yE/Ch0BWbKpCAh5aInLdlluRmaCzIKyGzgXsiwnNVljWtWDwUFnyqo01bWTpttnBvUfH5BoKXP/SQJfX17dzWKW6SS72yDprQbGMXmLmnkYEyB3wPenQYjYnoakVFobz3LM9GyRhy/OGn486Xdnt5dNx+E0fCPp3T0ThfyLDPtdMcgjMrmxd0QUkK82LWY1mGc2+pWVarJgU3TpjXnZmwAu95S2sx5NLUZL5D61KAVa8K+G7Nrk1faXIEsus3AQ+YXdmr+BCjvsSW7NpJiPW3aR14LAKu7nYgVh1Ayzq0gTQ+pWqCOBu9pUTm0tqLRdaENq2FiD5WbaKRwaQuwkjtWJztQi0I4sIWN1cXlN2xcHBwmuMZWElwBxDOwjo7P5Z/o8ES+Pvottk6PpftD5msuPswMo6NtJTpbKg5gRLXPKQ5EQSlFHjS3juKqxURStCQtyCuoR15+Qz7Ew2h8/4inoMUkI+KpLyeeVTfkRDxiRTzbt26tLXmajZwlz9HZ/aX20rPV69fO5aCjXB9/fzjcPsGzmRb7/HD9qqv2y8S4vppedk9f74zHQxY9itIOfGHmyZIfoh0tqcGwpjqLaIe7QdYamdLOUpaMFsN9dz08isaGO7p3e+cgyw3crPSQbUwPj4/Cfa4swdOr3SH3mfPKko/ssVs7t3vzZNCxaXu1K/JX4DBhp1+RY9gTt3aFHdcgA7K8eI5S5JJbnUZOjb6hXz79xfp2xa7V5sH2xK6LTyeNtv3r4T6amLATK6OavGqCh8QmUGlTApxaYqOxS2V5YV7nY2bt7t3j1ckBS9H7EvD+F46B9sRrOpOG6fdYABEziL7yKyrIR7bb3bPW3clF+3GGK93/2MOmh2hL8bY/cbvnGec6jArCgvSZjLBvAkHwQrFvAHkqfd3r0umx5lVjIsv3jkGeG7Qi0weLwBY0gZqLsE2UBIoqYxW6aUvBAtHLQtGdZQIn4U0UjImo1hW4aSsvAlvVi12SgZqwxNTElr63CdQfgLFZumbF58ovreZbIZuyeKZUoN6kPvy9Rnj0+qI+GOf375r2/ccL1P0ATCyrkF0TWaVArQlEFthz57LeTkGu4D5XEPgAoo0CNSVYCgPNhMYOfq1w3QTXulC6kgS0LDHJm4eSeAYsqyxQIZsSWalAvQkMwADADghzTtH73Go1DXf3ds+k9XVnhbSSUo9iLupNkO5fHjaueg/9o9G1MTr64x3+ex5AwaPuCI3HBAbKxhPk2c4c856hV5hvirlWIOZweJX3N88wd7HlVohni7gMFaHPC/FJX5p07u9/Th/dDv7euraOL/qHCu+qoi5mPJ7hPAsvHMRLV1TIb4Q8VB43L+ThMVcdq/LAFaq2B+GawS47mKEBER7ZZedis5+oByMJaf8EG+hy+3scrVoD1MfZooFaaDQ3TwmFBcPe7jE7yBpgspy/zQYepCgF891y3y291u7etC6+nXQvLi9OtvdNaMKaM7FmY6fpSGTorfu7y5v7iy0fvE4MYbfrDons+SzUPvJTusKh0vwuMtnnl8cn3dvT8+0d9Swqs0KRybw41oFflTqdFrWtk7c80+DzvMKSgPqneYnFYeNP8QqjyV9bt7t9w8SfZMR9hyzvXffZmPNvdKkUt3fkQQgzNNk/yWyH0bnPNWidUIiDurpt9Wc04k3GERL/OnsBIf7bf9v7Vq+GOyH23L+5bruyDekWjd60B4MoBZ3ZA6KonF1+67bOzrZ12DvegrVot4qWNvTVzGBnMxil5vODbu9ad6eU+11MRESQhsAXYoz0jd7V3ITCk3gbDaBQI0gOGcTLuq2pIvyrT5FkXrx56nj4/b4NdDbpErtvouNgqY60ESfyNnCp52GPpP9l3B0jOlUt36tR9lhsYikTK2pLRkNVWN/zE45nB+V1bqyoQeVxIVZU82JFwDGq2yOisnkxZtwe8t92hqhYJGMWYaS/ikWUDIo03Q9G34eefmL+GV+17szW79vXO6A0qjs1PH3IVOuAQ+Z6dgVu+v1EDMiVqkheRdWAyBCtjxe6Sfe3QN4HsITaT+SlVsJY8sk5boXlh7CEetXkhSVoMPImgl+1f74ZYaGpWGGcEuO0G8VzwxgWvdF9CRXIm+4pEtg9pUlllYeZSmUHWT17RPR23AvtfezXcwjcwpUStQ7GrBVOeRjzK6+DCcoVshsiW6SrDkYW2F+0R9AW7pwVwY5JeUG+tO5UBHLU67EdDQHu4cEBi4jdtr6xM2W5X8axYOl8y4WwF93u4ZBSvMLR/HwPuUOfceGyZZnRspRSxaw38zIJ4V5ugWez6rW8IbxQT5RiLX5ow/oM34N5GGkmp8Kj3V6pCogpiyKLFRcBPpzUzSudXWdifR13DTJFXQtPg7hxeNzDZoX65kWCCtwdDaMOsDwV6X3dC1ICd9DPt5WLuyQXuKEaJgWg6kxICmGKa0ULBdFCkUUBYVoA7FRGC37GdkUKBZFC6TUCVV4sjB2bioPQtxxtrEbUQlZvYT8MxfyQrxdZQRBGHtANKuhLUxbrRRYdBFM3+EXBNUYTGhDuOjhKESzZMLQP82itmNUvIPnuvhuj5GWtnrbGYhadHH97T9+MYduefr8yVOHO/vb33zeohNvnJ+aU4ng3Sbr44IIsFkjFYBlYgIqNEZ2kBT7ZnV+Io8CXLONkpUCLHi4SzFMHfvOpA1DfmE93f5W4baKdRoEeAFDX460+msg+oflioTMIWhz3g2jyw10R0pr7S5qNbKQX8dHqbgV8eSqGUpfSEQQrq5Z5F9XZoBMx37lLePdxzxFfNa2SkEExJ1DQ8+VxGb+HAaD9ZfccYU8d7s0glQOU8wt2qlW4lyLmZw2Oi1j3YTHPO/eomJ8HgXcf9hzhLdJ1C25M5RfxcGOAZ4fFcwJ+H5ljx56bhLsX5csR5CL7xoAgA0HbPUW5BAleZLsZEH3eYg/2d/UdexRHPyiWtcPw5wdzo8jeMyDMC5sK7SHOxbN5o8gONaDirnAoFtCsO+b2xG+G9zvy+yP9XoJYcHT8Fj7GP3hnBxZ599/Rg8hd9HB+m3/E7uORTNsEHPaIh7MXbQK+LDyYcQ9wrmd3PdHvXVKbSk1M2HzBYMM759SzbkNxuZ58lihEvy/FDaE1mlVD8Z8v7fb07rr5IIyGfzylo3e6N+U0o4dzOUqm+gTx5cwGizM+NqX64glVaa64QV1+w8aUvXTWI0v3ebTqcbTgcYIF5gROyW86NDwcbN2uH08dNE4QM9dmXdLBBu099UlV1INEx/dog3ug+H5cD5DWltEpFlvWGl3Rkijx+zdnrVizbmgAQtjYIumErR4hUh82v963oQcnO4YJLttZyxCNlyHLchQKX0obklaTZE2T6orUlEUx4UBfsKp+gNlBBUIuXU0rC2+xLLwVOYq3lBfcS2dnhWy/OWmdVcIdFO6qyrvAcxPuoAtcFDloCuDZiBh/Mm39mRPiTPGcK5uPUV0TVDwz5n22NzDK+6BFLeTC++sqkLNoCivRqixXB1dcn482COy3jHUO+PrUr70ix7Anbu3MHvDOG3dqjEzkN0+KcnU9wtU6gR87C106+tAwe2fo3Z5QTF0P6c/s6GhoO8Y/8rVo3pUJOV5IxZIau+KW3hlSnoNdcs0VozxxduoMUZeNf41umyYau8bTTAyNCGEZ1pHtefaIfVGMsWJCjG8QlZCKPYS1PigVVV3DT336STh7HU6ekh/y+cBBPQPH3Esd/ydHmSgnljRNBKKCAuBsEtnmwSXL5w3WPWQN/OrxTAYn7CZRBkSwmsK5hUxCZhby8BEFzc1jgQV2pLW7d49XJ7Ml9kuHVjYWQg76wvHLZ3d28lS3XK6k79EMlJWAqCy3PFVg5ymH3h61icsIVnbHKlgzSCwCR9wEIhWRLnGrein4Gxp2L2SRG9yA+gxzcV54K4szyarM0dxg14BidSDsGZT8BYcM7A+uMoY/EKHMiB5EMaXYzy1hmG2K2jYzehaLmYdfHqOfFROBVAA32hab0qKgfAZbmve+RTvYVab03pnSmhZ3L65hSi9xL+6IKc23YIBN6YCB9teS1lJT3bZY0ozCKks6S1hLt6R5y6qypPODu3RLGqj/Xe3NyRv18g1pwF9WwZ6RHb02OaS2o3Ojh2aDo4c7PBqbAep9MhUU4eDoCblEvyfH766HR64/bDJqSdBtx796YvlZ4AR/z8Dkc9VPIXpyGN1QAkIjin6iSIzgt2MPFuYUdx1jD7N8c5u2LZ51R//Avawp+epb/VyLoCSxMSKzfYMRnd/LMXZQ2qFfYcc1XNrcKPwq00ZkTjsuIsZ1ivu/I6c3Rf50IxbEfTWQD4JFNCzTJA9I9TKTH3bbPjwlBueADZ/hHZQoCk4hiw7PP8+aKocfJZh/axNMlIUyCDl6aCCL6zth0puJMzNt1iJCAxZ/uV5TAEsxi0QUMHdM4xAsK8WfJZZsZ4o/OHmhrrwywz+fNLW1/WuaEiNAqaHJUfpZneu89g1afYlHjrtdayZub2paTZaF2Y8Sn5Gc0yqbFWvkzxpb4nrmWaO+Lmuse4MsH2zAGlqjXmsm1MGc+YH3DFyOA0WP3mn5vkT6qz5xqT9YEsgDhzb1KwreENGXCTQWsgCbvgZp9P2PMIPXP0mMB/ZFTJN0Z7daNv2asWO/GoTLalQHwzggW0Se5is9tGuvTovSUWWS9RHwzzD1sD1Tg6wnl/4TfM5UwM+i0UgLNZrcVBiOTQDXswRtUWyKtYTwzq7pEe/BuMWW6+uqNBozQt6wdmyMyDlCS9sVkGkcVAGZHMi0nggM0hqwNWg3NWRkN3YpKANyjMxL8mRQJuCgfQjHLJcp6cMxQNWVvMIx8JD5pFUOvT0Kx2QEK1RXNadwDDxiPuOppXsT5FXLW7W8zUu8Sc1ao1re2PLGBzeSyxvjof1d4OTUVLc1CxwPa7XAbQxrgQtc//KwcdV76B+Nro3R0R/v8N/zYFaooLxd7tEQ38rMzvVketRLBuMFuMmWai7Z+ck2Q02tUEuDmlwWakvHHfWUzLs/+9qkPXZrJ69kms6RhQbYqfTJ3dcnm0JCtxObKXMLFW11KYVPrkwCW6c5Xwnjof3VJtXUNFeCNgmvYFBi8snDycVdt315ft49ubm5vJljPD9XgZy5bpkbyMxOjvUs6lUApgUQ6gxTLIBA6XgLjeZd4cl8VHCmzjOEOr4UasMDm6e6rh9qcGeQ3mKvgjR9d0OgRmyxkPILKS0D7LvXKlA/BqpSuq+Nzwfm4Nt7X9v6uGolO9t4Wya+t4fqRkG+DL/IMk34S3DJ//437j5Pif1MeXz3NvykbbicFWVAPXrAnfQZ5AHD9hDP8Q52sbcf7VgKhnvm4isPbkAR21O8l2/xyQpxqJZ/XojDehofPkO9Xqh9h7u9WNoc09noYSXbN4VeKxD63r9HD1snv7SGIr5Kpz/w+8UI6LPpd1UM7C6O4XdRVS8Y8rpYOrfzy/kc87myx7drD0VAhf9G+Mtl46/yjrM5/l3/bJwKKsA3ArxRukIHNGTbW8QLUelkoWwmB6ogUpWOed8CuNE8XTRQ6yL5o7tNBQXwvZzW/ZqbbgfL+ZkDttLucgBdLZvxgdJLUdSX6Hdz5q9oYCMaKNJhB9MA78x1IzSQXPEDt25w8R7WcSmAJJTynXpAedyKJsrVEpUiHX9HZ/eX2kvPVq9fO5eDjnJ9/P0B0BD40j6h1d+JKIuDIKfN371tH4QbvJFfqzGs9xPZqT2rBZQgl63dO724GgxPCRnt2hFZuZdZmiUrdxtNe9QA0lAy2Dr9/Wfvt3J6envfucR33wZt1LRugCbex3hk3+rYohVsySdf2e9HyMXblQssH2xPLnCdp96cc4EhVsqLcpN1i6RmyvQEWVsi0z5dejDIQRJvgre7F63zSHowZSlqePkikv4SstQ+JJIulTrpIyh8K87c0mFglHnFqt1tte9OLy+6N62L48vzOdwOsnr2qAI3tYKUtgJqbuBC20VDcNuXF7d3rYu7Obw6nR5keRXAqZOICyxUDY4YsooCYVxvMalcYZkyg1gqGUygcC3yi0R1x8ijy32FZVospbRViPPCEig1jnSwqmiF4aJM4bJVIz7PgPGjia0B9RNUUKZMDi5bEeIT+Tnw9ijnOyPTRUip/WSQ8g2OmPWiWZDz7WKzHxREPJDqQfljv4VDfn+PmfI1SzMMD4sdxMjvmF7sM5OKCpRePzMfix2aHywMhnBhW4XPjP6um7hrGiPDC8YhFI7NxLNpsGQynuESBEDCWblzJoXPCqu0jrdnSFX3lywXBzGl9ibW81rzRT465DPB1wrF1Ll/pXuwWPuQRDoIDfFZ+juXAuQZI9zDpocqiFOnd5btw4LSO4P9OnTbBu5V7Jo+bbNsFxaUpuFMrEAJqgRveiRLd2CJgDeSSl6LIBZq+5z0bVUerrVAztHDRQ4d2/aiEWEHjYe0wRO94v8= \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio.png b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio.png index fdc54dd85..6fe1174a5 100644 Binary files a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio.png and b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer3_application_support/images/MLPro-BF-Systems_class_diagram.drawio.png differ diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/03_control.rst b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/03_control.rst new file mode 100644 index 000000000..b8ed57bc5 --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/03_control.rst @@ -0,0 +1,12 @@ +.. _target_api_oa_control: +OA Control +========== + +.. image:: control/images/MLPro-OA-Control.drawio.png + :scale: 50% + +.. automodule:: mlpro.oa.control.basics + :members: + :undoc-members: + :private-members: + :show-inheritance: \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio new file mode 100644 index 000000000..d913c80eb --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio.png b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio.png new file mode 100644 index 000000000..d448ccf10 Binary files /dev/null and b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/control/images/MLPro-OA-Control_class_diagram.drawio.png differ diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.bkp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.bkp deleted file mode 100644 index f1a02d7be..000000000 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.bkp +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.dtmp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.dtmp deleted file mode 100644 index fe1d2e850..000000000 --- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_oa/streams/images/.$MLPro-OA-Stream-Processing_class_diagram.drawio.dtmp +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_bf/03_bf_control.rst b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_bf/03_bf_control.rst new file mode 100644 index 000000000..82d1284ac --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_bf/03_bf_control.rst @@ -0,0 +1,9 @@ +.. _target_pool_bf_control: +BF-CONTROL - Closed-loop Control +================================ + +.. toctree:: + :maxdepth: 2 + :glob: + + bf_control/* \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_bf/bf_control/.gitkeep b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_bf/bf_control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/10_streams.rst b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/10_streams.rst index 215ec7ef0..cfee65612 100644 --- a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/10_streams.rst +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/10_streams.rst @@ -1,6 +1,6 @@ .. _target_api_pool_oa_streams: OA Stream Processing -=============== +==================== .. toctree:: :maxdepth: 2 diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/30_control.rst b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/30_control.rst new file mode 100644 index 000000000..73c22358c --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/30_control.rst @@ -0,0 +1,9 @@ +.. _target_api_pool_oa_control: +OA Control +========== + +.. toctree:: + :maxdepth: 2 + :glob: + + control/* \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/.gitkeep b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/.gitkeep b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/.$MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio.bkp b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/.$MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio.bkp new file mode 100644 index 000000000..fb8c3b773 --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/.$MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio.bkp @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/.gitkeep b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_architecture.drawio b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_architecture.drawio new file mode 100644 index 000000000..082117b75 --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_architecture.drawio @@ -0,0 +1 @@ +7Vpdd+I2EP01nNM+kGNZ2MaPIZB02zRNl+ymu29aLIxaYVFbBNxfXxlL+EMOGIhx2LN5iTWWZGnmzszViA68ma/vQrSY/c48TDum4a07cNgxTcuEhviXSOJUAkxopxI/JJ6UZYIx+Q9LoRzoL4mHo0JHzhjlZFEUTlgQ4AkvyFAYslWx25TR4lcXyMeaYDxBVJc+E4/PUqkJ1TaSF79g4s/Up22rl76ZI9VbbiWaIY+tciI46sCbkDGePs3XN5gm6lOKef4QP9P7f+y7X/+M/kWfBr89PXzuppPdHjJku4cQB/zoqSMffiSjh/6nP6Knp+c5uDMg7MJ06hdEl1JhH+9F+/HDsHvDAh4ySnEot89jpdSQLQMPJ/MaHThYzQjH4wWaJG9XAkdCNuNzKlpAPE7FPBIXoK/acq7k/QsOOREGu6bED4SMs2QCJFsUT8WWB3KZoitelwy7RylgaykBcszmmIexGCdn2RpX4Rs4aXuVgQUYqtMsBxRHIRxJhPrbyTMjiAdphwNs4mr6xp7AtGyykM+YzwJER5l0ULRI1ueeJdrc6PlvzHksDYGWnBWtJJQYxn/J8ZvGl6RxBRyoBMN1/vUwzrcecUjE7gVWUqGHotlmOVUIiDgK+XXi3EIyoSiKyESJbwnNluSpTgELcCqR740tJhLdHIEIoV+2DCd4hx2kfcWqfMz3+ZCOsBBTxMlLcXFVYNkMFTtFca7DgpGAR7mZHxNBBlwIisA1eyXvP6y/eEhXkMF2u5XjkWxo0eV8gaWhgAGBWwwYfUsPGE5FvACNxQtT0/JPd4gEHVNMZzx8Tf9//vpzG2GlbKOmfVZRjH0+a1QbubbPnmQwoBksTbqMkkl8iT5RSqK9vtG2TygvzesYr1DotZpbQTG3Wnsy6868KVNiPmkaxaSZZdYsb4Iz+GCvpg++Aqrz+GDvVXzYNCGc30Rysv3k6XYZTDhhwQU6pg3enWNamt6vq7Wrs7+cNouqL+u2SBPrss014Rv+e2UAU7YlBbZd2c78NGnEuUaZ/zae58xqw+cMa1XYVckO46YamQTQKbFJ6F5ZxVnSLciBO4gpUEx0x1xpKNHmeiua6miYHAm46Oz0JEhWpwBnXw44Cssnoa8tUJWP4gIXx2LKrj7rnAtPAOjQ+XGCf+sT/Kkn7opIBJ3duKmLv55bEdIcN/uDtfB4aE3A6uufdaydK90/pJnKANB5wJgjjttwnAul2UCe+/fz7FcKVBICXePKtXpWAQZdaB0T0w8FLHCs4nddd3cVq2vu7F/EajZarYdNpxFuJuTb7Yb87Cz5Jf/u+zpY1kZ8KxXZg8HsQKM+mN8MqHq1cBxHHM81/L7/4y2wS8cQYNY83zZ3eQP0G7UhphxdoHq7oFQ+AO2XD4Betxljvtgypx/HtXMd1zR0HM2Wu+b+asIbMeSuabRwDSYg9QrZNZKfM5iDAK/aoA+XSgOcmjSgdyINOO1WzmjDpI0wwuMP+FlR1cqVVFW5tbqcWig8vBsstUMpjdJ5R/GWupSy1L+h8KbXT2V4K1+lDJbT6UXe+rulGnWjFymimf2oLDVS9uM8OPof \ No newline at end of file diff --git a/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio new file mode 100644 index 000000000..c21951c4f --- /dev/null +++ b/doc/rtd/content/99_appendices/appendix2/sub/pool/mlpro_oa/control/controllers/images/MLPro-OA-Control-RL-PID-Controller_class_diagram.drawio @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drafts_Amerik/basic_control.py b/drafts_Amerik/basic_control.py new file mode 100644 index 000000000..d34682c56 --- /dev/null +++ b/drafts_Amerik/basic_control.py @@ -0,0 +1,151 @@ +import gymnasium as gym +import numpy as np +import matplotlib.pyplot as plt +from stable_baselines3 import DDPG +from stable_baselines3.common.noise import NormalActionNoise, OrnsteinUhlenbeckActionNoise +import random + + +from mlpro.bf.math.basics import Log +from mlpro.bf.mt import Async, Log, Task, Workflow +from mlpro.bf.streams import * + +from mlpro.bf.math import * +from mlpro.bf.streams.basics import InstDict, StreamShared +from mlpro.bf.various import * +from datetime import datetime, timedelta +from mlpro.bf.control.controllers.pid_controller import PIDController +from mlpro.bf.control.basics import CTRLError + + + +env = gym.make("Pendulum-v1",render_mode="human") + +def Random_games(): + + action_size = env.action_space.shape[0] + + for episode in range(10): + env.reset() + + while True: + env.render() + + action = np.random.uniform(-1.0,1.0,size=action_size) + + next_state,reward, done, info,_ = env.step(action) + print(f'Next state{len(next_state)}\n',f'reward:{reward}') + + if done: + break +def dpg_algorithm(): + # The noise objects for DDPG + n_actions = env.action_space.shape[-1] + action_noise = NormalActionNoise(mean=np.zeros(n_actions), sigma=0.1 * np.ones(n_actions)) + + model = DDPG("MlpPolicy", env, action_noise=action_noise, verbose=1) + model.learn(total_timesteps=10000, log_interval=10) + vec_env = model.get_env() + + obs = vec_env.reset() + while True: + action, _states = model.predict(obs) + obs, rewards, dones, info = vec_env.step(action) + env.render() +def main(): + + # Parameter + setpoint = 22.0 # Sollwert in °C + initial_temp = 15.0 # Starttemperatur in °C + ambient_temp = 15.0 # Außentemperatur in °C + time_step = 1 # Zeitintervall in Minuten + total_time =5000 # Gesamte Simulationszeit in Minuten + + # PID-Koeffizienten + Kp = 10.0 # Proportionaler Koeffizient + Ti = 100.01 # Integraler Koeffizient + Td = 250.0 # Differenzieller Koeffizient + + # Heizwendel Parameter + coil_mass = 10.0 # Masse der Heizwendel (kg) + specific_heat_coil = 0.5 # Spezifische Wärmekapazität der Heizwendel (J/(kg*K)) + coil_temp = initial_temp # Anfangstemperatur der Heizwendel + heat_transfer_coeff = 0.1 # Wärmeübertragungskoeffizient (W/K) + + # Initialisierung + time = np.arange(0, total_time + time_step, time_step) + temperature = np.zeros_like(time,dtype=float) + setpoints = np.zeros_like(time,dtype=float) + temperature[0] = initial_temp + setpoints[0]= setpoint + # PID-Regler Variablen + integral = 0 + previous_error = 0 + + + # Simulation + for i in range(1, len(time)): + + #if i%600 ==0: + # setpoint+= random.randint(-2,2) + error = setpoint - temperature[i - 1] + integral += error * time_step + derivative = (error - previous_error) / time_step + + # PID-Regler Berechnung + control_signal = Kp * error + (Kp/Ti)*integral + Kp*Td * derivative + + # Begrenzung der Steuergröße und Normierung auf 0 bis 1 + control_signal = np.clip(control_signal, 0, 100) / 100 + + # Heizwendel-Erwärmung + power_input = control_signal * 100 # z.B. in Watt + coil_temp += (power_input - heat_transfer_coeff * (coil_temp - ambient_temp)) / (coil_mass * specific_heat_coil) * time_step + print(f"difference:{coil_temp-ambient_temp}",f"Power:{power_input}") + + # Wärmeübertragung zum Raum + heating_power = heat_transfer_coeff * (coil_temp - temperature[i - 1]) + + + # Temperaturänderung des Raums + delta_temp = heating_power * time_step / 60 + temperature[i] = temperature[i - 1] + delta_temp + + # Temperaturveränderung durch Umgebung + temperature[i] += (ambient_temp - temperature[i]) * 0.01 + + # Update der PID-Variablen + previous_error = error + setpoints[i]+=setpoint + + # Plotten der Ergebnisse + plt.plot(time, temperature, label='Raumtemperatur') + plt.plot(time,setpoints, color='r', linestyle='--', label='Sollwert') + plt.xlabel('Zeit (Minuten)') + plt.ylabel('Temperatur (°C)') + plt.title('Temperaturregelung mit normiertem PID-Algorithmus') + plt.legend() + plt.grid(True) + plt.show() + +def create_instance(): + p_set = Set() + elem = Element(p_set=p_set) + elem.set_values([1,2,3,4]) + inst = Instance(p_feature_data=elem) + print(inst.get_feature_data().get_values()) + + +pid = PIDController(12,10,2.5) +p_set = Set() +elem = Element(p_set=p_set) +elem.set_values([12]) +error = CTRLError(elem) + +for i in range(2): + print(pid.compute_action(error)) + elem = Element(p_set=p_set) + elem.set_values([11]) + error = CTRLError(elem) + + diff --git a/drafts_Amerik/pid2.py b/drafts_Amerik/pid2.py new file mode 100644 index 000000000..5120def95 --- /dev/null +++ b/drafts_Amerik/pid2.py @@ -0,0 +1,322 @@ + +from mlpro.bf.math.basics import Log +from mlpro.bf.mt import Async, Log, Task, Workflow +from mlpro.bf.streams import * + +from mlpro.bf.math import * +from mlpro.bf.streams.basics import InstDict, StreamShared +from mlpro.bf.various import * +from datetime import datetime +import matplotlib.pyplot as plt +from mlpro.bf.various import Log + + +class Link(Task): + + + def __init__(self, p_id=None, p_name: str = None, p_range_max: int = Async.C_RANGE_THREAD, p_autorun=..., p_class_shared=None, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(p_id, p_name, p_range_max, p_autorun, p_class_shared, p_visualize, p_logging, **p_kwargs) + + + + def _run(self, **p_kwargs): + print('Task 1') + #control_signal=self._so.get_setpoint(self.get_id()) + setpoint= self._so.get_setpoint(self.get_id()) + act_value= self._so.get_actual_value(self.get_id()) + self._so.set_error(setpoint-act_value,self.get_id()) + #print(setpoint-act_value) + +class PIDTask(Task): + + def __init__(self,kp: float, ki: float,kd: float, p_id=None, p_name: str = None, p_range_max: int = Async.C_RANGE_THREAD, p_autorun=..., p_class_shared=None, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(p_id, p_name, p_range_max, p_autorun, p_class_shared, p_visualize, p_logging, **p_kwargs) + + self.kp = kp + self.Ti = ki + self.Td = kd + self.integral = 0.0 + self.prev_error =0.0 + self.time_step = 1.0 + + def _run(self, **p_kwargs): + print('Task 2') + error = self._so.get_error(self.get_id()) + self.integral += error * self.time_step + derivative = (error - self.prev_error) / self.time_step + # PID-Regler Berechnung + control_signal = self.kp * error + (self.kp/self.Ti)*self.integral + self.kp* derivative*self.Td + # Begrenzung der Steuergröße und Normierung auf 0 bis 1 + control_signal = np.clip(control_signal, 0, 100) / 100 + self._so.set_control_signal(control_signal,self.get_id()) + #print(control_signal) + self.prev_error = error + +class ProcessTask(Task): + + def __init__(self, p_id=None, p_name: str = None, p_range_max: int = Async.C_RANGE_THREAD, p_autorun=..., p_class_shared=None, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(p_id, p_name, p_range_max, p_autorun, p_class_shared, p_visualize, p_logging, **p_kwargs) + + # Heizwendel Parameter + self.coil_mass = 10.0 # Masse der Heizwendel (kg) + self.specific_heat_coil = 0.5 # Spezifische Wärmekapazität der Heizwendel (J/(kg*K)) + self.coil_temp = 15 # Anfangstemperatur der Heizwendel + self.heat_transfer_coeff = 0.1 # Wärmeübertragungskoeffizient (W/K) + self.ambient_temp = 15.0 + self.time_step=1 + + def _run(self, **p_kwargs): + + print('Task 3') + control_signal = self._so.get_control_signal(self.get_id()) + act_value=self._so.get_actual_value(self.get_id()) + + + + + # Heizwendel-Erwärmung + power_input = control_signal * 100 # z.B. in Watt + + self.coil_temp += (power_input - self.heat_transfer_coeff * (self.coil_temp - self.ambient_temp)) / (self.coil_mass * self.specific_heat_coil) * self.time_step + print(f"difference:{self.coil_temp-self.ambient_temp}",f"Power:{power_input}") + + # Wärmeübertragung zum Raum + heating_power = self.heat_transfer_coeff * (self.coil_temp - act_value) + + # Temperaturänderung des Raums + delta_temp = heating_power/ 60 + act_value+=delta_temp + act_value += (self.ambient_temp-act_value)*0.01 + self._so.set_actual_value(act_value,self.get_id()) + #print(act_value) + + +class MasterShared(Shared): + + def __init__(self,p_range: int = Range.C_RANGE_PROCESS): + super().__init__(p_range) + + self.setpoint = 0.0 + self.actual_value = 0.0 + self.control_signal = 0.0 + self.error= 0.0 + self.actual_values =[] + + self.SpShared = Shared() + self.ActShared = Shared() + self.CrtlShared= Shared() + self.ErrShared = Shared() + + + + def set_setpoint(self,setpoint,p_id): + + test=self.SpShared.lock(p_id,3) + if test: + self.SpShared.clear_results() + self.SpShared.add_result(p_id,setpoint) + self.SpShared.unlock() + + + def get_setpoint(self,p_id): + + test =self.SpShared.lock(p_id,3) + if test: + dummy = list(self.SpShared.get_results().values()) + if len(dummy)>0: + self.setpoint = dummy[-1] + + self.SpShared.unlock() + + return self.setpoint + + def set_error(self,error,p_id): + + test=self.ErrShared.lock(p_id,3) + if test: + self.ErrShared.clear_results() + self.ErrShared.add_result(p_id,error) + self.ErrShared.unlock() + + + def get_error(self,p_id): + + test =self.ErrShared.lock(p_id,3) + if test: + dummy = list(self.ErrShared.get_results().values()) + if len(dummy)>0: + self.error = dummy[-1] + + self.ErrShared.unlock() + + return self.error + + def set_control_signal(self,control_signal,p_id): + + test=self.CrtlShared.lock(p_id,3) + if test: + self.CrtlShared.clear_results() + self.CrtlShared.add_result(p_id,control_signal) + + self.CrtlShared.unlock() + + + def get_control_signal(self,p_id): + + test =self.CrtlShared.lock(p_id,3) + if test: + dummy = list(self.CrtlShared.get_results().values()) + if len(dummy)>0: + self.control_signal = dummy[-1] + self.CrtlShared.unlock() + + return self.control_signal + + def set_actual_value(self,actual_value,p_id): + + test=self.ActShared.lock(p_id,3) + if test: + self.ActShared.clear_results() + self.ActShared.add_result(p_id,actual_value) + self.actual_values.append(actual_value) + self.ActShared.unlock() + + + def get_actual_value(self,p_id): + + test =self.ActShared.lock(p_id,3) + if test: + dummy = list(self.ActShared.get_results().values()) + if len(dummy)>0: + self.actual_value = dummy[-1] + + self.ActShared.unlock() + + return self.actual_value + +class RLWorkflow(Workflow): + + def __init__(self, p_name: str = None, p_range_max=Async.C_RANGE_THREAD, p_class_shared=None, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(p_name, p_range_max, p_class_shared, p_visualize, p_logging, **p_kwargs) + + + +class RLSecenario(ScenarioBase): + + def __init__(self, p_mode, p_id=None, p_cycle_limit=0, p_auto_setup: bool = True, p_visualize: bool = True, p_logging=Log.C_LOG_ALL): + super().__init__(p_mode, p_id, p_cycle_limit, p_auto_setup, p_visualize, p_logging) + + + def setup(self): + + """ + Specialized method to set up a stream scenario. It is automatically called by the constructor + and calls in turn the custom method _setup(). + """ + + self._workflow = self._setup( p_mode=self.get_mode(), + p_visualize=self.get_visualization(), + p_logging=Log.C_LOG_NOTHING)#self.get_log_level() ) + + + def _setup(self, p_mode, p_visualize:bool, p_logging): + + + # 2 Set up a stream workflow + wf = RLWorkflow(p_name="wf1",p_range_max=Workflow.C_RANGE_THREAD,p_class_shared=MasterShared) + + t1 = Link(p_name="t1",logging=Log.C_LOG_NOTHING) + t3 = ProcessTask(p_name="t2",logging=Log.C_LOG_NOTHING) + t2 = PIDTask(10,100,250,p_name="t3",logging=Log.C_LOG_NOTHING) + + wf._so.set_actual_value(15.0,self.get_id()) + wf._so.set_setpoint(22.0,self.get_id()) + + # 2.1 Set up and add an own custom task + wf.add_task( p_task=t1 ) + wf.add_task( p_task=t2) + wf.add_task( p_task=t3 ) + + # 3 Return stream and workflow + return wf + + def get_latency(self) -> timedelta: + return None + + + def _run_cycle(self): + + """ + Gets next instance from the stream and lets process it by the stream workflow. + + Returns + ------- + success : bool + True on success. False otherwise. + error : bool + True on error. False otherwise. + adapted : bool + True, if something within the scenario has adapted something in this cycle. False otherwise. + end_of_data : bool + True, if the end of the related data source has been reached. False otherwise. + """ + + try: + self._workflow.run( p_range=Workflow.C_RANGE_THREAD, p_wait=True) #alt p_wait=True + end_of_data = False + except StopIteration: + end_of_data = True + + return False, False, False, end_of_data + + +cycle_limit = 5000 + +logging = Log.C_LOG_NOTHING +visualize = False + +myscenario = RLSecenario( p_mode=Mode.C_MODE_SIM, + p_cycle_limit=cycle_limit, + p_visualize=visualize, + p_logging=logging ) + + +myscenario.run() +temperature=myscenario._workflow._so.actual_values +# Plotten der Ergebnisse +plt.plot([i for i in range(len(temperature))], temperature, label='Raumtemperatur') +#plt.plot(time,setpoints, color='r', linestyle='--', label='Sollwert') +plt.xlabel('Zeit (Minuten)') +plt.ylabel('Temperatur (°C)') +plt.title('Temperaturregelung mit normiertem PID-Algorithmus') +plt.legend() +plt.grid(True) +plt.show() +input('Press ENTER to exist...') + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mlpro/bf/control/__init__.py b/src/mlpro/bf/control/__init__.py new file mode 100644 index 000000000..eace87d6b --- /dev/null +++ b/src/mlpro/bf/control/__init__.py @@ -0,0 +1 @@ +from mlpro.bf.control.basics import * \ No newline at end of file diff --git a/src/mlpro/bf/control/basics.py b/src/mlpro/bf/control/basics.py new file mode 100644 index 000000000..9389c291a --- /dev/null +++ b/src/mlpro/bf/control/basics.py @@ -0,0 +1,430 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.bf.control +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-08-31 0.0.0 DA Creation +## -- 2024-09-04 0.1.0 DA Updates on class design +## -- 2024-09-07 0.2.0 DA Classes CTRLError, Controller: design updates +## -- 2024-09-11 0.3.0 DA - class CTRLError renamed ControlError +## -- - new class ControlPanel +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.3.0 (2024-09-11) + +This module provides basic classes around the topic closed-loop control. + +""" + +from mlpro.bf.math.basics import Element +from mlpro.bf.various import Log, TStampType +from mlpro.bf.mt import Task, Workflow +from mlpro.bf.math import Element, Function +from mlpro.bf.streams import InstDict, Instance, StreamTask, StreamWorkflow, StreamShared, StreamScenario +from mlpro.bf.systems import ActionElement, Action, System +from mlpro.bf.various import Log + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class SetPoint (Instance): + """ + """ + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_setpoint_data: Element, + p_tstamp: TStampType = None, + **p_kwargs ): + + super().__init__( p_feature_data = p_setpoint_data, + p_label_data = None, + p_tstamp = p_tstamp, + **p_kwargs ) + + +## ------------------------------------------------------------------------------------------------- + def _get_values(self): + return self.get_feature_data().get_values() + + +## ------------------------------------------------------------------------------------------------- + def _set_values(self, p_values): + self.get_feature_data().set_values( p_values = p_values) + + +## ------------------------------------------------------------------------------------------------- + values = property( fget=_get_values, fset=_set_values ) + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlError (Instance): + """ + """ + +## ------------------------------------------------------------------------------------------------- + def _get_values(self): + return self.get_feature_data().get_values() + + +## ------------------------------------------------------------------------------------------------- + def _set_values(self, p_values): + self.get_feature_data().set_values( p_values = p_values) + + +## ------------------------------------------------------------------------------------------------- + values = property( fget=_get_values, fset=_set_values ) + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class Controller (StreamTask): + """ + Template class for closed-loop controllers. + """ + + C_TYPE = 'Controller' + C_NAME = '????' + + +## ------------------------------------------------------------------------------------------------- + def set_parameter(self, **p_param): + pass + + +## ------------------------------------------------------------------------------------------------- + def _run(self, p_inst: InstDict): + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def compute_action(self, p_ctrl_error: ControlError) -> Action: + """ + Custom method to compute and return an action based on an incoming control error. + + Parameters + ---------- + p_ctrl_error : CTRLError + Control error. + + + Returns + ------- + + """ + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def _compute_action( self, + p_ctrl_error : ControlError, + p_action_element : ActionElement, + p_ctrl_id : int = 0, + p_ae_id : int = 0 ): + """ + Custom method to compute and an action based on an incoming control error. The result needs + to be stored in the action element handed over. I/O values can be accessed as follows: + + SISO + ---- + Get single error value: error_siso = p_ctrl_error.values[p_ctrl_id] + Set single action value: p_action_element.values[p_ae_id] = action_siso + + MIMO + ---- + Get multiple error values: error_mimo = p_ctrl_error.values + Set multiplie action values: p_action_element.values = action_mimo + + + Parameters + ---------- + p_ctrl_error : CTRLError + Control error. + p_action_element : ActionElement + Action element to be filled with resulting action value(s). + p_ctrl_id : int = 0 + SISO controllers only. Id of the related source value in p_ctrl_error. + p_ae_id : int = 0 + SISO controller olny. Id of the related destination value in p_action_element. + """ + + raise NotImplementedError + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControllerFct (Controller): + """ + Wrapper class for controllers based on a mathematical function mapping an error to an action. + + Parameters + ---------- + p_fct : Function + Function object mapping a control error to an action + + See class Controller for further parameters. + """ + + C_TYPE = 'Controller Fct' + C_NAME = '' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_fct : Function, + p_name: str = None, + p_range_max=Task.C_RANGE_THREAD, + p_duplicate_data: bool = False, + p_visualize: bool = False, + p_logging = Log.C_LOG_ALL, + **p_kwargs ): + + super().__init__( p_name = p_name, + p_range_max = p_range_max, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = p_logging, + **p_kwargs ) + + self._fct : Function = p_fct + + +## ------------------------------------------------------------------------------------------------- + def set_parameter(self, **p_param): + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def compute_action(self, p_ctrl_error: ControlError) -> Action: + + raise NotImplementedError + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MultiController (Controller, StreamWorkflow): + """ + """ + + C_TYPE = 'Multi-Controller' + C_NAME = '' + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlSystem (StreamTask): + """ + Wrapper class for state-based systems. + """ + + C_TYPE = 'Control System' + C_NAME = '' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_system : System, + p_name: str = None, + p_range_max=Task.C_RANGE_THREAD, + p_duplicate_data: bool = False, + p_visualize: bool = False, + p_logging = Log.C_LOG_ALL, + **p_kwargs ): + + super().__init__( p_name = p_name, + p_range_max = p_range_max, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = p_logging, + **p_kwargs ) + + self._system : System = p_system + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlPanel (Log): + """ + Enables external control of a closed-loop control. + """ + + C_TYPE = 'Control Panel' + C_NAME = '????' + +## ------------------------------------------------------------------------------------------------- + def start(self): + """ + (Re-)starts a closed-loop control. + """ + + self.log(Log.C_LOG_TYPE_S, 'Control process started') + self._start() + + +## ------------------------------------------------------------------------------------------------- + def _start(self): + """ + Custom method to (re-)start a closed-loop control. + """ + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def stop(self): + """ + Ends a closed-loop control. + """ + + self.log(Log.C_LOG_TYPE_S, 'Control process stopped') + self._stop() + + +## ------------------------------------------------------------------------------------------------- + def _stop(self): + """ + Custom method to end a closed-loop control. + """ + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def change_setpoint( self, p_setpoint : SetPoint ): + """ + Changes the setpoint values of a closed-loop control. + + Parameters + ---------- + p_setpoint: SetPoint + New setpoint values. + """ + + self.log(Log.C_LOG_TYPE_S, 'Setpoint values changed to', p_setpoint.values) + self._change_setpoint( p_setpoint = p_setpoint ) + + +## ------------------------------------------------------------------------------------------------- + def _change_setpoint( self, p_setpoint : SetPoint ): + """ + Custom method to change setpoint values. + """ + + raise NotImplementedError + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlShared (StreamShared, ControlPanel): + +## ------------------------------------------------------------------------------------------------- + def _start(self): + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def _stop(self): + + raise NotImplementedError + + +## ------------------------------------------------------------------------------------------------- + def _change_setpoint(self, p_setpoint: SetPoint): + + raise NotImplementedError + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlCycle (StreamWorkflow): + """ + Container class for all tasks of a control cycle. + """ + + C_TYPE = 'Control Cycle' + C_NAME = '' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_name: str = None, + p_range_max = Workflow.C_RANGE_THREAD, + p_class_shared = ControlShared, + p_visualize : bool = False, + p_logging = Log.C_LOG_ALL, + **p_kwargs ): + + super().__init__( p_name=p_name, + p_range_max=p_range_max, + p_class_shared=p_class_shared, + p_visualize=p_visualize, + p_logging=p_logging, + **p_kwargs ) + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class ControlScenario ( StreamScenario ): + """ + ... + """ + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_mode, + p_cycle_limit=0, + p_visualize:bool=False, + p_logging=Log.C_LOG_ALL ): + + self._control_cycle : ControlCycle = None + + super.__init__( p_mode, + p_cycle_limit=p_cycle_limit, + p_auto_setup=True, + p_visualize=p_visualize, + p_logging=p_logging ) + + +## ------------------------------------------------------------------------------------------------- + def get_control_panel(self) -> ControlPanel: + """ + Returns + ------- + panel : ControlPanel + Object that enables the external control of a closed-loop control process. + """ + return self._control_cycle.get_so() diff --git a/src/mlpro/bf/control/controllers/__init__.py b/src/mlpro/bf/control/controllers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/mlpro/bf/control/controllers/pid_controller.py b/src/mlpro/bf/control/controllers/pid_controller.py new file mode 100644 index 000000000..f43678d71 --- /dev/null +++ b/src/mlpro/bf/control/controllers/pid_controller.py @@ -0,0 +1,194 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.bf.control.controller +## -- Module : pid_controller.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-01 0.0.0 DA Creation +## -- 2024-09-19 0.0.0 ASP Implemebtation PIDController +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-01) + +This module provides an implementation of a PID controller. + +Learn more: + +https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller + +""" + +from mlpro.bf.mt import Log, Task +from mlpro.bf.control.basics import ControlError, Controller +from mlpro.bf.systems.basics import ActionElement +import numpy as np + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class PIDController (Controller): + """ + PID controller. + """ + + + def __init__(self,Kp: float, Ti: float = 0.0 ,Tv: float= 0.0,disable_integral:bool = False,disable_derivitave:bool = False,enable_windup: bool = False,windup_limit:float =0,output_limits: tuple = (0,100) ,p_name: str = None, p_range_max=Task.C_RANGE_THREAD, p_duplicate_data: bool = False, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(p_name, p_range_max, p_duplicate_data, p_visualize, p_logging, **p_kwargs) + + self.Kp = Kp + self.Ti = Ti # [s] + self.Tv = Tv # [s] + self.disable_integral = disable_integral + self.disable_derivitave = disable_derivitave + self.integral = 0.0 + self.prev_error = 0.0 + self.previous_time = None #[datetime] + self.enable_windup = enable_windup + self.windup_limit = windup_limit + self.output_limits = output_limits + +## ------------------------------------------------------------------------------------------------- + def set_parameter(self, **p_param): + """ + Sets/changes the parameters of the PID controller. + + Parameters + ---------- + Kp : float + gain factor + Ti : float + settling time + Tv : float + dead time + """ + + # set kp value + self.Kp = p_param.get('Kp',self.Kp) + # set Ti value + self.Ti = p_param.get('Ti',self.Ti) + #set Tv value + p_param.get('Tv',self.Tv) +## ------------------------------------------------------------------------------------------------- + def get_parameter_values(self)-> np.ndarray: + return np.array([self.Kp,self.Ti,self.Tv]) + +## ------------------------------------------------------------------------------------------------- + + def _compute_action(self, p_ctrl_error: ControlError, p_action_element: ActionElement, p_ctrl_id: int = 0, p_ae_id: int = 0): + + """ + Custom method to compute and an action based on an incoming control error. The result needs + to be stored in the action element handed over. I/O values can be accessed as follows: + + SISO + ---- + Get single error value: error_siso = p_ctrl_error.values[p_ctrl_id] + Set single action value: p_action_element.values[p_ae_id] = action_siso + + MIMO + ---- + Get multiple error values: error_mimo = p_ctrl_error.values + Set multiplie action values: p_action_element.values = action_mimo + + + Parameters + ---------- + p_ctrl_error : CTRLError + Control error. + p_action_element : ActionElement + Action element to be filled with resulting action value(s). + p_ctrl_id : int = 0 + SISO controllers only. Id of the related source value in p_ctrl_error. + p_ae_id : int = 0 + SISO controller olny. Id of the related destination value in p_action_element. + """ + + + #get control error + error_siso = p_ctrl_error.get_feature_data().get_values()[p_ctrl_id] + + delta_time = 0 + + current_time = p_ctrl_error.get_tstamp() + + #calculate time difference + if self.previous_time is not None: + delta_time = current_time- self.previous_time + delta_time = delta_time.total_seconds() + + #propertional term + p_term = self.Kp * error_siso + + #integral term + i_term = 0 + + #ignore i term , if it is disabled + if not self.disable_integral: + + #calculat integral term + self.integral += error_siso*delta_time + + # anti - windup + if self.enable_windup and self.windup_limit is not None: + self.integral = max(min(self.integral, self.windup_limit), -self.windup_limit) + + #calculate i term , if Ti not zero + if self.Ti != 0: + i_term = (self.Kp/self.Ti)* self.integral + + + # derivitave term + d_term =0 + + #ignore i term , if it is disabled or delta is equal zero + if delta_time> 0 and not self.disable_derivitave: + d_term = self.Kp*self.Tv*(error_siso- self.prev_error)/delta_time + + #compute action value + action_siso = p_term+i_term+d_term + + #apply action limits + lower_bound, upper_bound = self.output_limits + + action_siso = min(max(action_siso,lower_bound), upper_bound) + + # safe the current values for the next iteration + self.prev_error = error_siso + self.previous_time = current_time + + #set action value + p_action_element.set_values([action_siso]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mlpro/bf/control/tasks/__init__.py b/src/mlpro/bf/control/tasks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/mlpro/bf/ops.py b/src/mlpro/bf/ops.py index edf19135f..8bdba6d94 100644 --- a/src/mlpro/bf/ops.py +++ b/src/mlpro/bf/ops.py @@ -304,6 +304,7 @@ def run_cycle(self): # 3 Update visualization + if self._visualize: self.update_plot() diff --git a/src/mlpro/bf/streams/basics.py b/src/mlpro/bf/streams/basics.py index aee0b741a..443d8b561 100644 --- a/src/mlpro/bf/streams/basics.py +++ b/src/mlpro/bf/streams/basics.py @@ -68,12 +68,13 @@ ## -- 2024-06-07 2.0.2 LSB Fixing timedelta handling in ND plotting ## -- 2024-07-19 2.0.3 DA Class StreamTask: excluded non-numeric feature data from default ## -- visualization 2D,3D,ND +## -- 2024-09-11 2.1.0 DA Class Instance: new parent KWArgs ## ------------------------------------------------------------------------------------------------- """ -Ver. 2.0.3 (2024-07-19) +Ver. 2.1.0 (2024-09-11) -This module provides classes for standardized stream processing. +This module provides classes for standardized data stream processing. """ import datetime @@ -83,7 +84,7 @@ from typing import Dict, Tuple from mlpro.bf.math.basics import * -from mlpro.bf.various import * +from mlpro.bf.various import Id, TStamp, KWArgs from mlpro.bf.ops import Mode, ScenarioBase from mlpro.bf.plot import PlotSettings from mlpro.bf.math import Dimension, Element @@ -113,7 +114,7 @@ class Label (Dimension): pass ## ------------------------------------------------------------------------------------------------- ## ------------------------------------------------------------------------------------------------- -class Instance (Id, TStamp): +class Instance (Id, TStamp, KWArgs): """ Instance class to store the current instance and the corresponding labels of the stream @@ -141,8 +142,7 @@ def __init__( self, self._feature_data = p_feature_data self._label_data = p_label_data TStamp.__init__(self, p_tstamp=p_tstamp) - # Id.__init__(self, p_id = 0) - self._kwargs = p_kwargs.copy() + KWArgs.__init__(self, **p_kwargs) ## ------------------------------------------------------------------------------------------------- @@ -173,7 +173,7 @@ def set_label_data(self, p_label_data:Element): ## ------------------------------------------------------------------------------------------------- def get_kwargs(self): - return self._kwargs + return self._get_kwargs() ## ------------------------------------------------------------------------------------------------- @@ -181,7 +181,7 @@ def copy(self): duplicate = self.__class__( p_feature_data=self.get_feature_data().copy(), p_label_data=self.get_label_data(), p_tstamp=self.get_tstamp(), - p_kwargs=self._kwargs ) + p_kwargs=self._get_kwargs() ) duplicate.id = self.id return duplicate @@ -390,7 +390,9 @@ def _omit_instance(self, p_inst:Instance) -> bool: Parameters ---------- - p_inst : Instance + p_inst : Instancep_set = {} +p_set[0] = tuple([1,Instance(12)]) +print(p_set) An input instance to be filtered. Returns @@ -1225,8 +1227,14 @@ def _update_plot_2d( self, # 5 Update of ax limits if ax_limits_changed: - p_settings.axes.set_xlim( self._plot_2d_xmin, self._plot_2d_xmax ) - p_settings.axes.set_ylim( self._plot_2d_ymin, self._plot_2d_ymax ) + try: + p_settings.axes.set_xlim( self._plot_2d_xmin, self._plot_2d_xmax ) + except: + pass + try: + p_settings.axes.set_ylim( self._plot_2d_ymin, self._plot_2d_ymax ) + except: + pass ## ------------------------------------------------------------------------------------------------- diff --git a/src/mlpro/bf/systems/basics.py b/src/mlpro/bf/systems/basics.py index 444d1623d..74b9987bb 100644 --- a/src/mlpro/bf/systems/basics.py +++ b/src/mlpro/bf/systems/basics.py @@ -45,10 +45,16 @@ ## -- 2023-05-01 2.0.0 LSB New class MultiSystem ## -- 2024-05-14 2.0.1 SY Migration from MLPro to MLPro-Int-MuJoCo ## -- 2024-05-24 2.1.0 DA Class State: removed parent class TStamp +## -- 2024-09-07 2.2.0 DA - Class ActionElement: new property values +## -- - Renamed Class Controller to SAGateway +## -- - Renamed method System.add_controller to add_sagateway +## -- 2024-09-09 2.3.0 DA Class Action: parent TSTamp replaced by Instance +## -- 2024-09-11 2.4.0 DA - code review and documentation +## -- - new method State.get_kwargs() ## ------------------------------------------------------------------------------------------------- """ -Ver. 2.1.0 (2024-05-24) +Ver. 2.4.0 (2024-09-11) This module provides models and templates for state based systems. """ @@ -71,6 +77,7 @@ + ## ------------------------------------------------------------------------------------------------- ## ------------------------------------------------------------------------------------------------- class State(Instance, Element): @@ -92,6 +99,8 @@ class State(Instance, Element): This optional flag labels the state as a final error state. Default=False. p_timeout : bool This optional flag signals that the cycle limit of an episode has been reached. Default=False. + p_kwargs : dict + Further optional named parameters. """ ## ------------------------------------------------------------------------------------------------- @@ -177,6 +186,11 @@ def set_feature_data(self, p_feature_data: Element): self.set_values(p_feature_data.get_values()) +## ------------------------------------------------------------------------------------------------- + def get_kwargs(self): + return self._get_kwargs() + + ## ------------------------------------------------------------------------------------------------- def copy(self): """ @@ -222,16 +236,16 @@ class ActionElement (Element): ---------- p_action_space : Set Related action space. - p_weight : float + p_weight : float = 1.0 Weight of action element. Default = 1.0. """ ## ------------------------------------------------------------------------------------------------- def __init__( self, p_action_space : Set, - p_weight : float = 1.0): + p_weight : float = 1.0 ): - super().__init__(p_action_space) + Element.__init__(self, p_action_space) self.set_weight(p_weight) @@ -241,21 +255,24 @@ def get_weight(self): ## ------------------------------------------------------------------------------------------------- - def set_weight(self, p_weight): + def set_weight(self, p_weight : float): self.weight = p_weight +## ------------------------------------------------------------------------------------------------- + values = property( fget=Element.get_values, fset=Element.set_values) + + ## ------------------------------------------------------------------------------------------------- ## ------------------------------------------------------------------------------------------------- -class Action(ElementList, TStamp): +class Action(Instance, ElementList): """ - Objects of this class represent actions of (multi-)agents. Every element - of the internal list is related to an agent, and its partial subsection. - Action values for the first agent can be added while object instantiation. - Action values of further agents can be added by using method self.add_elem(). + Objects of this class represent actions of (multi-)agents. Every element of the internal list is + related to an agent, and its partial subsection. Action values for the first agent can be added + while object instantiation. Action values of further agents can be added by using method self.add_elem(). Parameters ---------- @@ -271,15 +288,18 @@ class Action(ElementList, TStamp): def __init__( self, p_agent_id = 0, p_action_space : Set = None, - p_values: np.ndarray = None ): + p_values: np.ndarray = None, + p_tstamp : TStampType = None ): ElementList.__init__(self) - TStamp.__init__(self) + action_elem = None + + if ( p_action_space is not None ) and ( p_values is not None ): + action_elem = ActionElement(p_action_space) + action_elem.set_values(p_values) + self.add_elem(p_agent_id, action_elem) - if (p_action_space is not None) and (p_values is not None): - e = ActionElement(p_action_space) - e.set_values(p_values) - self.add_elem(p_agent_id, e) + Instance.__init__( self, p_feature_data=action_elem, p_tstamp = p_tstamp ) ## ------------------------------------------------------------------------------------------------- @@ -504,20 +524,20 @@ class Actuator (Dimension): ## ------------------------------------------------------------------------------------------------- ## ------------------------------------------------------------------------------------------------- -class Controller (EventManager): +class SAGateway (EventManager): """ - Template for a controller that enables access to sensors and actuators. + Template for a gateway implementation that enables access to sensors and actuators. Parameters ---------- p_id - Unique id of the controller. + Unique id of the gateway. p_name : str - Optional name of the controller. + Optional name of the gateway. p_logging Log level (see class Log for more details). Default = Log.C_LOG_ALL. p_kwargs : dict - Further keyword arguments specific to the controller. + Further keyword arguments specific to the gateway. Attributes ---------- @@ -525,7 +545,7 @@ class Controller (EventManager): Event that is raised on a communication error """ - C_TYPE = 'Controller' + C_TYPE = 'SAGateway' C_EVENT_COMM_ERROR = 'COMM_ERROR' ## ------------------------------------------------------------------------------------------------- @@ -546,7 +566,7 @@ def __init__(self, p_id, p_name:str = '', p_logging : bool = Log.C_LOG_ALL, **p_ ## ------------------------------------------------------------------------------------------------- def reset(self) -> bool: """ - Resets the controller by calling custom method _reset(). + Resets the gateway by calling custom method _reset(). Returns ------- @@ -580,7 +600,7 @@ def _reset(self) -> bool: ## ------------------------------------------------------------------------------------------------- def add_sensor(self, p_sensor : Sensor): """ - Adds a sensor to the controller. + Adds a sensor to the gateway. Parameters ---------- @@ -666,7 +686,7 @@ def _get_sensor_value(self, p_id): ## ------------------------------------------------------------------------------------------------- def add_actuator(self, p_actuator : Actuator): """ - Adds an actuator to the controller. + Adds an actuator to the gateway. Parameters ---------- @@ -1070,11 +1090,26 @@ class System (FctSTrans, FctSuccess, FctBroken, Task, Mode, Plottable, Persisten Parameters ---------- - p_mode + p_id + Optional external id + p_name : str + Optional name of the task. Default is None. + p_range_max : int + Maximum range of asynchonicity. See class Range. Default is Range.C_RANGE_THREAD. + p_autorun : int + On value C_AUTORUN_RUN method run() is called imediately during instantiation. + On vaule C_AUTORUN_LOOP method run_loop() is called. + Value C_AUTORUN_NONE (default) causes an object instantiation without starting further + actions. + p_class_shared = None + Optional class for a shared object (class Shared or a child class of Shared) + p_mode = Mode.C_MODE_SIM Mode of the system. Possible values are Mode.C_MODE_SIM(default) or Mode.C_MODE_REAL. - p_latency : timedelta + p_latency : timedelta = None Optional latency of the system. If not provided, the internal value of constant C_LATENCY is used by default. + p_t_step : timedelta = None + ... p_fct_strans : FctSTrans Optional external function for state transition. p_fct_success : FctSuccess @@ -1084,15 +1119,15 @@ class System (FctSTrans, FctSuccess, FctBroken, Task, Mode, Plottable, Persisten p_mujoco_file Path to XML file for MuJoCo model. p_frame_skip : int - Frame to be skipped every step. Default = 1. - p_state_mapping - State mapping if the MLPro state and MuJoCo state have different naming. - p_action_mapping - Action mapping if the MLPro action and MuJoCo action have different naming. + MuJoCo only: frame to be skipped every step. Default = 1. + p_state_mapping = None + MuJoCo only: state mapping if the MLPro state and MuJoCo state have different naming. + p_action_mapping = None + MuJoCo only: action mapping if the MLPro action and MuJoCo action have different naming. p_use_radian : bool - Use radian if the action and the state based on radian unit. Default = True. + MuJoCo only: use radian if the action and the state based on radian unit. Default = True. p_camera_conf : tuple - Default camera configuration on MuJoCo Simulation (xyz position, elevation, distance). + MuJoCo only: default camera configuration on MuJoCo Simulation (xyz position, elevation, distance). p_visualize : bool Boolean switch for env/agent visualisation. Default = False. p_logging @@ -1153,10 +1188,10 @@ def __init__( self, self._state = None self._prev_state = None self._last_action = None - self._controllers = [] + self._gateways = [] self._mapping_actions = {} self._mapping_states = {} - self._t_step = p_t_step + self._t_step = p_t_step if p_mujoco_file is not None: try: @@ -1220,7 +1255,8 @@ def __init__( self, self._registered_on_so = False - ## ------------------------------------------------------------------------------------------------- + +## ------------------------------------------------------------------------------------------------- @staticmethod def setup_spaces(): """ @@ -1415,7 +1451,7 @@ def reset(self, p_seed=None) -> None: self._state.set_initial(True) if self.get_mode() == Mode.C_MODE_REAL: - for con in self._controllers: con.reset() + for con in self._gateways: con.reset() self._import_state() @@ -1435,31 +1471,31 @@ def _reset(self, p_seed=None) -> None: ## ------------------------------------------------------------------------------------------------- - def add_controller(self, p_controller : Controller, p_mapping : list) -> bool: + def add_gateway(self, p_gateway : SAGateway, p_mapping : list) -> bool: """ - Adds a controller and a related mapping of states and actions to sensors and actuators. + Adds a sensor/actuator-gateway and a related mapping of states and actions to sensors and actuators. Parameters ---------- - p_controller : Controller - Controller object to be added. + p_gateway : SAGateway + gateway object to be added. p_mapping : list A list of mapping tuples following the syntax ( [Type = 'S' or 'A'], [Name of state/action] [Name of sensor/actuator] ) Returns ------- successful : bool - True, if controller and related mapping was added successfully. False otherwise. + True, if gateway and related mapping was added successfully. False otherwise. """ # 0 Preparation states = self._state_space actions = self._action_space - sensors = p_controller.get_sensors() - actuators = p_controller.get_actuators() + sensors = p_gateway.get_sensors() + actuators = p_gateway.get_actuators() mapping_int = [] successful = True - self.log(Log.C_LOG_TYPE_I, 'Adding controller "' + p_controller.get_name() + '"...') + self.log(Log.C_LOG_TYPE_I, 'Adding gateway "' + p_gateway.get_name() + '"...') # 1 Check/conversion of mapping entries @@ -1502,21 +1538,21 @@ def add_controller(self, p_controller : Controller, p_mapping : list) -> bool: raise ParamError('Type "' + entry[0] + '" not valid!') if not successful: - self.log(Log.C_LOG_TYPE_E, 'Controller "' + p_controller.get_name() + '" could not be added') + self.log(Log.C_LOG_TYPE_E, 'SA-Gateway "' + p_gateway.get_name() + '" could not be added') return False - # 2 Takeover of mapping entries and controller + # 2 Takeover of mapping entries and gateway for entry in mapping_int: if entry[0] == 'S': - self._mapping_states[entry[3]] = ( p_controller, entry[4] ) + self._mapping_states[entry[3]] = ( p_gateway, entry[4] ) self.log(Log.C_LOG_TYPE_I, 'State component "' + entry[1] + '" assigned to sensor "' + entry[2] +'"') else: - self._mapping_actions[entry[3]] = ( p_controller, entry[4] ) + self._mapping_actions[entry[3]] = ( p_gateway, entry[4] ) self.log(Log.C_LOG_TYPE_I, 'Action component "' + entry[1] + '" assigned to actuator "' + entry[2] +'"') - self._controllers.append(p_controller) - self.log(Log.C_LOG_TYPE_I, 'Controller "' + p_controller.get_name() + '" added successfully') + self._gateways.append(p_gateway) + self.log(Log.C_LOG_TYPE_I, 'SA-Gateway "' + p_gateway.get_name() + '" added successfully') return True @@ -1600,7 +1636,7 @@ def process_action(self, p_action: Action, p_t_step: timedelta = None) -> bool: else: result = self._process_action(p_action) - self._prev_state = state + self._prev_state = state self._last_action = p_action if result: @@ -1806,7 +1842,7 @@ def _import_state(self) -> bool: try: mapping = self._mapping_states[state_dim_id] except: - self.log(Log.C_LOG_TYPE_E, 'State component "' + state_dim_name + '" not assigned to a controller/sensor') + self.log(Log.C_LOG_TYPE_E, 'State component "' + state_dim_name + '" not assigned to a gateway/sensor') successful = False else: sensor_value = mapping[0].get_sensor_value( p_id = mapping[1] ) @@ -1844,7 +1880,7 @@ def _export_action(self, p_action: Action) -> bool: mapping = self._mapping_actions[action_dim_id] except: action_dim_name = action_elem.get_related_set().get_dim(action_dim_id).get_name() - self.log(Log.C_LOG_TYPE_E, 'Action component "' + action_dim_name + '" not assigned to a controller/sensor') + self.log(Log.C_LOG_TYPE_E, 'Action component "' + action_dim_name + '" not assigned to a gateway/sensor') successful = False else: actuator_value = action_elem.get_value(p_dim_id=action_dim_id) @@ -2089,6 +2125,7 @@ def _reset(self, p_seed=None) -> None: for system in self._subsystems: system.reset(p_seed = p_seed) + ## ------------------------------------------------------------------------------------------------- def get_subsystem_ids(self): return self._subsystem_ids @@ -2224,7 +2261,7 @@ def compute_success(self, p_state: State) -> bool: class DemoScenario(ScenarioBase): """ - Demo Scenario Class to demonstrate systems, inherits from the ScenarioBase. + Demo Scenario Class to demonstrate systems. Parameters ---------- @@ -2248,9 +2285,9 @@ class DemoScenario(ScenarioBase): Log level (see constants of class Log). Default: Log.C_LOG_ALL. """ - C_NAME = 'Demo System Scenario' - C_ACTION_RANDOM = 'random' - C_ACTION_CONSTANT = 'constant' + C_NAME = 'Demo System Scenario' + C_ACTION_RANDOM = 'random' + C_ACTION_CONSTANT = 'constant' ## ------------------------------------------------------------------------------------------------- def __init__(self, diff --git a/src/mlpro/oa/control/__init__.py b/src/mlpro/oa/control/__init__.py new file mode 100644 index 000000000..5c5386358 --- /dev/null +++ b/src/mlpro/oa/control/__init__.py @@ -0,0 +1 @@ +from mlpro.oa.control.basics import * \ No newline at end of file diff --git a/src/mlpro/oa/control/basics.py b/src/mlpro/oa/control/basics.py new file mode 100644 index 000000000..1618106d8 --- /dev/null +++ b/src/mlpro/oa/control/basics.py @@ -0,0 +1,222 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.control +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-12 0.0.0 DA Creation +## -- 2024-09-16 0.1.0 DA Initial implementation of class OAController +## -- 2024-09-19 0.2.0 DA Completion of classes and their parents +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.2.0 (2024-09-19) + +This module provides basic classes around the topic online-adaptive closed-loop control. + +""" + + +from mlpro.bf.systems import State, Action +from mlpro.bf.control import * +from mlpro.bf.ml import Model +from mlpro.bf.streams import InstDict + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAController (Controller, Model): + """ + Template class for online-adaptive closed-loop controllers. Please implement methods _compute_action() + and _adapt() in child classes. + + Parameters + ---------- + p_ada : bool = True + Boolean switch for adaptivitiy. Default = True. + p_name : str = None + Optional name of the task. Default is None. + p_range_max : int = Task.C_RANGE_THREAD + Maximum range of asynchonicity. See class Range. Default is Task.C_RANGE_PROCESS. + p_duplicate_data : bool = False + If True, instances will be duplicated before processing. Default = False. + p_visualize : bool = False + Boolean switch for visualisation. Default = False. + p_logging = Log.C_LOG_ALL + Log level (see constants of class Log). Default: Log.C_LOG_ALL + p_kwargs : dict + Further optional named parameters. + """ + + C_TYPE = 'OA Controller' + C_NAME = '????' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_ada: bool = True, + p_name: str = None, + p_range_max = Task.C_RANGE_THREAD, + p_duplicate_data : bool = False, + p_visualize : bool = False, + p_logging = Log.C_LOG_ALL, + **p_kwargs ): + + Controller.__init__( p_name = p_name, + p_range_max = p_range_max, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = False, + **p_kwargs ) + + Model.__init__( p_ada = p_ada, + p_visualize = p_visualize, + p_logging = p_logging ) + + +## ------------------------------------------------------------------------------------------------- + def _run(self, p_inst: InstDict): + """ + Computes the next action based on the current control error and adapts on further contextual + information like setpoint, state, action. + """ + + # 0 Intro + setpoint : SetPoint = None + state : State = None + ctrl_error : ControlError = None + + + # 1 Determine the contextual data for action computation + for (inst_type, inst) in p_inst.values(): + if isinstance(p_inst,SetPoint): + setpoint = p_inst + elif isinstance(p_inst,State): + state = p_inst + elif isinstance(p_inst, ControlError): + ctrl_error = p_inst + + if setpoint is None: + raise Error( 'Setpoint instance not found. Please check control cycle.') + if state is None: + raise Error( 'State instance not found. Please check control cycle.') + if ctrl_error is None: + raise Error( 'Control error instance not found. Please check control cycle.') + + + # 2 Compute the next action + action = self.compute_action( p_ctrl_error = ctrl_error ) + + + # 3 Adapt + self.adapt( p_ctrl_error = ctrl_error, + p_state = state, + p_setpoint = setpoint, + p_action = action ) + + +## ------------------------------------------------------------------------------------------------- + def _adapt( self, + p_setpoint: SetPoint, + p_ctrl_error: ControlError, + p_state: State, + p_action: Action ) -> bool: + """ + Specialized custom method for online adaptation in closed-loop control scenarios. + + Parameters + ---------- + p_setpoint : SetPoint + Setpoint. + p_ctrl_error : ControlError + Control error. + p_state : State + State of control system. + p_action : Action + Current action of the controller. + """ + + raise NotImplementedError + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAMultiController (MultiController, Model): + """ + """ + + C_TYPE = 'OA Multi-Controller' + C_NAME = '' + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControlSystem (ControlSystem, Model): + """ + Wrapper class for state-based systems. + """ + + C_TYPE = 'OA Control System' + C_NAME = '' + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControlPanel (ControlPanel): + """ + Enables external control of a closed-loop control. + """ + + C_TYPE = 'OA Control Panel' + C_NAME = '????' + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControlShared (ControlShared, OAControlPanel): + """ + ... + """ + + pass + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControlCycle (ControlCycle, Model): + """ + Container class for all tasks of a control cycle. + """ + + C_TYPE = 'OA Control Cycle' + C_NAME = '' + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControlScenario (ControlScenario, Model): + """ + ... + """ + + pass diff --git a/src/mlpro/oa/control/controllers/__init__.py b/src/mlpro/oa/control/controllers/__init__.py new file mode 100644 index 000000000..95a37e97b --- /dev/null +++ b/src/mlpro/oa/control/controllers/__init__.py @@ -0,0 +1,2 @@ +from mlpro.oa.control.controllers.wrapper_fct import OAControllerFct +from mlpro.oa.control.controllers.wrapper_rl import OAControllerRL \ No newline at end of file diff --git a/src/mlpro/oa/control/controllers/oa_pid_controller.py b/src/mlpro/oa/control/controllers/oa_pid_controller.py new file mode 100644 index 000000000..f3943d4fc --- /dev/null +++ b/src/mlpro/oa/control/controllers/oa_pid_controller.py @@ -0,0 +1,126 @@ +from mlpro.bf.control.controllers.pid_controller import PIDController +from mlpro.bf.ml.basics import * +from mlpro.rl import Policy,SARSElement +from mlpro.bf.systems import Action, State + + +class RLPID(Policy): + + def __init__(self, p_observation_space: MSpace, p_action_space: MSpace,pid_controller:PIDController ,policy:Policy=None,p_id=None, p_buffer_size: int = 1, p_ada: bool = True, p_visualize: bool = False, p_logging=Log.C_LOG_ALL ): + super().__init__(p_observation_space, p_action_space, p_id, p_buffer_size, p_ada, p_visualize, p_logging) + + self._pid_controller = pid_controller + self._policy = policy + self._old_action = None #None + self._action_space = p_action_space + + + ## ------------------------------------------------------------------------------------------------- + def _init_hyperparam(self, **p_par): + + # 1 Create a dispatcher hyperparameter tuple for the RLPID policy + self._hyperparam_tuple = HyperParamDispatcher(p_set=self._hyperparam_space) + + # 2 Extend RLPID policy's hp space and tuple from policy + try: + self._hyperparam_space.append( self._policy.get_hyperparam().get_related_set(), p_new_dim_ids=False) + self._hyperparam_tuple.add_hp_tuple(self._policy.get_hyperparam()) + except: + pass + + ## ------------------------------------------------------------------------------------------------- + def get_hyperparam(self) -> HyperParamTuple: + return self._policy.get_hyperparam() + + ## ------------------------------------------------------------------------------------------------- + def _update_hyperparameters(self) -> bool: + return self._policy._update_hyperparameters() + + ## ------------------------------------------------------------------------------------------------- + + def _adapt(self, p_sars_elem: SARSElement) -> bool: + + if self._old_action is None: + #create a pid action + self._old_action = Action(p_action_space=self._action_space,p_values=self._pid_controller.get_parameter_values()) + + #get SARS Elements + p_state,p_action,p_reward,p_state_new=tuple(p_sars_elem.get_data().keys()) + + # create a new SARS + p_sars_elem_new = SARSElement(p_state=p_state, + p_action=self._old_action, + p_reward=p_reward, + p_state_new=p_state_new) + + #adapt own policy + is_adapted = self._policy.adapt(p_kwargs=p_sars_elem_new) + + # compute new action with new error value (second s of Sars element) + self._old_action=self._policy.compute_action(p_obs=p_state_new) + + #get the pid paramter values + pid_values = self._old_action.get_feature_data().get_values() + + #set paramter pid + self._pid_controller.set_parameter(p_param={"Kp":pid_values[0], + "Ti":pid_values[1], + "Tv":pid_values[2]}) + return is_adapted + + ## ------------------------------------------------------------------------------------------------- + + def compute_action(self, p_obs: State) -> Action: + + #get action + action=self._pid_controller.compute_action(p_ctrl_error=p_obs) + + #return action + return action + +class RLPIDOffPolicy(Policy): + + def __init__(self, p_observation_space: MSpace, p_action_space: MSpace,pid_controller:PIDController ,p_id=None, p_buffer_size: int = 1, p_ada: bool = True, p_visualize: bool = False, p_logging=Log.C_LOG_ALL ): + super().__init__(p_observation_space, p_action_space, p_id, p_buffer_size, p_ada, p_visualize, p_logging) + + self._pid_controller = pid_controller + self._action_space = p_action_space.get_dim(p_id=0).get + + + def _init_hyperparam(self, **p_par): + + # create hp + # 1- add dim (Kp,Tn,Tv) in hp space + # 2- create hp tuple from hp space + # 3- set hp tuple values + + + # 1 + self._hyperparam_space.add_dim( self._action_space.get_dim(p_id=0)) + self._hyperparam_space.add_dim(self._action_space.get_dim(p_id=1)) + self._hyperparam_space.add_dim(self._action_space.get_dim(p_id=2)) + + # 2 + self._hyperparam_tuple = HyperParamTuple( p_set=self._hyperparam_space ) + + #3 + self._hyperparam_tuple.set_values(self._pid_controller.get_parameter_values()) + + + ## ------------------------------------------------------------------------------------------------- + + + def _adapt(self, p_sars_elem: SARSElement) -> bool: + return False + + ## ------------------------------------------------------------------------------------------------- + + + def compute_action(self, p_obs: State) -> Action: + + #get action + action=self._pid_controller.compute_action(p_ctrl_error=p_obs) + + #return action + return action + diff --git a/src/mlpro/oa/control/controllers/wrapper_fct.py b/src/mlpro/oa/control/controllers/wrapper_fct.py new file mode 100644 index 000000000..323faf3f7 --- /dev/null +++ b/src/mlpro/oa/control/controllers/wrapper_fct.py @@ -0,0 +1,46 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.control.controllers +## -- Module : wrapper_fct.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-19 0.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-19) + +This module provides a wrapper class for MLPro's adaptive functions. + +""" + + +from mlpro.oa.control import OAController + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControllerFct (OAController): + """ + Wrapper class for controllers based on an online-adaptive function mapping an error to an action. + + Parameters + ---------- + p_fct : Function + Function object mapping a control error to an action + + See class Controller for further parameters. + """ + + C_TYPE = 'OA Controller Fct' + C_NAME = '' + +## ------------------------------------------------------------------------------------------------- + def switch_adaptivity(self, p_ada: bool): + try: + self._fct.switch_adaptivity(p_ada) + except: + pass diff --git a/src/mlpro/oa/control/controllers/wrapper_rl.py b/src/mlpro/oa/control/controllers/wrapper_rl.py new file mode 100644 index 000000000..56e42a21b --- /dev/null +++ b/src/mlpro/oa/control/controllers/wrapper_rl.py @@ -0,0 +1,135 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.control.controller +## -- Module : wrapper_rl.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-19 0.1.0 DA Initial implementation of class OAControllerRL +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.1.0 (2024-09-19) + +This module provides a wrapper class for MLPro's RL policies. + +""" + + +from mlpro.bf.control.basics import ControlError, SetPoint +from mlpro.bf.math.basics import Log +from mlpro.bf.mt import Log, Task +from mlpro.bf.systems.basics import Action, State +from mlpro.oa.control import OAController +from mlpro.rl import SARSElement, FctReward, Policy + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class OAControllerRL (OAController): + """ + Wrapper class for online-adaptive closed-loop controllers reusing reinforcement learning objects + like a policy and a reward function. + + Parameters + ---------- + p_rl_policy : Policy + RL policy object. + p_rl_fct_reward : FctReward + RL reward function. + p_ada : bool + Boolean switch for adaptivitiy. Default = True. + p_name : str + Optional name of the task. Default is None. + p_range_max : int + Maximum range of asynchonicity. See class Range. Default is Range.C_RANGE_PROCESS. + p_duplicate_data : bool + If True, instances will be duplicated before processing. Default = False. + p_visualize : bool + Boolean switch for visualisation. Default = False. + p_logging + Log level (see constants of class Log). Default: Log.C_LOG_ALL + p_kwargs : dict + Further optional named parameters. + """ + + C_TYPE = 'OA Controller RL' + C_NAME = '' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_rl_policy : Policy, + p_rl_fct_reward : FctReward, + p_ada : bool = True, + p_name: str = None, + p_range_max=Task.C_RANGE_THREAD, + p_duplicate_data: bool = False, + p_visualize: bool = False, + p_logging=Log.C_LOG_ALL, + **p_kwargs ): + + self._rl_policy : Policy = p_rl_policy + self._rl_fct_reward : FctReward = p_rl_fct_reward + self._error_old : ControlError = None + self._action_old : Action = None + + super().__init__( p_ada = p_ada, + p_name = p_name, + p_range_max = p_range_max, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = p_logging, + **p_kwargs ) + + +## ------------------------------------------------------------------------------------------------- + def switch_adaptivity(self, p_ada: bool): + + super().switch_adaptivity(p_ada=p_ada) + self._rl_policy.switch_adaptivity(p_ada=p_ada) + + +## ------------------------------------------------------------------------------------------------- + def compute_action(self, p_ctrl_error: ControlError) -> Action: + + return self._rl_policy.compute_action( p_obs = p_ctrl_error ) + + +## ------------------------------------------------------------------------------------------------- + def _adapt( self, + p_setpoint: SetPoint, + p_ctrl_error: ControlError, + p_state: State, + p_action: Action) -> bool: + + # 0 Intro + adapted = False + + + # 1 Adaptation from the second cycle on + if self._error_old is not None: + + # 1.1 Call reward function + reward = self._rl_fct_reward.compute_reward( p_state_old = self._error_old, p_state_new = p_ctrl_error ) + + + # 1.2 Setup SARS element + sars_elem : SARSElement = SARSElement( p_state = self._error_old, + p_action = self._action_old, + p_reward = reward, + p_state_new = p_ctrl_error ) + + + # 1.3 Trigger adaptation of the RL policy + adapted = self._rl_policy.adapt( p_sars_elem = sars_elem ) + + + # 2 Buffering of current action and error + self._error_old = p_ctrl_error + self._action_old = p_action + + + # 3 Outro + return adapted \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/clusteranalyzers/basics.py b/src/mlpro/oa/streams/tasks/clusteranalyzers/basics.py index 1add9bf01..6ef956849 100644 --- a/src/mlpro/oa/streams/tasks/clusteranalyzers/basics.py +++ b/src/mlpro/oa/streams/tasks/clusteranalyzers/basics.py @@ -36,16 +36,21 @@ ## -- - new method _get_cluster_relations() ## -- - new method get_cluster_influences() ## -- 2024-06-16 1.2.1 DA Bugfix in ClusterAnalyzer.align_cluster_properties() +## -- 2024-08-20 1.3.0 DA Raising of events Cluster.C_CLUSTER_ADDED, Cluster.C_CLUSTER_REMOVED +## -- 2024-08-21 1.3.1 DA Resolved name collision of class mlpro.bf.events.Event ## ------------------------------------------------------------------------------------------------- """ -Ver. 1.2.1 (2024-06-16) +Ver. 1.3.1 (2024-08-21) This module provides a template class for online cluster analysis. """ +from typing import List, Tuple from matplotlib.figure import Figure + +from mlpro.bf.events import Event as MLProEvent from mlpro.bf.math.properties import * from mlpro.bf.mt import PlotSettings from mlpro.bf.streams import Instance, InstDict @@ -54,7 +59,6 @@ from mlpro.oa.streams import OATask from mlpro.bf.math.normalizers import Normalizer from mlpro.oa.streams.tasks.clusteranalyzers.clusters import Cluster, ClusterId -from typing import List, Tuple @@ -247,6 +251,10 @@ def _add_cluster(self, p_cluster:Cluster) -> bool: if self.get_visualization(): p_cluster.init_plot( p_figure=self._figure, p_plot_settings=self.get_plot_settings() ) + self._raise_event( p_event_id = self.C_EVENT_CLUSTER_ADDED, + p_event_object = MLProEvent( p_raising_object = self, + p_cluster = p_cluster ) ) + ## ------------------------------------------------------------------------------------------------- def _remove_cluster(self, p_cluster:Cluster): @@ -262,6 +270,10 @@ def _remove_cluster(self, p_cluster:Cluster): p_cluster.remove_plot(p_refresh=True) del self._clusters[p_cluster.id] + self._raise_event( p_event_id = self.C_EVENT_CLUSTER_REMOVED, + p_event_object = MLProEvent( p_raising_object = self, + p_cluster = p_cluster ) ) + ## ------------------------------------------------------------------------------------------------- def _get_cluster_relations( self, diff --git a/stepResponse.png b/stepResponse.png new file mode 100644 index 000000000..05f0e13aa Binary files /dev/null and b/stepResponse.png differ diff --git a/templates/new_howto/howto_bf_control_controllers_pid_controller.py b/templates/new_howto/howto_bf_control_controllers_pid_controller.py new file mode 100644 index 000000000..e2ded7226 --- /dev/null +++ b/templates/new_howto/howto_bf_control_controllers_pid_controller.py @@ -0,0 +1,97 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.bf.examples +## -- Module : howto_bf_zz_999_description.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2023-01-01 0.0.0 FN Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2023-01-01) + +This module demonstrates ... + +You will learn: + +1) How to implement a P, PI and PID Controller + +2) How to use a PID Controller without and with anti wind up mechanism + +3) How to use a controller to create a control signal and set new pid parameters + +""" + + +from mlpro.bf.control.controllers.pid_controller import PIDController +from mlpro.bf.control.basics import CTRLError, Controller +from mlpro.bf.math.basics import Log +from mlpro.bf.mt import Log, Task +from mlpro.bf.various import Log +from mlpro.bf.math import * +from mlpro.bf.systems import Action, ActionElement + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyPIDController (PIDController): + """ + This class demonstrates how to ... + """ + + # needed for proper logging (see class mlpro.bf.various.Log) + C_TYPE = 'Demo' + C_NAME = 'PID Control' + +## ------------------------------------------------------------------------------------------------- + def __init__(self, Kp: float, Ti: float, Tv: float, disable_integral: bool = False, disable_derivitave: bool = False, enable_windup: bool = False, windup_limit: float = 0, output_limits: tuple = ..., p_name: str = None, p_range_max=Task.C_RANGE_THREAD, p_duplicate_data: bool = False, p_visualize: bool = False, p_logging=Log.C_LOG_ALL, **p_kwargs): + super().__init__(Kp, Ti, Tv, disable_integral, disable_derivitave, enable_windup, windup_limit, output_limits, p_name, p_range_max, p_duplicate_data, p_visualize, p_logging, **p_kwargs) + + +# 1 Preparation of demo test +if __name__ == '__main__': + + + # 1.Parameters for demo mode + Kp = 12 + Ti = 10 + Tv = 2.5 + element = Element(Set()) + print(element.get_dim_ids()) + element.set_values([12]) + crtl_error = CTRLError(element,p_tstamp=datetime.now()) + + action_element= ActionElement(Set()) + + + # 2. create diffrent instances of the class pid_controller + # create an instance of a P-Controller + p_controller = PIDController(Kp=Kp,disable_integral=True, disable_derivitave=True) + # create an instance of a PI-Controller + pi_controller = PIDController(Kp=True, Ti=10,disable_derivitave=True) + # create an instance of a PID-Controller without anti wind up mechanism + pid_controller = PIDController(Kp=True, Ti=10,Tv=Tv) + # create an instance of a PID-Controller with anti wind up mechanism + pid_controller_antiWindUp = PIDController(Kp=True, Ti=10,Tv=Tv,enable_windup=True,windup_limit=100,output_limits=(0,100)) + + + # 3. run compute action + p_controller._compute_action(crtl_error,action_element) + p_controller._compute_action(crtl_error,action_element) + pi_controller._compute_action(crtl_error,action_element) + pid_controller._compute_action(crtl_error,action_element) + pid_controller_antiWindUp._compute_action(crtl_error,action_element) + + + # 4. set new pid parameter + p_controller.set_parameter(Kp= 6) + pi_controller.set_parameter(Kp= 6,Ti=4) + pid_controller.set_parameter(Kp=6,Ti=4,Tv=12) + + + + + + diff --git a/test/howtos/bf/control/howto_bf_control_001_basic_control_loop.py b/test/howtos/bf/control/howto_bf_control_001_basic_control_loop.py new file mode 100644 index 000000000..4ea9c2698 --- /dev/null +++ b/test/howtos/bf/control/howto_bf_control_001_basic_control_loop.py @@ -0,0 +1,95 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.bf.control +## -- Module : howto_bf_control_001_basic_control_loop.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-11 0.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-11) + +This module demonstrates ... + +You will learn: + +1) How to ... + +2) How to ... + +3) How to ... + +""" + +from time import sleep + +from mlpro.bf.control import Controller, ControlSystem, ControlCycle, ControlScenario + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyController (Controller): + pass + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyControlScenario (ControlScenario): + +## ------------------------------------------------------------------------------------------------- + def _setup(self, p_mode, p_visualize: bool, p_logging): + + # 1 Prepare control system (e.g. by wrapping) + + # 2 Prepare control cycle + + # ... + + + + + +# 1 Preparation of demo/unit test mode +if __name__ == '__main__': + # 1.1 Parameters for demo mode + cycle_limit = 200 + logging = Log.C_LOG_ALL + visualize = True + +else: + # 1.2 Parameters for internal unit test + cycle_limit = 2 + logging = Log.C_LOG_NOTHING + visualize = False + + + +# 2 Init control scenario +myscenario = MyControlScenario() +panel = myscenario.get_control_panel() + + + +# 3 Start the control process asynchronously +myscenario.run() +panel.start() + + + +# 4 Change setpoint value in a loop +for i in range(10): + sleep(1) + panel.change_setpoint() + + + +# 5 Stop control process +panel.stop() + diff --git a/test/howtos/bf/control/howto_bf_control_101_pid_controller_standalone.py b/test/howtos/bf/control/howto_bf_control_101_pid_controller_standalone.py new file mode 100644 index 000000000..b8c0d84e4 --- /dev/null +++ b/test/howtos/bf/control/howto_bf_control_101_pid_controller_standalone.py @@ -0,0 +1,80 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : test/howtos/bf +## -- Module : howto_bf_control_101_pid_controller_standalone.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-01 0.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-01) + +This module demonstrates ... + +You will learn: + +1) How to ... + +2) How to ... + +3) How to ... + +""" + + +from mlpro.bf.various import Log + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyDemo (Log): + """ + This class demonstrates how to ... + """ + + # needed for proper logging (see class mlpro.bf.various.Log) + C_TYPE = 'Demo' + C_NAME = 'Parallel Algorithm' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_logging=Log.C_LOG_ALL ): + + super().__init__( p_logging=p_logging ) + + +## ------------------------------------------------------------------------------------------------- + def execute(self): + # Log something + self.log(Log.C_LOG_TYPE_I, 'Here we go...') + + + + + + +# 1 Preparation of demo/unit test mode +if __name__ == '__main__': + # 1.1 Parameters for demo mode + cycle_limit = 200 + logging = Log.C_LOG_ALL + visualize = True + +else: + # 1.2 Parameters for internal unit test + cycle_limit = 2 + logging = Log.C_LOG_NOTHING + visualize = False + + + +# 2 Instantiate the demo objects +demo = MyDemo( p_logging = logging ) + + + +# 3 Demo actions +demo.execute() diff --git a/test/howtos/bf/control/howto_bf_control_102_pid_controller_embedded.py b/test/howtos/bf/control/howto_bf_control_102_pid_controller_embedded.py new file mode 100644 index 000000000..6adb07a7a --- /dev/null +++ b/test/howtos/bf/control/howto_bf_control_102_pid_controller_embedded.py @@ -0,0 +1,80 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : test/howtos/bf +## -- Module : howto_bf_control_102_pid_controller_embedded.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-01 0.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-01) + +This module demonstrates ... + +You will learn: + +1) How to ... + +2) How to ... + +3) How to ... + +""" + + +from mlpro.bf.various import Log + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyDemo (Log): + """ + This class demonstrates how to ... + """ + + # needed for proper logging (see class mlpro.bf.various.Log) + C_TYPE = 'Demo' + C_NAME = 'Parallel Algorithm' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_logging=Log.C_LOG_ALL ): + + super().__init__( p_logging=p_logging ) + + +## ------------------------------------------------------------------------------------------------- + def execute(self): + # Log something + self.log(Log.C_LOG_TYPE_I, 'Here we go...') + + + + + + +# 1 Preparation of demo/unit test mode +if __name__ == '__main__': + # 1.1 Parameters for demo mode + cycle_limit = 200 + logging = Log.C_LOG_ALL + visualize = True + +else: + # 1.2 Parameters for internal unit test + cycle_limit = 2 + logging = Log.C_LOG_NOTHING + visualize = False + + + +# 2 Instantiate the demo objects +demo = MyDemo( p_logging = logging ) + + + +# 3 Demo actions +demo.execute() diff --git a/test/howtos/bf/control/howto_bf_control_103_pid_controller_cascaded.py b/test/howtos/bf/control/howto_bf_control_103_pid_controller_cascaded.py new file mode 100644 index 000000000..b576e6655 --- /dev/null +++ b/test/howtos/bf/control/howto_bf_control_103_pid_controller_cascaded.py @@ -0,0 +1,80 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : test/howtos/bf +## -- Module : howto_bf_control_103_pid_controller_cascaded.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2024-09-01 0.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.0.0 (2024-09-01) + +This module demonstrates ... + +You will learn: + +1) How to ... + +2) How to ... + +3) How to ... + +""" + + +from mlpro.bf.various import Log + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class MyDemo (Log): + """ + This class demonstrates how to ... + """ + + # needed for proper logging (see class mlpro.bf.various.Log) + C_TYPE = 'Demo' + C_NAME = 'Parallel Algorithm' + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_logging=Log.C_LOG_ALL ): + + super().__init__( p_logging=p_logging ) + + +## ------------------------------------------------------------------------------------------------- + def execute(self): + # Log something + self.log(Log.C_LOG_TYPE_I, 'Here we go...') + + + + + + +# 1 Preparation of demo/unit test mode +if __name__ == '__main__': + # 1.1 Parameters for demo mode + cycle_limit = 200 + logging = Log.C_LOG_ALL + visualize = True + +else: + # 1.2 Parameters for internal unit test + cycle_limit = 2 + logging = Log.C_LOG_NOTHING + visualize = False + + + +# 2 Instantiate the demo objects +demo = MyDemo( p_logging = logging ) + + + +# 3 Demo actions +demo.execute() diff --git a/test/howtos/bf/howto_bf_mt_002_tasks_and_workflows.py b/test/howtos/bf/howto_bf_mt_002_tasks_and_workflows.py index ae4671118..bff6c1e9f 100644 --- a/test/howtos/bf/howto_bf_mt_002_tasks_and_workflows.py +++ b/test/howtos/bf/howto_bf_mt_002_tasks_and_workflows.py @@ -79,6 +79,8 @@ def __init__( self, ## ------------------------------------------------------------------------------------------------- def _run(self, **p_kwargs): + print('Hello World') + tid = self.get_tid() # 1 Dummy implementation to simulate a busy sub-task diff --git a/test/howtos/bf/howto_bf_streams_101_basics.py b/test/howtos/bf/howto_bf_streams_101_basics.py index 277f05bef..21e87671c 100644 --- a/test/howtos/bf/howto_bf_streams_101_basics.py +++ b/test/howtos/bf/howto_bf_streams_101_basics.py @@ -47,7 +47,7 @@ class MyTask (StreamTask): ## ------------------------------------------------------------------------------------------------- def _run(self, p_inst : InstDict): - pass + print('Hello World') @@ -111,6 +111,7 @@ def _setup(self, p_mode, p_visualize: bool, p_logging): if __name__ == '__main__': myscenario.init_plot() + myscenario.run() input('Press ENTER to start stream processing...') myscenario.run() diff --git a/test/howtos/bf/howto_bf_systems_010_systems_controllers_actuators_sensors.py b/test/howtos/bf/howto_bf_systems_010_systems_controllers_actuators_sensors.py index 17b839a11..d5cabc159 100644 --- a/test/howtos/bf/howto_bf_systems_010_systems_controllers_actuators_sensors.py +++ b/test/howtos/bf/howto_bf_systems_010_systems_controllers_actuators_sensors.py @@ -8,10 +8,11 @@ ## -- 2022-12-05 1.0.0 DA Creation ## -- 2022-12-09 1.1.0 DA Simplification ## -- 2023-04-19 1.1.1 LSB Renamed the module +## -- 2024-09-09 1.2.0 DA Refactoring ## ------------------------------------------------------------------------------------------------- """ -Ver. 1.1.1 (2023-04-19) +Ver. 1.2.0 (2024-09-09) This module demonstrates the principles of using classes System, Controller, Actuator and Sensor. To this regard we assume a custom system with two state and action components and a custom controller @@ -36,12 +37,12 @@ -class MyController (Controller): +class MySAGateway (SAGateway): C_NAME = 'Dummy' def _reset(self) -> bool: - self.log(Log.C_LOG_TYPE_S, 'Pseudo-reset of the controller') + self.log(Log.C_LOG_TYPE_S, 'Pseudo-reset of the sa-gateway') return True @@ -100,26 +101,26 @@ def _reset(self, p_seed=None) -> None: sys = MySystem( p_latency=latency, p_logging=logging ) -# 2 Instantiate and configure own controller -con = MyController( p_id=0, p_name='2x2', p_logging=logging ) +# 2 Instantiate and configure own sensor/actuator gateway +sagw = MySAGateway( p_id=0, p_name='2x2', p_logging=logging ) s1 = Sensor(p_name_short='Sensor 1') s2 = Sensor(p_name_short='Sensor 2') a1 = Actuator(p_name_short='Actuator 1') a2 = Actuator(p_name_short='Actuator 2') -con.add_sensor( p_sensor=s1 ) -con.add_sensor( p_sensor=s2 ) -con.add_actuator( p_actuator=a1 ) -con.add_actuator( p_actuator=a2 ) +sagw.add_sensor( p_sensor=s1 ) +sagw.add_sensor( p_sensor=s2 ) +sagw.add_actuator( p_actuator=a1 ) +sagw.add_actuator( p_actuator=a2 ) -# 3 Add controller to system and assign sensors to states and actuators to actions -sys.add_controller( p_controller=con, - p_mapping=[ ( 'S', 'State 1', 'Sensor 1' ), - ( 'S', 'State 2', 'Sensor 2' ), - ( 'A', 'Action 1', 'Actuator 1' ), - ( 'A', 'Action 2', 'Actuator 2') ] ) +# 3 Add gateway to system and assign sensors to states and actuators to actions +sys.add_gateway( p_gateway=sagw, + p_mapping=[ ( 'S', 'State 1', 'Sensor 1' ), + ( 'S', 'State 2', 'Sensor 2' ), + ( 'A', 'Action 1', 'Actuator 1' ), + ( 'A', 'Action 2', 'Actuator 2') ] ) # 4 Switch system to real mode diff --git a/test/test_pool_policies.py b/test/test_pool_policies.py index f6aef7e90..d7c95a9c6 100644 --- a/test/test_pool_policies.py +++ b/test/test_pool_policies.py @@ -19,7 +19,7 @@ """ -import pytest +#import pytest from mlpro.rl import * from mlpro.rl.pool.envs.bglp import BGLP from mlpro.rl.pool.policies.dummy import MyDummyPolicy