diff --git a/JetBrains.gitignore b/JetBrains.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3649d6dc25268693224aee006e1c189c009bad14
--- /dev/null
+++ b/JetBrains.gitignore
@@ -0,0 +1,77 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
diff --git a/Python.gitignore b/Python.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6769e21d99a63338394e47bc4c7d0aba1e88d5a5
--- /dev/null
+++ b/Python.gitignore
@@ -0,0 +1,160 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+#   in version control.
+#   https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+#  and can be added to the global gitignore or merged into this file.  For a more nuclear
+#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
\ No newline at end of file
diff --git a/README.md b/README.md
index 4643889d2194fbf966083cfc9620c663a9b887bc..eb7071e7bbe3785115a07ba7926e7d484f52be04 100644
--- a/README.md
+++ b/README.md
@@ -1,92 +1,8 @@
 # McPy
 
+McPy (Monte Carlo Python) is a library that allows you to add uncertainties to your calculation. It is a thin wrapper
+to your regular floating numbers and allow easy definition of underlying uncertainty
+distributions.
 
-
-## Getting started
-
-To make it easy for you to get started with GitLab, here's a list of recommended next steps.
-
-Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
-
-## Add your files
-
-- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
-
-```
-cd existing_repo
-git remote add origin https://gitlab.tugraz.at/flexsensor-public/mcpy.git
-git branch -M main
-git push -uf origin main
-```
-
-## Integrate with your tools
-
-- [ ] [Set up project integrations](https://gitlab.tugraz.at/flexsensor-public/mcpy/-/settings/integrations)
-
-## Collaborate with your team
-
-- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
-- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
-- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
-- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
-
-## Test and Deploy
-
-Use the built-in continuous integration in GitLab.
-
-- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
-- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
-- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
-- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
-- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
-
-***
-
-# Editing this README
-
-When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
-
-## Suggestions for a good README
-Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
-
-## Name
-Choose a self-explaining name for your project.
-
-## Description
-Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
-
-## Badges
-On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
-
-## Visuals
-Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
-
-## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
-
-## Usage
-Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
-
-## Support
-Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
-
-## Roadmap
-If you have ideas for releases in the future, it is a good idea to list them in the README.
-
-## Contributing
-State if you are open to contributions and what your requirements are for accepting them.
-
-For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
-
-You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
-
-## Authors and acknowledgment
-Show your appreciation to those who have contributed to the project.
-
-## License
-For open source projects, say how it is licensed.
-
-## Project status
-If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
+Every uncertainty variable can be used to randly draw samples and calculate a Monte Carlo Analysis
+according to GUM.
\ No newline at end of file
diff --git a/examples/MyPyUI_Test.py b/examples/MyPyUI_Test.py
new file mode 100644
index 0000000000000000000000000000000000000000..1570f9a87e9dd8d7945fae1a93bfa80d76c5726c
--- /dev/null
+++ b/examples/MyPyUI_Test.py
@@ -0,0 +1,34 @@
+import os
+import sys
+import pathlib
+import os
+sys.path.append('./src')
+print(os.getcwd())
+
+import mcpy
+
+from PySide6.QtWidgets import QApplication
+
+if __name__ == "__main__":
+    app = QApplication()
+
+    # from_obs = DirectObservations([ 0.20064, 0.2019, 0.19771, 0.20089, 0.20024, 0.19878, 0.19946,
+    #         0.20024, 0.2035, 0.20248, 0.19879, 0.20307, 0.20065, 0.20007,
+    #         0.20055, 0.19979, 0.19985, 0.20152, 0.20144, 0.20133, 0.20067, 0.19878,
+    #         0.20078, 0.20174, 0.2006], k=3)
+    # ui = UncertaintyWidget(from_obs)
+
+    # uexp = ((40e-3 * 19e-3) / 100)
+    # normal = mcpy.Normal(6.7e-3, uexp, 3)
+    # ui = UncertaintyWidget(normal)
+
+    R1 = 100
+    a1 = 5e-3
+    R1_l = R1 - a1
+    R1_u = R1 + a1
+    rect1 = mcpy.Rectangular(R1, a1, k=2)
+    rect1.mc_sample(200000)
+    ui = mcpy.UncertaintyWidget(rect1)
+
+    ui.show()
+    sys.exit(app.exec())
diff --git a/examples/VoltageMeasurements.csv b/examples/VoltageMeasurements.csv
new file mode 100644
index 0000000000000000000000000000000000000000..1c5d699a6bd0cb7af42d3528feb4a98f256cebb8
--- /dev/null
+++ b/examples/VoltageMeasurements.csv
@@ -0,0 +1,25 @@
+-0.0019142,0.20064
+-0.0019352,0.2019
+-0.001883,0.19771
+-0.0019142,0.20089
+-0.0019185,0.20024
+-0.0019188,0.19878
+-0.0019038,0.19946
+-0.001922,0.20024
+-0.0019476,0.2035
+-0.0019507,0.20248
+-0.0018944,0.19879
+-0.0019459,0.20307
+-0.0019277,0.20065
+-0.0019272,0.20007
+-0.001936,0.20055
+-0.001915,0.19979
+-0.0019008,0.19985
+-0.0019237,0.20152
+-0.0019199,0.20144
+-0.0019513,0.20133
+-0.0019168,0.20067
+-0.0019115,0.19878
+-0.0019218,0.20078
+-0.0019413,0.20174
+-0.0019147,0.2006
diff --git a/examples/VoltageMeasurements2.csv b/examples/VoltageMeasurements2.csv
new file mode 100644
index 0000000000000000000000000000000000000000..4c7f63fe44a5274ea822486afc2ce2d2204358f1
--- /dev/null
+++ b/examples/VoltageMeasurements2.csv
@@ -0,0 +1,25 @@
+-0.0019088,0.20085
+-0.0019172,0.19924
+-0.0019012,0.1987
+-0.0019136,0.20011
+-0.0019186,0.20085
+-0.0019015,0.19945
+-0.0019237,0.20159
+-0.0019265,0.20073
+-0.001919,0.19996
+-0.0019082,0.19964
+-0.0019078,0.19924
+-0.0019213,0.20065
+-0.0019139,0.19998
+-0.0018986,0.19812
+-0.0019134,0.19958
+-0.0019119,0.20105
+-0.0019122,0.19882
+-0.001901,0.19939
+-0.0019038,0.20012
+-0.0019156,0.20029
+-0.0019028,0.20035
+-0.0019302,0.20127
+-0.0019289,0.20118
+-0.00193,0.20035
+-0.0019053,0.20079
diff --git a/examples/example_Wheatstone_Bridge.ipynb b/examples/example_Wheatstone_Bridge.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..a0bab0b51625a3106713f87fde3f8fcfeb3c1b38
--- /dev/null
+++ b/examples/example_Wheatstone_Bridge.ipynb
@@ -0,0 +1,571 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T12:04:35.446371Z",
+     "end_time": "2023-05-14T12:04:35.517231Z"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0.1b\n",
+      "1999999\n"
+     ]
+    }
+   ],
+   "source": [
+    "import os\n",
+    "import mcpy as mcpy\n",
+    "print(mcpy.version)\n",
+    "N = int((1/(1-0.95))*10**5)\n",
+    "print(N)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "# Resistors in the Wheatstone Bridge\n",
+    "## Resistors R21, R22, R3\n",
+    "### Resistor R21\n",
+    "For resistors, it's safe to assume a rectangular distribution, due to the fact that there is no special\n",
+    "knowledge about the possible values within the interval. Thus, it's assumed that it is equally\n",
+    "probable to lie anywhere within it.\n",
+    "\n",
+    "According to the corresponding datasheets S102C.pdf [3, p. 1] the resistance tolerance is given\n",
+    "by +-0,005"
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "R(1.000E+02, 1.000E+02) uc = 2.887E-03\n"
+     ]
+    },
+    {
+     "ename": "UnboundLocalError",
+     "evalue": "local variable 'result' referenced before assignment",
+     "output_type": "error",
+     "traceback": [
+      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
+      "\u001B[1;31mUnboundLocalError\u001B[0m                         Traceback (most recent call last)",
+      "Cell \u001B[1;32mIn[5], line 5\u001B[0m\n\u001B[0;32m      3\u001B[0m R21 \u001B[38;5;241m=\u001B[39m mcpy\u001B[38;5;241m.\u001B[39mRectangular(R21_, delta_a_R21_)\n\u001B[0;32m      4\u001B[0m \u001B[38;5;28mprint\u001B[39m(R21)\n\u001B[1;32m----> 5\u001B[0m \u001B[43mR21\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mplot\u001B[49m\u001B[43m(\u001B[49m\u001B[43mN\u001B[49m\u001B[43m)\u001B[49m\n",
+      "File \u001B[1;32mE:\\flexsensor\\mcpy\\mcpy\\UncertaintyDistributions.py:145\u001B[0m, in \u001B[0;36mUncertainty.plot\u001B[1;34m(self, N)\u001B[0m\n\u001B[0;32m    143\u001B[0m r \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrand(N)\n\u001B[0;32m    144\u001B[0m plt\u001B[38;5;241m.\u001B[39mtitle(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__class__\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m)\n\u001B[1;32m--> 145\u001B[0m \u001B[43mplt\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mhist\u001B[49m\u001B[43m(\u001B[49m\u001B[43mr\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbins\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m100\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m    146\u001B[0m plt\u001B[38;5;241m.\u001B[39mshow()\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\matplotlib\\pyplot.py:2618\u001B[0m, in \u001B[0;36mhist\u001B[1;34m(x, bins, range, density, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, data, **kwargs)\u001B[0m\n\u001B[0;32m   2612\u001B[0m \u001B[38;5;129m@_copy_docstring_and_deprecators\u001B[39m(Axes\u001B[38;5;241m.\u001B[39mhist)\n\u001B[0;32m   2613\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mhist\u001B[39m(\n\u001B[0;32m   2614\u001B[0m         x, bins\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, \u001B[38;5;28mrange\u001B[39m\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, density\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, weights\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[0;32m   2615\u001B[0m         cumulative\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, bottom\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, histtype\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbar\u001B[39m\u001B[38;5;124m'\u001B[39m, align\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmid\u001B[39m\u001B[38;5;124m'\u001B[39m,\n\u001B[0;32m   2616\u001B[0m         orientation\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mvertical\u001B[39m\u001B[38;5;124m'\u001B[39m, rwidth\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, log\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, color\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[0;32m   2617\u001B[0m         label\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, stacked\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, \u001B[38;5;241m*\u001B[39m, data\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[1;32m-> 2618\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m gca()\u001B[38;5;241m.\u001B[39mhist(\n\u001B[0;32m   2619\u001B[0m         x, bins\u001B[38;5;241m=\u001B[39mbins, \u001B[38;5;28mrange\u001B[39m\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mrange\u001B[39m, density\u001B[38;5;241m=\u001B[39mdensity, weights\u001B[38;5;241m=\u001B[39mweights,\n\u001B[0;32m   2620\u001B[0m         cumulative\u001B[38;5;241m=\u001B[39mcumulative, bottom\u001B[38;5;241m=\u001B[39mbottom, histtype\u001B[38;5;241m=\u001B[39mhisttype,\n\u001B[0;32m   2621\u001B[0m         align\u001B[38;5;241m=\u001B[39malign, orientation\u001B[38;5;241m=\u001B[39morientation, rwidth\u001B[38;5;241m=\u001B[39mrwidth, log\u001B[38;5;241m=\u001B[39mlog,\n\u001B[0;32m   2622\u001B[0m         color\u001B[38;5;241m=\u001B[39mcolor, label\u001B[38;5;241m=\u001B[39mlabel, stacked\u001B[38;5;241m=\u001B[39mstacked,\n\u001B[0;32m   2623\u001B[0m         \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39m({\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdata\u001B[39m\u001B[38;5;124m\"\u001B[39m: data} \u001B[38;5;28;01mif\u001B[39;00m data \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;28;01melse\u001B[39;00m {}), \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\matplotlib\\__init__.py:1459\u001B[0m, in \u001B[0;36m_preprocess_data.<locals>.inner\u001B[1;34m(ax, data, *args, **kwargs)\u001B[0m\n\u001B[0;32m   1456\u001B[0m \u001B[38;5;129m@functools\u001B[39m\u001B[38;5;241m.\u001B[39mwraps(func)\n\u001B[0;32m   1457\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21minner\u001B[39m(ax, \u001B[38;5;241m*\u001B[39margs, data\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[0;32m   1458\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m data \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m-> 1459\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m func(ax, \u001B[38;5;241m*\u001B[39m\u001B[38;5;28mmap\u001B[39m(sanitize_sequence, args), \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m   1461\u001B[0m     bound \u001B[38;5;241m=\u001B[39m new_sig\u001B[38;5;241m.\u001B[39mbind(ax, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m   1462\u001B[0m     auto_label \u001B[38;5;241m=\u001B[39m (bound\u001B[38;5;241m.\u001B[39marguments\u001B[38;5;241m.\u001B[39mget(label_namer)\n\u001B[0;32m   1463\u001B[0m                   \u001B[38;5;129;01mor\u001B[39;00m bound\u001B[38;5;241m.\u001B[39mkwargs\u001B[38;5;241m.\u001B[39mget(label_namer))\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\matplotlib\\axes\\_axes.py:6790\u001B[0m, in \u001B[0;36mAxes.hist\u001B[1;34m(self, x, bins, range, density, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, **kwargs)\u001B[0m\n\u001B[0;32m   6786\u001B[0m \u001B[38;5;66;03m# Loop through datasets\u001B[39;00m\n\u001B[0;32m   6787\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m i \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mrange\u001B[39m(nx):\n\u001B[0;32m   6788\u001B[0m     \u001B[38;5;66;03m# this will automatically overwrite bins,\u001B[39;00m\n\u001B[0;32m   6789\u001B[0m     \u001B[38;5;66;03m# so that each histogram uses the same bins\u001B[39;00m\n\u001B[1;32m-> 6790\u001B[0m     m, bins \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39mhistogram(x[i], bins, weights\u001B[38;5;241m=\u001B[39mw[i], \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mhist_kwargs)\n\u001B[0;32m   6791\u001B[0m     tops\u001B[38;5;241m.\u001B[39mappend(m)\n\u001B[0;32m   6792\u001B[0m tops \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39marray(tops, \u001B[38;5;28mfloat\u001B[39m)  \u001B[38;5;66;03m# causes problems later if it's an int\u001B[39;00m\n",
+      "File \u001B[1;32m<__array_function__ internals>:200\u001B[0m, in \u001B[0;36mhistogram\u001B[1;34m(*args, **kwargs)\u001B[0m\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\numpy\\lib\\histograms.py:780\u001B[0m, in \u001B[0;36mhistogram\u001B[1;34m(a, bins, range, density, weights)\u001B[0m\n\u001B[0;32m    680\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124mr\u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m    681\u001B[0m \u001B[38;5;124;03mCompute the histogram of a dataset.\u001B[39;00m\n\u001B[0;32m    682\u001B[0m \n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    776\u001B[0m \n\u001B[0;32m    777\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m    778\u001B[0m a, weights \u001B[38;5;241m=\u001B[39m _ravel_and_check_weights(a, weights)\n\u001B[1;32m--> 780\u001B[0m bin_edges, uniform_bins \u001B[38;5;241m=\u001B[39m \u001B[43m_get_bin_edges\u001B[49m\u001B[43m(\u001B[49m\u001B[43ma\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbins\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mrange\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mweights\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    782\u001B[0m \u001B[38;5;66;03m# Histogram is an integer or a float array depending on the weights.\u001B[39;00m\n\u001B[0;32m    783\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m weights \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\numpy\\lib\\histograms.py:446\u001B[0m, in \u001B[0;36m_get_bin_edges\u001B[1;34m(a, bins, range, weights)\u001B[0m\n\u001B[0;32m    443\u001B[0m         bin_type \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39mresult_type(bin_type, \u001B[38;5;28mfloat\u001B[39m)\n\u001B[0;32m    445\u001B[0m     \u001B[38;5;66;03m# bin edges must be computed\u001B[39;00m\n\u001B[1;32m--> 446\u001B[0m     bin_edges \u001B[38;5;241m=\u001B[39m \u001B[43mnp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mlinspace\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    447\u001B[0m \u001B[43m        \u001B[49m\u001B[43mfirst_edge\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlast_edge\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mn_equal_bins\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m1\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[0;32m    448\u001B[0m \u001B[43m        \u001B[49m\u001B[43mendpoint\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mTrue\u001B[39;49;00m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdtype\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbin_type\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    449\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m bin_edges, (first_edge, last_edge, n_equal_bins)\n\u001B[0;32m    450\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n",
+      "File \u001B[1;32m<__array_function__ internals>:200\u001B[0m, in \u001B[0;36mlinspace\u001B[1;34m(*args, **kwargs)\u001B[0m\n",
+      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\numpy\\core\\function_base.py:128\u001B[0m, in \u001B[0;36mlinspace\u001B[1;34m(start, stop, num, endpoint, retstep, dtype, axis)\u001B[0m\n\u001B[0;32m    124\u001B[0m div \u001B[38;5;241m=\u001B[39m (num \u001B[38;5;241m-\u001B[39m \u001B[38;5;241m1\u001B[39m) \u001B[38;5;28;01mif\u001B[39;00m endpoint \u001B[38;5;28;01melse\u001B[39;00m num\n\u001B[0;32m    126\u001B[0m \u001B[38;5;66;03m# Convert float/complex array scalars to float, gh-3504\u001B[39;00m\n\u001B[0;32m    127\u001B[0m \u001B[38;5;66;03m# and make sure one can use variables that have an __array_interface__, gh-6634\u001B[39;00m\n\u001B[1;32m--> 128\u001B[0m start \u001B[38;5;241m=\u001B[39m \u001B[43masanyarray\u001B[49m\u001B[43m(\u001B[49m\u001B[43mstart\u001B[49m\u001B[43m)\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m1.0\u001B[39;49m\n\u001B[0;32m    129\u001B[0m stop  \u001B[38;5;241m=\u001B[39m asanyarray(stop)  \u001B[38;5;241m*\u001B[39m \u001B[38;5;241m1.0\u001B[39m\n\u001B[0;32m    131\u001B[0m dt \u001B[38;5;241m=\u001B[39m result_type(start, stop, \u001B[38;5;28mfloat\u001B[39m(num))\n",
+      "File \u001B[1;32mE:\\flexsensor\\mcpy\\mcpy\\MCSamples.py:92\u001B[0m, in \u001B[0;36mMCSamples.__mul__\u001B[1;34m(self, other)\u001B[0m\n\u001B[0;32m     90\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(other, ud\u001B[38;5;241m.\u001B[39mUncertainty):\n\u001B[0;32m     91\u001B[0m     result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__mul__\u001B[39m(other\u001B[38;5;241m.\u001B[39mvnom)\n\u001B[1;32m---> 92\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(\u001B[43mresult\u001B[49m, np\u001B[38;5;241m.\u001B[39mndarray):\n\u001B[0;32m     93\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m MCSamples(result, unit\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39munit, definition\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mdefinition, description\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mdescription,\n\u001B[0;32m     94\u001B[0m                      coverage\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mcoverage)\n\u001B[0;32m     95\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\n",
+      "\u001B[1;31mUnboundLocalError\u001B[0m: local variable 'result' referenced before assignment"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": "<Figure size 640x480 with 1 Axes>",
+      "image/png": "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RseOHdPgwYMVHNw2Hx3X7uHicrkUFRXlNxYVFaW6uromb3E848wHVwEAAPtVV1f7PsDy27og3w49b9485eTk+H52u9267LLLVF1drfDw8E5cGQAAOF91dXVyOp3q27dvm91nu4dLdHS0ampq/MZqamoUHh7e4ucvOBwOORyOJuPh4eGECwAAlmnLl3m0+3cVpaSkqKyszG9s06ZNSklJae9dAwCALibgcPnvf/+ryspKVVZWSvrf250rKytVVVUl6X+XeTIzM33zp0+frn379unXv/61du/eraefflovv/yyZs+e3TaPAAAAdBsBh8t7772nUaNGadSoUZKknJwcjRo1yvftsl988YUvYiTpiiuu0MaNG7Vp0yaNHDlSy5Yt0x/+8AelpaW10UMAAADdhRUf+V9XV6eIiAi53W5e4wIAgCXa4/m73V/jAgAA0FYIFwAAYA3CBQAAWINwAQAA1iBcAACANQgXAABgDcIFAABYg3ABAADWIFwAAIA1CBcAAGANwgUAAFiDcAEAANYgXAAAgDUIFwAAYA3CBQAAWINwAQAA1iBcAACANQgXAABgDcIFAABYg3ABAADWIFwAAIA1CBcAAGANwgUAAFiDcAEAANYgXAAAgDUIFwAAYA3CBQAAWINwAQAA1iBcAACANQgXAABgDcIFAABYg3ABAADWIFwAAIA1CBcAAGANwgUAAFiDcAEAANYgXAAAgDUIFwAAYA3CBQAAWINwAQAA1iBcAACANQgXAABgDcIFAABYg3ABAADWIFwAAIA1CBcAAGANwgUAAFiDcAEAANYgXAAAgDUIFwAAYA3CBQAAWINwAQAA1iBcAACANQgXAABgDcIFAABYg3ABAADWIFwAAIA1CBcAAGANwgUAAFiDcAEAANYgXAAAgDUIFwAAYA3CBQAAWKNV4VJYWKjY2FiFhYUpOTlZ27dvP+v8goICDRs2TL169ZLT6dTs2bN18uTJVi0YAAB0XwGHy7p165STk6O8vDzt2LFDI0eOVFpamg4dOtTs/Jdeeklz585VXl6edu3apeeee07r1q3Tww8//K0XDwAAupeAw2X58uWaNm2apk6dqmuuuUZFRUW66KKL9Pzzzzc7f9u2bRozZowmTZqk2NhY3XLLLbr77rvPeZYGAADgmwIKl8bGRlVUVCg1NfWrOwgOVmpqqsrLy5vdZvTo0aqo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"
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "R21_ = 100                       # Ohm\n",
+    "delta_a_R21_ = (5e-3 * R21_) / 100    # Ohm\n",
+    "R21 = mcpy.Rectangular(R21_, delta_a_R21_)\n",
+    "print(R21)\n",
+    "R21.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:46.900624Z",
+     "end_time": "2023-05-14T11:43:47.165243Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "### Resistor R22\n",
+    "According to the corresponding datasheets VCS301.pdf [4, p. 1] the resistance tolerance is given\n",
+    "by +-1%."
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R22_ = 4e-3                    # Ohm\n",
+    "delta_a_R22_ = (1 * R22_) / 100    # Ohm\n",
+    "R22 = mcpy.Rectangular(R22_, delta_a_R22_)\n",
+    "print(R22)\n",
+    "R22.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:47.123525Z",
+     "end_time": "2023-05-14T11:43:47.414858Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R3_ = 10e3                   # Ohm\n",
+    "delta_a_R3_ = (5e-3 * R3_) / 100    # Ohm\n",
+    "R3 = mcpy.Rectangular(R3_, delta_a_R3_)\n",
+    "print(R3)\n",
+    "R3.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:47.371572Z",
+     "end_time": "2023-05-14T11:43:47.591376Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R4_ = 10e3\n",
+    "delta_R4_ = 0.5\n",
+    "R4 = mcpy.Rectangular(R4_, delta_R4_)\n",
+    "print(R4)\n",
+    "R4.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:47.594378Z",
+     "end_time": "2023-05-14T11:43:47.822000Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "## Uncertainties of the voltage measurements, u(UH) and u(U0)\n",
+    "The values of the 25 measurements are saved in the comma-separated-values (CSV)\n",
+    "file `VoltageMeasurments.csv`, with **U0** in the first column and **UH** in the second (both in Volts).\n",
+    "**U0** has been measured with the multimeter range *100mV* and **UH** with the range of *1V*."
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "measurements = pd.read_csv(\"VoltageMeasurements.csv\", sep=',', names=['u0', 'uh'])"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:47.808727Z",
+     "end_time": "2023-05-14T11:43:47.824863Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "U0_mean = mcpy.DirectObservations(measurements['u0'])\n",
+    "print(f\"{U0_mean.vnom:.3E}, sigma: {U0_mean.std:.3E}, ustd: {U0_mean.ustd:.3E}\")\n",
+    "U0_mean.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:47.824863Z",
+     "end_time": "2023-05-14T11:43:48.171169Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "UH_mean = mcpy.DirectObservations(measurements['uh'])\n",
+    "print(f\"{UH_mean.vnom:.3E}, sigma: {UH_mean.std:.3E}, ustd: {UH_mean.ustd:.3E}\")\n",
+    "UH_mean.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:48.171169Z",
+     "end_time": "2023-05-14T11:43:48.453684Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "## Standard uncertainty due to the accuracy u(U0;1)\n",
+    "u(U0;1) is the standard uncertainty due to the accuracy of the multimeter for the choosen\n",
+    "range. The range for U0 has been set to 100mV , the tightes tolerance is given with treading\n",
+    "U01 = 40e-3% and has to be applied on the reading as well as trange\n",
+    "U01 = 20e-3% for the\n",
+    "range."
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "U01_ = 100e-3                  # Ohm\n",
+    "delta_a_U01_ = (40e-3 * U0_mean.vnom + 20e-3*U01_) / 100    # Ohm\n",
+    "U01 = mcpy.Rectangular(U01_, delta_a_U01_)\n",
+    "print(U01)\n",
+    "U01.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:48.455684Z",
+     "end_time": "2023-05-14T11:43:48.729889Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "u(U0;2) is the standard uncertainty due to the digitization of the multimeter for the choosen\n",
+    "range. The range for U0 has been set to 100mV , the tightes tolerance is given with tResolution\n",
+    "U0;2 = 10:00 10􀀀6V . Since the range hast been set to 100mV the bounds aU0;2 has to be calculated\n",
+    "by using the range:"
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "U02_ = 100e-3                  # Ohm\n",
+    "delta_a_U02_ = (10e-6 /2)    # Ohm\n",
+    "print(delta_a_U02_)\n",
+    "U02 = mcpy.Rectangular(U02_, delta_a_U02_)\n",
+    "print(U02)\n",
+    "U02.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:48.707870Z",
+     "end_time": "2023-05-14T11:43:48.913271Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "Standard uncertainty due to the accuracy u(UH;1)\n",
+    "u(UH;1) is the standard uncertainty due to the accuracy of the multimeter for the choosen range.\n",
+    "The range for UH has been set to 1V , the tightes tolerance is given with treading\n",
+    "UH;1\n",
+    "= 30:00  10􀀀3%\n",
+    "and has to be applied on the reading as well as trange\n",
+    "UH;1\n",
+    "= 10:00  10􀀀3% for the range.\n",
+    "Assuming a rectangluar distribution, a can be be determined by:\n"
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "UH1_ = 1\n",
+    "delta_a_UH1_ = (30e-3 * UH_mean.vnom + 10e-3*UH1_) / 100    # Ohm\n",
+    "print(delta_a_UH1_)\n",
+    "UH1 = mcpy.Rectangular(UH1_, delta_a_UH1_)\n",
+    "print(UH1)\n",
+    "UH1.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:48.911271Z",
+     "end_time": "2023-05-14T11:43:49.110631Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "UH2_ = 100e-3                  # Ohm\n",
+    "delta_a_UH2_ = (100e-6 /2)    # Ohm\n",
+    "print(delta_a_UH2_)\n",
+    "UH2 = mcpy.Rectangular(UH2_, delta_a_UH2_)\n",
+    "print(UH2)\n",
+    "UH2.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:49.109625Z",
+     "end_time": "2023-05-14T11:43:49.375667Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "## Uncertainty of the Pt100 resistance deviation\n",
+    "At the measurement temperature, the tolerance of the Pt100 sensor (the maximum deviation\n",
+    "from the standard characteristic line) is given on the calibration certificate as +-6.7m."
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "delta_R1 = mcpy.Rectangular(0, 6.7e-3)\n",
+    "print(delta_R1)\n",
+    "delta_R1.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:49.376668Z",
+     "end_time": "2023-05-14T11:43:49.597460Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "## Uncertainty of the self heating\n",
+    "The self heating has been noted by a colleague as normally distributed with a mean of 6:7103\n",
+    "and a relative expanded uncertainty of Ur(s) = 40:00% for a coverage factor of k = 3."
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "uexp = ((40e-3*19e-3)/100)\n",
+    "u_delta_theta = mcpy.Normal(6.7e-3, uexp, 3)\n",
+    "print(u_delta_theta)\n",
+    "u_delta_theta.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:49.595458Z",
+     "end_time": "2023-05-14T11:43:49.800552Z"
+    }
+   }
+  },
+  {
+   "cell_type": "markdown",
+   "source": [
+    "# Monte Carlo Analysis"
+   ],
+   "metadata": {
+    "collapsed": false
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "RZ = mcpy.Uncertainty(vnom=105e-3)\n",
+    "RZ.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:49.801551Z",
+     "end_time": "2023-05-14T11:43:49.988714Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R2 = R21.rand(N) + R22.rand(N)\n",
+    "R2.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:49.989722Z",
+     "end_time": "2023-05-14T11:43:50.166002Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R3.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:50.165003Z",
+     "end_time": "2023-05-14T11:43:50.372054Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "R4.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:50.368052Z",
+     "end_time": "2023-05-14T11:43:50.571052Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "UH = UH_mean.rand(N) - UH1.rand(N) - UH2.rand(N)\n",
+    "#UH_mean.plot(N)\n",
+    "#UH1.plot(N)\n",
+    "#UH2.plot(N)\n",
+    "UH.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:50.571052Z",
+     "end_time": "2023-05-14T11:43:50.765244Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "U0 = U0_mean.rand(N) - U01.rand(N) - U02.rand(N)\n",
+    "#U0_mean.plot(N)\n",
+    "#U01.plot(N)\n",
+    "#U02.plot(N)\n",
+    "U0.plot(N)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:43:50.761243Z",
+     "end_time": "2023-05-14T11:43:51.010483Z"
+    }
+   }
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "outputs": [],
+   "source": [
+    "RL = mcpy.Uncertainty(vnom=42e-3)\n",
+    "# R1 = (R2 + RZ.rand(N)) * (( UH.rand(N) * ( R3.rand(N) + RZ.rand(N) ) - U0.rand(N) *\n",
+    "#                     ( R3.rand(N) + R4.rand(N) + 2 * RZ.rand(N)) ) /\n",
+    "#                   ( U0.rand(N) * ( R3.rand(N) + R4.rand(N) + 2 * RZ.rand(N) )\n",
+    "#                     + UH.rand(N) * ( R4.rand(N) + RZ.rand(N) ) )) \\\n",
+    "#      - RL.rand(N) - RZ.rand(N) + delta_R1.rand(N)\n",
+    "R1 = (R2 + RZ) * (( UH * ( R3 + RZ ) - U0 *\n",
+    "                    ( R3 + R4 + 2 * RZ) ) /\n",
+    "                  ( U0 * ( R3 + R4 + 2 * RZ )\n",
+    "                    + UH * ( R4 + RZ ) )) \\\n",
+    "     - RL - RZ + delta_R1\n",
+    "R1.plot(N)\n",
+    "print(R1)"
+   ],
+   "metadata": {
+    "collapsed": false,
+    "ExecuteTime": {
+     "start_time": "2023-05-14T11:34:28.436392Z",
+     "end_time": "2023-05-14T11:34:28.764518Z"
+    }
+   }
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 2
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython2",
+   "version": "2.7.6"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/example_Wheatstone_Bridge.py b/examples/example_Wheatstone_Bridge.py
new file mode 100644
index 0000000000000000000000000000000000000000..d09486fb5b2dd692901c3d59e4f49188d44c2aa2
--- /dev/null
+++ b/examples/example_Wheatstone_Bridge.py
@@ -0,0 +1,131 @@
+import os
+import sys
+
+sys.path.append('./src')
+import mcpy
+import pandas as pd
+
+from mcpy.BaseType.MCSamples import MCSamples
+
+print(mcpy.version)
+N = int((1 / (1 - 0.95)) * 10 ** 6)
+print(f"N={N}")
+
+# R21
+R21_ = 100  # Ohm
+delta_a_R21_ = (5e-3 * R21_) / 100  # Ohm
+R21 = mcpy.Rectangular(R21_, delta_a_R21_)
+#R21.mc_sample(200000)
+print(f"R21 = {R21}")
+#R21.generate_plot()
+
+R22_ = 4e-3  # Ohm
+delta_a_R22_ = (1 * R22_) / 100  # Ohm
+R22 = mcpy.Rectangular(R22_, delta_a_R22_)
+print(f"R22 = {R22}")
+#R22.plot(N)
+
+R3_ = 10e3  # Ohm
+delta_a_R3_ = (5e-3 * R3_) / 100  # Ohm
+R3 = mcpy.Rectangular(R3_, delta_a_R3_)
+print(f"R3 = {R3}")
+#R3.plot(N)
+
+R4_ = 10e3
+delta_R4_ = 0.5
+R4 = mcpy.Rectangular(R4_, delta_R4_)
+print(f"R4 = {R4}")
+#R4.plot(N)
+
+measurements = pd.read_csv("./examples/VoltageMeasurements.csv", sep=',', names=['u0', 'uh'])
+
+U0_mean = mcpy.DirectObservations(measurements['u0'])
+print(f"U0_mean = {U0_mean}")
+#U0_mean.plot(N)
+
+
+UH_mean = mcpy.DirectObservations(measurements['uh'])
+print(f"UH_mean = {UH_mean}")
+#UH_mean.plot(N)
+
+U01_ = 100e-3  # Ohm
+delta_a_U01_ = (40e-3 * float(U0_mean) + 20e-3 * U01_) / 100  # Ohm
+U01 = mcpy.Rectangular(0, delta_a_U01_)
+print(f"U01 = {U01}")
+#U01.plot(N)
+
+U02_ = 100e-3  # Ohm
+delta_a_U02_ = (10e-6 / 2)  # Ohm
+U02 = mcpy.Rectangular(0, delta_a_U02_)
+print(f"U02 = {U02}")
+#U02.plot(N)
+
+UH1_ = 1
+delta_a_UH1_ = (30e-3 * float(U0_mean) + 10e-3 * UH1_) / 100  # Ohm
+UH1 = mcpy.Rectangular(0, delta_a_UH1_)
+print(f"UH1 = {UH1}")
+#UH1.plot(N)
+
+UH2_ = 100e-3  # Ohm
+delta_a_UH2_ = (100e-6 / 2)  # Ohm
+UH2 = mcpy.Rectangular(0, delta_a_UH2_)
+print(f"UH2 = {UH2}")
+#UH2.plot(N)
+
+delta_R1 = mcpy.Rectangular(0, 6.7e-3)
+print(f"delta_R1 = {delta_R1}")
+#delta_R1.plot(N)
+
+uexp = ((40e-3 * 19e-3) / 100)
+u_delta_theta = mcpy.Normal(6.7e-3, uexp, 3)
+print(f"u_delta_theta = {u_delta_theta}")
+#u_delta_theta.plot(N)
+
+# ======================================================================================================================
+
+RZ = mcpy.Uncertainty(105e-3)
+print(f"RZ = {RZ}")
+#RZ.plot(N)
+
+R2: MCSamples = R21.mc_sample(N) + R22.mc_sample(N)
+print(f"R2 = {R2}")
+#R2.plot(N)
+
+#R3.plot(N)
+print(f"R3 = {R3}")
+
+#R4.plot(N)
+print(f"R4 = {R4}")
+
+UH: MCSamples = UH_mean.mc_sample(N) - UH1.mc_sample(N) - UH2.mc_sample(N)
+print(f"UH = {UH}")
+# UH_mean.plot(N)
+# UH1.plot(N)
+# UH2.plot(N)
+#UH.plot(N)
+
+U0 = U0_mean.mc_sample(N) - U01.mc_sample(N) - U02.mc_sample(N)
+print(f"U0 = {U0}")
+# U0_mean.plot(N)
+# U01.plot(N)
+# U02.plot(N)
+#U0.plot(N)
+
+RL = 42e-3#mcpy.Uncertainty(42e-3)
+print(f"RL = {RL}")
+R1: MCSamples = (R2 + RZ.mc_sample(N)) * ((UH.rand(N) * (R3.mc_sample(N) + RZ.mc_sample(N)) - U0.mc_sample(N) *
+                                           (R3.mc_sample(N) + R4.mc_sample(N) + 2 * RZ.mc_sample(N))) /
+                                          (U0.mc_sample(N) * (R3.mc_sample(N) + R4.mc_sample(N) + 2 * RZ.mc_sample(N))
+                                           + UH.rand(N) * (R4.mc_sample(N) + RZ.mc_sample(N)))) \
+                - RL - RZ.mc_sample(N) + delta_R1.mc_sample(N)
+print(f"R1 = {float(R1)} {R1.std}")
+R1.plot(N)
+
+R1 = (float(R2) + float(RZ)) * (
+        (float(UH) * (float(R3) + float(RZ)) - float(U0) * (float(R3) + float(R4) + float(RZ) * 2))
+        /
+        (float(U0) * (float(R3) + float(R4) + float(RZ) * 2) + float(UH) * (float(R4) + float(RZ)))
+) - float(RL) - float(RZ) + float(delta_R1)
+
+print(f"R1 = {R1}")
+R1.plot(N)
\ No newline at end of file
diff --git a/init.py b/init.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae73e89ea3f191f5bc3c8d8e1f30c70c3605ddb8
--- /dev/null
+++ b/init.py
@@ -0,0 +1,7 @@
+import os
+import sys
+from pathlib import Path
+
+path = str(Path(f"{os.path.dirname(os.path.realpath(__file__))}/mcpy").absolute())
+sys.path.append(path)
+print(path)
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..946cec066e9579d21ebd85d412c8a04e5e37765f
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,20 @@
+[project]
+name = "mcpy"
+version = "0.0.1b"
+authors = [
+  { name="Christoph Schmidt", email="cschmidt.fs@gmail.com" },
+]
+description = "A module for working with monte carlo analysis."
+readme = "README.md"
+requires-python = ">=3.7"
+dependencies = [
+    'pyside6','numpy','scipy','pandas','matplotlib','PySide6 '
+]
+classifiers = [
+    "Programming Language :: Python :: 3",
+    "License :: OSI Approved :: GNU General Public License v3.0",
+    "Operating System :: OS Independent",
+]
+
+[project.urls]
+"Homepage" = "https://gitlab.tugraz.at/flexsensor/mcpy"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f2ba6076426174259b0b502bf4909600fc2370e
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+numpy
+scipy
+pandas
+matplotlib
+PySide6
\ No newline at end of file
diff --git a/src/mcpy/BaseType/BaseFloat.py b/src/mcpy/BaseType/BaseFloat.py
new file mode 100644
index 0000000000000000000000000000000000000000..15e0d64e28ca464e1e52ae8d1bf80b7b164cae4d
--- /dev/null
+++ b/src/mcpy/BaseType/BaseFloat.py
@@ -0,0 +1,30 @@
+from decimal import Decimal
+class BaseFloat:
+    def __init__(self, vnom: float, unit: str = ""):
+        self._vnom: float = vnom
+        self._unit: str = unit if unit is not None else ""
+
+    @property
+    def unit(self):
+        return self._unit
+
+    @unit.setter
+    def unit(self, value):
+        self._unit = value
+
+    @property
+    def vnom(self):
+        return self._vnom
+
+    @vnom.setter
+    def vnom(self, value):
+        self._vnom = value
+
+    def __float__(self):
+        return float(self.vnom)
+
+    def __int__(self):
+        return int(self.vnom)
+
+    def __str__(self):
+        return f"{self.vnom} {self._unit}".strip()
diff --git a/src/mcpy/BaseType/MCSamples.py b/src/mcpy/BaseType/MCSamples.py
new file mode 100644
index 0000000000000000000000000000000000000000..4d4482e6f076da8bd96ce9b9118b8fe5c6be62ad
--- /dev/null
+++ b/src/mcpy/BaseType/MCSamples.py
@@ -0,0 +1,233 @@
+import numpy as np
+from scipy.stats import norm
+#import mcpy.BaseType.UncertaintyDistributions as ud
+
+
+class MCSamples(np.ndarray):
+    def __new__(cls, input_array,
+                coverage: float = None, k: float = None,
+                unit: str = "",
+                definition: str = None,
+                description: str = None):
+        obj = np.asarray(input_array).view(cls)
+        obj._mean = np.mean(input_array)
+        obj._std = np.std(input_array)
+
+        obj._unit = unit
+        obj._definition = definition
+        obj._description = description
+        #
+        if coverage is None and k is not None:
+            obj._k = k
+            obj._coverage = 1 - norm.pdf(k)
+        elif coverage is not None and k is None:
+            obj._coverage = coverage
+            obj._k = norm.ppf(obj._coverage)
+        else:
+            raise ValueError("Either coverage or k must be specified")
+
+        obj.layout = None
+        obj.figure = None
+        obj.canvas = None
+
+        return obj
+
+    @property
+    def N(self):
+        return len(self)
+
+    @property
+    def coverage(self):
+        return self._coverage
+
+    @coverage.setter
+    def coverage(self, value):
+        self._coverage = value
+        self._k = norm.ppf(self._coverage)
+
+    @property
+    def k(self):
+        return self._k
+
+    @k.setter
+    def k(self, value):
+        self._k = value
+        self._coverage = 1 - norm.pdf(self._k)
+
+
+    @property
+    def unit(self):
+        return self._unit
+
+    @unit.setter
+    def unit(self, value):
+        self._unit = value
+
+    @property
+    def definition(self):
+        return self._definition
+
+    @definition.setter
+    def definition(self, value):
+        self._definition = value
+
+    @property
+    def description(self):
+        return self._description
+
+    @description.setter
+    def description(self, value):
+        self._description = value
+
+
+    def rand(self, N):
+       return self
+
+    def plot(self):
+        #self.logger.debug("Generating plot for normal distribution")
+
+        try:
+            # import the necessary widgets
+            from PySide6 import QtWidgets, QtCore
+            from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+            from matplotlib.figure import Figure
+            from matplotlib import pyplot as plt
+            from matplotlib.ticker import ScalarFormatter
+
+        except ImportError as e:
+            self.logger.error("Unable to import necessary modules for generating plot")
+            raise e
+        plt.rcParams.update({'font.size': 8})
+
+        if self.layout is None:
+            self.layout = QtWidgets.QVBoxLayout()
+
+        if self.figure is None:
+            self.figure = plt.figure(figsize=(3, 10))
+
+        if self.canvas is None:
+            self.canvas = FigureCanvas(self.figure)
+
+        self.layout.addWidget(self.canvas)
+
+        self.figure.clear()
+        ax = self.figure.add_subplot(111)
+        #plt.title(self.__class__.__name__)
+        ax.hist(np.array(self), bins=100)
+        self.canvas.draw()
+        return self.layout
+
+    @property
+    def std(self):
+        return self._std
+
+    @property
+    def mean(self):
+        return self._mean
+
+
+    @property
+    def uncertainty(self):
+        from mcpy.BaseType.UncertaintyDistributions import Uncertainty
+        return Uncertainty(
+            float(self.mean),
+            ustd=float(self.std),
+            coverage=self.coverage,
+            unit=self.unit,
+            definition=self.definition,
+            description=self.description
+        )
+
+    def __array_finalize__(self, obj):
+        if obj is None:
+            return
+        # self.unit = getattr(obj, 'unit', None)
+        # self.definition = getattr(obj, 'definition', None)
+        # self.description = getattr(obj, 'description', None)
+        # self.coverage = getattr(obj, '_coverage', None)
+        # self._mean = getattr(obj, '_mean', None)
+        # self._std = getattr(obj, '_std', None)
+        # self.k = getattr(obj, '_k', None)
+        super().__array_finalize__(obj)
+
+    #def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *args, **kwargs):
+    #   print("std called")
+    #    return super().std(axis, dtype, out, ddof, keepdims, *args, **kwargs)
+
+    # def __array_wrap__(self, out_arr, context=None):
+    #     # Ensure the output is wrapped as an MCSamples instance
+    #     return np.ndarray.__array_wrap__(self, out_arr, context)
+    #
+    # def __getitem__(self, index):
+    #     result = super().__getitem__(index)
+    #     if isinstance(result, np.ndarray):
+    #         return MCSamples(result, unit=self.unit, definition=self.definition,description=self.description,
+    #                          coverage=self.coverage)
+    #     return result
+
+    def __add__(self, other):
+        if isinstance(other, float):
+            result = super().__add__(other)
+        else:
+            result = np.array(super().__add__(np.array(other)))
+        return MCSamples(result, unit=self.unit, definition=self.definition, description=self.description,
+                             coverage=self.coverage)
+
+    def __sub__(self, other):
+        if isinstance(other, float):
+            result = super().__sub__(other)
+        else:
+            result = np.array(super().__sub__(np.array(other)))
+        return MCSamples(result, unit=self.unit, definition=self.definition, description=self.description,
+                         coverage=self.coverage)
+    #
+    def __mul__(self, other):
+        if isinstance(other, float):
+            result = super().__mul__(other)
+        else:
+            result = np.array(super().__mul__(np.array(other)))
+        return MCSamples(result, unit=self.unit, definition=self.definition, description=self.description,
+                         coverage=self.coverage)
+    #
+    def __truediv__(self, other):
+        if isinstance(other, float):
+            result = super().__truediv__(other)
+        else:
+            result = np.array(super().__truediv__(np.array(other)))
+        return MCSamples(result, unit=self.unit, definition=self.definition, description=self.description,
+                         coverage=self.coverage)
+
+    def __repr__(self):
+        #if self.unit is not None:
+        #    #return f"MCSamples({super().__repr__()}, unit={self.unit})"
+        #else:
+        #    return super().__repr__()
+        return f"MCSamples"#({self.mean:.3E}, ustd {self.uncertainty.ustd:.3E}, N={len(self)})"
+
+    def __str__(self):
+        return f"MCSamples({self.uncertainty.value:.3E}, ustd {self.uncertainty.ustd:.3E}, N={len(self)})"
+
+    def __float__(self) -> float:
+        if isinstance(self, MCSamples):
+            return float(self.mean)
+
+class MCSamplesUI():
+    pass
+
+if __name__ == "__main__":
+    np1 = np.array([1, 2, 3, 4, 5])
+    R21 = MCSamples([1, 2, 3, 4, 5])
+    print(f"R21 : {R21}")
+    np2 = np.array([5, 2, 6, 1, 9])
+    R22 = MCSamples([5, 2, 6, 1, 9])
+    print(f"R22: {R22}")
+    R2 = R21 + R22
+    print(f"R2: {R2}")
+    R2.plot(N)
+
+    RZ = ud.Uncertainty(105e-3)
+    print(f"R2: {RZ}")
+    # Test adding a MC sample with an distribution
+    #R1 = (float(R2) + float(RZ))#
+    #R1 = (R2 + RZ)#
+    #print(f"R1: {R1}")
\ No newline at end of file
diff --git a/src/mcpy/BaseType/UIBaseClass.py b/src/mcpy/BaseType/UIBaseClass.py
new file mode 100644
index 0000000000000000000000000000000000000000..3186f8a81578d7c48f20180495eef43b78a53c71
--- /dev/null
+++ b/src/mcpy/BaseType/UIBaseClass.py
@@ -0,0 +1,95 @@
+class UIBase(object):
+    def __init__(self, parent, logger):
+        self._x = None
+        self._y = None
+        self.parent = parent
+        self.logger = logger
+        self.layout = None
+        self.figure = None
+        self.canvas = None
+
+    def generate_ui(self):
+        raise NotImplementedError
+
+    def generate_plot(self):
+        self.logger.debug("Generating plot for normal distribution")
+
+        try:
+            # import the necessary widgets
+            from PySide6 import QtWidgets, QtCore
+            from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+            from matplotlib.figure import Figure
+            from matplotlib import pyplot as plt
+            from matplotlib.ticker import ScalarFormatter
+
+        except ImportError as e:
+            self.logger.error("Unable to import necessary modules for generating plot")
+            raise e
+        plt.rcParams.update({'font.size': 8})
+
+        if self.layout is None:
+            self.layout = QtWidgets.QVBoxLayout()
+
+        if self.figure is None:
+            self.figure = plt.figure(figsize=(3, 10))
+
+        if self.canvas is None:
+            self.canvas = FigureCanvas(self.figure)
+
+        self.layout.addWidget(self.canvas)
+
+        # Generate data points for the rectangular distribution (implemented by the subclass)
+        self._x, self._y = self._plot_points()
+
+        # Clear the existing plot and plot the new data
+        self.figure.clear()
+        ax = self.figure.add_subplot(111)
+
+        self._set_axis(ax)  # Set the axis formatting (implemented by the subclass)
+        self._show_confidence_interval(ax)  # Show the confidence interval (implemented by the subclass)
+
+        # PLot the data
+        self._plot(ax)
+        y_formatter = ScalarFormatter(useOffset=True)
+        ax.yaxis.set_major_formatter(y_formatter)
+
+        self._set_labels(ax)  # Set the labels (x-axis, y-axis and title) for the plot (implemented by the subclass)
+       # self.figure.tight_layout()
+
+        self.canvas.draw()
+        return self.layout
+
+    def _plot(self, ax):
+        ax.plot(self._x, self._y, linewidth=1)
+
+    def _plot_points(self):
+        '''
+        Defines the x and y plot points for the distribution. Must be
+        implemented by the subclass
+        :return:
+        '''
+        raise NotImplementedError("This method must be implemented by the subclass")
+
+    def _set_axis(self, ax):
+        '''
+        Sets the axis labels for the plot. Must be implemented by the subclass
+        :param ax:
+        :return:
+        '''
+        raise NotImplementedError("This method must be implemented by the subclass")
+
+    def _show_confidence_interval(self, ax):
+        '''
+        Shows the confidence interval on the plot. Must be implemented by the subclass
+        :param ax:
+        :return:
+        '''
+        raise NotImplementedError("This method must be implemented by the subclass")
+
+    def _set_labels(self, ax):
+        '''
+        Sets the labels (x-axis, y-axis and title) for the plot. Must be implemented by the subclass
+        :param ax:
+        :return:
+        '''
+        raise NotImplementedError("This method must be implemented by the subclass")
diff --git a/src/mcpy/BaseType/UncertaintyDistributions.py b/src/mcpy/BaseType/UncertaintyDistributions.py
new file mode 100644
index 0000000000000000000000000000000000000000..882ee2ea656d9aac073b4398fd792312997cd2dc
--- /dev/null
+++ b/src/mcpy/BaseType/UncertaintyDistributions.py
@@ -0,0 +1,267 @@
+import logging
+import sqlite3
+from abc import abstractmethod
+from typing import Dict, Any
+
+import numpy as np
+import pandas as pd
+from matplotlib import pyplot as plt
+from pandas.core.arrays import ExtensionScalarOpsMixin, ExtensionArray
+from pandas.core.dtypes.base import register_extension_dtype, ExtensionDtype
+from pandas.core.dtypes.dtypes import PandasExtensionDtype
+from scipy.stats import norm
+
+
+#import mcpy
+from mcpy.BaseType.UIBaseClass import UIBase
+
+
+class Uncertainty:
+    NORMAL = "Normal"
+    RECTANGULAR = "Rectangular"
+    TRIANGULAR = "Triangular"
+    UNIFORM = "Uniform"
+    DIRECT_OBSERVATION = "Direct Observation"
+
+    TYPE_A = "Type A"
+    TYPE_B = "Type B"
+
+
+    NONE = "None"
+
+    LIST_TYPE_B = [NORMAL, RECTANGULAR, TRIANGULAR, UNIFORM, NONE]
+    LIST_TYPE = [TYPE_A, TYPE_B]
+
+    def __init__(self, value: float,
+                 coverage: float = None, k: float = None,
+                 unit: str = "1", definition: str = None, description: str = None, ustd: float = 0,
+                 *args, **kwargs):
+
+        self.logger = logging.getLogger(__name__)
+
+        self.type = self.NONE
+        self.distribution = self.NONE
+
+        # self.__new__(value)
+        self._value = value
+        self._unit = unit
+        self._definition = definition
+        self._description = description
+
+        if coverage is None and k is not None:
+            self._k = k
+            self._coverage = 1-norm.pdf(k)
+        elif coverage is not None and k is None:
+            self._coverage = coverage
+            self._k = norm.ppf(self._coverage)
+        elif coverage is None and k is None:
+            self.logger.warning(f"No coverage or k value was given. Using default coverage of 0.95. k = {k}")
+            self._coverage = 0.95
+            self._k = norm.ppf(self._coverage)
+
+        self._ustd = ustd
+        self._uexp = self._calc_uexp(self._ustd)
+
+        self._mcsamples = None
+        # return obj
+
+        self._ui = UIBase(self, self.logger)
+
+    @property
+    def ui(self) -> UIBase:
+        return self._ui
+    # ==================================================================================================================
+    # Properties
+    # ==================================================================================================================
+    @property
+    def value(self):
+        return self._value
+
+    @property
+    def coverage(self):
+        return self._coverage
+
+    @property
+    def k(self):
+        return self._k
+
+    @property
+    def unit(self):
+        return self._unit
+
+    @property
+    def ustd(self):
+        if self._ustd is None:
+            raise NotImplementedError("The standard uncertainty has not been implemented!")
+        return self._ustd
+
+    @property
+    def uexp(self):
+        if self._uexp is None:
+            raise NotImplementedError("The expanded uncertainty has not been implemented!")
+        return self._uexp
+
+    # ==================================================================================================================
+    # Properties & Setters
+    # ==================================================================================================================
+    @property
+    def definition(self):
+        return self._definition
+
+    @definition.setter
+    def definition(self, value):
+        self._definition = value
+
+    @property
+    def description(self):
+        return self._description
+
+    @description.setter
+    def description(self, value):
+        self._description = value
+
+    # ==================================================================================================================
+    # Calculations
+    # ==================================================================================================================
+    def _calc_uexp(self, standard_uncertainty):
+        """
+            Calculation of the expanded uncertainty according to
+            GUM
+        """
+        if standard_uncertainty is None:
+            return None
+        return self.k * standard_uncertainty
+
+    def _calc_std(self, *args, **kwargs):
+        raise NotImplementedError
+
+    # ==================================================================================================================
+    # Uncertainty distribution functions
+    # ==================================================================================================================
+    def rand_t(self, N, n, mu, sigma):
+        """
+            Draw samples from a standard Student's t distribution with `n-1` degrees
+            of freedom for mean of n measurements of variable
+            distributed normally with expectation `std` and standard deviation
+            `sigma`.
+            @arg N: Number of samples to draw
+            @arg n: Number of measurement samples (degrees of freedom = n-1)
+            @arg mu: expectation
+            @arg sigma: standard deviation
+            @return probability distribution
+        """
+        nu = n - 1
+        return mu + np.random.standard_t(nu, N) * (sigma / np.sqrt(n))
+
+    def rand_n(self, N, mu, sigma):
+        """
+            Normally distributed samples with expectation `mu` and standard
+            deviation `sigma`.
+            @arg N: Number of samples to draw
+            @arg mu: expectation
+            @arg sigma: standard deviation
+            @return probability distribution
+        """
+        return mu + np.random.standard_normal(N) * sigma
+
+    def rand_r(self, N, a, b):
+        """
+            Rectangularly distributed samples in the interval [a,b]
+            @arg N: Number of samples to draw
+            @arg a: lower bound
+            @arg b: upper bound
+            @return probability distribution
+        """
+        return a + np.random.random(N) * (b - a)
+
+    def rand_trap(self, N, a, b, d):
+        """
+            Rectangularly distributed samples in the interval [a,b]
+            @arg N: Number of samples to draw
+            @arg a: lower bound
+            @arg b: upper bound
+            @arg d: upper bound
+            @return probability distribution
+        """
+        return a + ((b - a) / 2) * ((1 + d) * np.random.random(N) + (1 - d) * np.random.random(N))
+
+    # ==================================================================================================================
+    #
+    # ==================================================================================================================
+    def mc_sample(self, N=None):
+        if N is None and self._mcsamples is not None:
+            return self._mcsamples
+        elif N is not None and self._mcsamples is None:
+            self._mcsamples = mcpy.MCSamples(np.zeros(N) + float(self))
+        else:
+            raise ValueError("N is None and no samples have been generated yet!")
+        return self._mcsamples
+
+    def _get_params(self) -> dict:
+        return {'value': float(self),
+                'coverage': self.coverage if self.coverage is not None else "NaN",
+                'unit': self.unit if self.unit is not None else "NaN",
+                'definition': self.definition if self.definition is not None else "NaN",
+                'description': self.description if self.description is not None else "NaN",
+                'type': self.type if self.type is not None else "NaN",
+                'distribution': self.distribution if self.distribution is not None else "NaN"
+                }
+
+    def to_dict(self) -> dict:
+        tup = self._get_params()
+        if tup is None:
+            tup = "NaN"
+        tup = {**tup}
+        return tup
+
+    @classmethod
+    def from_dict(cls, tup):
+        if tup['distribution'] == "Normal":
+            return mcpy.Normal(**tup)
+        elif tup['distribution'] == "StudentT":
+            return mcpy.StudentT(**tup)
+        elif tup['distribution'] == "Rectangular":
+            return mcpy.Rectangular(**tup)
+        elif tup['distribution'] == "Triangular":
+            return mcpy.Triangular(**tup)
+        elif tup['distribution'] == "Trapezoidal":
+            return mcpy.Trapezoidal(**tup)
+        else:
+            raise ValueError(f"Unknown type {tup['type']}!")
+
+    #def generate_ui(self) -> 'QGridLayout':
+    #    raise NotImplementedError("The uncertainty UI interface has not been implemented!")
+
+    # ==================================================================================================================
+    #
+    # ==================================================================================================================
+    def __float__(self):
+        # return str(self.as_dataframe())
+        return float(self.value)
+
+    def __int__(self):
+        # return str(self.as_dataframe())
+        return int(self.value)
+
+    def __repr__(self):
+        # return str(self.as_dataframe())
+        #return f"{np.round(self, 3)} +- {np.round(self.uexp, 3)}"
+        return str(self)
+
+    def __str__(self):
+        # return str(self.as_dataframe())
+        return f"{np.round(float(self), 3)} +- {np.round(self.uexp, 3)}"
+
+
+if __name__ == "__main__":
+    # pd.api.extensions.register_extension_dtype(UncertaintyDtype)
+    N = 1000000
+
+    R1 = 10
+    a1 = 5e-3
+    rect1 = mcpy.Rectangular(R1, a1)
+    rect2 = mcpy.Triangular(R1, a1)
+    result1 = rect1.mc_sample(N) + rect2.mc_sample(N) + mcpy.Uncertainty(2).mc_sample(N)
+    result2 = float(rect1) + float(rect2) + 2
+    print(result1)
+    print(result2)
diff --git a/src/mcpy/BaseType/__init__.py b/src/mcpy/BaseType/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/mcpy/TypeAUncertainty/DirectObservations.py b/src/mcpy/TypeAUncertainty/DirectObservations.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ad80c3c7b7d9dca648610de565e3adbfc8dc0d7
--- /dev/null
+++ b/src/mcpy/TypeAUncertainty/DirectObservations.py
@@ -0,0 +1,226 @@
+import logging
+import math
+
+import numpy as np
+import pandas as pd
+from numpy import ndarray
+
+import mcpy
+from mcpy.BaseType.MCSamples import MCSamples
+from mcpy.BaseType.UIBaseClass import UIBase
+from mcpy.userinterface.DataFrameViewer import DataFrameViewer
+
+
+class DirectObservations(mcpy.Uncertainty):
+
+    def __init__(self, observations: ndarray, method: str = "Direct", unc_eval: str = "Experimental",
+                 **kwargs):
+        arg_value = float(np.mean(observations))
+        super().__init__(arg_value, **kwargs)
+        self.type = self.TYPE_A
+        self.distribution = self.DIRECT_OBSERVATION
+
+        self._observations = observations
+        self._n = len(self._observations)
+        self._method = method
+        self._unc_eval = unc_eval
+
+        self._std = float(np.std(self._observations, ddof=1))
+        self._ustd = self._calc_ustd(self.std)
+        self._uexp = self._calc_uexp(self._ustd)
+
+        self._ui: UIBase = DirectObservationsUI(self)
+
+    @property
+    def n(self):
+        return self._n
+
+    @property
+    def method(self):
+        return self._method
+
+    @property
+    def unc_eval(self):
+        return self._unc_eval
+
+    @property
+    def std(self):
+        return self._std
+
+    @property
+    def coverage(self):
+        return self._coverage
+
+    @coverage.setter
+    def coverage(self, value):
+        self._coverage = value
+
+    def _calc_ustd(self, standard_deviation: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.9, p. 25, Formular (13).
+            for a Student-t distribution made from observations
+        """
+        return np.sqrt((self._n - 1) / (self._n - 3)) * standard_deviation / np.sqrt(self._n)
+
+    def as_dataframe(self):
+        return pd.DataFrame(data={
+            'Definition': self.definition,
+            'Value': self.vnom,
+            'Standard Deviation': self.std,
+            'Standard Uncertainty': self.ustd,
+            'Expanded Uncertainty': self.uexp,
+            "Distribution": "Student-t"
+        }, index=[0])
+
+    def mc_sample(self, N):
+        """
+        Generate N samples for a MC analysis
+        """
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_t(N, self.n, float(self), self.std))
+        return self._mcsamples
+
+    def to_dict(self) -> tuple:
+        tup = self._get_params()
+        tup = {**tup, **{'observations': self.observations, 'method': self.method, 'unc_eval': self.unc_eval}}
+        return (self.__class__.__name__, tup)
+
+    def __str__(self):
+        st = f"Obs({float(self):.2E}, {self.std:.2E}) [ustd = {self.ustd:.2E}, uexp({self.coverage}) = {self.uexp:.2E}]"
+
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}"
+
+    def __repr__(self):
+        return str(self)
+
+
+class DirectObservationsUI(UIBase):
+    def __init__(self, parent: DirectObservations, logger=None):
+        if logger is None:
+            self.logger = logging.getLogger(__name__)
+        else:
+            self.logger = logger
+
+        super().__init__(parent, self.logger)
+
+        self.value = self.parent.value
+        self.std = self.parent.std
+
+    # ==================================================================================================================
+    # UI Element Functions
+    # ==================================================================================================================
+
+    def _plot_points(self):
+        x = np.linspace(self.value - 3 * self.std, self.value + 3 * self.std, 1000)
+        y = (1 / (self.std * math.sqrt(2 * math.pi))) * np.exp(-0.5 * ((x - self.value) / self.std) ** 2)
+        return x, y
+
+    def _set_axis(self, ax):
+        # Adapt the axis text, so it just shows the mean and the standard deviation
+        ax.set_xticks([self.value - self.parent.k * self.std,
+                       self.value - self.std,
+                       self.value,
+                       self.value + self.std,
+                       self.value + self.parent.k * self.std])
+
+        ax.set_xticklabels([f'{self.value - self.parent.k * self.std:.2E}',
+                            f'{self.value - self.std:.2E}',
+                            f'{self.value:.2E}',
+                            f'{self.value + self.std:.2E}',
+                            f'{self.value + self.parent.k * self.std:.2E}'], fontsize=8)
+
+    def _show_confidence_interval(self, ax):
+        ax.axvline(self.value - self.std, color='red', linestyle='--')
+        ax.axvline(self.value + self.std, color='red', linestyle='--')
+
+        ax.axvline(self.value - self.parent.k * self.std, color='orange')
+        ax.axvline(self.value + self.parent.k * self.std, color='orange')
+        # Add a text to the plot
+        ax.text(self.value - self.parent.k * self.std, 0.1, f' {self.parent.coverage * 100:.0f}% CI', color='red')
+
+    def _set_labels(self, ax):
+        ax.set_xlabel('$x$')
+        ax.set_ylabel('Probability Density (PDF)')
+        ax.set_title(f'Normal: $\mu$={self.value:.5E}, $\sigma$={self.std:.3E}', fontsize=10)
+
+
+    def generate_ui(self):
+        print("Generating UI")
+        # import the necessary widgets
+        from PySide6 import QtWidgets, QtCore
+        # Create a new grid layout
+        layout = QtWidgets.QGridLayout()
+
+        lbl_num_of_obs = QtWidgets.QLabel("Number of Observations")
+        txt_num_of_obs = QtWidgets.QLineEdit(str(self.parent.n))
+        lbl_num_of_obs.setBuddy(txt_num_of_obs)
+        layout.addWidget(lbl_num_of_obs, 0, 0)
+        layout.addWidget(txt_num_of_obs, 0, 1, 1, 2)
+        btn_data = QtWidgets.QPushButton("Data")
+        layout.addWidget(btn_data, 0, 3)
+
+        self.obs_viewer = DataFrameViewer(self.parent._observations)
+        btn_data.clicked.connect(self.obs_viewer.show)
+
+        # Add a line in between
+        line = QtWidgets.QFrame()
+        line.setFrameShape(QtWidgets.QFrame.HLine)
+        line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        layout.addWidget(line, 1, 0, 1, 4)
+
+        # Create a label textfield buddy
+        lbl_value = QtWidgets.QLabel(f"Value [{self.parent.unit}]")
+        txt_value = QtWidgets.QLineEdit(str(self.value))
+        lbl_value.setBuddy(txt_value)
+
+        # Add to the layout
+        layout.addWidget(lbl_value, 2, 0)
+        layout.addWidget(txt_value, 2, 1, 1, 3)
+
+        lbl_std = QtWidgets.QLabel(f"Standard Deviation [{self.parent.unit}]")
+        txt_std = QtWidgets.QLineEdit(f"{self.std:.2E}")
+        lbl_std.setBuddy(txt_std)
+        layout.addWidget(lbl_std, 3, 0)
+        layout.addWidget(txt_std, 3, 1, 1, 3)
+
+        lbl_usd = QtWidgets.QLabel(f"Standard Uncertainty [{self.parent.unit}]")
+        txt_usd = QtWidgets.QLineEdit(f"{self.parent.ustd:.2E}")
+        lbl_usd.setBuddy(txt_usd)
+        layout.addWidget(lbl_usd, 4, 0)
+        layout.addWidget(txt_usd, 4, 1, 1, 3)
+
+        # Add a line in between
+        line = QtWidgets.QFrame()
+        line.setFrameShape(QtWidgets.QFrame.HLine)
+        line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        layout.addWidget(line, 5, 0, 1, 4)
+
+        lbl_coverage = QtWidgets.QLabel("Coverage [%]")
+        txt_coverage = QtWidgets.QLineEdit(f"{self.parent.coverage * 100:.2f}")
+        lbl_coverage.setBuddy(txt_coverage)
+        lbl_k = QtWidgets.QLabel("Coverage Factor")
+        txt_k = QtWidgets.QLineEdit(str(self.parent.k))
+        lbl_k.setBuddy(txt_k)
+        layout.addWidget(lbl_coverage, 6, 0)
+        layout.addWidget(txt_coverage, 6, 1)
+        layout.addWidget(lbl_k, 6, 2)
+        layout.addWidget(txt_k, 6, 3)
+
+        lbl_uexp = QtWidgets.QLabel("Expanded Uncertainty")
+        txt_uexp = QtWidgets.QLineEdit(f"{self.parent.uexp:.2E}")
+        lbl_uexp.setBuddy(txt_uexp)
+        layout.addWidget(lbl_uexp, 7, 0)
+        layout.addWidget(txt_uexp, 7, 1, 1, 3)
+
+        print(f"UI generated {layout}")
+        return layout
+
+if __name__ == "__main__":
+    obs = [1, 2, 3, 4, 5, 6]
+    from_obs = DirectObservations(obs)
+
+    print(from_obs)
diff --git a/src/mcpy/TypeAUncertainty/__init__.py b/src/mcpy/TypeAUncertainty/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/mcpy/TypeBUncertainty/Normal.py b/src/mcpy/TypeBUncertainty/Normal.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c6396454d4e3b827594c55659bae0e434f691b8
--- /dev/null
+++ b/src/mcpy/TypeBUncertainty/Normal.py
@@ -0,0 +1,168 @@
+import logging
+import math
+import numpy as np
+
+
+from mcpy.BaseType.MCSamples import MCSamples
+from mcpy.BaseType.UIBaseClass import UIBase
+from mcpy.BaseType.UncertaintyDistributions import Uncertainty
+
+
+class Normal(Uncertainty):
+
+    def __init__(self, value: float, uexp: float, coverage: float = None, k: float = None, *args, **kwargs):
+        super().__init__(value, coverage=coverage, k=k, *args, **kwargs)
+        self.type = self.TYPE_B
+        self.distribution = self.NORMAL
+
+        self._uexp = uexp  # Expanded uncertainty
+        self._ustd = self._calc_ustd(self._uexp)
+        self._std = self._ustd
+
+        self._ui = NormalUI(self)
+
+    @property
+    def ui(self) -> UIBase:
+        return self._ui
+
+    @property
+    def std(self):
+        return self._std
+
+    def mc_sample(self, N=None) -> MCSamples:
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_n(N, float(self), self.std), k=self.k)
+        return self._mcsamples
+
+    def _calc_ustd(self, expanded_uncertainty: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.9, p. 25, Formular (13).
+            for a Student-t distribution made from observations
+        """
+        return expanded_uncertainty / self.k
+
+    def to_dict(self) -> dict:
+        tup = super().to_dict()
+        tup = {**tup, **{'uexp': self.uexp, 'coverage': self.coverage}}
+        return tup
+
+    def __str__(self):
+        st = f"Normal({float(self):.2E}, {self.std:.2E}) [ustd = {self.ustd:.2E}, uexp({self.coverage:.3E}) = {self.uexp:.3E}]"
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}]"
+
+
+
+class NormalUI(UIBase):
+    def __init__(self, parent: Normal, logger=None):
+        if logger is None:
+            self.logger = logging.getLogger(__name__)
+        else:
+            self.logger = logger
+
+        super().__init__(parent, self.logger)
+
+        self.value = self.parent.value
+        self.std = self.parent.std
+
+    # ==================================================================================================================
+    # UI Element Functions
+    # ==================================================================================================================
+    def _plot_points(self):
+        x = np.linspace(self.value - 3 * self.std, self.value + 3 * self.std, 1000)
+        y = (1 / (self.std * math.sqrt(2 * math.pi))) * np.exp(-0.5 * ((x - self.value) / self.std) ** 2)
+        # Norm y to 1
+        y = y / np.max(y)
+        return x, y
+
+    def _set_axis(self, ax):
+
+        # Adapt the axis text, so it just shows the mean and the standard deviation
+        ax.set_xticks([self.value - self.parent.k * self.std,
+                       self.value - self.std,
+                       self.value,
+                       self.value + self.std,
+                       self.value + self.parent.k * self.std])
+
+        ax.set_xticklabels([f'{self.parent.k * self.std:.2E}',
+                            f'{ self.std:.2E}',
+                            0,
+                            f'{self.std:.2E}',
+                            f'{self.parent.k * self.std:.2E}'], fontsize=8)
+        ax.text(1, -0.12, "+%g" % self.value, transform=ax.transAxes, horizontalalignment='right', fontsize=9)
+
+    def _show_confidence_interval(self, ax):
+        ax.axvline(self.value - self.std, color='red', linestyle='--')
+        ax.axvline(self.value + self.std, color='red', linestyle='--')
+        ax.text(self.value - self.std, 1, f' $\sigma$', color='red')
+
+        ax.axvline(self.value - self.parent.k * self.std, color='orange')
+        ax.axvline(self.value + self.parent.k * self.std, color='orange')
+        ax.text(self.value - self.parent.k * self.std, 1, f' {self.parent.coverage * 100:.0f}% CI', color='orange')
+
+    def _set_labels(self, ax):
+        ax.set_xlabel('X')
+        ax.set_ylabel('Probability Density')
+        ax.set_title(f'Normal: $\mu$={self.value}, $\sigma$={self.std:.2E}')
+
+    def generate_ui(self):
+        print("Generating UI")
+        # Import the necessary widgets
+        from PySide6 import QtWidgets, QtCore
+        # Create a new grid layout
+        layout = QtWidgets.QGridLayout()
+
+        # Create a label textfield buddy
+        lbl_value = QtWidgets.QLabel(f"Value [{self.parent.unit}]")
+        txt_value = QtWidgets.QLineEdit(f"{self.value}")
+        lbl_value.setBuddy(txt_value)
+        # Add to the layout
+        layout.addWidget(lbl_value, 0, 0)
+        layout.addWidget(txt_value, 0, 1, 1, 3)
+
+        lbl_std = QtWidgets.QLabel(f"Standard Deviation [{self.parent.unit}]")
+        txt_std = QtWidgets.QLineEdit(f"{self.std:.2E}")
+        lbl_std.setBuddy(txt_std)
+        layout.addWidget(lbl_std, 1, 0)
+        layout.addWidget(txt_std, 1, 1, 1, 3)
+
+        lbl_usd = QtWidgets.QLabel(f"Standard Uncertainty [{self.parent.unit}]")
+        txt_usd = QtWidgets.QLineEdit(f"{self.parent.ustd:.2E}")
+        lbl_usd.setBuddy(txt_usd)
+        layout.addWidget(lbl_usd, 2, 0)
+        layout.addWidget(txt_usd, 2, 1, 1, 3)
+
+        # Add a line in between
+        line = QtWidgets.QFrame()
+        line.setFrameShape(QtWidgets.QFrame.HLine)
+        line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        layout.addWidget(line, 3, 0, 1, 4)
+
+        lbl_coverage = QtWidgets.QLabel("Coverage [%]")
+        txt_coverage = QtWidgets.QLineEdit(f"{self.parent.coverage * 100:.2f}")
+        lbl_coverage.setBuddy(txt_coverage)
+        lbl_k = QtWidgets.QLabel("Coverage Factor")
+        txt_k = QtWidgets.QLineEdit(f"{self.parent.k}")
+        lbl_k.setBuddy(txt_k)
+        layout.addWidget(lbl_coverage, 4, 0)
+        layout.addWidget(txt_coverage, 4, 1)
+        layout.addWidget(lbl_k, 4, 2)
+        layout.addWidget(txt_k, 4, 3)
+
+
+        lbl_uexp = QtWidgets.QLabel("Expanded Uncertainty")
+        txt_uexp = QtWidgets.QLineEdit(f"{self.parent.uexp}")
+        lbl_uexp.setBuddy(txt_uexp)
+        layout.addWidget(lbl_uexp, 5, 0)
+        layout.addWidget(txt_uexp, 5, 1, 1, 3)
+        print(f"UI generated {layout}")
+        return layout
+
+
+if __name__ == "__main__":
+    uexp = ((40e-3 * 19e-3) / 100)
+    normal = Normal(6.7e-3, uexp, 3)
+    print(normal)
diff --git a/src/mcpy/TypeBUncertainty/Rectangular.py b/src/mcpy/TypeBUncertainty/Rectangular.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3b287a0bddfca34da80f604c493d1d8d3573809
--- /dev/null
+++ b/src/mcpy/TypeBUncertainty/Rectangular.py
@@ -0,0 +1,233 @@
+import logging
+
+import numpy as np
+
+from mcpy import Uncertainty
+from mcpy.BaseType.MCSamples import MCSamples
+from mcpy.BaseType.UIBaseClass import UIBase
+
+
+class Rectangular(Uncertainty):
+
+    def __init__(self, value: float, hlim: float, *args, **kwargs):
+        """
+            Defines a rectangular distribution where an input value is distributed equally over a certain range.
+            Arguments:
+                vnom (float): Input Value
+                hlim (float): The half span between limits (a, b) of the variability of the quantity
+                (Halfwidth of Limits field)
+            Keyword Arguemtns:
+                definition (str):
+                unit (str):
+                description (str):
+        """
+        super().__init__(value, *args, **kwargs)
+        self.type = self.TYPE_B
+        self.distribution = self.RECTANGULAR
+
+        self._hlim = hlim  # Halfwidth of Limits
+        self._a = float(self) - self.hlim
+        self._b = float(self) + self.hlim
+        self._ustd = self._calc_ustd(self._hlim)
+        self._uexp = self._calc_uexp(self._ustd)
+
+        self._ui = RectangularUI(self, self.logger)
+
+    @property
+    def a(self):
+        return self._a
+
+    @property
+    def b(self):
+        return self._b
+
+    @property
+    def hlim(self):
+        return self._hlim
+
+    def _calc_ustd(self, hlim: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.2, p. 19
+            for a rectangular distribution
+        """
+        return hlim / np.sqrt(3)
+
+    def mc_sample(self, N=None) -> MCSamples:
+        print(f"Generating {N} samples for {self}")
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_r(N, self.a, self.b), k=self.k)
+        return self._mcsamples
+
+    def to_dict(self) -> dict:
+        tup = super().to_dict()
+        tup = {**tup, **{'hlim': self.hlim, 'a': self.a, 'b': self.b}}
+        return tup
+
+    def generate_plot(self):
+        print("Generating Plot")
+
+        # import the necessary widgets
+        from PySide6.QtWidgets import QVBoxLayout
+        from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+        from matplotlib import pyplot as plt
+
+        layout = QVBoxLayout()
+
+        figure = plt.figure()
+        canvas = FigureCanvas(figure)
+        layout.addWidget(canvas)
+
+        # Clear the existing plot and plot the new data
+        figure.clear()
+        ax = figure.add_subplot(111)
+        a = self.a
+        b = self.b
+        # Add vertical lines
+        ax.plot([a, a], [0, 1 / (b - a)], 'r')
+        ax.plot([b, b], [0, 1 / (b - a)], 'r')
+
+        # Add horizontal line
+        ax.plot([a, b], [0, 1 / (self.parent.b - self.parent.a)], 'r')
+        # Draw vertical lines at a and b
+        # ax.axvline(self.a, color='r', linestyle='--', label='Lower Bound (a)')
+        # ax.axvline(self.b, color='g', linestyle='--', label='Upper Bound (b)')
+
+        ax.set_xlabel('X')
+        ax.set_ylabel('Probability Density')
+        ax.set_title(f'Rectangular')
+        canvas.draw()
+
+        return layout
+
+    def __str__(self):
+        st = f"Rect({self.a:.2E}, {self.b:.2E}) [ustd = {self.ustd:.2E}, uexp({self.coverage}) = {self.uexp:.2E}]"
+
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}"
+
+
+
+class RectangularUI(UIBase):
+    def __init__(self, parent: Rectangular, logger=None):
+        if logger is None:
+            self.logger = logging.getLogger(__name__)
+        else:
+            self.logger = logger
+
+        super().__init__(parent, self.logger)
+
+    # ==================================================================================================================
+    # UI Element Functions
+    # ==================================================================================================================
+    def _plot_points(self):
+        # Generate data points for the rectangular distribution
+        # plot a rectangle with height h and width a but leave the bottom side open
+        x = [self.parent.value - self.parent.hlim * 1.5, self.parent.value - self.parent.hlim,
+             self.parent.value - self.parent.hlim,
+             self.parent.value + self.parent.hlim, self.parent.value + self.parent.hlim,
+             self.parent.value + self.parent.hlim * 1.5]
+        y = [0, 0, 1, 1, 0, 0]
+        # Concat the data points
+        return x, y
+
+    def _set_axis(self, ax):
+        pass
+        # # Adapt the axis text, so it just shows the mean and the standard deviation
+        # ax.set_xticks([self.value - self.parent.k * self.std,
+        #                self.value - self.std,
+        #                self.value,
+        #                self.value + self.std,
+        #                self.value + self.parent.k * self.std])
+        #
+        # ax.set_xticklabels([f'{self.parent.k * self.std:.2E}',
+        #                     f'{ self.std:.2E}',
+        #                     0,
+        #                     f'{self.std:.2E}',
+        #                     f'{self.parent.k * self.std:.2E}'], fontsize=8)
+        # ax.text(1, -0.12, "+%g" % self.value, transform=ax.transAxes, horizontalalignment='right', fontsize=9)
+
+    def _show_confidence_interval(self, ax):
+        pass
+        ax.axvline(self.parent.value, color='red', linestyle='--')
+        ax.text(self.parent.value, 0.9, f' $\mu$', color='red')
+        # Draw an arrow between the mean and the confidence interval
+        ax.annotate("", xy=(self.parent.value - self.parent.hlim, 0.5), xytext=(self.parent.value, 0.5),
+                    arrowprops=dict(arrowstyle="<->", color='orange'))
+        # Add a text
+        ax.text(self.parent.value - self.parent.hlim / 2, 0.45, f' $a$', color='orange', horizontalalignment='center')
+
+    def _set_labels(self, ax):
+        ax.set_xlabel('$x$')
+        ax.set_ylabel('Probability Density ($PDF$)')
+        ax.set_title(f'Rectangular: $\mu$ = {self.parent.value}, $a$={self.parent.a}')
+
+    def generate_ui(self):
+        print("Generating UI")
+        # Import the necessary widgets
+        from PySide6 import QtWidgets
+        # Create a new grid layout
+        layout = QtWidgets.QGridLayout()
+
+        # Create a label textfield buddy
+        lbl_value = QtWidgets.QLabel(f"Value [{self.parent.unit}]")
+        txt_value = QtWidgets.QLineEdit(f"{self.parent.value}")
+        lbl_value.setBuddy(txt_value)
+        # Add to the layout
+        layout.addWidget(lbl_value, 0, 0)
+        layout.addWidget(txt_value, 0, 1, 1, 3)
+
+        lbl_hlim = QtWidgets.QLabel(f"Halfwidth of Limits [{self.parent.unit}]")
+        txt_hlim = QtWidgets.QLineEdit(f"{self.parent.hlim:.2E}")
+        lbl_hlim.setBuddy(txt_hlim)
+        layout.addWidget(lbl_hlim, 1, 0)
+        layout.addWidget(txt_hlim, 1, 1)
+
+        lbl_limits = QtWidgets.QLabel(f"Limits  [{self.parent.unit}]")
+        txt_limits = QtWidgets.QLineEdit(f"({self.parent.a:.2f}, {self.parent.b:.2f})")
+        lbl_limits.setBuddy(txt_limits)
+        layout.addWidget(lbl_limits, 1, 2)
+        layout.addWidget(txt_limits, 1, 3)
+
+        lbl_usd = QtWidgets.QLabel(f"Standard Uncertainty [{self.parent.unit}]")
+        txt_usd = QtWidgets.QLineEdit(f"{self.parent.ustd:.2E}")
+        lbl_usd.setBuddy(txt_usd)
+        layout.addWidget(lbl_usd, 2, 0)
+        layout.addWidget(txt_usd, 2, 1, 1, 3)
+
+        # Add a line in between
+        line = QtWidgets.QFrame()
+        line.setFrameShape(QtWidgets.QFrame.HLine)
+        line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        layout.addWidget(line, 3, 0, 1, 4)
+
+        lbl_coverage = QtWidgets.QLabel("Coverage [%]")
+        txt_coverage = QtWidgets.QLineEdit(f"{self.parent.coverage * 100:.2f}")
+        lbl_coverage.setBuddy(txt_coverage)
+        lbl_k = QtWidgets.QLabel("Coverage Factor")
+        txt_k = QtWidgets.QLineEdit(f"{self.parent.k}")
+        lbl_k.setBuddy(txt_k)
+        layout.addWidget(lbl_coverage, 4, 0)
+        layout.addWidget(txt_coverage, 4, 1)
+        layout.addWidget(lbl_k, 4, 2)
+        layout.addWidget(txt_k, 4, 3)
+
+        lbl_uexp = QtWidgets.QLabel("Expanded Uncertainty")
+        txt_uexp = QtWidgets.QLineEdit(f"{self.parent.uexp:.2E}")
+        lbl_uexp.setBuddy(txt_uexp)
+        layout.addWidget(lbl_uexp, 5, 0)
+        layout.addWidget(txt_uexp, 5, 1, 1, 3)
+        print(f"UI generated {layout}")
+        return layout
+
+
+if __name__ == "__main__":
+    R1 = 100
+    a1 = 5e-3
+    R1_l = R1 - a1
+    R1_u = R1 + a1
+
+    rect1 = Rectangular(R1, a1)
+    print(rect1)
diff --git a/src/mcpy/TypeBUncertainty/StudentT.py b/src/mcpy/TypeBUncertainty/StudentT.py
new file mode 100644
index 0000000000000000000000000000000000000000..3268ef1ca36db1bf2c02b95cc8ef64128555b508
--- /dev/null
+++ b/src/mcpy/TypeBUncertainty/StudentT.py
@@ -0,0 +1,53 @@
+import numpy as np
+from scipy.stats import norm
+
+from mcpy import Uncertainty
+
+
+class StudentT(Uncertainty):
+
+
+    def __init__(self, value: float, uexp: float, df: float, *args, **kwargs):
+        super().__init__(value, *args, **kwargs)
+        self._uexp = uexp  # Expanded uncertainty
+        self._df = df  # Degrees of freedom
+        self._ustd = self._calc_ustd(self._uexp)
+        self._std = self._ustd * np.sqrt(self.df - 1)
+
+    @property
+    def df(self):
+        return self._df
+
+    @property
+    def std(self):
+        return self._std
+
+    def _calc_ustd(self, expanded_uncertainty: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.9, p. 25, Formular (13).
+            for a Student-t distribution made from observations
+        """
+        return expanded_uncertainty / self.k
+
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_t(N, self.df - 1, self.vnom, self.std))
+        return self._mcsamples
+
+    def __str__(self):
+        st = f"StudentT({self:.2E}, {self.std:.2E}) [ustd = {self.ustd:.2E}, uexp({self.coverage:.3E}) = {self.uexp:.3E}]"
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}]"
+
+    def to_dict(self) -> dict:
+        tup = super().to_dict()
+        tup = {**tup, **{'uexp': self.uexp, 'df': self.df}}
+        return tup
+
+if __name__ == "__main__":
+    uexp = ((40e-3 * 19e-3) / 100)
+    df = 24
+    studentt = StudentT(6.7e-3, uexp, 24)
+    print(studentt)
\ No newline at end of file
diff --git a/src/mcpy/TypeBUncertainty/Trapezoidal.py b/src/mcpy/TypeBUncertainty/Trapezoidal.py
new file mode 100644
index 0000000000000000000000000000000000000000..bea1bb640779cc6a114e452149da37d1706a8cbe
--- /dev/null
+++ b/src/mcpy/TypeBUncertainty/Trapezoidal.py
@@ -0,0 +1,90 @@
+from mcpy import Uncertainty
+from mcpy.BaseType.MCSamples import MCSamples
+
+
+class Trapezoidal(Uncertainty):
+    def __init__(self, value: float, hlim: float, d: float, *args, **kwargs):
+        """
+            Defines a trapezoidal distribution where an input value is distributed equally over a certain range.
+            Arguments:
+                vnom (float): Input Value
+                hlim (float): The half span between limits (a, b) of the variability of the quantity
+                (Halfwidth of Limits field)
+                sfac (float): The shape factor beta (0 to 1) determines the width of the section over which the
+                distribution is even, compared to the total width. All distributions between rectangular (b = 1)
+                and triangular distribution (b = 0) are possible
+            Keyword Arguemtns:
+                definition (str):
+                unit (str):
+                description (str):
+        """
+        super().__init__(value, *args, **kwargs)
+        self._hlim = hlim  # Halfwidth of Limits
+        self._a = float(self) - self.hlim
+        self._b = float(self) + self.hlim
+        if 0 <= d <= 1:
+            self._d = d  # Shapefactor
+        else:
+            raise ValueError(f"The shapefactor (beta) must be between 0 and 1 (given {d}).")
+        self._ustd = self._calc_ustd(float(self), self.hlim)
+        self._uexp = self._calc_uexp(self._ustd)
+
+    @property
+    def a(self):
+        return self._a
+
+    @property
+    def b(self):
+        return self._b
+
+    @property
+    def d(self):
+        return self._d
+
+    @d.setter
+    def d(self, value):
+        self._d = value
+
+
+    @property
+    def hlim(self):
+        return self._hlim
+
+    @hlim.setter
+    def hlim(self, value):
+        self._hlim = value
+
+    def _calc_ustd(self, a: float, b: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.4, p. 22
+            for a trapezoidal distribution
+        """
+        return ((b - a) ** 2 / 24) * (1 + self.d ** 2)
+
+    def mc_sample(self, N) -> MCSamples:
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_trap(N, self.a, self.b, self.d))
+        return self._mcsamples
+
+    def to_dict(self) -> dict:
+        tup = super().to_dict()
+        tup = {**tup, **{'hlim': self.hlim, 'd': self.d}}
+        return tup
+
+    def __str__(self):
+        st = f"Trap({self.a:.2E}, {self.b:.2E}, {self.d:.3E}) [ustd = {self.ustd:.2E}, uexp({self.coverage}) = {self.uexp:.2E}]"
+
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}"
+
+if __name__ == "__main__":
+    R1 = 100
+    a1 = 5e-3
+    R1_l = R1 - a1
+    R1_u = R1 + a1
+
+    trapez = Trapezoidal(R1, a1, 0.8)
+    print(trapez)
\ No newline at end of file
diff --git a/src/mcpy/TypeBUncertainty/Triangluar.py b/src/mcpy/TypeBUncertainty/Triangluar.py
new file mode 100644
index 0000000000000000000000000000000000000000..d847e41dd4208b2c59228dd52a0af91c3ba2fe4c
--- /dev/null
+++ b/src/mcpy/TypeBUncertainty/Triangluar.py
@@ -0,0 +1,61 @@
+from mcpy import Uncertainty
+from mcpy.BaseType.MCSamples import MCSamples
+from mcpy.UncertaintyTypes.TypeBUncertainty import TypeBUncertainty
+
+
+class Triangular(Uncertainty):
+    def __init__(self, value: float, hlim: float, *args, **kwargs):
+        super().__init__(value, *args, **kwargs)
+        self._mcsamples = None
+        self._hlim = hlim  # Halfwidth of Limits
+        self._a = float(self) - self.hlim
+        self._b = float(self) + self.hlim
+        self._ustd = self._calc_ustd(self.a, self.b)
+        self._uexp = self._calc_uexp(self._ustd)
+
+    @property
+    def a(self):
+        return self._a
+
+    @property
+    def b(self):
+        return self._b
+
+    @property
+    def hlim(self):
+        return self._hlim
+
+    def _calc_ustd(self, a: float, b: float):
+        """
+            Calculation of the standard uncertainty according to
+            GUM Supplement 1 (JCGM 101:2008), section 6.4.5.3, p. 23
+            for a trapezoidal distribution
+        """
+        return ((b - a) ** 2 / 24)
+
+    def mc_sample(self, N) -> MCSamples:
+        if self._mcsamples is None:
+            self._mcsamples = MCSamples(self.rand_trap(N, self.a, self.b, 0))
+        return self._mcsamples
+
+    def to_dict(self) -> dict:
+        tup = super().to_dict()
+        tup = {**tup, **{'hlim': self.hlim}}
+        return tup
+
+    def __str__(self):
+        st = f"Triangular({self.a:.2E}, {self.b:.2E}) [ustd = {self.ustd:.2E}, uexp({self.coverage}) = {self.uexp:.2E}]"
+
+        if self.definition is None or self.definition == "":
+            return st
+        else:
+            return f"{self.definition} = {st}"
+
+if __name__ == "__main__":
+    R1 = 100
+    a1 = 5e-3
+    R1_l = R1 - a1
+    R1_u = R1 + a1
+
+    trapez = Triangular(R1, a1)
+    print(trapez)
\ No newline at end of file
diff --git a/src/mcpy/TypeBUncertainty/__init__.py b/src/mcpy/TypeBUncertainty/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/mcpy/UncertaintyTypes/TypeADistribution.py b/src/mcpy/UncertaintyTypes/TypeADistribution.py
new file mode 100644
index 0000000000000000000000000000000000000000..e79e5ad2051dae1077c646488a691720577f1896
--- /dev/null
+++ b/src/mcpy/UncertaintyTypes/TypeADistribution.py
@@ -0,0 +1,22 @@
+from abc import ABC
+
+import numpy as np
+from numpy import ndarray
+
+from mcpy import Uncertainty
+
+
+class TypeAUncertainty(Uncertainty, ABC):
+    def __init__(self, observations: ndarray, *args, **kwargs):
+        self._observations: ndarray = observations
+        self._n = len(self._observations)
+        self._vnom = float(np.mean(self._observations))
+        super().__init__(vnom=self._vnom, *args, **kwargs)
+
+    @property
+    def observations(self):
+        return self._observations
+
+    @property
+    def n(self):
+        return self._n
diff --git a/src/mcpy/UncertaintyTypes/TypeBUncertainty.py b/src/mcpy/UncertaintyTypes/TypeBUncertainty.py
new file mode 100644
index 0000000000000000000000000000000000000000..a19adde541ad490d986eb32360ca95df4a65b976
--- /dev/null
+++ b/src/mcpy/UncertaintyTypes/TypeBUncertainty.py
@@ -0,0 +1,9 @@
+from abc import ABC
+
+import mcpy.BaseType.UncertaintyDistributions as ud
+
+
+class TypeBUncertainty(ud.Uncertainty, ABC):
+    def __init__(self, vnom: float, *args, **kwargs):
+        super().__init__(vnom, *args, **kwargs)
+
diff --git a/src/mcpy/UncertaintyTypes/__init__.py b/src/mcpy/UncertaintyTypes/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/mcpy/__init__.py b/src/mcpy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..722907b4ecb82ff322277a3d76bf5299c10a3b04
--- /dev/null
+++ b/src/mcpy/__init__.py
@@ -0,0 +1,16 @@
+import os
+import sys
+
+
+from .BaseType.UncertaintyDistributions import Uncertainty
+from .TypeAUncertainty.DirectObservations import DirectObservations
+from .TypeBUncertainty.Normal import Normal
+from .TypeBUncertainty.StudentT import StudentT
+from .TypeBUncertainty.Rectangular import Rectangular
+from .TypeBUncertainty.Trapezoidal import Trapezoidal
+from .TypeBUncertainty.Triangluar import Triangular
+from .BaseType.MCSamples import MCSamples
+from .BaseType.UIBaseClass import UIBase
+from .userinterface.UncertaintyWidget import UncertaintyWidget
+
+from .__version__ import version
\ No newline at end of file
diff --git a/src/mcpy/__version__.py b/src/mcpy/__version__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f1580cd565bc78589c568ddcc3e73597c62d77b
--- /dev/null
+++ b/src/mcpy/__version__.py
@@ -0,0 +1 @@
+version = '0.1b'
\ No newline at end of file
diff --git a/src/mcpy/userinterface/DataFrameViewer.py b/src/mcpy/userinterface/DataFrameViewer.py
new file mode 100644
index 0000000000000000000000000000000000000000..2382b5eb9fda290fddd515a1bc56d1b43ab1314e
--- /dev/null
+++ b/src/mcpy/userinterface/DataFrameViewer.py
@@ -0,0 +1,42 @@
+import numpy as np
+from PySide6.QtGui import QStandardItemModel, QStandardItem
+from PySide6.QtWidgets import QTableView, QMainWindow, QTableWidgetItem, QVBoxLayout, QWidget, QTableWidget
+
+
+class DataFrameViewer(QMainWindow):
+    def __init__(self, data):
+        super().__init__()
+
+        self.setWindowTitle("NumPy Array Table View")
+        self.setGeometry(100, 100, 600, 400)
+
+        # Create a QTableWidget to display the data
+        self.table_widget = QTableWidget(self)
+        if isinstance(data, list):
+            data = np.array(data).reshape((len(data), 1))
+        self.set_data(data.reshape((len(data), 1)))
+
+        # Set the table as the central widget
+        central_widget = QWidget()
+        layout = QVBoxLayout()
+        layout.addWidget(self.table_widget)
+        central_widget.setLayout(layout)
+        self.setCentralWidget(central_widget)
+
+    def set_data(self, data):
+        # Check if the input is a NumPy array
+        if not isinstance(data, np.ndarray):
+            raise ValueError(f"Input must be a NumPy array, got {type(data)}")
+
+        # Get the dimensions of the array
+        num_rows, num_cols = data.shape
+
+        # Set the number of rows and columns in the table
+        self.table_widget.setRowCount(num_rows)
+        self.table_widget.setColumnCount(num_cols)
+
+        # Fill the table with data from the NumPy array
+        for row in range(num_rows):
+            for col in range(num_cols):
+                item = QTableWidgetItem(str(data[row, col]))
+                self.table_widget.setItem(row, col, item)
\ No newline at end of file
diff --git a/src/mcpy/userinterface/MCMWidget.py b/src/mcpy/userinterface/MCMWidget.py
new file mode 100644
index 0000000000000000000000000000000000000000..809aab794b0882fc2549fe123f678065e48280ba
--- /dev/null
+++ b/src/mcpy/userinterface/MCMWidget.py
@@ -0,0 +1,38 @@
+from PySide6.QtWidgets import QWidget
+
+from mcpy.BaseType import MCSamples
+from mcpy.userinterface.Ui_MCControlWidget import Ui_MCControlWindow
+
+
+class MonteCarloWidget(QWidget):
+    # Init the UI file
+    def __init__(self, mc_samples: MCSamples = None, parent=None, logger=None):
+        super().__init__()
+        self._ui = Ui_MCControlWindow()
+        self._ui.setupUi(self)
+        self._mc_samples: MCSamples = None
+
+        if mc_samples is not None:
+            self.mc_samples: MCSamples = mc_samples
+            self._update_ui()
+        else:
+            self._ui.text_samples_n.setText("No MCM sampled data!")
+
+    @property
+    def mc_samples(self) -> MCSamples:
+        return self._mc_samples
+
+    @mc_samples.setter
+    def mc_samples(self, value: MCSamples):
+        self._mc_samples = value
+        self._update_ui()
+
+    def _update_ui(self):
+        self._ui.text_samples_n.setText(f"{self.mc_samples.N}")
+        self._ui.txt_mean.setText(f"{self.mc_samples.mean:.3E}")
+        self._ui.txt_std.setText(f"{self.mc_samples.std:.3E}")
+        self._ui.txt_cov.setText(f"{self.mc_samples.coverage*100:.3f}%")
+        self._ui.txt_cov_factor.setText(f"{self.mc_samples.k}")
+        self._ui.txt_unit.setText(f"{self.mc_samples.unit}")
+
+        self._ui.grd_plot_area.addLayout(self.mc_samples.plot(), 0, 0)
diff --git a/src/mcpy/userinterface/Ui_MCControlWidget.py b/src/mcpy/userinterface/Ui_MCControlWidget.py
new file mode 100644
index 0000000000000000000000000000000000000000..7df1e7691920c1e83b02364884e906eabadeae16
--- /dev/null
+++ b/src/mcpy/userinterface/Ui_MCControlWidget.py
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'MCControlWidget.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+    QMetaObject, QObject, QPoint, QRect,
+    QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+    QFont, QFontDatabase, QGradient, QIcon,
+    QImage, QKeySequence, QLinearGradient, QPainter,
+    QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QLabel,
+    QLineEdit, QPlainTextEdit, QSizePolicy, QTabWidget,
+    QWidget)
+
+class Ui_MCControlWindow(object):
+    def setupUi(self, MCControlWindow):
+        if not MCControlWindow.objectName():
+            MCControlWindow.setObjectName(u"MCControlWindow")
+        MCControlWindow.resize(510, 532)
+        self.gridLayout_2 = QGridLayout(MCControlWindow)
+        self.gridLayout_2.setObjectName(u"gridLayout_2")
+        self.grd_mcm_members = QGridLayout()
+        self.grd_mcm_members.setObjectName(u"grd_mcm_members")
+        self.gridLayout_3 = QGridLayout()
+        self.gridLayout_3.setObjectName(u"gridLayout_3")
+        self.lbl_samples_n = QLabel(MCControlWindow)
+        self.lbl_samples_n.setObjectName(u"lbl_samples_n")
+
+        self.gridLayout_3.addWidget(self.lbl_samples_n, 1, 1, 1, 1)
+
+        self.lbl_exp_uncert = QLabel(MCControlWindow)
+        self.lbl_exp_uncert.setObjectName(u"lbl_exp_uncert")
+
+        self.gridLayout_3.addWidget(self.lbl_exp_uncert, 7, 1, 1, 1)
+
+        self.label_3 = QLabel(MCControlWindow)
+        self.label_3.setObjectName(u"label_3")
+
+        self.gridLayout_3.addWidget(self.label_3, 2, 1, 1, 1)
+
+        self.txt_std = QLineEdit(MCControlWindow)
+        self.txt_std.setObjectName(u"txt_std")
+
+        self.gridLayout_3.addWidget(self.txt_std, 3, 2, 1, 3)
+
+        self.txt_cov = QLineEdit(MCControlWindow)
+        self.txt_cov.setObjectName(u"txt_cov")
+
+        self.gridLayout_3.addWidget(self.txt_cov, 5, 2, 1, 1)
+
+        self.text_samples_n = QLineEdit(MCControlWindow)
+        self.text_samples_n.setObjectName(u"text_samples_n")
+
+        self.gridLayout_3.addWidget(self.text_samples_n, 1, 2, 1, 3)
+
+        self.lbl_cov_factor = QLabel(MCControlWindow)
+        self.lbl_cov_factor.setObjectName(u"lbl_cov_factor")
+
+        self.gridLayout_3.addWidget(self.lbl_cov_factor, 5, 3, 1, 1)
+
+        self.txt_mean = QLineEdit(MCControlWindow)
+        self.txt_mean.setObjectName(u"txt_mean")
+
+        self.gridLayout_3.addWidget(self.txt_mean, 2, 2, 1, 3)
+
+        self.lbl_coverage = QLabel(MCControlWindow)
+        self.lbl_coverage.setObjectName(u"lbl_coverage")
+
+        self.gridLayout_3.addWidget(self.lbl_coverage, 5, 1, 1, 1)
+
+        self.frame_2 = QFrame(MCControlWindow)
+        self.frame_2.setObjectName(u"frame_2")
+        self.frame_2.setFrameShape(QFrame.HLine)
+        self.frame_2.setFrameShadow(QFrame.Sunken)
+
+        self.gridLayout_3.addWidget(self.frame_2, 8, 1, 1, 4)
+
+        self.txt_unit = QLineEdit(MCControlWindow)
+        self.txt_unit.setObjectName(u"txt_unit")
+
+        self.gridLayout_3.addWidget(self.txt_unit, 9, 2, 1, 3)
+
+        self.lbl_std = QLabel(MCControlWindow)
+        self.lbl_std.setObjectName(u"lbl_std")
+
+        self.gridLayout_3.addWidget(self.lbl_std, 3, 1, 1, 1)
+
+        self.frame = QFrame(MCControlWindow)
+        self.frame.setObjectName(u"frame")
+        self.frame.setFrameShape(QFrame.HLine)
+        self.frame.setFrameShadow(QFrame.Sunken)
+
+        self.gridLayout_3.addWidget(self.frame, 4, 1, 1, 4)
+
+        self.txt_cov_factor = QLineEdit(MCControlWindow)
+        self.txt_cov_factor.setObjectName(u"txt_cov_factor")
+
+        self.gridLayout_3.addWidget(self.txt_cov_factor, 5, 4, 1, 1)
+
+        self.lbl_unit = QLabel(MCControlWindow)
+        self.lbl_unit.setObjectName(u"lbl_unit")
+
+        self.gridLayout_3.addWidget(self.lbl_unit, 9, 1, 1, 1)
+
+        self.lineEdit_3 = QLineEdit(MCControlWindow)
+        self.lineEdit_3.setObjectName(u"lineEdit_3")
+
+        self.gridLayout_3.addWidget(self.lineEdit_3, 7, 2, 1, 3)
+
+        self.label = QLabel(MCControlWindow)
+        self.label.setObjectName(u"label")
+        font = QFont()
+        font.setPointSize(11)
+        font.setBold(True)
+        self.label.setFont(font)
+
+        self.gridLayout_3.addWidget(self.label, 0, 1, 1, 4)
+
+
+        self.grd_mcm_members.addLayout(self.gridLayout_3, 0, 1, 1, 1)
+
+
+        self.gridLayout_2.addLayout(self.grd_mcm_members, 0, 0, 1, 1)
+
+        self.tabWidget = QTabWidget(MCControlWindow)
+        self.tabWidget.setObjectName(u"tabWidget")
+        self.tab_plot_area = QWidget()
+        self.tab_plot_area.setObjectName(u"tab_plot_area")
+        self.grd_plot_area = QGridLayout(self.tab_plot_area)
+        self.grd_plot_area.setObjectName(u"grd_plot_area")
+        self.tabWidget.addTab(self.tab_plot_area, "")
+        self.tab_description = QWidget()
+        self.tab_description.setObjectName(u"tab_description")
+        self.gridLayout_6 = QGridLayout(self.tab_description)
+        self.gridLayout_6.setObjectName(u"gridLayout_6")
+        self.gridLayout_5 = QGridLayout()
+        self.gridLayout_5.setObjectName(u"gridLayout_5")
+        self.lbl_description = QLabel(self.tab_description)
+        self.lbl_description.setObjectName(u"lbl_description")
+
+        self.gridLayout_5.addWidget(self.lbl_description, 0, 0, 1, 1)
+
+        self.txt_description = QPlainTextEdit(self.tab_description)
+        self.txt_description.setObjectName(u"txt_description")
+        self.txt_description.setMaximumSize(QSize(16777215, 250))
+
+        self.gridLayout_5.addWidget(self.txt_description, 1, 0, 1, 1)
+
+
+        self.gridLayout_6.addLayout(self.gridLayout_5, 0, 0, 1, 1)
+
+        self.tabWidget.addTab(self.tab_description, "")
+
+        self.gridLayout_2.addWidget(self.tabWidget, 1, 0, 1, 1)
+
+
+        self.retranslateUi(MCControlWindow)
+
+        self.tabWidget.setCurrentIndex(0)
+
+
+        QMetaObject.connectSlotsByName(MCControlWindow)
+    # setupUi
+
+    def retranslateUi(self, MCControlWindow):
+        MCControlWindow.setWindowTitle(QCoreApplication.translate("MCControlWindow", u"Form", None))
+        self.lbl_samples_n.setText(QCoreApplication.translate("MCControlWindow", u"Number of Samples", None))
+        self.lbl_exp_uncert.setText(QCoreApplication.translate("MCControlWindow", u"Expanded Uncertainty", None))
+        self.label_3.setText(QCoreApplication.translate("MCControlWindow", u"Mean", None))
+        self.lbl_cov_factor.setText(QCoreApplication.translate("MCControlWindow", u"Coverage Factor", None))
+        self.lbl_coverage.setText(QCoreApplication.translate("MCControlWindow", u"Coverage [%]", None))
+        self.lbl_std.setText(QCoreApplication.translate("MCControlWindow", u"Standard Deviation", None))
+        self.lbl_unit.setText(QCoreApplication.translate("MCControlWindow", u"Unit", None))
+        self.label.setText(QCoreApplication.translate("MCControlWindow", u"Monte Carlo Samples", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_plot_area), QCoreApplication.translate("MCControlWindow", u"Sample Plot", None))
+        self.lbl_description.setText(QCoreApplication.translate("MCControlWindow", u"Description", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_description), QCoreApplication.translate("MCControlWindow", u"Description", None))
+    # retranslateUi
+
diff --git a/src/mcpy/userinterface/Ui_MCMControlWidget.py b/src/mcpy/userinterface/Ui_MCMControlWidget.py
new file mode 100644
index 0000000000000000000000000000000000000000..c7e7753da2d63502f81dc4949a0103c4fe77d3fe
--- /dev/null
+++ b/src/mcpy/userinterface/Ui_MCMControlWidget.py
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'MCMControlWidget.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+    QMetaObject, QObject, QPoint, QRect,
+    QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+    QFont, QFontDatabase, QGradient, QIcon,
+    QImage, QKeySequence, QLinearGradient, QPainter,
+    QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QLabel,
+    QLineEdit, QPlainTextEdit, QSizePolicy, QTabWidget,
+    QWidget)
+
+class Ui_MCMControlWindow(object):
+    def setupUi(self, MCMControlWindow):
+        if not MCMControlWindow.objectName():
+            MCMControlWindow.setObjectName(u"MCMControlWindow")
+        MCMControlWindow.resize(510, 532)
+        self.gridLayout_2 = QGridLayout(MCMControlWindow)
+        self.gridLayout_2.setObjectName(u"gridLayout_2")
+        self.grd_mcm_members = QGridLayout()
+        self.grd_mcm_members.setObjectName(u"grd_mcm_members")
+        self.gridLayout_3 = QGridLayout()
+        self.gridLayout_3.setObjectName(u"gridLayout_3")
+        self.lbl_samples_n = QLabel(MCMControlWindow)
+        self.lbl_samples_n.setObjectName(u"lbl_samples_n")
+
+        self.gridLayout_3.addWidget(self.lbl_samples_n, 1, 1, 1, 1)
+
+        self.label_2 = QLabel(MCMControlWindow)
+        self.label_2.setObjectName(u"label_2")
+
+        self.gridLayout_3.addWidget(self.label_2, 7, 1, 1, 1)
+
+        self.label_3 = QLabel(MCMControlWindow)
+        self.label_3.setObjectName(u"label_3")
+
+        self.gridLayout_3.addWidget(self.label_3, 2, 1, 1, 1)
+
+        self.txt_std = QLineEdit(MCMControlWindow)
+        self.txt_std.setObjectName(u"txt_std")
+
+        self.gridLayout_3.addWidget(self.txt_std, 3, 2, 1, 3)
+
+        self.lineEdit = QLineEdit(MCMControlWindow)
+        self.lineEdit.setObjectName(u"lineEdit")
+
+        self.gridLayout_3.addWidget(self.lineEdit, 5, 2, 1, 1)
+
+        self.text_samples_n = QLineEdit(MCMControlWindow)
+        self.text_samples_n.setObjectName(u"text_samples_n")
+
+        self.gridLayout_3.addWidget(self.text_samples_n, 1, 2, 1, 3)
+
+        self.lbl_cov_factor = QLabel(MCMControlWindow)
+        self.lbl_cov_factor.setObjectName(u"lbl_cov_factor")
+
+        self.gridLayout_3.addWidget(self.lbl_cov_factor, 5, 3, 1, 1)
+
+        self.txt_mean = QLineEdit(MCMControlWindow)
+        self.txt_mean.setObjectName(u"txt_mean")
+
+        self.gridLayout_3.addWidget(self.txt_mean, 2, 2, 1, 3)
+
+        self.lbl_coverage = QLabel(MCMControlWindow)
+        self.lbl_coverage.setObjectName(u"lbl_coverage")
+
+        self.gridLayout_3.addWidget(self.lbl_coverage, 5, 1, 1, 1)
+
+        self.frame_2 = QFrame(MCMControlWindow)
+        self.frame_2.setObjectName(u"frame_2")
+        self.frame_2.setFrameShape(QFrame.HLine)
+        self.frame_2.setFrameShadow(QFrame.Sunken)
+
+        self.gridLayout_3.addWidget(self.frame_2, 8, 1, 1, 4)
+
+        self.txt_unit = QLineEdit(MCMControlWindow)
+        self.txt_unit.setObjectName(u"txt_unit")
+
+        self.gridLayout_3.addWidget(self.txt_unit, 9, 2, 1, 3)
+
+        self.lbl_std = QLabel(MCMControlWindow)
+        self.lbl_std.setObjectName(u"lbl_std")
+
+        self.gridLayout_3.addWidget(self.lbl_std, 3, 1, 1, 1)
+
+        self.frame = QFrame(MCMControlWindow)
+        self.frame.setObjectName(u"frame")
+        self.frame.setFrameShape(QFrame.HLine)
+        self.frame.setFrameShadow(QFrame.Sunken)
+
+        self.gridLayout_3.addWidget(self.frame, 4, 1, 1, 4)
+
+        self.lineEdit_2 = QLineEdit(MCMControlWindow)
+        self.lineEdit_2.setObjectName(u"lineEdit_2")
+
+        self.gridLayout_3.addWidget(self.lineEdit_2, 5, 4, 1, 1)
+
+        self.lbl_unit = QLabel(MCMControlWindow)
+        self.lbl_unit.setObjectName(u"lbl_unit")
+
+        self.gridLayout_3.addWidget(self.lbl_unit, 9, 1, 1, 1)
+
+        self.lineEdit_3 = QLineEdit(MCMControlWindow)
+        self.lineEdit_3.setObjectName(u"lineEdit_3")
+
+        self.gridLayout_3.addWidget(self.lineEdit_3, 7, 2, 1, 3)
+
+        self.label = QLabel(MCMControlWindow)
+        self.label.setObjectName(u"label")
+        font = QFont()
+        font.setPointSize(11)
+        font.setBold(True)
+        self.label.setFont(font)
+
+        self.gridLayout_3.addWidget(self.label, 0, 1, 1, 4)
+
+
+        self.grd_mcm_members.addLayout(self.gridLayout_3, 0, 1, 1, 1)
+
+
+        self.gridLayout_2.addLayout(self.grd_mcm_members, 0, 0, 1, 1)
+
+        self.tabWidget = QTabWidget(MCMControlWindow)
+        self.tabWidget.setObjectName(u"tabWidget")
+        self.tab_plot_area = QWidget()
+        self.tab_plot_area.setObjectName(u"tab_plot_area")
+        self.gridLayout_8 = QGridLayout(self.tab_plot_area)
+        self.gridLayout_8.setObjectName(u"gridLayout_8")
+        self.tabWidget.addTab(self.tab_plot_area, "")
+        self.tab_description = QWidget()
+        self.tab_description.setObjectName(u"tab_description")
+        self.gridLayout_6 = QGridLayout(self.tab_description)
+        self.gridLayout_6.setObjectName(u"gridLayout_6")
+        self.gridLayout_5 = QGridLayout()
+        self.gridLayout_5.setObjectName(u"gridLayout_5")
+        self.lbl_description = QLabel(self.tab_description)
+        self.lbl_description.setObjectName(u"lbl_description")
+
+        self.gridLayout_5.addWidget(self.lbl_description, 0, 0, 1, 1)
+
+        self.txt_description = QPlainTextEdit(self.tab_description)
+        self.txt_description.setObjectName(u"txt_description")
+        self.txt_description.setMaximumSize(QSize(16777215, 250))
+
+        self.gridLayout_5.addWidget(self.txt_description, 1, 0, 1, 1)
+
+
+        self.gridLayout_6.addLayout(self.gridLayout_5, 0, 0, 1, 1)
+
+        self.tabWidget.addTab(self.tab_description, "")
+
+        self.gridLayout_2.addWidget(self.tabWidget, 1, 0, 1, 1)
+
+
+        self.retranslateUi(MCMControlWindow)
+
+        self.tabWidget.setCurrentIndex(1)
+
+
+        QMetaObject.connectSlotsByName(MCMControlWindow)
+    # setupUi
+
+    def retranslateUi(self, MCMControlWindow):
+        MCMControlWindow.setWindowTitle(QCoreApplication.translate("MCMControlWindow", u"Form", None))
+        self.lbl_samples_n.setText(QCoreApplication.translate("MCMControlWindow", u"Number of Samples", None))
+        self.label_2.setText(QCoreApplication.translate("MCMControlWindow", u"TextLabel", None))
+        self.label_3.setText(QCoreApplication.translate("MCMControlWindow", u"Mean", None))
+        self.lbl_cov_factor.setText(QCoreApplication.translate("MCMControlWindow", u"Coverage Factor", None))
+        self.lbl_coverage.setText(QCoreApplication.translate("MCMControlWindow", u"Coverage [%]", None))
+        self.lbl_std.setText(QCoreApplication.translate("MCMControlWindow", u"Standard Deviation", None))
+        self.lbl_unit.setText(QCoreApplication.translate("MCMControlWindow", u"Unit", None))
+        self.label.setText(QCoreApplication.translate("MCMControlWindow", u"Monte Carlo Samples", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_plot_area), QCoreApplication.translate("MCMControlWindow", u"Sample Plot", None))
+        self.lbl_description.setText(QCoreApplication.translate("MCMControlWindow", u"Description", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_description), QCoreApplication.translate("MCMControlWindow", u"Description", None))
+    # retranslateUi
+
diff --git a/src/mcpy/userinterface/Ui_UncertaintyControlWidget.py b/src/mcpy/userinterface/Ui_UncertaintyControlWidget.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb50b4f20c976ee19e963508d11716548b4fd04b
--- /dev/null
+++ b/src/mcpy/userinterface/Ui_UncertaintyControlWidget.py
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'UncertaintyControlWidget.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+    QMetaObject, QObject, QPoint, QRect,
+    QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+    QFont, QFontDatabase, QGradient, QIcon,
+    QImage, QKeySequence, QLinearGradient, QPainter,
+    QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialogButtonBox,
+    QFrame, QGridLayout, QLabel, QLineEdit,
+    QPlainTextEdit, QPushButton, QSizePolicy, QTabWidget,
+    QVBoxLayout, QWidget)
+
+class Ui_UncertaintyControlWidget(object):
+    def setupUi(self, UncertaintyControlWidget):
+        if not UncertaintyControlWidget.objectName():
+            UncertaintyControlWidget.setObjectName(u"UncertaintyControlWidget")
+        UncertaintyControlWidget.resize(427, 478)
+        self.gridLayout = QGridLayout(UncertaintyControlWidget)
+        self.gridLayout.setObjectName(u"gridLayout")
+        self.buttonBox = QDialogButtonBox(UncertaintyControlWidget)
+        self.buttonBox.setObjectName(u"buttonBox")
+        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
+
+        self.gridLayout.addWidget(self.buttonBox, 7, 0, 1, 1)
+
+        self.gridLayout_3 = QGridLayout()
+        self.gridLayout_3.setObjectName(u"gridLayout_3")
+        self.tabWidget = QTabWidget(UncertaintyControlWidget)
+        self.tabWidget.setObjectName(u"tabWidget")
+        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
+        self.tabWidget.setSizePolicy(sizePolicy)
+        self.tabWidget.setMaximumSize(QSize(16777215, 350))
+        self.plot_area = QWidget()
+        self.plot_area.setObjectName(u"plot_area")
+        self.grd_plot_area = QGridLayout(self.plot_area)
+        self.grd_plot_area.setObjectName(u"grd_plot_area")
+        self.tabWidget.addTab(self.plot_area, "")
+        self.tab = QWidget()
+        self.tab.setObjectName(u"tab")
+        self.gridLayout_6 = QGridLayout(self.tab)
+        self.gridLayout_6.setObjectName(u"gridLayout_6")
+        self.text_description = QPlainTextEdit(self.tab)
+        self.text_description.setObjectName(u"text_description")
+        sizePolicy.setHeightForWidth(self.text_description.sizePolicy().hasHeightForWidth())
+        self.text_description.setSizePolicy(sizePolicy)
+
+        self.gridLayout_6.addWidget(self.text_description, 2, 0, 1, 1)
+
+        self.gridLayout_5 = QGridLayout()
+        self.gridLayout_5.setObjectName(u"gridLayout_5")
+        self.text_unit = QLineEdit(self.tab)
+        self.text_unit.setObjectName(u"text_unit")
+
+        self.gridLayout_5.addWidget(self.text_unit, 0, 1, 1, 1)
+
+        self.label_4 = QLabel(self.tab)
+        self.label_4.setObjectName(u"label_4")
+
+        self.gridLayout_5.addWidget(self.label_4, 0, 0, 1, 1)
+
+        self.label_5 = QLabel(self.tab)
+        self.label_5.setObjectName(u"label_5")
+
+        self.gridLayout_5.addWidget(self.label_5, 1, 0, 1, 1)
+
+        self.txt_definition = QLineEdit(self.tab)
+        self.txt_definition.setObjectName(u"txt_definition")
+
+        self.gridLayout_5.addWidget(self.txt_definition, 1, 1, 1, 1)
+
+
+        self.gridLayout_6.addLayout(self.gridLayout_5, 0, 0, 1, 1)
+
+        self.label_7 = QLabel(self.tab)
+        self.label_7.setObjectName(u"label_7")
+
+        self.gridLayout_6.addWidget(self.label_7, 1, 0, 1, 1)
+
+        self.tabWidget.addTab(self.tab, "")
+        self.tab_2 = QWidget()
+        self.tab_2.setObjectName(u"tab_2")
+        self.gridLayout_8 = QGridLayout(self.tab_2)
+        self.gridLayout_8.setObjectName(u"gridLayout_8")
+        self.gridLayout_2 = QGridLayout()
+        self.gridLayout_2.setObjectName(u"gridLayout_2")
+        self.label_6 = QLabel(self.tab_2)
+        self.label_6.setObjectName(u"label_6")
+
+        self.gridLayout_2.addWidget(self.label_6, 0, 0, 1, 1)
+
+        self.plainTextEdit = QPlainTextEdit(self.tab_2)
+        self.plainTextEdit.setObjectName(u"plainTextEdit")
+
+        self.gridLayout_2.addWidget(self.plainTextEdit, 1, 0, 1, 1)
+
+
+        self.gridLayout_8.addLayout(self.gridLayout_2, 0, 0, 1, 1)
+
+        self.tabWidget.addTab(self.tab_2, "")
+
+        self.gridLayout_3.addWidget(self.tabWidget, 0, 0, 1, 1)
+
+
+        self.gridLayout.addLayout(self.gridLayout_3, 6, 0, 1, 1)
+
+        self.verticalFrame_2 = QFrame(UncertaintyControlWidget)
+        self.verticalFrame_2.setObjectName(u"verticalFrame_2")
+        self.grd_unc_info = QVBoxLayout(self.verticalFrame_2)
+        self.grd_unc_info.setObjectName(u"grd_unc_info")
+
+        self.gridLayout.addWidget(self.verticalFrame_2, 5, 0, 1, 1)
+
+        self.gridLayout_7 = QGridLayout()
+        self.gridLayout_7.setObjectName(u"gridLayout_7")
+        self.cb_type = QComboBox(UncertaintyControlWidget)
+        self.cb_type.setObjectName(u"cb_type")
+
+        self.gridLayout_7.addWidget(self.cb_type, 2, 1, 1, 1)
+
+        self.label_3 = QLabel(UncertaintyControlWidget)
+        self.label_3.setObjectName(u"label_3")
+        sizePolicy1 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
+        sizePolicy1.setHorizontalStretch(0)
+        sizePolicy1.setVerticalStretch(0)
+        sizePolicy1.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth())
+        self.label_3.setSizePolicy(sizePolicy1)
+        self.label_3.setMaximumSize(QSize(16777215, 16777215))
+
+        self.gridLayout_7.addWidget(self.label_3, 3, 0, 1, 1)
+
+        self.label_2 = QLabel(UncertaintyControlWidget)
+        self.label_2.setObjectName(u"label_2")
+        sizePolicy2 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
+        sizePolicy2.setHorizontalStretch(0)
+        sizePolicy2.setVerticalStretch(0)
+        sizePolicy2.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
+        self.label_2.setSizePolicy(sizePolicy2)
+        self.label_2.setMaximumSize(QSize(16777215, 16777215))
+
+        self.gridLayout_7.addWidget(self.label_2, 2, 0, 1, 1)
+
+        self.cb_distribution = QComboBox(UncertaintyControlWidget)
+        self.cb_distribution.setObjectName(u"cb_distribution")
+        self.cb_distribution.setEditable(False)
+
+        self.gridLayout_7.addWidget(self.cb_distribution, 3, 1, 1, 1)
+
+        self.label = QLabel(UncertaintyControlWidget)
+        self.label.setObjectName(u"label")
+        self.label.setMaximumSize(QSize(16777215, 22))
+        font = QFont()
+        font.setPointSize(11)
+        font.setBold(True)
+        self.label.setFont(font)
+
+        self.gridLayout_7.addWidget(self.label, 0, 0, 1, 2)
+
+        self.btn_open_mcm = QPushButton(UncertaintyControlWidget)
+        self.btn_open_mcm.setObjectName(u"btn_open_mcm")
+
+        self.gridLayout_7.addWidget(self.btn_open_mcm, 4, 1, 1, 1)
+
+
+        self.gridLayout.addLayout(self.gridLayout_7, 0, 0, 1, 1)
+
+
+        self.retranslateUi(UncertaintyControlWidget)
+
+        self.tabWidget.setCurrentIndex(2)
+
+
+        QMetaObject.connectSlotsByName(UncertaintyControlWidget)
+    # setupUi
+
+    def retranslateUi(self, UncertaintyControlWidget):
+        UncertaintyControlWidget.setWindowTitle(QCoreApplication.translate("UncertaintyControlWidget", u"Form", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.plot_area), QCoreApplication.translate("UncertaintyControlWidget", u"PDF", None))
+        self.label_4.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Unit", None))
+        self.label_5.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Definition", None))
+        self.label_7.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Description", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("UncertaintyControlWidget", u"Details", None))
+        self.label_6.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Expanded Uncertainty", None))
+        self.plainTextEdit.setPlainText(QCoreApplication.translate("UncertaintyControlWidget", u"GUM 6.2.1 [p. 23]\n"
+"The expanded uncertainty U is obtained by multiplying the combined standard uncertainty uc(y) by a coverage factor k.\n"
+"", None))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("UncertaintyControlWidget", u"Details", None))
+        self.label_3.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Uncertainty Distribution", None))
+        self.label_2.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Type", None))
+        self.label.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Uncertainty", None))
+        self.btn_open_mcm.setText(QCoreApplication.translate("UncertaintyControlWidget", u"Open Monte Carlo Samples", None))
+    # retranslateUi
+
diff --git a/src/mcpy/userinterface/UncertaintyWidget.py b/src/mcpy/userinterface/UncertaintyWidget.py
new file mode 100644
index 0000000000000000000000000000000000000000..41d0f80565730dde6072c20e36c118dd11c02c6b
--- /dev/null
+++ b/src/mcpy/userinterface/UncertaintyWidget.py
@@ -0,0 +1,53 @@
+from PySide6.QtWidgets import QWidget, QGridLayout, QTextEdit
+
+from mcpy import Uncertainty
+from mcpy.userinterface.MCMWidget import MonteCarloWidget
+from mcpy.userinterface.Ui_UncertaintyControlWidget import Ui_UncertaintyControlWidget
+
+
+class UncertaintyWidget(QWidget):
+    # Init the UI file
+    def __init__(self, uncertainty: Uncertainty = None, parent=None, logger=None):
+        super().__init__()
+        self._ui = Ui_UncertaintyControlWidget()
+        self._ui.setupUi(self)
+
+        if uncertainty is not None:
+            self._uncertainty = uncertainty
+            self._update_ui()
+
+        self.mcm_window = MonteCarloWidget()
+
+
+
+    def _update_ui(self):
+        self.layout: QGridLayout = self.uncertainty.ui.generate_ui()
+
+        self._ui.grd_unc_info.addLayout(self.layout)
+        self._ui.cb_distribution.addItems(self.uncertainty.LIST_TYPE_B)
+        self._ui.cb_distribution.setCurrentText(self.uncertainty.distribution)
+        self._ui.cb_type.addItems(self.uncertainty.LIST_TYPE)
+        self._ui.cb_type.setCurrentText(self.uncertainty.type)
+
+        self._ui.text_unit.setText(self.uncertainty.unit)
+        self._ui.txt_definition.setText(self.uncertainty.definition)
+        self._ui.text_description.setPlainText(self.uncertainty.description)
+
+        self._ui.grd_plot_area.addLayout(self.uncertainty.ui.generate_plot(), 0, 0)
+        self._ui.tabWidget.setCurrentIndex(0)
+
+        self._ui.btn_open_mcm.clicked.connect(self._on_open_mcm_clicked)
+        # .setLayout(self.layout)
+
+    def _on_open_mcm_clicked(self):
+        self.mcm_window.mc_samples = self.uncertainty.mc_sample()
+        self.mcm_window.show()
+
+    @property
+    def uncertainty(self):
+        return self._uncertainty
+
+    @uncertainty.setter
+    def uncertainty(self, value):
+        self._uncertainty = value
+        self._update_ui()
diff --git a/src/mcpy/userinterface/__init__.py b/src/mcpy/userinterface/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/mcpy/userinterface/resources/MCControlWidget.ui b/src/mcpy/userinterface/resources/MCControlWidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..e65d6bae6c6aa8c92ad13eb04d39bc3e21b4dd76
--- /dev/null
+++ b/src/mcpy/userinterface/resources/MCControlWidget.ui
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MCControlWindow</class>
+ <widget class="QWidget" name="MCControlWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>510</width>
+    <height>532</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="grd_mcm_members">
+     <item row="0" column="1">
+      <layout class="QGridLayout" name="gridLayout_3">
+       <item row="1" column="1">
+        <widget class="QLabel" name="lbl_samples_n">
+         <property name="text">
+          <string>Number of Samples</string>
+         </property>
+        </widget>
+       </item>
+       <item row="7" column="1">
+        <widget class="QLabel" name="lbl_exp_uncert">
+         <property name="text">
+          <string>Expanded Uncertainty</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLabel" name="label_3">
+         <property name="text">
+          <string>Mean</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="2" colspan="3">
+        <widget class="QLineEdit" name="txt_std"/>
+       </item>
+       <item row="5" column="2">
+        <widget class="QLineEdit" name="txt_cov"/>
+       </item>
+       <item row="1" column="2" colspan="3">
+        <widget class="QLineEdit" name="text_samples_n"/>
+       </item>
+       <item row="5" column="3">
+        <widget class="QLabel" name="lbl_cov_factor">
+         <property name="text">
+          <string>Coverage Factor</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2" colspan="3">
+        <widget class="QLineEdit" name="txt_mean"/>
+       </item>
+       <item row="5" column="1">
+        <widget class="QLabel" name="lbl_coverage">
+         <property name="text">
+          <string>Coverage [%]</string>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="1" colspan="4">
+        <widget class="QFrame" name="frame_2">
+         <property name="frameShape">
+          <enum>QFrame::HLine</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Sunken</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="9" column="2" colspan="3">
+        <widget class="QLineEdit" name="txt_unit"/>
+       </item>
+       <item row="3" column="1">
+        <widget class="QLabel" name="lbl_std">
+         <property name="text">
+          <string>Standard Deviation</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1" colspan="4">
+        <widget class="QFrame" name="frame">
+         <property name="frameShape">
+          <enum>QFrame::HLine</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Sunken</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="4">
+        <widget class="QLineEdit" name="txt_cov_factor"/>
+       </item>
+       <item row="9" column="1">
+        <widget class="QLabel" name="lbl_unit">
+         <property name="text">
+          <string>Unit</string>
+         </property>
+        </widget>
+       </item>
+       <item row="7" column="2" colspan="3">
+        <widget class="QLineEdit" name="lineEdit_3"/>
+       </item>
+       <item row="0" column="1" colspan="4">
+        <widget class="QLabel" name="label">
+         <property name="font">
+          <font>
+           <pointsize>11</pointsize>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>Monte Carlo Samples</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tab_plot_area">
+      <attribute name="title">
+       <string>Sample Plot</string>
+      </attribute>
+      <layout class="QGridLayout" name="grd_plot_area"/>
+     </widget>
+     <widget class="QWidget" name="tab_description">
+      <attribute name="title">
+       <string>Description</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_6">
+       <item row="0" column="0">
+        <layout class="QGridLayout" name="gridLayout_5">
+         <item row="0" column="0">
+          <widget class="QLabel" name="lbl_description">
+           <property name="text">
+            <string>Description</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QPlainTextEdit" name="txt_description">
+           <property name="maximumSize">
+            <size>
+             <width>16777215</width>
+             <height>250</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/mcpy/userinterface/resources/UncertaintyControlWidget.ui b/src/mcpy/userinterface/resources/UncertaintyControlWidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..eff2b987e3fcc021754a58538c24eae53443d3af
--- /dev/null
+++ b/src/mcpy/userinterface/resources/UncertaintyControlWidget.ui
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UncertaintyControlWidget</class>
+ <widget class="QWidget" name="UncertaintyControlWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>427</width>
+    <height>478</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="7" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="0">
+    <layout class="QGridLayout" name="gridLayout_3">
+     <item row="0" column="0">
+      <widget class="QTabWidget" name="tabWidget">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>350</height>
+        </size>
+       </property>
+       <property name="currentIndex">
+        <number>2</number>
+       </property>
+       <widget class="QWidget" name="plot_area">
+        <attribute name="title">
+         <string>PDF</string>
+        </attribute>
+        <layout class="QGridLayout" name="grd_plot_area"/>
+       </widget>
+       <widget class="QWidget" name="tab">
+        <attribute name="title">
+         <string>Details</string>
+        </attribute>
+        <layout class="QGridLayout" name="gridLayout_6">
+         <item row="2" column="0">
+          <widget class="QPlainTextEdit" name="text_description">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0">
+          <layout class="QGridLayout" name="gridLayout_5">
+           <item row="0" column="1">
+            <widget class="QLineEdit" name="text_unit"/>
+           </item>
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_4">
+             <property name="text">
+              <string>Unit</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLabel" name="label_5">
+             <property name="text">
+              <string>Definition</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QLineEdit" name="txt_definition"/>
+           </item>
+          </layout>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_7">
+           <property name="text">
+            <string>Description</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="tab_2">
+        <attribute name="title">
+         <string>Details</string>
+        </attribute>
+        <layout class="QGridLayout" name="gridLayout_8">
+         <item row="0" column="0">
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_6">
+             <property name="text">
+              <string>Expanded Uncertainty</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QPlainTextEdit" name="plainTextEdit">
+             <property name="plainText">
+              <string>GUM 6.2.1 [p. 23]
+The expanded uncertainty U is obtained by multiplying the combined standard uncertainty uc(y) by a coverage factor k.
+</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="5" column="0">
+    <widget class="QFrame" name="verticalFrame_2">
+     <layout class="QVBoxLayout" name="grd_unc_info"/>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout_7">
+     <item row="2" column="1">
+      <widget class="QComboBox" name="cb_type"/>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="label_3">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Uncertainty Distribution</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Type</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QComboBox" name="cb_distribution">
+       <property name="editable">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0" colspan="2">
+      <widget class="QLabel" name="label">
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>22</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>11</pointsize>
+         <bold>true</bold>
+        </font>
+       </property>
+       <property name="text">
+        <string>Uncertainty</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QPushButton" name="btn_open_mcm">
+       <property name="text">
+        <string>Open Monte Carlo Samples</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/mcpy/userinterface/resources/convert.sh b/src/mcpy/userinterface/resources/convert.sh
new file mode 100644
index 0000000000000000000000000000000000000000..052c6e37e1195aa287a47d684e5e348195596897
--- /dev/null
+++ b/src/mcpy/userinterface/resources/convert.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Convert .ui files to .py files
+for ui in *.ui; do
+    pyside6-uic $ui > ../Ui_${ui%.*}.py
+done
+ #pyside6-rcc ../../resources.qrc -o ../../resources_rc.py
diff --git a/test.py b/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..c1c9ea006ba7dc91abb15d0a5b5b9ef2287422f7
--- /dev/null
+++ b/test.py
@@ -0,0 +1,38 @@
+import pandas as pd
+from scipy.stats import norm
+
+class Uncertainty:
+    def __init__(self, value: float, coverage: float = 0.95, unit: str = "", definition: str = None,
+                 description: str = None, ustd: float = 0):
+        self._value = value
+        self._unit = unit
+        self._definition = definition
+        self._description = description
+        self._coverage = coverage
+        self._k = norm.ppf(self._coverage)
+        self._ustd = ustd
+        self._uexp = self._calc_uexp(self._ustd)
+        self._mcsamples = None
+
+    def __float__(self):
+        return self._value
+
+    def _calc_uexp(self, ustd):
+        # Calculate uncertainty expression based on ustd
+        return self._value * ustd
+
+    def
+
+# Create a DataFrame with a column of Uncertainty instances
+data = [
+    Uncertainty(1.23),
+    Uncertainty(4.56),
+    Uncertainty(7.89)
+]
+
+df = pd.DataFrame({'Column1': data})
+
+# Check the data type of the DataFrame column
+print(df)
+df = Uncertainty(1.23) + Uncertainty(4.56)
+print(df)
diff --git a/tests/UnitTest.py b/tests/UnitTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..db493865724715caefb89ab16f657a37ae54ec34
--- /dev/null
+++ b/tests/UnitTest.py
@@ -0,0 +1,126 @@
+import os
+import unittest
+
+from scipy.stats import norm
+
+from mcpy.TypeBUncertainty.Normal import Normal
+from mcpy.TypeBUncertainty.Rectangular import Rectangular
+
+
+class TestNormalDistribution(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.value = 6.7e-3
+        cls.uexp = ((40e-3 * 19e-3) / 100)
+        cls.k = 3
+        cls.coverage = 1 - norm.pdf(cls.k)
+        cls.definition = "Sample normal Definition"
+        cls.description = "Sample normal Description"
+        cls.unit = "nm"
+
+    def test_to_dict(self):
+        # Setup the normal distribution
+        normal = Normal(self.value, self.uexp, k=self.k, unit=self.unit)
+        normal.definition = self.definition
+        normal.description = self.description
+
+
+        self.assertEqual(
+            normal.to_dict(),
+            {'coverage': self.coverage,
+             'definition': self.definition,
+             'description': self.description,
+             'type': 'Type B',
+             'distribution': 'Normal',
+             'uexp': self.uexp,
+             'unit': self.unit,
+             'value': self.value}
+        )
+
+    def test_from_dict(self):
+        normal_reference = Normal(self.value, self.uexp, k=self.k, unit=self.unit)
+        normal_reference.definition = self.definition
+        normal_reference.description = self.description
+
+
+        from_dict = {'coverage': self.coverage,
+             'definition': self.definition,
+             'description': self.description,
+             'type': 'Type B',
+             'distribution': 'Normal',
+             'uexp': self.uexp,
+             'unit': self.unit,
+             'value': self.value}
+
+        normal_from_dict = Normal.from_dict(from_dict)
+
+        self.assertEqual(type(normal_from_dict), Normal)
+
+        self.assertEqual(
+            normal_from_dict.to_dict(),
+            from_dict
+        )
+
+class TestRectangularDistribution(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.value = 100.0
+        cls.hlim = 5e-3
+        cls.a = 100 - 5e-3
+        cls.b = 100 + 5e-3
+        cls.k = 3
+        cls.coverage = 1 - norm.pdf(3)
+        cls.definition = "Sample Rect Definition"
+        cls.description = "Sample Rect Description"
+        cls.unit = "nm"
+
+    def test_to_dict(self):
+        # Setup the normal distribution
+        rect = Rectangular(self.value, self.a, k=self.k, unit=self.unit)
+        rect.definition = self.definition
+        rect.description = self.description
+
+        print(rect.to_dict())
+        self.assertEqual(
+            rect.to_dict(),
+            {'coverage': self.coverage,
+             'definition': self.definition,
+             'description': self.description,
+             'type': 'Type B',
+             'distribution': 'Rectangular',
+             'a': self.a,
+             'b': self.b,
+             'hlim': self.hlim,
+             'unit': self.unit,
+             'value': self.value}
+        )
+
+    def test_from_dict(self):
+        normal_reference = Normal(self.value, self.uexp, k=self.k, unit=self.unit)
+        normal_reference.definition = self.definition
+        normal_reference.description = self.description
+
+
+        from_dict = {'coverage': self.coverage,
+             'definition': self.definition,
+             'description': self.description,
+             'type': 'Type B',
+             'distribution': 'Normal',
+             'uexp': self.uexp,
+             'unit': self.unit,
+             'value': self.value}
+
+        normal_from_dict = Normal.from_dict(from_dict)
+
+        self.assertEqual(type(normal_from_dict), Normal)
+
+        self.assertEqual(
+            normal_from_dict.to_dict(),
+            from_dict
+        )
+
+
+if __name__ == '__main__':
+    unittest.main()