From b7abc39cf611a83a9a24e62ce33d434313889559 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 19 Jun 2025 06:53:29 -0500 Subject: [PATCH 01/68] Analog Input - Voltage and Thermocouple Single Task --- .../nidaqmx_continuous_analog_input.py | 38 ++++ .../nidaqmx_continuous_analog_input_panel.py | 168 ++++++++++++++++ examples/sample/sample.py | 2 +- poetry.lock | 187 +++++++++++++++++- pyproject.toml | 1 + 5 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py create mode 100644 examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py diff --git a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py new file mode 100644 index 00000000..246e0537 --- /dev/null +++ b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py @@ -0,0 +1,38 @@ +"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" + +import nipanel +import nidaqmx +import pathlib +import time + +script_path = pathlib.Path(__file__) +panel_script_path = str(script_path.with_name("nidaqmx_continuous_analog_input_panel.py")) + +panel = nipanel.StreamlitPanel( + panel_id="nidaqmx_continuous_analog_input_panel", + streamlit_script_path=panel_script_path, +) + +data_arr = [] +with nidaqmx.Task() as task: + task.ai_channels.add_ai_voltage_chan("Mod1/ai2") + task.ai_channels.add_ai_thrmcpl_chan("Mod1/ai3") + try: + total_read = 0 + while True: + data = task.read(number_of_samples_per_channel=3) + read = len(data) + total_read += read + + data_arr.append(data) + time.sleep(1) + panel.set_value("amplitude",data_arr[-1][-1]) + panel.set_value("Volts",data_arr[-1][0]) + except KeyboardInterrupt: + pass + finally: + task.stop() + print(f"\nAcquired {total_read} total samples.") + + + diff --git a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py new file mode 100644 index 00000000..b83f09b5 --- /dev/null +++ b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py @@ -0,0 +1,168 @@ +"""Streamlit application script for displaying values using nipanel package.""" +import nipanel +import streamlit as st +import streamlit.components.v1 as components +from streamlit_echarts import st_echarts + +panel = nipanel.StreamlitPanelValueAccessor(panel_id="nidaqmx_continuous_analog_input_panel") + +add_refresh_component = components.declare_component( + "panelRefreshComponent", + url=f"http://localhost:42001/panels/refresh/{panel.panel_id}",) +add_refresh_component() + + +st.title("Analog Input - Voltage and Thermocouple in a Single Task") +voltage_tab, thermocouple_tab = st.tabs(["Voltage", "Thermocouple"]) + +st.markdown( + """ + + """, + unsafe_allow_html=True +) + + +list_of_therm_amp = panel.get_value("amplitude") +list_of_voltage_amp = panel.get_value("Volts") + +if "therm_history" not in st.session_state: + st.session_state.therm_history = [] +if "volts_history" not in st.session_state: + st.session_state.volts_history = [] + +for therm_amp in list_of_therm_amp: + st.session_state.therm_history.append(therm_amp) +for voltage_amp in list_of_voltage_amp: + st.session_state.volts_history.append(voltage_amp) + +therm_amp_graph = { + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["thermocouple_amplitude"]}, + "xAxis": { + "type": "category", + "data":list(range(len(st.session_state.therm_history))), + "name": "Time" + }, + "yAxis": { + "type": "value", + "name": "Thermocouple Amplitude" + }, + "series": [ + { + "name": "thermocouple_amplitude", + "type": "line", + "data": st.session_state.therm_history, + "color": "red" + }, + + + ], +} +st_echarts(options=therm_amp_graph, height="400px") + +voltage_amp_graph = { + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["voltage_amplitude"]}, + "xAxis": { + "type": "category", + "data": list(range(len(st.session_state.volts_history))), + "name": "Time" + }, + "yAxis": { + "type": "value", + "name": "Voltage Amplitude" + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": st.session_state.volts_history, + }, + + ], +} +st_echarts(options=voltage_amp_graph, height="400px") + +st.header("Voltage & Thermocouple") +voltage_therm_graph = { + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["voltage_amplitude", "thermocouple_amplitude"]}, + "xAxis": { + "type": "category", + "data": list(range(len(st.session_state.volts_history))), + "name": "Time" + }, + "yAxis": { + "type": "value", + "name": "Voltage and Thermocouple Amplitude" + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": st.session_state.volts_history, + "emphasis": {"focus":"series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + { + "name": "thermocouple_amplitude", + "type": "line", + "data": st.session_state.therm_history, + "color": "red", + "emphasis": {"focus":"series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], +} +st_echarts(options=voltage_therm_graph, height="400px") + +with voltage_tab: + left_volt_tab, center_volt_tab, right_volt_tab = st.columns(3) + with left_volt_tab: + st.selectbox(options=["Mod1/ai2"], label="Physical Channels", disabled=True) + st.selectbox(options=["Off"], label="Logging Modes", disabled=False) + with center_volt_tab: + st.selectbox(options=["-5"],label="Min Value") + st.selectbox(options=["5"],label="Max Value") + st.selectbox(options=["1000"], label="Samples per Loops", disabled=False) + with right_volt_tab: + st.selectbox(options=["default"], label="Terminal Configurations") + st.selectbox(options=["OnboardClock"], label="Sample Clock Sources", disabled=False) + + +thermocouple_tab.header("Thermocouple") +with thermocouple_tab: + left, middle, right = st.columns(3) + with left: + st.selectbox(options=["Mod1/ai3"], label="Physical Channel", disabled=True) + st.selectbox(options=["0"], label="Min", disabled=False) + st.selectbox(options=["100"], label="Max", disabled=False) + st.selectbox(options=["Off"], label="Logging Mode", disabled=False) + + with middle: + st.selectbox(options=["Deg C"], label = "Units", disabled=False) + st.selectbox(options=["J"], label="Thermocouple Type", disabled=False) + st.selectbox(options=["Constant Value"], label="CJC Source", disabled=False) + st.selectbox(options=["1000"], label="Samples per Loop", disabled=False) + with right: + st.selectbox(options=["25"],label="CJC Value", disabled=False) + st.selectbox(options=["OnboardClock"], label="Sample Clock Source", disabled=False) + st.selectbox(options=[" "], label="Actual Sample Rate", disabled=True) + + + + + + + + + + + diff --git a/examples/sample/sample.py b/examples/sample/sample.py index 09977e43..188c1f24 100644 --- a/examples/sample/sample.py +++ b/examples/sample/sample.py @@ -12,7 +12,7 @@ streamlit_script_path=panel_script_path, ) panel.set_value("sample_string", "Hello, World!") -panel.set_value("sample_int", 42) +panel.set_value("sample_int", 6) panel.set_value("sample_float", 3.14) panel.set_value("sample_bool", True) panel.set_value("float_values", [1.1, 2.2, 3.3]) diff --git a/poetry.lock b/poetry.lock index 2adc8d0e..deb57309 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1700,6 +1700,23 @@ files = [ dev = ["pre-commit", "tox"] testing = ["coverage", "pytest", "pytest-benchmark"] +[[package]] +name = "prettytable" +version = "3.16.0" +description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" +optional = false +python-versions = ">=3.9" +files = [ + {file = "prettytable-3.16.0-py3-none-any.whl", hash = "sha256:b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa"}, + {file = "prettytable-3.16.0.tar.gz", hash = "sha256:3c64b31719d961bf69c9a7e03d0c1e477320906a98da63952bc6698d6164ff57"}, +] + +[package.dependencies] +wcwidth = "*" + +[package.extras] +tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] + [[package]] name = "protobuf" version = "4.25.8" @@ -1865,6 +1882,28 @@ snowballstemmer = ">=2.2.0" [package.extras] toml = ["tomli (>=1.2.3)"] +[[package]] +name = "pyecharts" +version = "2.0.8" +description = "Python options, make charting easier" +optional = false +python-versions = "*" +files = [ + {file = "pyecharts-2.0.8-py3-none-any.whl", hash = "sha256:8b711ba139f39f89bc1b2a869d7adda89dc74c910d158a1f9063109fe66bc985"}, + {file = "pyecharts-2.0.8.tar.gz", hash = "sha256:908dbd939862dd3c76bb53697bdb41d3cdd0b5ba48ca69a76a6085d0aa27dbdf"}, +] + +[package.dependencies] +jinja2 = "*" +prettytable = "*" +simplejson = "*" + +[package.extras] +images = ["PIL"] +phantomjs = ["snapshot-phantomjs"] +pyppeteer = ["snapshot-pyppeteer"] +selenium = ["snapshot-selenium"] + [[package]] name = "pyflakes" version = "2.5.0" @@ -2299,6 +2338,125 @@ enabler = ["pytest-enabler (>=2.2)"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] +[[package]] +name = "simplejson" +version = "3.20.1" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" +files = [ + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f5272b5866b259fe6c33c4a8c5073bf8b359c3c97b70c298a2f09a69b52c7c41"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5c0de368f3052a59a1acf21f8b2dd28686a9e4eba2da7efae7ed9554cb31e7bc"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0821871404a537fd0e22eba240c74c0467c28af6cc435903eca394cfc74a0497"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c939a1e576bded47d7d03aa2afc2ae90b928b2cf1d9dc2070ceec51fd463f430"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3c4f0a61cdc05550782ca4a2cdb311ea196c2e6be6b24a09bf71360ca8c3ca9b"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6c21f5c026ca633cfffcb6bc1fac2e99f65cb2b24657d3bef21aed9916cc3bbf"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:8d23b7f8d6b72319d6d55a0261089ff621ce87e54731c2d3de6a9bf7be5c028c"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:cda5c32a98f392909088111ecec23f2b0d39346ceae1a0fea23ab2d1f84ec21d"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e580aa65d5f6c3bf41b9b4afe74be5d5ddba9576701c107c772d936ea2b5043a"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a586ce4f78cec11f22fe55c5bee0f067e803aab9bad3441afe2181693b5ebb5"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74a1608f9e6e8c27a4008d70a54270868306d80ed48c9df7872f9f4b8ac87808"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03db8cb64154189a92a7786209f24e391644f3a3fa335658be2df2af1960b8d8"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eea7e2b7d858f6fdfbf0fe3cb846d6bd8a45446865bc09960e51f3d473c2271b"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e66712b17d8425bb7ff8968d4c7c7fd5a2dd7bd63728b28356223c000dd2f91f"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2cc4f6486f9f515b62f5831ff1888886619b84fc837de68f26d919ba7bbdcbc"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3c2df555ee4016148fa192e2b9cd9e60bc1d40769366134882685e90aee2a1e"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:78520f04b7548a5e476b5396c0847e066f1e0a4c0c5e920da1ad65e95f410b11"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f4bd49ecde87b0fe9f55cc971449a32832bca9910821f7072bbfae1155eaa007"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7eaae2b88eb5da53caaffdfa50e2e12022553949b88c0df4f9a9663609373f72"}, + {file = "simplejson-3.20.1-cp310-cp310-win32.whl", hash = "sha256:e836fb88902799eac8debc2b642300748f4860a197fa3d9ea502112b6bb8e142"}, + {file = "simplejson-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a19b552b212fc3b5b96fc5ce92333d4a9ac0a800803e1f17ebb16dac4be5"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:325b8c107253d3217e89d7b50c71015b5b31e2433e6c5bf38967b2f80630a8ca"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88a7baa8211089b9e58d78fbc1b0b322103f3f3d459ff16f03a36cece0d0fcf0"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:299b1007b8101d50d95bc0db1bf5c38dc372e85b504cf77f596462083ee77e3f"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ec618ed65caab48e81e3ed29586236a8e57daef792f1f3bb59504a7e98cd10"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2cdead1d3197f0ff43373cf4730213420523ba48697743e135e26f3d179f38"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3466d2839fdc83e1af42e07b90bc8ff361c4e8796cd66722a40ba14e458faddd"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d492ed8e92f3a9f9be829205f44b1d0a89af6582f0cf43e0d129fa477b93fe0c"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f924b485537b640dc69434565463fd6fc0c68c65a8c6e01a823dd26c9983cf79"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e8eacf6a3491bf76ea91a8d46726368a6be0eb94993f60b8583550baae9439e"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d04bf90b4cea7c22d8b19091633908f14a096caa301b24c2f3d85b5068fb8"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:69dd28d4ce38390ea4aaf212902712c0fd1093dc4c1ff67e09687c3c3e15a749"}, + {file = "simplejson-3.20.1-cp311-cp311-win32.whl", hash = "sha256:dfe7a9da5fd2a3499436cd350f31539e0a6ded5da6b5b3d422df016444d65e43"}, + {file = "simplejson-3.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:896a6c04d7861d507d800da7642479c3547060bf97419d9ef73d98ced8258766"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f31c4a3a7ab18467ee73a27f3e59158255d1520f3aad74315edde7a940f1be23"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884e6183d16b725e113b83a6fc0230152ab6627d4d36cb05c89c2c5bccfa7bc6"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03d7a426e416fe0d3337115f04164cd9427eb4256e843a6b8751cacf70abc832"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000602141d0bddfcff60ea6a6e97d5e10c9db6b17fd2d6c66199fa481b6214bb"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af8377a8af78226e82e3a4349efdde59ffa421ae88be67e18cef915e4023a595"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15c7de4c88ab2fbcb8781a3b982ef883696736134e20b1210bca43fb42ff1acf"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:455a882ff3f97d810709f7b620007d4e0aca8da71d06fc5c18ba11daf1c4df49"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fc0f523ce923e7f38eb67804bc80e0a028c76d7868500aa3f59225574b5d0453"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76461ec929282dde4a08061071a47281ad939d0202dc4e63cdd135844e162fbc"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19c2da8c043607bde4d4ef3a6b633e668a7d2e3d56f40a476a74c5ea71949f"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2578bedaedf6294415197b267d4ef678fea336dd78ee2a6d2f4b028e9d07be3"}, + {file = "simplejson-3.20.1-cp312-cp312-win32.whl", hash = "sha256:339f407373325a36b7fd744b688ba5bae0666b5d340ec6d98aebc3014bf3d8ea"}, + {file = "simplejson-3.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:627d4486a1ea7edf1f66bb044ace1ce6b4c1698acd1b05353c97ba4864ea2e17"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:71e849e7ceb2178344998cbe5ade101f1b329460243c79c27fbfc51c0447a7c3"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b63fdbab29dc3868d6f009a59797cefaba315fd43cd32ddd998ee1da28e50e29"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1190f9a3ce644fd50ec277ac4a98c0517f532cfebdcc4bd975c0979a9f05e1fb"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1336ba7bcb722ad487cd265701ff0583c0bb6de638364ca947bb84ecc0015d1"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e975aac6a5acd8b510eba58d5591e10a03e3d16c1cf8a8624ca177491f7230f0"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a6dd11ee282937ad749da6f3b8d87952ad585b26e5edfa10da3ae2536c73078"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab980fcc446ab87ea0879edad41a5c28f2d86020014eb035cf5161e8de4474c6"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f5aee2a4cb6b146bd17333ac623610f069f34e8f31d2f4f0c1a2186e50c594f0"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:652d8eecbb9a3b6461b21ec7cf11fd0acbab144e45e600c817ecf18e4580b99e"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8c09948f1a486a89251ee3a67c9f8c969b379f6ffff1a6064b41fea3bce0a112"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cbbd7b215ad4fc6f058b5dd4c26ee5c59f72e031dfda3ac183d7968a99e4ca3a"}, + {file = "simplejson-3.20.1-cp313-cp313-win32.whl", hash = "sha256:ae81e482476eaa088ef9d0120ae5345de924f23962c0c1e20abbdff597631f87"}, + {file = "simplejson-3.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:1b9fd15853b90aec3b1739f4471efbf1ac05066a2c7041bf8db821bb73cd2ddc"}, + {file = "simplejson-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c7edf279c1376f28bf41e916c015a2a08896597869d57d621f55b6a30c7e1e6d"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9202b9de38f12e99a40addd1a8d508a13c77f46d87ab1f9095f154667f4fe81"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:391345b4157cc4e120027e013bd35c45e2c191e2bf48b8913af488cdc3b9243c"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6fdcc9debb711ddd2ad6d69f9386a3d9e8e253234bbb30513e0a7caa9510c51"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9daf8cdc7ee8a9e9f7a3b313ba0a003391857e90d0e82fbcd4d614aa05cb7c3b"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:c02f4868a3a46ffe284a51a88d134dc96feff6079a7115164885331a1ba8ed9f"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:3d7310172d5340febd258cb147f46aae30ad57c445f4d7e1ae8461c10aaf43b0"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:4762e05577955312a4c6802f58dd02e040cc79ae59cda510aa1564d84449c102"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:8bb98fdf318c05aefd08a92583bd6ee148e93c6756fb1befb7b2d5f27824be78"}, + {file = "simplejson-3.20.1-cp36-cp36m-win32.whl", hash = "sha256:9a74e70818818981294b8e6956ce3496c5e1bd4726ac864fae473197671f7b85"}, + {file = "simplejson-3.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e041add470e8f8535cc05509485eb7205729a84441f03b25cde80ad48823792e"}, + {file = "simplejson-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e9d73f46119240e4f4f07868241749d67d09873f40cb968d639aa9ccc488b86"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae6e637dc24f8fee332ed23dd070e81394138e42cd4fd9d0923e5045ba122e27"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:efd3bc6c6b17e3d4620eb6be5196f0d1c08b6ce7c3101fa8e292b79e0908944b"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87fc623d457173a0213bc9ca4e346b83c9d443f63ed5cca847fb0cacea3cfc95"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec6a1e0a7aff76f0e008bebfa950188b9c50b58c1885d898145f48fc8e189a56"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:9c079606f461a6e950099167e21e13985147c8a24be8eea66c9ad68f73fad744"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:9faceb68fba27ef17eda306e4cd97a7b4b14fdadca5fbb15790ba8b26ebeec0c"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:7ceed598e4bacbf5133fe7a418f7991bb2df0683f3ac11fbf9e36a2bc7aa4b85"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ede69c765e9901861ad7c6139023b7b7d5807c48a2539d817b4ab40018002d5f"}, + {file = "simplejson-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:d8853c269a4c5146ddca4aa7c70e631795e9d11239d5fedb1c6bbc91ffdebcac"}, + {file = "simplejson-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ed6a17fd397f0e2b3ad668fc9e19253ed2e3875ad9086bd7f795c29a3223f4a1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7551682b60bba3a9e2780742e101cf0a64250e76de7d09b1c4b0c8a7c7cc6834"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd9577ec1c8c3a43040e3787711e4c257c70035b7551a21854b5dec88dad09e1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8e197e4cf6d42c2c57e7c52cd7c1e7b3e37c5911df1314fb393320131e2101"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bd09c8c75666e7f62a33d2f1fb57f81da1fcbb19a9fe7d7910b5756e1dd6048"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bd6bfe5678d73fbd5328eea6a35216503796428fc47f1237432522febaf3a0c"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b75d448fd0ceb2e7c90e72bb82c41f8462550d48529980bc0bab1d2495bfbb"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7e15b716d09f318c8cda3e20f82fae81684ce3d3acd1d7770fa3007df1769de"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3e7963197d958fcf9e98b212b80977d56c022384621ff463d98afc3b6b1ce7e8"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:2e671dd62051129185d3a9a92c60101f56cbc174854a1a3dfb69114ebd9e1699"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e25b2a0c396f3b84fb89573d07b0e1846ed563eb364f2ea8230ca92b8a8cb786"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:489c3a43116082bad56795215786313832ba3991cca1f55838e52a553f451ab6"}, + {file = "simplejson-3.20.1-cp38-cp38-win32.whl", hash = "sha256:4a92e948bad8df7fa900ba2ba0667a98303f3db206cbaac574935c332838208e"}, + {file = "simplejson-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:49d059b8363327eee3c94799dd96782314b2dbd7bcc293b4ad48db69d6f4d362"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a8011f1dd1d676befcd4d675ebdbfdbbefd3bf350052b956ba8c699fca7d8cef"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e91703a4c5fec53e36875ae426ad785f4120bd1d93b65bed4752eeccd1789e0c"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e39eaa57c7757daa25bcd21f976c46be443b73dd6c3da47fe5ce7b7048ccefe2"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceab2ce2acdc7fbaa433a93006758db6ba9a659e80c4faa13b80b9d2318e9b17"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d4f320c33277a5b715db5bf5b10dae10c19076bd6d66c2843e04bd12d1f1ea5"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b6436c48e64378fa844d8c9e58a5ed0352bbcfd4028369a9b46679b7ab79d2d"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e18345c8dda5d699be8166b61f9d80aaee4545b709f1363f60813dc032dac53"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:90b573693d1526bed576f6817e2a492eaaef68f088b57d7a9e83d122bbb49e51"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:272cc767826e924a6bd369ea3dbf18e166ded29059c7a4d64d21a9a22424b5b5"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:51b41f284d603c4380732d7d619f8b34bd04bc4aa0ed0ed5f4ffd0539b14da44"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e6697a3067d281f01de0fe96fc7cba4ea870d96d7deb7bfcf85186d74456503"}, + {file = "simplejson-3.20.1-cp39-cp39-win32.whl", hash = "sha256:6dd3a1d5aca87bf947f3339b0f8e8e329f1badf548bdbff37fac63c17936da8e"}, + {file = "simplejson-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:463f1fca8fbf23d088e5850fdd0dd4d5faea8900a9f9680270bd98fd649814ca"}, + {file = "simplejson-3.20.1-py3-none-any.whl", hash = "sha256:8a6c1bbac39fa4a79f83cbf1df6ccd8ff7069582a9fd8db1e52cea073bc2c697"}, + {file = "simplejson-3.20.1.tar.gz", hash = "sha256:e64139b4ec4f1f24c142ff7dcafe55a22b811a74d86d66560c8815687143037d"}, +] + [[package]] name = "six" version = "1.17.0" @@ -2581,6 +2739,22 @@ watchdog = {version = ">=2.1.5,<7", markers = "platform_system != \"Darwin\""} [package.extras] snowflake = ["snowflake-connector-python (>=3.3.0)", "snowflake-snowpark-python[modin] (>=1.17.0)"] +[[package]] +name = "streamlit-echarts" +version = "0.4.0" +description = "Echarts custom component for Streamlit" +optional = false +python-versions = ">=3.6" +files = [ + {file = "streamlit-echarts-0.4.0.tar.gz", hash = "sha256:33cc5329b99ddce8b64ce6c4607733e02db575c379af6394a8c78ae5df14934d"}, + {file = "streamlit_echarts-0.4.0-py3-none-any.whl", hash = "sha256:aa86679da0e7680ee43b7a6def31439273a686a8d71de522c55655047e80ec9b"}, +] + +[package.dependencies] +pyecharts = ">=1.9" +simplejson = ">=3.0" +streamlit = ">=0.63" + [[package]] name = "tenacity" version = "9.1.2" @@ -2783,7 +2957,18 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "2405bfc23e77ee98c4fe58845fa73632b884c4bf6acded29ece6c9380a168675" +content-hash = "7239a2757fe3a06c6ddafa7f51763d7ee77976a7d5f96b05ea1f9fbfa631c801" diff --git a/pyproject.toml b/pyproject.toml index 11ecccc0..0b8cfc70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ ni-measurement-plugin-sdk = {version=">=2.3"} typing-extensions = ">=4.13.2" streamlit = ">=1.24" nitypes = {version=">=0.1.0dev1", allow-prereleases=true} +streamlit-echarts = "^0.4.0" [tool.poetry.group.dev.dependencies] types-grpcio = ">=1.0" From 871f6e192778ddeb9bd8ee9d35b70b766a2ab609 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 24 Jun 2025 14:51:29 -0500 Subject: [PATCH 02/68] add niscope Signed-off-by: Dilmi Wickramanayake --- examples/nidaqmx/niscope_example.py | 194 ++++++++++++++++++++++++++++ examples/nidaqmx/niscope_panel.py | 39 ++++++ pyproject.toml | 7 + 3 files changed, 240 insertions(+) create mode 100644 examples/nidaqmx/niscope_example.py create mode 100644 examples/nidaqmx/niscope_panel.py diff --git a/examples/nidaqmx/niscope_example.py b/examples/nidaqmx/niscope_example.py new file mode 100644 index 00000000..2f88b80c --- /dev/null +++ b/examples/nidaqmx/niscope_example.py @@ -0,0 +1,194 @@ +import argparse +import niscope +import numpy +import pprint +import sys +import nipanel +from pathlib import Path +import time +pp = pprint.PrettyPrinter(indent=4, width=80) +panel_script_path = Path(__file__).with_name("niscope_panel.py") +panel = nipanel.create_panel(panel_script_path) + +# def example( +# resource_name, +# options, +# +# ): +# + +def example(resource_name, channels, options, length, total_acquisition_time_in_seconds, voltage, sample_rate_in_hz, samples_per_fetch,): + # fetch_into() allows you to preallocate and reuse the destination of the fetched waveforms, which can result in better performance at the expense of the usability of fetch(). + channels = [ch.strip() for ch in channels.split(",")] + num_channels = len(channels) + num_records = 1000 + total_num_wfms = num_channels * num_records + # preallocate a single array for all samples in all waveforms + # Supported array types are: numpy.float64, numpy.int8, numpy.int16, numpy.int32 + # int8, int16, int32 are for fetching unscaled data, which is the fastest way to fetch. + # Gain and Offset are stored in the returned WaveformInfo objects and can be applied to the data by the user later. + + wfm = numpy.ndarray(length * total_num_wfms, dtype=numpy.float64) + with niscope.Session(resource_name=resource_name, options=options) as session: + session.configure_vertical(range=2, coupling=niscope.VerticalCoupling.AC) + session.configure_horizontal_timing(min_sample_rate=100000000, min_num_pts=length, ref_position=50.0, num_records=num_records, enforce_realtime=True) + total_samples = int(total_acquisition_time_in_seconds * sample_rate_in_hz) + with session.initiate(): + waveforms = session.channels[channels].fetch_into(waveform=wfm, num_records=num_records) + for i in range(len(waveforms)): + time.sleep(0.2) + panel.set_value("samples", total_samples) + panel.set_value("Waveform", waveforms[i].samples.tolist()) + + +def _main(argsv): + parser = argparse.ArgumentParser(description='Fetches data directly into a preallocated numpy array.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-n', '--resource-name', default='Dev2', help='Resource name of an NI digitizer.') + parser.add_argument('-c', '--channels', default='0', help='Channel(s) to use') + parser.add_argument('-l', '--length', default=100, type=int, help='Measure record length') + parser.add_argument('-v', '--voltage', default=1.0, type=float, help='Voltage range (V)') + parser.add_argument('-op', '--option-string', default='', type=str, help='Option string') + parser.add_argument("-t", "--time", default=10, type=int, help="Time to sample (s)") + parser.add_argument("-r", "--sample-rate", default=1000.0, type=float, help="Sample Rate (Hz)") + parser.add_argument( + "-s", "--samples-per-fetch", default=100, type=int, help="Samples per fetch" + ) + args = parser.parse_args(argsv) + example(args.resource_name, args.channels, args.option_string, args.length, args.voltage, args.time, + args.sample_rate, + args.samples_per_fetch) + + + +def main(): + _main(sys.argv[1:]) + + +def test_example(): + options = {'simulate': True, 'driver_setup': {'Model': '5124', 'BoardType': 'PXI', }, } + example('Dev2', '0, 1', options, 100, 1.0) + + +def test_main(): + cmd_line = ['--option-string', 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', ] + _main(cmd_line) + + +if __name__ == '__main__': + main() + +# # We use fetch_into which allows us to allocate a single buffer per channel and "fetch into" it a section at a time without having to +# # reconstruct the waveform once we are done +# def example( +# resource_name, +# options, +# total_acquisition_time_in_seconds, +# voltage, +# sample_rate_in_hz, +# samples_per_fetch, +# ): +# total_samples = int(total_acquisition_time_in_seconds * sample_rate_in_hz) +# # 1. Opening session +# with niscope.Session(resource_name=resource_name, options=options) as session: +# # We will acquire on all channels of the device +# channel_list = [ +# c for c in range(session.channel_count) +# ] # Need an actual list and not a range + +# # 2. Creating numpy arrays +# waveforms = [np.ndarray(total_samples, dtype=np.float64) for c in channel_list] +# offset = session._fetch_offset + +# # 3. Configuring +# session.configure_horizontal_timing( +# min_sample_rate=sample_rate_in_hz, +# min_num_pts=1, +# ref_position=0.0, +# num_records=1, +# enforce_realtime=True, +# ) +# session.channels[channel_list].configure_vertical( +# voltage, coupling=niscope.VerticalCoupling.DC, enabled=True +# ) +# # Configure software trigger, but never send the trigger. +# # This starts an infinite acquisition, until you call session.abort() or session.close() +# session.configure_trigger_software() +# current_pos = 0 + +# # 4. initiating +# with session.initiate(): +# while current_pos < total_samples: +# # We fetch each channel at a time so we don't have to de-interleave afterwards +# # We do not keep the wfm_info returned from fetch_into +# for channel, waveform in zip(channel_list, waveforms): +# data = waveform.tolist() +# panel.set_value("total", current_pos) +# time.sleep(0.2) +# panel.set_value("Waveform", data) +# panel.set_value("samples", total_samples) +# # session.channels[channel].fetch(num_samples=1000) +# # 5. fetching - we return the slice of the waveform array that we want to "fetch into" +# session.channels[channel].fetch_into( +# waveform[current_pos : current_pos + samples_per_fetch], +# relative_to=niscope.FetchRelativeTo.READ_POINTER, +# offset=0, +# record_number=0, +# num_records=1, +# timeout=hightime.timedelta(seconds=5.0), +# ) +# current_pos += samples_per_fetch + + +# def _main(argsv): +# parser = argparse.ArgumentParser( +# description="Fetch more samples than will fit in memory.", +# formatter_class=argparse.ArgumentDefaultsHelpFormatter, +# ) +# parser.add_argument( +# "-n", "--resource-name", default="Dev2", help="Resource name of an NI digitizer." +# ) +# parser.add_argument("-t", "--time", default=10, type=int, help="Time to sample (s)") +# parser.add_argument("-v", "--voltage", default=1.0, type=float, help="Voltage range (V)") +# parser.add_argument("-op", "--option-string", default="", type=str, help="Option string") +# parser.add_argument("-r", "--sample-rate", default=1000.0, type=float, help="Sample Rate (Hz)") +# parser.add_argument( +# "-s", "--samples-per-fetch", default=100, type=int, help="Samples per fetch" +# ) +# args = parser.parse_args(argsv) +# example( +# args.resource_name, +# args.option_string, +# args.time, +# args.voltage, +# args.sample_rate, +# args.samples_per_fetch, +# ) + + +# def main(): +# _main(sys.argv[1:]) + + +# def test_example(): +# options = { +# "simulate": True, +# "driver_setup": { +# "Model": "5124", +# "BoardType": "PXI", +# }, +# } +# example("Dev2", options, 10, 1.0, 1000.0, 100) + + +# def test_main(): +# cmd_line = [ +# "--option-string", +# "Simulate=1, DriverSetup=Model:5124; BoardType:PXI", +# ] +# _main(cmd_line) + + +# if __name__ == "__main__": +# main() + + diff --git a/examples/nidaqmx/niscope_panel.py b/examples/nidaqmx/niscope_panel.py new file mode 100644 index 00000000..7fae255c --- /dev/null +++ b/examples/nidaqmx/niscope_panel.py @@ -0,0 +1,39 @@ +import streamlit as st +from streamlit_echarts import st_echarts + +import nipanel + +panel = nipanel.get_panel_accessor() + +waveform = panel.get_value("Waveform") +samples = panel.get_value("samples") +graph = { + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Amplitude (V)"]}, + "xAxis": { + "type": "category", + "data": samples, + "name": "Samples", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Amplitude(V)", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "niscope data", + "type": "line", + "data": waveform, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + + ], +} +st_echarts(options=graph, height="400px") \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0b8cfc70..15808cfe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,13 @@ sphinx-autoapi = ">=1.8.4" m2r2 = ">=0.3.2" toml = ">=0.10.2" +[tool.poetry.group.examples] +optional = true + +[tool.poetry.group.examples.dependencies] +streamlit-echarts = ">=0.4.0" +nidaqmx = ">=0.8.0" + [build-system] requires = ["poetry-core>=1.8.0"] build-backend = "poetry.core.masonry.api" From 336d7b5af4575a41bd92958151e04214b8f6a43a Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 25 Jun 2025 14:22:35 -0500 Subject: [PATCH 03/68] Rename Signed-off-by: Dilmi Wickramanayake --- examples/nidaqmx/niscope_example.py | 194 ------------------ .../nidaqmx_continuous_analog_input.py | 38 ---- .../nidaqmx_continuous_analog_input_panel.py | 168 --------------- examples/niscope/niscope_example.py | 95 +++++++++ .../{nidaqmx => niscope}/niscope_panel.py | 0 5 files changed, 95 insertions(+), 400 deletions(-) delete mode 100644 examples/nidaqmx/niscope_example.py delete mode 100644 examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py delete mode 100644 examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py create mode 100644 examples/niscope/niscope_example.py rename examples/{nidaqmx => niscope}/niscope_panel.py (100%) diff --git a/examples/nidaqmx/niscope_example.py b/examples/nidaqmx/niscope_example.py deleted file mode 100644 index 2f88b80c..00000000 --- a/examples/nidaqmx/niscope_example.py +++ /dev/null @@ -1,194 +0,0 @@ -import argparse -import niscope -import numpy -import pprint -import sys -import nipanel -from pathlib import Path -import time -pp = pprint.PrettyPrinter(indent=4, width=80) -panel_script_path = Path(__file__).with_name("niscope_panel.py") -panel = nipanel.create_panel(panel_script_path) - -# def example( -# resource_name, -# options, -# -# ): -# - -def example(resource_name, channels, options, length, total_acquisition_time_in_seconds, voltage, sample_rate_in_hz, samples_per_fetch,): - # fetch_into() allows you to preallocate and reuse the destination of the fetched waveforms, which can result in better performance at the expense of the usability of fetch(). - channels = [ch.strip() for ch in channels.split(",")] - num_channels = len(channels) - num_records = 1000 - total_num_wfms = num_channels * num_records - # preallocate a single array for all samples in all waveforms - # Supported array types are: numpy.float64, numpy.int8, numpy.int16, numpy.int32 - # int8, int16, int32 are for fetching unscaled data, which is the fastest way to fetch. - # Gain and Offset are stored in the returned WaveformInfo objects and can be applied to the data by the user later. - - wfm = numpy.ndarray(length * total_num_wfms, dtype=numpy.float64) - with niscope.Session(resource_name=resource_name, options=options) as session: - session.configure_vertical(range=2, coupling=niscope.VerticalCoupling.AC) - session.configure_horizontal_timing(min_sample_rate=100000000, min_num_pts=length, ref_position=50.0, num_records=num_records, enforce_realtime=True) - total_samples = int(total_acquisition_time_in_seconds * sample_rate_in_hz) - with session.initiate(): - waveforms = session.channels[channels].fetch_into(waveform=wfm, num_records=num_records) - for i in range(len(waveforms)): - time.sleep(0.2) - panel.set_value("samples", total_samples) - panel.set_value("Waveform", waveforms[i].samples.tolist()) - - -def _main(argsv): - parser = argparse.ArgumentParser(description='Fetches data directly into a preallocated numpy array.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('-n', '--resource-name', default='Dev2', help='Resource name of an NI digitizer.') - parser.add_argument('-c', '--channels', default='0', help='Channel(s) to use') - parser.add_argument('-l', '--length', default=100, type=int, help='Measure record length') - parser.add_argument('-v', '--voltage', default=1.0, type=float, help='Voltage range (V)') - parser.add_argument('-op', '--option-string', default='', type=str, help='Option string') - parser.add_argument("-t", "--time", default=10, type=int, help="Time to sample (s)") - parser.add_argument("-r", "--sample-rate", default=1000.0, type=float, help="Sample Rate (Hz)") - parser.add_argument( - "-s", "--samples-per-fetch", default=100, type=int, help="Samples per fetch" - ) - args = parser.parse_args(argsv) - example(args.resource_name, args.channels, args.option_string, args.length, args.voltage, args.time, - args.sample_rate, - args.samples_per_fetch) - - - -def main(): - _main(sys.argv[1:]) - - -def test_example(): - options = {'simulate': True, 'driver_setup': {'Model': '5124', 'BoardType': 'PXI', }, } - example('Dev2', '0, 1', options, 100, 1.0) - - -def test_main(): - cmd_line = ['--option-string', 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', ] - _main(cmd_line) - - -if __name__ == '__main__': - main() - -# # We use fetch_into which allows us to allocate a single buffer per channel and "fetch into" it a section at a time without having to -# # reconstruct the waveform once we are done -# def example( -# resource_name, -# options, -# total_acquisition_time_in_seconds, -# voltage, -# sample_rate_in_hz, -# samples_per_fetch, -# ): -# total_samples = int(total_acquisition_time_in_seconds * sample_rate_in_hz) -# # 1. Opening session -# with niscope.Session(resource_name=resource_name, options=options) as session: -# # We will acquire on all channels of the device -# channel_list = [ -# c for c in range(session.channel_count) -# ] # Need an actual list and not a range - -# # 2. Creating numpy arrays -# waveforms = [np.ndarray(total_samples, dtype=np.float64) for c in channel_list] -# offset = session._fetch_offset - -# # 3. Configuring -# session.configure_horizontal_timing( -# min_sample_rate=sample_rate_in_hz, -# min_num_pts=1, -# ref_position=0.0, -# num_records=1, -# enforce_realtime=True, -# ) -# session.channels[channel_list].configure_vertical( -# voltage, coupling=niscope.VerticalCoupling.DC, enabled=True -# ) -# # Configure software trigger, but never send the trigger. -# # This starts an infinite acquisition, until you call session.abort() or session.close() -# session.configure_trigger_software() -# current_pos = 0 - -# # 4. initiating -# with session.initiate(): -# while current_pos < total_samples: -# # We fetch each channel at a time so we don't have to de-interleave afterwards -# # We do not keep the wfm_info returned from fetch_into -# for channel, waveform in zip(channel_list, waveforms): -# data = waveform.tolist() -# panel.set_value("total", current_pos) -# time.sleep(0.2) -# panel.set_value("Waveform", data) -# panel.set_value("samples", total_samples) -# # session.channels[channel].fetch(num_samples=1000) -# # 5. fetching - we return the slice of the waveform array that we want to "fetch into" -# session.channels[channel].fetch_into( -# waveform[current_pos : current_pos + samples_per_fetch], -# relative_to=niscope.FetchRelativeTo.READ_POINTER, -# offset=0, -# record_number=0, -# num_records=1, -# timeout=hightime.timedelta(seconds=5.0), -# ) -# current_pos += samples_per_fetch - - -# def _main(argsv): -# parser = argparse.ArgumentParser( -# description="Fetch more samples than will fit in memory.", -# formatter_class=argparse.ArgumentDefaultsHelpFormatter, -# ) -# parser.add_argument( -# "-n", "--resource-name", default="Dev2", help="Resource name of an NI digitizer." -# ) -# parser.add_argument("-t", "--time", default=10, type=int, help="Time to sample (s)") -# parser.add_argument("-v", "--voltage", default=1.0, type=float, help="Voltage range (V)") -# parser.add_argument("-op", "--option-string", default="", type=str, help="Option string") -# parser.add_argument("-r", "--sample-rate", default=1000.0, type=float, help="Sample Rate (Hz)") -# parser.add_argument( -# "-s", "--samples-per-fetch", default=100, type=int, help="Samples per fetch" -# ) -# args = parser.parse_args(argsv) -# example( -# args.resource_name, -# args.option_string, -# args.time, -# args.voltage, -# args.sample_rate, -# args.samples_per_fetch, -# ) - - -# def main(): -# _main(sys.argv[1:]) - - -# def test_example(): -# options = { -# "simulate": True, -# "driver_setup": { -# "Model": "5124", -# "BoardType": "PXI", -# }, -# } -# example("Dev2", options, 10, 1.0, 1000.0, 100) - - -# def test_main(): -# cmd_line = [ -# "--option-string", -# "Simulate=1, DriverSetup=Model:5124; BoardType:PXI", -# ] -# _main(cmd_line) - - -# if __name__ == "__main__": -# main() - - diff --git a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py deleted file mode 100644 index 246e0537..00000000 --- a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py +++ /dev/null @@ -1,38 +0,0 @@ -"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" - -import nipanel -import nidaqmx -import pathlib -import time - -script_path = pathlib.Path(__file__) -panel_script_path = str(script_path.with_name("nidaqmx_continuous_analog_input_panel.py")) - -panel = nipanel.StreamlitPanel( - panel_id="nidaqmx_continuous_analog_input_panel", - streamlit_script_path=panel_script_path, -) - -data_arr = [] -with nidaqmx.Task() as task: - task.ai_channels.add_ai_voltage_chan("Mod1/ai2") - task.ai_channels.add_ai_thrmcpl_chan("Mod1/ai3") - try: - total_read = 0 - while True: - data = task.read(number_of_samples_per_channel=3) - read = len(data) - total_read += read - - data_arr.append(data) - time.sleep(1) - panel.set_value("amplitude",data_arr[-1][-1]) - panel.set_value("Volts",data_arr[-1][0]) - except KeyboardInterrupt: - pass - finally: - task.stop() - print(f"\nAcquired {total_read} total samples.") - - - diff --git a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py deleted file mode 100644 index b83f09b5..00000000 --- a/examples/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py +++ /dev/null @@ -1,168 +0,0 @@ -"""Streamlit application script for displaying values using nipanel package.""" -import nipanel -import streamlit as st -import streamlit.components.v1 as components -from streamlit_echarts import st_echarts - -panel = nipanel.StreamlitPanelValueAccessor(panel_id="nidaqmx_continuous_analog_input_panel") - -add_refresh_component = components.declare_component( - "panelRefreshComponent", - url=f"http://localhost:42001/panels/refresh/{panel.panel_id}",) -add_refresh_component() - - -st.title("Analog Input - Voltage and Thermocouple in a Single Task") -voltage_tab, thermocouple_tab = st.tabs(["Voltage", "Thermocouple"]) - -st.markdown( - """ - - """, - unsafe_allow_html=True -) - - -list_of_therm_amp = panel.get_value("amplitude") -list_of_voltage_amp = panel.get_value("Volts") - -if "therm_history" not in st.session_state: - st.session_state.therm_history = [] -if "volts_history" not in st.session_state: - st.session_state.volts_history = [] - -for therm_amp in list_of_therm_amp: - st.session_state.therm_history.append(therm_amp) -for voltage_amp in list_of_voltage_amp: - st.session_state.volts_history.append(voltage_amp) - -therm_amp_graph = { - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["thermocouple_amplitude"]}, - "xAxis": { - "type": "category", - "data":list(range(len(st.session_state.therm_history))), - "name": "Time" - }, - "yAxis": { - "type": "value", - "name": "Thermocouple Amplitude" - }, - "series": [ - { - "name": "thermocouple_amplitude", - "type": "line", - "data": st.session_state.therm_history, - "color": "red" - }, - - - ], -} -st_echarts(options=therm_amp_graph, height="400px") - -voltage_amp_graph = { - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["voltage_amplitude"]}, - "xAxis": { - "type": "category", - "data": list(range(len(st.session_state.volts_history))), - "name": "Time" - }, - "yAxis": { - "type": "value", - "name": "Voltage Amplitude" - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": st.session_state.volts_history, - }, - - ], -} -st_echarts(options=voltage_amp_graph, height="400px") - -st.header("Voltage & Thermocouple") -voltage_therm_graph = { - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["voltage_amplitude", "thermocouple_amplitude"]}, - "xAxis": { - "type": "category", - "data": list(range(len(st.session_state.volts_history))), - "name": "Time" - }, - "yAxis": { - "type": "value", - "name": "Voltage and Thermocouple Amplitude" - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": st.session_state.volts_history, - "emphasis": {"focus":"series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - { - "name": "thermocouple_amplitude", - "type": "line", - "data": st.session_state.therm_history, - "color": "red", - "emphasis": {"focus":"series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], -} -st_echarts(options=voltage_therm_graph, height="400px") - -with voltage_tab: - left_volt_tab, center_volt_tab, right_volt_tab = st.columns(3) - with left_volt_tab: - st.selectbox(options=["Mod1/ai2"], label="Physical Channels", disabled=True) - st.selectbox(options=["Off"], label="Logging Modes", disabled=False) - with center_volt_tab: - st.selectbox(options=["-5"],label="Min Value") - st.selectbox(options=["5"],label="Max Value") - st.selectbox(options=["1000"], label="Samples per Loops", disabled=False) - with right_volt_tab: - st.selectbox(options=["default"], label="Terminal Configurations") - st.selectbox(options=["OnboardClock"], label="Sample Clock Sources", disabled=False) - - -thermocouple_tab.header("Thermocouple") -with thermocouple_tab: - left, middle, right = st.columns(3) - with left: - st.selectbox(options=["Mod1/ai3"], label="Physical Channel", disabled=True) - st.selectbox(options=["0"], label="Min", disabled=False) - st.selectbox(options=["100"], label="Max", disabled=False) - st.selectbox(options=["Off"], label="Logging Mode", disabled=False) - - with middle: - st.selectbox(options=["Deg C"], label = "Units", disabled=False) - st.selectbox(options=["J"], label="Thermocouple Type", disabled=False) - st.selectbox(options=["Constant Value"], label="CJC Source", disabled=False) - st.selectbox(options=["1000"], label="Samples per Loop", disabled=False) - with right: - st.selectbox(options=["25"],label="CJC Value", disabled=False) - st.selectbox(options=["OnboardClock"], label="Sample Clock Source", disabled=False) - st.selectbox(options=[" "], label="Actual Sample Rate", disabled=True) - - - - - - - - - - - diff --git a/examples/niscope/niscope_example.py b/examples/niscope/niscope_example.py new file mode 100644 index 00000000..3429bd32 --- /dev/null +++ b/examples/niscope/niscope_example.py @@ -0,0 +1,95 @@ +import argparse +import niscope +import numpy as np +import pprint +import sys +import nipanel +from pathlib import Path +import time +import hightime +pp = pprint.PrettyPrinter(indent=4, width=80) +panel_script_path = Path(__file__).with_name("niscope_panel.py") +panel = nipanel.create_panel(panel_script_path) + + + +def example(resource_name, channels, options, length, total_acquisition_time_in_seconds, voltage, sample_rate_in_hz, samples_per_fetch,): + channels = [ch.strip() for ch in channels.split(",")] + num_channels = len(channels) + + num_records = 1000 + total_num_wfms = num_channels * num_records + current_pos = 0 + # preallocate a single array for all samples in all waveforms + # Supported array types are: numpy.float64, numpy.int8, numpy.int16, numpy.int32 + # int8, int16, int32 are for fetching unscaled data, which is the fastest way to fetch. + # Gain and Offset are stored in the returned WaveformInfo objects and can be applied to the data by the user later. + total_samples = int(total_acquisition_time_in_seconds * sample_rate_in_hz) + wfm = np.ndarray(length * total_num_wfms, dtype=np.int8) + with niscope.Session(resource_name=resource_name, options=options) as session: + + session.configure_vertical(range=10, coupling=niscope.VerticalCoupling.DC, enabled=True) + session.configure_horizontal_timing(min_sample_rate=100000000, min_num_pts=length, ref_position=50.0, num_records=num_records, enforce_realtime=True) + max_points_per_fetch = 1000 + session._fetch_meas_num_samples = max_points_per_fetch + session.configure_trigger_software() + + with session.initiate(): + waveforms = session.channels[channels].fetch_into( relative_to=niscope.FetchRelativeTo.READ_POINTER, + offset=0, record_number=0, timeout=hightime.timedelta(seconds=5.0), waveform=wfm, num_records=num_records) + offset = session._fetch_offset + gain = session.meas_array_gain + for i in range(len(waveforms)): + time.sleep(1) + amplitude_list = [] + current_pos += samples_per_fetch + panel.set_value("samples", total_samples) + + total_data = waveforms[i].samples.tolist() + print(waveforms[i]) + for amplitude in total_data: + amplitude = (amplitude * 10) * gain + offset + amplitude_list.append(amplitude) + panel.set_value("Waveform", amplitude_list) + +def _main(argsv): + parser = argparse.ArgumentParser(description='Fetches data directly into a preallocated numpy array.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-n', '--resource-name', default='Dev2', help='Resource name of an NI digitizer.') + parser.add_argument('-c', '--channels', default='0', help='Channel(s) to use') + parser.add_argument('-l', '--length', default=100, type=int, help='Measure record length') + parser.add_argument('-v', '--voltage', default=1.0, type=float, help='Voltage range (V)') + parser.add_argument('-op', '--option-string', default='', type=str, help='Option string') + parser.add_argument("-t", "--time", default=1, type=int, help="Time to sample (s)") + parser.add_argument("-r", "--sample-rate", default=1000.0, type=float, help="Sample Rate (Hz)") + parser.add_argument( + "-s", "--samples-per-fetch", default=1000, type=int, help="Samples per fetch" + ) + args = parser.parse_args(argsv) + example(args.resource_name, + args.channels, + args.option_string, + args.length, + args.voltage, + args.time, + args.sample_rate, + args.samples_per_fetch) + + + +def main(): + _main(sys.argv[1:]) + + +def test_example(): + options = {'simulate': True, 'driver_setup': {'Model': '5124', 'BoardType': 'PXI', }, } + example("Dev2", options, 1, 1.0, 1000.0, 1000) + + +def test_main(): + cmd_line = ['--option-string', 'Simulate=1, RangeCheck=1, DriverSetup=Model:5124; BoardType:PXI', ] + _main(cmd_line) + + +if __name__ == '__main__': + main() + diff --git a/examples/nidaqmx/niscope_panel.py b/examples/niscope/niscope_panel.py similarity index 100% rename from examples/nidaqmx/niscope_panel.py rename to examples/niscope/niscope_panel.py From a8f847ba0ac70c06d608e81a1049791024382f89 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 8 Jul 2025 09:40:10 -0500 Subject: [PATCH 04/68] Analog Input Filtering --- .../nidaqmx_continuous_analog_input.py | 4 +- .../nidaqmx_analog_input_filtering.py | 64 +++--- .../nidaqmx_analog_input_filtering_panel.py | 193 +++++++++++++++--- .../settings_enum.py | 12 +- 4 files changed, 220 insertions(+), 53 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input.py index f3ab592d..6abbfdac 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input.py @@ -11,8 +11,8 @@ panel = nipanel.create_panel(panel_script_path) with nidaqmx.Task() as task: - task.ai_channels.add_ai_voltage_chan("Dev1/ai0") - task.ai_channels.add_ai_thrmcpl_chan("Dev1/ai1") + task.ai_channels.add_ai_voltage_chan("Mod1/ai0") + task.ai_channels.add_ai_thrmcpl_chan("Mod1/ai1") task.timing.cfg_samp_clk_timing( rate=1000.0, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=3000 ) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 83f9d1c6..a55a0767 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -4,8 +4,8 @@ import nidaqmx -from nidaqmx.constants import AcquisitionType, ExcitationSource, Edge, Slope -from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause +from nidaqmx.constants import AcquisitionType, ExcitationSource, Edge, Slope, Timescale, TerminalConfiguration +from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause, TerminalConfig import nipanel import time @@ -13,18 +13,45 @@ panel = nipanel.create_panel(panel_script_path) - with nidaqmx.Task() as task: - chan_voltage = task.ai_channels.add_ai_voltage_chan("Mod3/ai10") - chan_strain_gage = task.ai_channels.add_ai_strain_gage_chan("Mod3/ai7", voltage_excit_source=ExcitationSource.EXTERNAL) - chan_current = task.ai_channels.add_ai_current_chan("Mod3/ai9") + terminal_config = TerminalConfig(panel.get_value("terminal_config", TerminalConfig.RSE.value)) + chan_voltage = task.ai_channels.add_ai_voltage_chan("Mod3/ai10", terminal_config=TerminalConfiguration.DEFAULT) + chan_strain_gage = task.ai_channels.add_ai_strain_gage_chan("Mod3/ai7", voltage_excit_source=ExcitationSource.EXTERNAL, max_val=0.001, min_val=-0.001) + chan_current = task.ai_channels.add_ai_current_chan("Mod3/ai9", max_val = 0.01, min_val= -0.01, ext_shunt_resistor_val=249) task.timing.cfg_samp_clk_timing( - rate = 1000.0, sample_mode = AcquisitionType.CONTINUOUS, samps_per_chan = 3000 + rate = 1000.0, sample_mode = AcquisitionType.CONTINUOUS, samps_per_chan = 1000 ) - + task.timing.samp_clk_dig_fltr_min_pulse_width = 20.0e-6 task.timing.samp_clk_dig_fltr_enable = True chan_voltage.ai_filter_response + filter = panel.get_value("filter", "No Filtering") + if filter == "No Filtering": + chan_voltage.ai_filter_freq = 0.0 + chan_current.ai_filter_freq = 0.0 + chan_strain_gage.ai_filter_freq = 0.0 + + chan_voltage.ai_filter_order = 0 + chan_current.ai_filter_order = 0 + chan_strain_gage.ai_filter_order = 0 + + chan_voltage.ai_filter_response = panel.get_value("filter_response", "Comb") + chan_current.ai_filter_response = panel.get_value("filter_response", "Comb") + chan_strain_gage.ai_filter_response = panel.get_value("filter_response", "Comb") + else: + chan_voltage.ai_filter_freq = panel.get_value("filter_freq", 1000.0) + chan_current.ai_filter_freq = panel.get_value("filter_freq", 1000.0) + chan_strain_gage.ai_filter_freq = panel.get_value("filter_freq", 1000.0) + + chan_voltage.ai_filter_order = panel.get_value("filter_order", 1) + chan_current.ai_filter_order = panel.get_value("filter_order", 1) + chan_strain_gage.ai_filter_order = panel.get_value("filter_order", 1) + + chan_voltage.ai_filter_response = panel.get_value("filter_response", "Comb") + chan_current.ai_filter_response = panel.get_value("filter_response", "Comb") + chan_strain_gage.ai_filter_response = panel.get_value("filter_response", "Comb") + + panel.set_value("source", [task.triggers.pause_trigger.dig_lvl_src]) panel.set_value("analog_source", [task.triggers.start_trigger.anlg_edge_src]) @@ -49,7 +76,11 @@ print(f"Press Ctrl + C to stop") while True: + date = panel.get_value("date", None) + time_input = panel.get_value("time", None) + hysteriresis = panel.get_value("hysteriesis", 0.0) + task.triggers.start_trigger.cfg_time_start_trig(when = date, timescale=Timescale.USE_HOST) level = panel.get_value("level", 0.0) new_slope = Slopes(panel.get_value("slope",Slopes.FALLING.value)) if slope != new_slope: @@ -59,6 +90,7 @@ task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=level, trigger_slope= Slope.RISING) else: task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=level, trigger_slope= Slope.FALLING) + task.triggers.start_trigger.anlg_edge_hyst = hysteriresis task.start() slope = new_slope @@ -88,21 +120,7 @@ task.triggers.start_trigger.cfg_dig_edge_start_trig - # task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/te1/SampleClock") - # task.triggers.start_trigger.cfg_time_start_trig(10) - # task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0") - # Configure a digital pause trigger (example) - # Replace "PFI0" with your actual trigger source if needed - - # task.triggers.pause_trigger.trig_type = TriggerType.DIGITAL_LEVEL - # task.triggers.pause_trigger.dig_lvl_src = "/Dev2/PFI0" - - # task.triggers.pause_trigger.dig_lvl_when - # task.triggers.pause_trigger.trig_type = TriggerType.ANALOG_LEVEL - # task.triggers.pause_trigger.anlg_lvl_src - # task.triggers.pause_trigger.anlg_lvl_when - - + data = task.read(number_of_samples_per_channel=100) panel.set_value("voltage_data", data[0]) panel.set_value("current_data", data[2]) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 6c7c312a..eff6cd47 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -2,7 +2,7 @@ import streamlit as st from streamlit_echarts import st_echarts -from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause +from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause, TerminalConfig import time import nipanel @@ -13,8 +13,6 @@ panel = nipanel.get_panel_accessor() -tabs = st.tabs(["Voltage", "Current", "Strain Gage"]) - st.markdown( """ """ -st.markdown(streamlit_style, unsafe_allow_html=True) - -source = panel.get_value("source", []) -analog_source = panel.get_value("analog_source", []) +st.markdown(streamlit_style, unsafe_allow_html=True) -voltage_data = panel.get_value("voltage_data", [1.0]) -current_data = panel.get_value("current_data", [1.0]) -strain_data = panel.get_value("strain_data", [1.0]) -sample_rate = panel.get_value("sample_rate", 0.0) -data_type = "" -with right_col: +with left_col: with st.container(border=True): st.title("Channel Settings") st.selectbox(options=["Mod3/ai10"], index=0, label="Physical Channels", disabled=True) - terminal_config = st.selectbox( - "terminal_config", - options=[(e.name, e.value) for e in TerminalConfig], - format_func=lambda x: x[0], - index=0, - ) - terminal_config = TerminalConfig[terminal_config[0]] - - panel.set_value("terminal_config", terminal_config) + enum_selectbox( + panel, + label="Terminal Configuration", + value=TerminalConfiguration.DEFAULT, + disabled=panel.get_value("is_running", False), + key="terminal_configuration", + ) st.title("Timing Settings") - st.selectbox("Sample Clock Source", options=["Onboard Clock"], index=0) - st.number_input("Sample Rate", value=1000, min_value=1, step=1) - st.number_input("Number of Samples", value=100, min_value=1, step=1) - st.selectbox("Actual Sample Rate", options=[""], disabled=True) + + st.selectbox("Sample Clock Source", options=["Onboard Clock"], index=0, disabled=True) + st.number_input( + "Sample Rate", + value=1000, + min_value=1, + step=1, + disabled=panel.get_value("is_running", False), + ) + st.number_input( + "Number of Samples", + value=100, + min_value=1, + step=1, + disabled=panel.get_value("is_running", False), + ) + st.selectbox("Actual Sample Rate", options=[panel.get_value("sample_rate")], disabled=True) st.title("Logging Settings") - st.selectbox("Logging Mode", options=["Off", "Log and Read"], index=0) - st.text_input("TDMS File Path", value="data.tdms") - + enum_selectbox( + panel, + label="Logging Mode", + value=LoggingMode.OFF, + disabled=panel.get_value("is_running", False), + key="logging_mode", + ) + tdms_file_path = st.text_input( + label="TDMS File Path", + disabled=panel.get_value("is_running", False), + value="data.tdms", + key="tdms_file_path", + ) st.title("Filtering Settings") - filter = st.selectbox("Filter", options = ["No Filtering", "Filter"]) + + filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) panel.set_value("filter", filter) - - filter_freq = st.number_input("Filtering Frequency", value = 1000.0, step = 1.0) - st.write(filter_freq) + enum_selectbox( + panel, + label="Filter Response", + value=FilterResponse.COMB, + disabled=panel.get_value("is_running", False), + key="filter_response", + ) + + filter_freq = st.number_input( + "Filtering Frequency", + value=1000.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + filter_order = st.number_input( + "Filter Order", + min_value=0, + max_value=1, + value=0, + disabled=panel.get_value("is_running", False), + ) + if filter == "No Filtering": + filter_freq = 0.0 + filter_order = 0 panel.set_value("filter_freq", filter_freq) - filter_order = st.number_input("Filter Order", min_value=0, max_value=1, value=0) + panel.set_value("filter_order", filter_order) - filter_response = st.selectbox("Filter Response", options=["Comb"]) - panel.set_value("filter_response", filter_response) - if filter == "No Filtering": - panel.set_value("filter_freq", 0.0) - st.selectbox("Actual Filter Frequency", options=[""], disabled=True) + st.selectbox("Actual Filter Frequency", options=[filter_freq], disabled=True) st.selectbox("Actual Filter Order", options=[filter_order], disabled=True) - st.selectbox("Actual Filter Response", options=[filter_response], disabled=True) - +with right_col: + voltage_data = panel.get_value("voltage_data", [1.0]) + current_data = panel.get_value("current_data", [1.0]) + strain_data = panel.get_value("strain_data", [1.0]) -with left_col: +sample_rate = panel.get_value("sample_rate", 0.0) +with right_col: with st.container(border=True): graph = { "animation": False, @@ -151,49 +191,124 @@ def run_update(): ], } st_echarts(options=graph, height="400px", key="graph", width="100%") -with left_col: + + +with right_col: with st.container(border=True): - tabs = st.tabs(["Voltage", "Current", "Strain Gage"]) -with left_col: + st.title("Trigger Settings") + tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs( + [ + "No Trigger", + "Digital Start", + "Digital Pause", + "Digital Reference", + "Analog Start", + "Analog Pause", + "Analog Reference", + "Time Start", + ] + ) + with tab1: + st.write( + "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." + ) + with tab2: + st.selectbox("Source->", " /Dev1/PFI0") + enum_selectbox( + panel, + label="Edge", + value=Edge.FALLING, + disabled=panel.get_value("is_running", False), + key="edge", + ) + with tab3: + st.selectbox("Source-", "/Dev1/PFI0") + pause_when = st.selectbox( + "Pause When", + options=[(e.name, e.value) for e in PauseWhen], + format_func=lambda x: x[0], + index=0, + ) + pause_when = PauseWhen[pause_when[0]] + panel.set_value("pause_when", pause_when) + with tab4: + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + with tab5: + st.selectbox("Source:", "APFI0") + enum_selectbox( + panel, + label="Slope", + value=Slope.FALLING, + disabled=panel.get_value("is_running", False), + key="slope", + ) + + level = st.number_input("Level") + panel.set_value("level", level) + hysteriesis = st.number_input( + "Hysteriesis", disabled=panel.get_value("is_running", False) + ) + panel.set_value("hysteriesis", hysteriesis) + + with tab6: + st.selectbox("source:", "APFI0") + analog_pause = st.selectbox( + "analog_pause", + options=[(e.name, e.value) for e in AnalogPause], + format_func=lambda x: x[0], + index=0, + ) + analog_pause = AnalogPause[analog_pause[0]] + panel.set_value("analog_pause", analog_pause) + + with tab7: + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." + ) + +with right_col: + tabs = st.tabs(["Voltage", "Current", "Strain Gage"]) with st.container(border=True): with tabs[0]: - data_type = "Voltage" st.title("Voltage Data") channel_left, channel_right = st.columns(2) with channel_left: - max_value_voltage = st.number_input( - "Max Value", - value=5.0, - step=0.1, + max_value_voltage = st.number_input( + "Max Value", value=5.0, step=0.1, disabled=panel.get_value("is_running", False) ) - panel.set_value("max_value_voltage",max_value_voltage) + panel.set_value("max_value_voltage", max_value_voltage) min_value_voltage = st.number_input( - "Min Value", - value=-5.0, - step=0.1, + "Min Value", value=-5.0, step=0.1, disabled=panel.get_value("is_running", False) ) panel.set_value("min_value_voltage", min_value_voltage) with tabs[1]: st.title("Current Data") - data_type = "Current" channel_left, channel_right = st.columns(2) with channel_left: - shunt_location = st.selectbox( - "shunt_location", - options=[(e.name, e.value) for e in ShuntLocation], - format_func=lambda x: x[0], - index=0, + enum_selectbox( + panel, + label="Shunt Resistor Location", + value=CurrentShuntResistorLocation.EXTERNAL, + disabled=panel.get_value("is_running", False), + key="shunt_location", + ) + enum_selectbox( + panel, + label="Units", + value=CurrentUnits.AMPS, + disabled=panel.get_value("is_running", False), + key="units", ) - shunt_location = ShuntLocation[shunt_location[0]] - panel.set_value("shunt_location", shunt_location) - st.selectbox(options=["Amps"], label="Units", index=0, disabled=True) with st.expander("More current info", expanded=False): min_value_current = st.number_input( "Min Value", value=-0.01, step=0.001, + disabled=panel.get_value("is_running", False), ) panel.set_value("min_value_current", min_value_current) max_value_current = st.number_input( @@ -201,16 +316,17 @@ def run_update(): value=0.01, step=1.0, key="max_value_current", + disabled=panel.get_value("is_running", False), ) current = panel.set_value("max_value_current", max_value_current) shunt_resistor_value = st.number_input( "Shunt Resistor Value", value=249.0, step=1.0, - ) + disabled=panel.get_value("is_running", False), + ) panel.set_value("shunt_resistor_value", shunt_resistor_value) with tabs[2]: - data_type = "Strain" st.title("Strain Gage Data") channel_left, channel_right = st.columns(2) with channel_left: @@ -221,36 +337,48 @@ def run_update(): ) panel.set_value("min_value_strain", min_value_strain) max_value_strain = st.number_input( - "Max Value", - value=0.01, - step=0.01, - max_value=2.0 + "Max Value", value=0.01, step=0.01, max_value=2.0 ) panel.set_value("max_value_strain", max_value_strain) - with st.expander("strain gage information", expanded=False): - st.title("strain gage information") + enum_selectbox( + panel, + label="Strain Units", + value=CurrentUnits.AMPS, + disabled=panel.get_value("is_running", False), + key="strain_units", + ) + with st.expander("Strain Gage Information", expanded=False): + st.title("Strain Gage Information") gage_factor = st.number_input( "Gage Factor", value=2.0, step=1.0, + disabled=panel.get_value("is_running", False), ) panel.set_value("gage_factor", gage_factor) nominal_gage = st.number_input( "nominal gage resistance", value=350.0, step=1.0, + disabled=panel.get_value("is_running", False), ) - panel.set_value("gage_resistance",nominal_gage) + panel.set_value("gage_resistance", nominal_gage) poisson_ratio = st.number_input( "poisson ratio", value=0.3, step=1.0, + disabled=panel.get_value("is_running", False), ) panel.set_value("poisson_ratio", poisson_ratio) - with st.expander("strain gage information", expanded=False): - st.title("bridge information") - st.selectbox(label="strain configuration", options=["Full Bridge I", "Quarter Bridge", "Half Bridge II", "Half Bridge I", "Full Bridge III", "Full Bridge II"], key="strain_config",index=0, disabled=False) - panel.set_value("strain_config", "strain_config") + with st.expander("Bridge Information", expanded=False): + st.title("Bridge Information") + enum_selectbox( + panel, + label="Strain Configuration", + value=StrainGageBridgeType.FULL_BRIDGE_I, + disabled=panel.get_value("is_running", False), + key="strain_configuration", + ) wire_resistance = st.number_input( "lead wire resistance", value=0.0, @@ -261,144 +389,22 @@ def run_update(): "initial bridge voltage", value=0.0, step=1.0, + disabled=panel.get_value("is_running", False), ) - panel.set_value("initial_voltage",initial_voltage) + panel.set_value("initial_voltage", initial_voltage) - st.selectbox(label="voltage excitation source", key = "voltage_excit",options=["External"], disabled=True) + st.selectbox( + label="voltage excitation source", + key="voltage_excit", + options=["External"], + disabled=True, + ) panel.set_value("voltage_excitation_source", "voltage_excit") voltage_excit = st.number_input( "voltage excitation value", value=2.5, step=1.0, key="voltage_excitation_value", + disabled=panel.get_value("is_running", False), ) - panel.set_value("voltage_excitation_value",voltage_excit) - -tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs(["No Trigger","Digital Start","Digital Pause","Digital Reference","Analog Start","Analog Pause", "Analog Reference", "Time Start"]) -with tab1: - st.write("To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information.") -with tab2: - st.selectbox("Source->", source) - edge_digital = st.selectbox( - "Edge", - options=[(e.name, e.value) for e in DigitalEdge], - format_func=lambda x: x[0], - index=0, - ) - edge_digital = DigitalEdge[edge_digital[0]] - panel.set_value("edge_digital", edge_digital) - -with tab3: - st.selectbox("Source-", source) - pause_when = st.selectbox( - "Pause When", - options=[(e.name, e.value) for e in PauseWhen], - format_func=lambda x: x[0], - index=0, - ) - pause_when = PauseWhen[pause_when[0]] - panel.set_value("pause_when", pause_when) -with tab4: - st.write("This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported") -with tab5: - st.selectbox("Source:", analog_source) - slope = st.selectbox( - "Slope", - options=[(e.name, e.value) for e in Slopes], - format_func=lambda x: x[0], - index=0, - ) - slope = Slopes[slope[0]] - panel.set_value("slope", slope) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input("Hysteriesis") - panel.set_value("hysteriesis", hysteriesis) - -with tab6: - st.selectbox("source:", analog_source) - analog_pause = st.selectbox( - "analog_pause", - options=[(e.name, e.value) for e in AnalogPause], - format_func=lambda x: x[0], - index=0, - ) - analog_pause = AnalogPause[analog_pause[0]] - panel.set_value("analog_pause", analog_pause) - -with tab7: - st.write("This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported.") -with tab8: - date = st.date_input("Date", value=None) - time_input = st.time_input("Time", value=None) - st.write("If time is not manually set, task will begin after 10 seconds") - - - -# graph_2= { -# "animation": False, -# "tooltip": {"trigger": "axis"}, -# "legend": {"data": ["Voltage (V)"]}, -# "xAxis": { -# "type": "category", -# "data": [x / sample_rate for x in range(len(current_data))], -# "name": "Time", -# "nameLocation": "center", -# "nameGap": 40, -# }, -# "yAxis": { -# "type": "value", -# "name": "Volts", -# "nameRotate": 90, -# "nameLocation": "center", -# "nameGap": 40, -# }, -# "series": [ -# { -# "name": "voltage_amplitude", -# "type": "line", -# "data": current_data, -# "emphasis": {"focus": "series"}, -# "smooth": True, -# "seriesLayoutBy": "row", -# }, -# ], -# } -# with tabs[1]: -# st_echarts(options=graph_2, height="400px", key="graph_2", width="100%") -# graph_3 = { -# "animation": False, -# "tooltip": {"trigger": "axis"}, -# "legend": {"data": ["Voltage (V)"]}, -# "xAxis": { -# "type": "category", -# "data": [x / sample_rate for x in range(len(strain_data))], -# "name": "Time", -# "nameLocation": "center", -# "nameGap": 40, -# }, -# "yAxis": { -# "type": "value", -# "name": "Volts", -# "nameRotate": 90, -# "nameLocation": "center", -# "nameGap": 40, -# }, -# "series": [ -# { -# "name": "voltage_amplitude", -# "type": "line", -# "data": strain_data, -# "emphasis": {"focus": "series"}, -# "smooth": True, -# "seriesLayoutBy": "row", -# }, -# ], -# } -# with tabs[2]: -# st_echarts(options=graph_3, height="400px", key="graph_3", width="100%") - - - - + panel.set_value("voltage_excitation_value", voltage_excit) diff --git a/examples/nidaqmx_analog_input_filtering/settings_enum.py b/examples/nidaqmx_analog_input_filtering/settings_enum.py index 09f26305..a2f208f4 100644 --- a/examples/nidaqmx_analog_input_filtering/settings_enum.py +++ b/examples/nidaqmx_analog_input_filtering/settings_enum.py @@ -1,30 +1,13 @@ - """Enumeration for amplitude values used in the simple graph example.""" import enum -from nidaqmx.constants import Edge, Slope, Timescale, TerminalConfiguration -class DigitalEdge(enum.StrEnum): - FALLING = "FALLING" - RISING = "RISING" + class PauseWhen(enum.StrEnum): HIGH = "High" LOW = "Low" -class Slopes(enum.StrEnum): - FALLING = "Falling" - RISING = "Rising" class AnalogPause(enum.StrEnum): ABOVE = "ABOVE" BELOW = "BELOW" - -class TerminalConfig(enum.StrEnum): - DEFAULT = "DEFAULT" - RSE = "RSE" - NRSE = "NRSE" - DIFF = "DIFF" - PSEUDO_DIFF = "PSEUDO_DIFF" -class ShuntLocation(enum.StrEnum): - DEFAULT = "DEFAULT" - EXTERNAL = "EXTERNAL" \ No newline at end of file diff --git a/examples/niscope/niscope_ex_fetch_forever.py b/examples/niscope/niscope_ex_fetch_forever.py index e7da4462..5f2a5ab8 100644 --- a/examples/niscope/niscope_ex_fetch_forever.py +++ b/examples/niscope/niscope_ex_fetch_forever.py @@ -46,11 +46,7 @@ try: print(f"Press Ctrl + C to stop") while True: -<<<<<<< HEAD offset = session._fetch_offset -======= - offset = session.meas_array_offset ->>>>>>> main gain = session.meas_array_gain for i in range(len(waveforms)): time.sleep(0.2) From 0f7ddc176c0951ebd88d8910f8ab938a1c8dfdac Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 10:28:46 -0500 Subject: [PATCH 06/68] Added README.md --- .../nidaqmx_analog_input_filtering/README.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 examples/nidaqmx_analog_input_filtering/README.md diff --git a/examples/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx_analog_input_filtering/README.md new file mode 100644 index 00000000..5bd4314b --- /dev/null +++ b/examples/nidaqmx_analog_input_filtering/README.md @@ -0,0 +1,20 @@ +Prerequisites +=============== +Requires a Physical or Simulated Device. Refer to the [Getting Started Section](https://github.com/ni/nidaqmx-python/blob/master/README.rst) to learn how to create a simulated device. +## Sample + +This is a nipanel example that displays an interactive Streamlit app and updates and fetches data from device. + +### Feature + +Script demonstrates analog input data getting continuously acquired, and being filtered. +- Supports various data types + +### Required Software + +- Python 3.9 or later + +### Usage + +Run `poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py` + From 79ae4db9992ef4347e0e4ec0f07e885c8edb0f64 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 11:23:16 -0500 Subject: [PATCH 07/68] fixed mypy & lint errors --- .../nidaqmx_analog_input_filtering.py | 3 +- .../nidaqmx_analog_input_filtering_panel.py | 29 +++++++++---------- .../settings_enum.py | 4 +++ examples/simple_graph/simple_graph_panel.py | 4 +-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index d15973a3..562b2efe 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -3,7 +3,6 @@ from pathlib import Path import nidaqmx -import numpy as numpy from nidaqmx.constants import ( AcquisitionType, CurrentShuntResistorLocation, @@ -16,7 +15,6 @@ Slope, StrainGageBridgeType, TerminalConfiguration, - Timescale, ) from settings_enum import AnalogPause, PauseWhen @@ -35,6 +33,7 @@ panel.set_value("is_running", True) panel.set_value("stop_button", False) + # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan_type = panel.get_value("chan_type", "1") if chan_type == "1": diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 853890f0..28311aa3 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -1,21 +1,20 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py.""" +"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" +import extra_streamlit_components as stx # type: ignore[import-untyped] import streamlit as st -from streamlit_echarts import st_echarts -import extra_streamlit_components as stx -from settings_enum import PauseWhen, AnalogPause from nidaqmx.constants import ( - TerminalConfiguration, - SampleTimingType, - FilterResponse, CurrentShuntResistorLocation, + CurrentUnits, Edge, - Slope, + FilterResponse, LoggingMode, - CurrentUnits, + Slope, StrainGageBridgeType, + TerminalConfiguration, ) -import time +from settings_enum import AnalogPause, PauseWhen +from streamlit_echarts import st_echarts + import nipanel from nipanel.controls import enum_selectbox @@ -47,9 +46,9 @@ with left_col: st.write(panel.get_value("is_running", False)) if is_running: - st.button(r"⏹️ Stop", key="stop_button") + st.button("Stop", key="stop_button") else: - st.button(r"▶️ Run", key="run_button") + st.button("Run", key="run_button") st.markdown( @@ -229,7 +228,7 @@ format_func=lambda x: x[0], index=0, ) - pause_when = PauseWhen[pause_when[0]] + pause_when = PauseWhen[pause_when[0]] # type: ignore panel.set_value("pause_when", pause_when) with tab4: st.write( @@ -260,7 +259,7 @@ format_func=lambda x: x[0], index=0, ) - analog_pause = AnalogPause[analog_pause[0]] + analog_pause = AnalogPause[analog_pause[0]] # type: ignore panel.set_value("analog_pause", analog_pause) with tab7: @@ -318,7 +317,7 @@ key="max_value_current", disabled=panel.get_value("is_running", False), ) - current = panel.set_value("max_value_current", max_value_current) + current = panel.set_value("max_value_current", max_value_current) # type:ignore shunt_resistor_value = st.number_input( "Shunt Resistor Value", value=249.0, diff --git a/examples/nidaqmx_analog_input_filtering/settings_enum.py b/examples/nidaqmx_analog_input_filtering/settings_enum.py index a2f208f4..6a484b5d 100644 --- a/examples/nidaqmx_analog_input_filtering/settings_enum.py +++ b/examples/nidaqmx_analog_input_filtering/settings_enum.py @@ -4,10 +4,14 @@ class PauseWhen(enum.StrEnum): + """Pause When Trigger Setting.""" + HIGH = "High" LOW = "Low" class AnalogPause(enum.StrEnum): + """Analog Pause Trigger.""" + ABOVE = "ABOVE" BELOW = "BELOW" diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 4d242594..a3afd9ff 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,7 +1,6 @@ """A Streamlit visualization panel for the simple_graph.py example script.""" import streamlit as st -from amplitude_enum import AmplitudeEnum from streamlit_echarts import st_echarts import nipanel @@ -25,8 +24,7 @@ with col5: st.metric("Max Value", f"{max(sine_values):.3f}") -with col6: - st.metric("Data Points", len(sine_values)) + # Prepare data for echarts data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] From 957ef545236c7ccaf13860bda22bdc8849201564 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 11:23:16 -0500 Subject: [PATCH 08/68] fixed mypy & lint errors --- .../nidaqmx_analog_input_filtering.py | 3 +- .../nidaqmx_analog_input_filtering_panel.py | 29 +++++++++---------- .../settings_enum.py | 4 +++ examples/simple_graph/simple_graph_panel.py | 4 +-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index d15973a3..562b2efe 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -3,7 +3,6 @@ from pathlib import Path import nidaqmx -import numpy as numpy from nidaqmx.constants import ( AcquisitionType, CurrentShuntResistorLocation, @@ -16,7 +15,6 @@ Slope, StrainGageBridgeType, TerminalConfiguration, - Timescale, ) from settings_enum import AnalogPause, PauseWhen @@ -35,6 +33,7 @@ panel.set_value("is_running", True) panel.set_value("stop_button", False) + # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan_type = panel.get_value("chan_type", "1") if chan_type == "1": diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 853890f0..28311aa3 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -1,21 +1,20 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py.""" +"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" +import extra_streamlit_components as stx # type: ignore[import-untyped] import streamlit as st -from streamlit_echarts import st_echarts -import extra_streamlit_components as stx -from settings_enum import PauseWhen, AnalogPause from nidaqmx.constants import ( - TerminalConfiguration, - SampleTimingType, - FilterResponse, CurrentShuntResistorLocation, + CurrentUnits, Edge, - Slope, + FilterResponse, LoggingMode, - CurrentUnits, + Slope, StrainGageBridgeType, + TerminalConfiguration, ) -import time +from settings_enum import AnalogPause, PauseWhen +from streamlit_echarts import st_echarts + import nipanel from nipanel.controls import enum_selectbox @@ -47,9 +46,9 @@ with left_col: st.write(panel.get_value("is_running", False)) if is_running: - st.button(r"⏹️ Stop", key="stop_button") + st.button("Stop", key="stop_button") else: - st.button(r"▶️ Run", key="run_button") + st.button("Run", key="run_button") st.markdown( @@ -229,7 +228,7 @@ format_func=lambda x: x[0], index=0, ) - pause_when = PauseWhen[pause_when[0]] + pause_when = PauseWhen[pause_when[0]] # type: ignore panel.set_value("pause_when", pause_when) with tab4: st.write( @@ -260,7 +259,7 @@ format_func=lambda x: x[0], index=0, ) - analog_pause = AnalogPause[analog_pause[0]] + analog_pause = AnalogPause[analog_pause[0]] # type: ignore panel.set_value("analog_pause", analog_pause) with tab7: @@ -318,7 +317,7 @@ key="max_value_current", disabled=panel.get_value("is_running", False), ) - current = panel.set_value("max_value_current", max_value_current) + current = panel.set_value("max_value_current", max_value_current) # type:ignore shunt_resistor_value = st.number_input( "Shunt Resistor Value", value=249.0, diff --git a/examples/nidaqmx_analog_input_filtering/settings_enum.py b/examples/nidaqmx_analog_input_filtering/settings_enum.py index a2f208f4..6a484b5d 100644 --- a/examples/nidaqmx_analog_input_filtering/settings_enum.py +++ b/examples/nidaqmx_analog_input_filtering/settings_enum.py @@ -4,10 +4,14 @@ class PauseWhen(enum.StrEnum): + """Pause When Trigger Setting.""" + HIGH = "High" LOW = "Low" class AnalogPause(enum.StrEnum): + """Analog Pause Trigger.""" + ABOVE = "ABOVE" BELOW = "BELOW" diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 4d242594..a3afd9ff 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,7 +1,6 @@ """A Streamlit visualization panel for the simple_graph.py example script.""" import streamlit as st -from amplitude_enum import AmplitudeEnum from streamlit_echarts import st_echarts import nipanel @@ -25,8 +24,7 @@ with col5: st.metric("Max Value", f"{max(sine_values):.3f}") -with col6: - st.metric("Data Points", len(sine_values)) + # Prepare data for echarts data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] From 886623e92d42938ec6babb8812ccc7b8648a759e Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 15:19:30 -0500 Subject: [PATCH 09/68] Revert changes --- .../nidaqmx_analog_input_filtering/README.md | 2 ++ examples/niscope/niscope_ex_fetch_forever.py | 2 +- examples/simple_graph/amplitude_enum.py | 11 ----------- examples/simple_graph/simple_graph.py | 18 +++++------------- examples/simple_graph/simple_graph_panel.py | 12 +++++------- 5 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 examples/simple_graph/amplitude_enum.py diff --git a/examples/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx_analog_input_filtering/README.md index 5bd4314b..6de44432 100644 --- a/examples/nidaqmx_analog_input_filtering/README.md +++ b/examples/nidaqmx_analog_input_filtering/README.md @@ -16,5 +16,7 @@ Script demonstrates analog input data getting continuously acquired, and being f ### Usage +poetry install --with examples +poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py Run `poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py` diff --git a/examples/niscope/niscope_ex_fetch_forever.py b/examples/niscope/niscope_ex_fetch_forever.py index 5f2a5ab8..68d73161 100644 --- a/examples/niscope/niscope_ex_fetch_forever.py +++ b/examples/niscope/niscope_ex_fetch_forever.py @@ -46,7 +46,7 @@ try: print(f"Press Ctrl + C to stop") while True: - offset = session._fetch_offset + offset = session.meas_array_offset gain = session.meas_array_gain for i in range(len(waveforms)): time.sleep(0.2) diff --git a/examples/simple_graph/amplitude_enum.py b/examples/simple_graph/amplitude_enum.py deleted file mode 100644 index b1f12ca3..00000000 --- a/examples/simple_graph/amplitude_enum.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Enumeration for amplitude values used in the simple graph example.""" - -import enum - - -class AmplitudeEnum(enum.IntEnum): - """Enumeration for amplitude values.""" - - SMALL = 1 - MEDIUM = 5 - BIG = 10 diff --git a/examples/simple_graph/simple_graph.py b/examples/simple_graph/simple_graph.py index 73f78320..f5208c52 100644 --- a/examples/simple_graph/simple_graph.py +++ b/examples/simple_graph/simple_graph.py @@ -1,43 +1,35 @@ """Example of using nipanel to display a sine wave graph using st_echarts.""" - import math import time from pathlib import Path import numpy as np -from amplitude_enum import AmplitudeEnum import nipanel + panel_script_path = Path(__file__).with_name("simple_graph_panel.py") panel = nipanel.create_panel(panel_script_path) amplitude = 1.0 frequency = 1.0 num_points = 100 - try: print(f"Panel URL: {panel.panel_url}") print("Press Ctrl+C to exit") # Generate and update the sine wave data periodically while True: - amplitude_enum = AmplitudeEnum(panel.get_value("amplitude_enum", AmplitudeEnum.SMALL.value)) - base_frequency = panel.get_value("base_frequency", 1.0) - - # Slowly vary the total frequency for a more dynamic visualization - frequency = base_frequency + 0.5 * math.sin(time.time() / 5.0) time_points = np.linspace(0, num_points, num_points) - sine_values = amplitude_enum.value * np.sin(frequency * time_points) - - panel.set_value("frequency", frequency) + sine_values = amplitude * np.sin(frequency * time_points) panel.set_value("time_points", time_points.tolist()) panel.set_value("sine_values", sine_values.tolist()) + panel.set_value("amplitude", amplitude) + panel.set_value("frequency", frequency) # Slowly vary the frequency for a more dynamic visualization frequency = 1.0 + 0.5 * math.sin(time.time() / 5.0) time.sleep(0.1) - except KeyboardInterrupt: - print("Exiting...") + print("Exiting...") \ No newline at end of file diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index a3afd9ff..01e057c4 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,10 +1,10 @@ """A Streamlit visualization panel for the simple_graph.py example script.""" - import streamlit as st from streamlit_echarts import st_echarts import nipanel + st.set_page_config(page_title="Simple Graph Example", page_icon="📈", layout="wide") st.title("Simple Graph Example") @@ -13,7 +13,6 @@ sine_values = panel.get_value("sine_values", [0.0]) amplitude = panel.get_value("amplitude", 1.0) frequency = panel.get_value("frequency", 1.0) - col1, col2, col3, col4, col5 = st.columns(5) with col1: st.metric("Amplitude", f"{amplitude:.2f}") @@ -21,13 +20,13 @@ st.metric("Frequency", f"{frequency:.2f} Hz") with col3: st.metric("Min Value", f"{min(sine_values):.3f}") - -with col5: +with col4: st.metric("Max Value", f"{max(sine_values):.3f}") +with col5: + st.metric("Data Points", len(sine_values)) # Prepare data for echarts data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] - # Configure the chart options options = { "animation": False, # Disable animation for smoother updates @@ -52,6 +51,5 @@ } ], } - # Display the chart -st_echarts(options=options, height="400px", key="graph") +st_echarts(options=options, height="400px", key="graph") \ No newline at end of file From 28f2209cef94976c94d45898fe97aee6723edb29 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 15:23:01 -0500 Subject: [PATCH 10/68] simple graph changes --- examples/simple_graph/simple_graph.py | 6 +++++- examples/simple_graph/simple_graph_panel.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/simple_graph/simple_graph.py b/examples/simple_graph/simple_graph.py index f5208c52..324cf7cc 100644 --- a/examples/simple_graph/simple_graph.py +++ b/examples/simple_graph/simple_graph.py @@ -1,4 +1,5 @@ """Example of using nipanel to display a sine wave graph using st_echarts.""" + import math import time from pathlib import Path @@ -14,6 +15,7 @@ amplitude = 1.0 frequency = 1.0 num_points = 100 + try: print(f"Panel URL: {panel.panel_url}") print("Press Ctrl+C to exit") @@ -31,5 +33,7 @@ # Slowly vary the frequency for a more dynamic visualization frequency = 1.0 + 0.5 * math.sin(time.time() / 5.0) time.sleep(0.1) + except KeyboardInterrupt: - print("Exiting...") \ No newline at end of file + print("Exiting...") + \ No newline at end of file diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 01e057c4..6550627a 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,4 +1,5 @@ """A Streamlit visualization panel for the simple_graph.py example script.""" + import streamlit as st from streamlit_echarts import st_echarts @@ -13,6 +14,7 @@ sine_values = panel.get_value("sine_values", [0.0]) amplitude = panel.get_value("amplitude", 1.0) frequency = panel.get_value("frequency", 1.0) + col1, col2, col3, col4, col5 = st.columns(5) with col1: st.metric("Amplitude", f"{amplitude:.2f}") @@ -27,6 +29,7 @@ # Prepare data for echarts data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] + # Configure the chart options options = { "animation": False, # Disable animation for smoother updates @@ -51,5 +54,6 @@ } ], } + # Display the chart -st_echarts(options=options, height="400px", key="graph") \ No newline at end of file +st_echarts(options=options, height="400px", key="graph") From 709d47eefa1525e77df66b072170cb9eb737cd43 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 15:23:01 -0500 Subject: [PATCH 11/68] simple graph changes --- examples/simple_graph/simple_graph.py | 3 +++ examples/simple_graph/simple_graph_panel.py | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/simple_graph/simple_graph.py b/examples/simple_graph/simple_graph.py index f5208c52..97a27b2e 100644 --- a/examples/simple_graph/simple_graph.py +++ b/examples/simple_graph/simple_graph.py @@ -1,4 +1,5 @@ """Example of using nipanel to display a sine wave graph using st_echarts.""" + import math import time from pathlib import Path @@ -14,6 +15,7 @@ amplitude = 1.0 frequency = 1.0 num_points = 100 + try: print(f"Panel URL: {panel.panel_url}") print("Press Ctrl+C to exit") @@ -31,5 +33,6 @@ # Slowly vary the frequency for a more dynamic visualization frequency = 1.0 + 0.5 * math.sin(time.time() / 5.0) time.sleep(0.1) + except KeyboardInterrupt: print("Exiting...") \ No newline at end of file diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 01e057c4..6550627a 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,4 +1,5 @@ """A Streamlit visualization panel for the simple_graph.py example script.""" + import streamlit as st from streamlit_echarts import st_echarts @@ -13,6 +14,7 @@ sine_values = panel.get_value("sine_values", [0.0]) amplitude = panel.get_value("amplitude", 1.0) frequency = panel.get_value("frequency", 1.0) + col1, col2, col3, col4, col5 = st.columns(5) with col1: st.metric("Amplitude", f"{amplitude:.2f}") @@ -27,6 +29,7 @@ # Prepare data for echarts data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] + # Configure the chart options options = { "animation": False, # Disable animation for smoother updates @@ -51,5 +54,6 @@ } ], } + # Display the chart -st_echarts(options=options, height="400px", key="graph") \ No newline at end of file +st_echarts(options=options, height="400px", key="graph") From 219c2de5cc18fa933a5d39921c946a8f5b86639f Mon Sep 17 00:00:00 2001 From: DilmiWickramanayake <155610400+DilmiWickramanayake@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:31:27 -0500 Subject: [PATCH 12/68] Update simple_graph.py --- examples/simple_graph/simple_graph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/simple_graph/simple_graph.py b/examples/simple_graph/simple_graph.py index 324cf7cc..4b63530f 100644 --- a/examples/simple_graph/simple_graph.py +++ b/examples/simple_graph/simple_graph.py @@ -36,4 +36,3 @@ except KeyboardInterrupt: print("Exiting...") - \ No newline at end of file From 809ced38086648b4d9788b2308d4053817f3ce44 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 15 Jul 2025 15:41:48 -0500 Subject: [PATCH 13/68] Poetry lock --- poetry.lock | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f7e6d63..24c02a2c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1427,7 +1427,7 @@ files = [ [[package]] name = "numpy" -version = "2.2.6" +version = "2.0.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" @@ -1484,7 +1484,7 @@ name = "numpy" version = "2.2.6" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.10" +python-versions = ">=3.9" files = [ {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, @@ -2787,6 +2787,7 @@ astroid = [ Jinja2 = "*" PyYAML = "*" sphinx = ">=7.4.0" +stdlib_list = {version = "*", markers = "python_version < \"3.10\""} [[package]] name = "sphinx-rtd-theme" @@ -2915,6 +2916,24 @@ lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] +[[package]] +name = "stdlib-list" +version = "0.11.1" +description = "A list of Python Standard Libraries (2.7 through 3.13)." +optional = false +python-versions = ">=3.9" +files = [ + {file = "stdlib_list-0.11.1-py3-none-any.whl", hash = "sha256:9029ea5e3dfde8cd4294cfd4d1797be56a67fc4693c606181730148c3fd1da29"}, + {file = "stdlib_list-0.11.1.tar.gz", hash = "sha256:95ebd1d73da9333bba03ccc097f5bac05e3aa03e6822a0c0290f87e1047f1857"}, +] + +[package.extras] +dev = ["build", "stdlib-list[doc,lint,test]"] +doc = ["furo", "sphinx"] +lint = ["mypy", "ruff"] +support = ["sphobjinv"] +test = ["coverage[toml]", "pytest", "pytest-cov"] + [[package]] name = "stevedore" version = "5.4.1" From ffca8c166b3cf9de94f07bc7ec59954669c20874 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 16 Jul 2025 07:19:54 -0500 Subject: [PATCH 14/68] update lint errors --- .../nidaqmx_analog_input_filtering.py | 9 ++++----- .../nidaqmx_analog_input_filtering_panel.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 72f7e956..ec674483 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -16,7 +16,6 @@ StrainGageBridgeType, TerminalConfiguration, ) -from settings_enum import AnalogPause, PauseWhen import nipanel @@ -32,8 +31,8 @@ panel.set_value("is_running", False) panel.set_value("is_running", True) panel.set_value("stop_button", False) - - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ + + # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan_type = panel.get_value("chan_type", "1") if chan_type == "1": @@ -84,7 +83,7 @@ chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) chan.ai_filter_response = panel.get_value("filter_response", FilterResponse.COMB) chan.ai_filter_order = 1 - + task.timing.cfg_samp_clk_timing( rate=panel.get_value("rate", 1000.0), sample_mode=AcquisitionType.CONTINUOUS, @@ -108,7 +107,7 @@ task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source="/Dev2/PFI0", trigger_edge=panel.get_value("edge", Edge.FALLING) ) - task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( + task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( "hysteresis", 0.0 ) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index dc389b3c..c2ef4eee 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -92,7 +92,7 @@ min_value=1.0, step=1.0, disabled=panel.get_value("is_running", False), - key = "rate" + key="rate", ) st.number_input( "Number of Samples", @@ -100,7 +100,7 @@ min_value=1, step=1, disabled=panel.get_value("is_running", False), - key = "total_samples" + key="total_samples", ) st.selectbox("Actual Sample Rate", options=[panel.get_value("sample_rate")], disabled=True) @@ -207,7 +207,6 @@ stx.TabBarItemData(id=7, title="Analog Reference", description=""), ], default=1, - ) trigger_type = id panel.set_value("trigger_type", trigger_type) From 66faa592a6537d0b0578e045b688d8fbcfb9eea4 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 16 Jul 2025 07:19:54 -0500 Subject: [PATCH 15/68] update lint errors --- .../nidaqmx_analog_input_filtering.py | 9 ++++----- .../nidaqmx_analog_input_filtering_panel.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 72f7e956..ec674483 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -16,7 +16,6 @@ StrainGageBridgeType, TerminalConfiguration, ) -from settings_enum import AnalogPause, PauseWhen import nipanel @@ -32,8 +31,8 @@ panel.set_value("is_running", False) panel.set_value("is_running", True) panel.set_value("stop_button", False) - - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ + + # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan_type = panel.get_value("chan_type", "1") if chan_type == "1": @@ -84,7 +83,7 @@ chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) chan.ai_filter_response = panel.get_value("filter_response", FilterResponse.COMB) chan.ai_filter_order = 1 - + task.timing.cfg_samp_clk_timing( rate=panel.get_value("rate", 1000.0), sample_mode=AcquisitionType.CONTINUOUS, @@ -108,7 +107,7 @@ task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source="/Dev2/PFI0", trigger_edge=panel.get_value("edge", Edge.FALLING) ) - task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( + task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( "hysteresis", 0.0 ) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index dc389b3c..c2ef4eee 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -92,7 +92,7 @@ min_value=1.0, step=1.0, disabled=panel.get_value("is_running", False), - key = "rate" + key="rate", ) st.number_input( "Number of Samples", @@ -100,7 +100,7 @@ min_value=1, step=1, disabled=panel.get_value("is_running", False), - key = "total_samples" + key="total_samples", ) st.selectbox("Actual Sample Rate", options=[panel.get_value("sample_rate")], disabled=True) @@ -207,7 +207,6 @@ stx.TabBarItemData(id=7, title="Analog Reference", description=""), ], default=1, - ) trigger_type = id panel.set_value("trigger_type", trigger_type) From c385fb23297ac9f399efbbbee411560a9ae10a26 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 08:51:22 -0500 Subject: [PATCH 16/68] changes to poetry lock file --- poetry.lock | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 1114bd82..fd847b27 100644 --- a/poetry.lock +++ b/poetry.lock @@ -502,6 +502,20 @@ typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "extra-streamlit-components" +version = "0.1.80" +description = "An all-in-one place, to find complex or just natively unavailable components on streamlit." +optional = false +python-versions = ">=3.6" +files = [ + {file = "extra_streamlit_components-0.1.80-py3-none-any.whl", hash = "sha256:7a8c151da5dcd1f1f97b6c29caa812a1d77928d20fc4bf42a3a4fd788274dd9e"}, + {file = "extra_streamlit_components-0.1.80.tar.gz", hash = "sha256:87d6c38e07381501d8882796adef17d1c1d4e3a79615864d95c1163d2bc136f6"}, +] + +[package.dependencies] +streamlit = ">=1.40.1" + [[package]] name = "flake8" version = "5.0.4" @@ -3263,4 +3277,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "45dc36d0ef51734fbde48be7f49ed705209f3b0d46c827cd0de4115fbf15ce62" +content-hash = "1b4c4105e78ce7eca099f1a45a130c93565d568f2263e70d6389ab59ed3bbe27" From 1ab9fa685fd039320683120ba35668dde97d7bb1 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 08:51:22 -0500 Subject: [PATCH 17/68] changes to poetry lock file --- .../nidaqmx_analog_input_filtering.py | 2 - .../nidaqmx_analog_input_filtering_panel.py | 37 +++++++++++++------ poetry.lock | 16 +++++++- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 3bcae847..849a1846 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -32,8 +32,6 @@ panel.set_value("is_running", True) panel.set_value("stop_button", False) - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan_type = panel.get_value("chan_type", "1") diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 3c5b8d43..1dc6c572 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -42,12 +42,18 @@ channel_left, channel_right = st.columns(2) with channel_left: max_value_voltage = st.number_input( - "Max Value", value=5.0, step=0.1, disabled=panel.get_value("is_running", False) + "Max Value", + value=5.0, + step=0.1, + disabled=panel.get_value("is_running", False), ) panel.set_value("max_value_voltage", max_value_voltage) min_value_voltage = st.number_input( - "Min Value", value=-5.0, step=0.1, disabled=panel.get_value("is_running", False) + "Min Value", + value=-5.0, + step=0.1, + disabled=panel.get_value("is_running", False), ) panel.set_value("min_value_voltage", min_value_voltage) @@ -84,7 +90,9 @@ key="max_value_current", disabled=panel.get_value("is_running", False), ) - current = panel.set_value("max_value_current", max_value_current) # type:ignore + current = panel.set_value( + "max_value_current", max_value_current + ) # type:ignore shunt_resistor_value = st.number_input( "Shunt Resistor Value", value=249.0, @@ -243,12 +251,12 @@ ) st.number_input( "Actual Sample Rate", - value= panel.get_value("actual_sample_rate", 1000.0), - key = "actual_sample_rate", - step = 1.0, - disabled= True + value=panel.get_value("actual_sample_rate", 1000.0), + key="actual_sample_rate", + step=1.0, + disabled=True, ) - + st.title("Logging Settings") enum_selectbox( panel, @@ -288,9 +296,14 @@ value=1, disabled=panel.get_value("is_running", False), ) - st.selectbox("Actual Filter Frequency", options=[panel.get_value("actual_filter_freq")], disabled=True) - st.selectbox("Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True) - + st.selectbox( + "Actual Filter Frequency", + options=[panel.get_value("actual_filter_freq")], + disabled=True, + ) + st.selectbox( + "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True + ) with right_col: @@ -381,7 +394,7 @@ "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." ) - + with right_col: with st.container(border=True): acquired_data = panel.get_value("acquired_data", [0.0]) diff --git a/poetry.lock b/poetry.lock index 1114bd82..fd847b27 100644 --- a/poetry.lock +++ b/poetry.lock @@ -502,6 +502,20 @@ typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "extra-streamlit-components" +version = "0.1.80" +description = "An all-in-one place, to find complex or just natively unavailable components on streamlit." +optional = false +python-versions = ">=3.6" +files = [ + {file = "extra_streamlit_components-0.1.80-py3-none-any.whl", hash = "sha256:7a8c151da5dcd1f1f97b6c29caa812a1d77928d20fc4bf42a3a4fd788274dd9e"}, + {file = "extra_streamlit_components-0.1.80.tar.gz", hash = "sha256:87d6c38e07381501d8882796adef17d1c1d4e3a79615864d95c1163d2bc136f6"}, +] + +[package.dependencies] +streamlit = ">=1.40.1" + [[package]] name = "flake8" version = "5.0.4" @@ -3263,4 +3277,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "45dc36d0ef51734fbde48be7f49ed705209f3b0d46c827cd0de4115fbf15ce62" +content-hash = "1b4c4105e78ce7eca099f1a45a130c93565d568f2263e70d6389ab59ed3bbe27" From 6354786cf76b97f3b435929c2bd00030844e948e Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 08:57:27 -0500 Subject: [PATCH 18/68] Pyright error --- .../nidaqmx_analog_input_filtering.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 849a1846..171ecd39 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -120,7 +120,7 @@ try: task.start() while not panel.get_value("stop_button", False): - data = task.read(number_of_samples_per_channel=100) + data = task.read(number_of_samples_per_channel=100) # pyright: ignore[reportArgumentType] panel.set_value("acquired_data", data) except KeyboardInterrupt: pass From 722c3d5d2bc217ac054cac43a678ebbf9c7d5ebc Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 09:02:55 -0500 Subject: [PATCH 19/68] lint error --- .../nidaqmx_analog_input_filtering.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 171ecd39..c0783a4f 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -120,7 +120,9 @@ try: task.start() while not panel.get_value("stop_button", False): - data = task.read(number_of_samples_per_channel=100) # pyright: ignore[reportArgumentType] + data = task.read( + number_of_samples_per_channel=100 # pyright: ignore[reportArgumentType] + ) panel.set_value("acquired_data", data) except KeyboardInterrupt: pass From bbdeb81e25007214d678f72de6f976234c59b726 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 09:04:37 -0500 Subject: [PATCH 20/68] fixed errors --- .../nidaqmx_analog_input_filtering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index c0783a4f..17f7643d 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -121,8 +121,8 @@ task.start() while not panel.get_value("stop_button", False): data = task.read( - number_of_samples_per_channel=100 # pyright: ignore[reportArgumentType] - ) + number_of_samples_per_channel=100 # pyright: ignore[reportArgumentType] + ) panel.set_value("acquired_data", data) except KeyboardInterrupt: pass From 065d6f44cb2b334b189265345176d1000412291a Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 15:16:21 -0500 Subject: [PATCH 21/68] Fixed panel comments --- .../nidaqmx_analog_input_filtering/README.md | 5 +- .../nidaqmx_analog_input_filtering.py | 41 +- .../nidaqmx_analog_input_filtering_panel.py | 439 +++++++++--------- .../README.md | 0 .../nidaqmx_continuous_analog_input.py | 2 +- .../nidaqmx_continuous_analog_input_panel.py | 0 .../settings_enum.py | 17 - 7 files changed, 240 insertions(+), 264 deletions(-) rename examples/{ => nidaqmx}/nidaqmx_analog_input_filtering/README.md (76%) rename examples/{ => nidaqmx}/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py (87%) rename examples/{ => nidaqmx}/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py (71%) rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/README.md (100%) rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/nidaqmx_continuous_analog_input.py (97%) rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/nidaqmx_continuous_analog_input_panel.py (100%) delete mode 100644 examples/nidaqmx_analog_input_filtering/settings_enum.py diff --git a/examples/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md similarity index 76% rename from examples/nidaqmx_analog_input_filtering/README.md rename to examples/nidaqmx/nidaqmx_analog_input_filtering/README.md index 6de44432..dcd518a0 100644 --- a/examples/nidaqmx_analog_input_filtering/README.md +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md @@ -16,7 +16,8 @@ Script demonstrates analog input data getting continuously acquired, and being f ### Usage +```pwsh poetry install --with examples -poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py -Run `poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py` +poetry run python examples/all_types/all_types.py +``` diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py similarity index 87% rename from examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py rename to examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 17f7643d..98a0e2f0 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -10,18 +10,31 @@ Edge, ExcitationSource, FilterResponse, - LoggingMode, - LoggingOperation, Slope, StrainGageBridgeType, TerminalConfiguration, ) +import time +import nidaqmx.system import nipanel - panel_script_path = Path(__file__).with_name("nidaqmx_analog_input_filtering_panel.py") panel = nipanel.create_panel(panel_script_path) panel.set_value("is_running", False) + +system = nidaqmx.system.System.local() + +channel_name = [] +for dev in system.devices: + for chan in dev.ai_physical_chans: + channel_name.append(chan.name) +panel.set_value("channel_name", channel_name) +trigger_sources = [] +for dev in system.devices: + if hasattr(dev, "terminals"): + for term in dev.terminals: + trigger_sources.append(term) +panel.set_value("trigger_sources", trigger_sources) try: print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") @@ -29,16 +42,18 @@ while True: while not panel.get_value("run_button", False): panel.set_value("is_running", False) + # time.sleep(0.1) panel.set_value("is_running", True) panel.set_value("stop_button", False) # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: + chan_type = panel.get_value("chan_type", "1") if chan_type == "2": chan = task.ai_channels.add_ai_current_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), max_val=panel.get_value("max_value_current", 0.01), min_val=panel.get_value("min_value_current", -0.01), ext_shunt_resistor_val=panel.get_value("shunt_resistor_value", 249.0), @@ -50,7 +65,7 @@ elif chan_type == "3": chan = task.ai_channels.add_ai_strain_gage_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), nominal_gage_resistance=panel.get_value("gage_resistance", 350.0), voltage_excit_source=ExcitationSource.EXTERNAL, # Only mode that works max_val=panel.get_value("max_value_strain", 0.001), @@ -66,27 +81,23 @@ ) else: chan = task.ai_channels.add_ai_voltage_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), terminal_config=panel.get_value( "terminal_configuration", TerminalConfiguration.DEFAULT ), max_val=panel.get_value("max_value_voltage", 5.0), min_val=panel.get_value("min_value_voltage", -5.0), ) + task.timing.cfg_samp_clk_timing( rate=panel.get_value("rate", 1000.0), sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=panel.get_value("total_samples", 100), ) - panel.set_value("actual_sample_rate", task._timing.samp_clk_rate) + panel.set_value("actual_sample_rate", task.timing.samp_clk_rate) panel.set_value("sample_rate", panel.get_value("rate", 100.0)) - - task.in_stream.configure_logging( - file_path=panel.get_value("tdms_file_path", "data.tdms"), - logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), - operation=LoggingOperation.OPEN_OR_CREATE, - ) + if panel.get_value("filter", "Filter") == "Filter": chan.ai_filter_enable = True chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) @@ -101,7 +112,7 @@ panel.set_value("actual_filter_freq", 0.0) panel.set_value("actual_filter_response", FilterResponse.COMB) panel.set_value("actual_filter_order", 0) - + trigger_type = panel.get_value("trigger_type") if trigger_type == "5": task.triggers.start_trigger.cfg_anlg_edge_start_trig( @@ -109,6 +120,8 @@ trigger_slope=panel.get_value("slope", Slope.FALLING), trigger_level=panel.get_value("level", 0.0), ) + + if trigger_type == "2": task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source="/Dev2/PFI0", trigger_edge=panel.get_value("edge", Edge.FALLING) diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py similarity index 71% rename from examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py rename to examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 1dc6c572..73f0034e 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -12,7 +12,6 @@ StrainGageBridgeType, TerminalConfiguration, ) -from settings_enum import AnalogPause, PauseWhen from streamlit_echarts import st_echarts import nipanel @@ -24,8 +23,122 @@ left_col, right_col = st.columns(2) -with right_col: + +st.markdown( + """ + + """, + unsafe_allow_html=True, +) + +streamlit_style = """ + + """ +st.markdown(streamlit_style, unsafe_allow_html=True) + + + +with left_col: with st.container(border=True): + is_running = panel.get_value("is_running", True) + if is_running: + st.button("Stop", key="stop_button") + else: + st.button("Run", key="run_button") + + st.title("Channel Settings") + physical_channel = st.selectbox(options=panel.get_value("channel_name", ["Mod2/ai0"]), index=0, label="Physical Channels", disabled=panel.get_value("is_running", False)) + panel.set_value("physical_channel", physical_channel) + enum_selectbox( + panel, + label="Terminal Configuration", + value=TerminalConfiguration.DEFAULT, + disabled=panel.get_value("is_running", False), + key="terminal_configuration", + ) + + st.title("Timing Settings") + + st.selectbox("Sample Clock Source", options=panel.get_value("trigger_sources", [""]), index=0, disabled=panel.get_value("is_running", False)) + st.number_input( + "Sample Rate", + value=1000.0, + min_value=1.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="rate", + ) + st.number_input( + "Number of Samples", + value=100, + min_value=1, + step=1, + disabled=panel.get_value("is_running", False), + key="total_samples", + ) + st.number_input( + "Actual Sample Rate", + value=panel.get_value("actual_sample_rate", 1000.0), + key="actual_sample_rate", + step=1.0, + disabled=True, + ) + + st.title("Logging Settings") + enum_selectbox( + panel, + label="Logging Mode", + value=LoggingMode.OFF, + disabled=panel.get_value("is_running", False), + key="logging_mode", + ) + tdms_file_path = st.text_input( + label="TDMS File Path", + disabled=panel.get_value("is_running", False), + value="data.tdms", + key="tdms_file_path", + ) + st.title("Filtering Settings") + + filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) + panel.set_value("filter", filter) + enum_selectbox( + panel, + label="Filter Response", + value=FilterResponse.COMB, + disabled=panel.get_value("is_running", False), + key="filter_response", + ) + + filter_freq = st.number_input( + "Filtering Frequency", + value=1000.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + filter_order = st.number_input( + "Filter Order", + min_value=0, + max_value=1, + value=1, + disabled=panel.get_value("is_running", False), + ) + st.selectbox( + "Actual Filter Frequency", + options=[panel.get_value("actual_filter_freq")], + disabled=True, + ) + st.selectbox( + "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True + ) + +with right_col: st.title("Task Types") chosen_id = stx.tab_bar( data=[ @@ -35,9 +148,12 @@ ], default=1, ) - tabs = st.tabs(["Voltage", "Current", "Strain Gage"]) - with st.container(border=True): - with tabs[0]: + + chan_type = chosen_id + panel.set_value("chan_type", chan_type) + + if chosen_id == "1": + with st.container(border=True): st.title("Voltage Data") channel_left, channel_right = st.columns(2) with channel_left: @@ -57,7 +173,8 @@ ) panel.set_value("min_value_voltage", min_value_voltage) - with tabs[1]: + if chosen_id == "2": + with st.container(border=True): st.title("Current Data") channel_left, channel_right = st.columns(2) with channel_left: @@ -100,7 +217,8 @@ disabled=panel.get_value("is_running", False), ) panel.set_value("shunt_resistor_value", shunt_resistor_value) - with tabs[2]: + if chosen_id == "3": + with st.container(border=True): st.title("Strain Gage Data") channel_left, channel_right = st.columns(2) with channel_left: @@ -183,131 +301,10 @@ ) panel.set_value("voltage_excitation_value", voltage_excit) -panel.set_value("chan_type", "1") - -pages = st.container() -chan_type = chosen_id -panel.set_value("chan_type", chan_type) - -is_running = panel.get_value("is_running", True) -with left_col: - if is_running: - st.button("Stop", key="stop_button") - else: - st.button("Run", key="run_button") - -st.markdown( - """ - - """, - unsafe_allow_html=True, -) - -streamlit_style = """ - - """ -st.markdown(streamlit_style, unsafe_allow_html=True) - - -with left_col: - with st.container(border=True): - - st.title("Channel Settings") - st.selectbox(options=["Mod3/ai10"], index=0, label="Physical Channels", disabled=True) - - enum_selectbox( - panel, - label="Terminal Configuration", - value=TerminalConfiguration.DEFAULT, - disabled=panel.get_value("is_running", False), - key="terminal_configuration", - ) - - st.title("Timing Settings") - - st.selectbox("Sample Clock Source", options=["Onboard Clock"], index=0, disabled=True) - st.number_input( - "Sample Rate", - value=1000.0, - min_value=1.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="rate", - ) - st.number_input( - "Number of Samples", - value=100, - min_value=1, - step=1, - disabled=panel.get_value("is_running", False), - key="total_samples", - ) - st.number_input( - "Actual Sample Rate", - value=panel.get_value("actual_sample_rate", 1000.0), - key="actual_sample_rate", - step=1.0, - disabled=True, - ) + - st.title("Logging Settings") - enum_selectbox( - panel, - label="Logging Mode", - value=LoggingMode.OFF, - disabled=panel.get_value("is_running", False), - key="logging_mode", - ) - tdms_file_path = st.text_input( - label="TDMS File Path", - disabled=panel.get_value("is_running", False), - value="data.tdms", - key="tdms_file_path", - ) - st.title("Filtering Settings") - filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) - panel.set_value("filter", filter) - enum_selectbox( - panel, - label="Filter Response", - value=FilterResponse.COMB, - disabled=panel.get_value("is_running", False), - key="filter_response", - ) - - filter_freq = st.number_input( - "Filtering Frequency", - value=1000.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - filter_order = st.number_input( - "Filter Order", - min_value=0, - max_value=1, - value=1, - disabled=panel.get_value("is_running", False), - ) - st.selectbox( - "Actual Filter Frequency", - options=[panel.get_value("actual_filter_freq")], - disabled=True, - ) - st.selectbox( - "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True - ) - - -with right_col: - with st.container(border=True): st.title("Trigger Settings") id = stx.tab_bar( data=[ @@ -323,109 +320,91 @@ ) trigger_type = id panel.set_value("trigger_type", trigger_type) - tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs( - [ - "No Trigger", - "Digital Start", - "Digital Pause", - "Digital Reference", - "Analog Start", - "Analog Pause", - "Analog Reference", - ] - ) - with tab1: - st.write( - "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." - ) - with tab2: - st.selectbox("Source->", " /Dev1/PFI0") - enum_selectbox( - panel, - label="Edge", - value=Edge.FALLING, - disabled=panel.get_value("is_running", False), - key="edge", - ) - with tab3: - st.selectbox("Source-", "/Dev1/PFI0") - pause_when = st.selectbox( - "Pause When", - options=[(e.name, e.value) for e in PauseWhen], - format_func=lambda x: x[0], - index=0, - ) - pause_when = PauseWhen[pause_when[0]] # type: ignore - panel.set_value("pause_when", pause_when) - with tab4: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - with tab5: - st.selectbox("Source:", "APFI0") - enum_selectbox( - panel, - label="Slope", - value=Slope.FALLING, - disabled=panel.get_value("is_running", False), - key="slope", - ) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input( - "Hysteriesis", disabled=panel.get_value("is_running", False) - ) - panel.set_value("hysteriesis", hysteriesis) + + if trigger_type == "1": + with st.container(border=True): + st.write( + "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." + ) + if trigger_type == "2": + with st.container(border=True): + st.selectbox("Source->", " /Dev1/PFI0") + enum_selectbox( + panel, + label="Edge", + value=Edge.FALLING, + disabled=panel.get_value("is_running", False), + key="edge", + ) + if trigger_type == "3": + with st.container(border=True): + st.selectbox("Source-", "/Dev1/PFI0") + st.selectbox("PauseWhen", options=["High", "Low"]) + if trigger_type == "4": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + if trigger_type == "5": + with st.container(border=True): + st.selectbox("Source:", "APFI0") + enum_selectbox( + panel, + label="Slope", + value=Slope.FALLING, + disabled=panel.get_value("is_running", False), + key="slope", + ) - with tab6: - st.selectbox("source:", "APFI0") - analog_pause = st.selectbox( - "analog_pause", - options=[(e.name, e.value) for e in AnalogPause], - format_func=lambda x: x[0], - index=0, - ) - analog_pause = AnalogPause[analog_pause[0]] # type: ignore - panel.set_value("analog_pause", analog_pause) + level = st.number_input("Level") + panel.set_value("level", level) + hysteriesis = st.number_input( + "Hysteriesis", disabled=panel.get_value("is_running", False) + ) + panel.set_value("hysteriesis", hysteriesis) - with tab7: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) + if trigger_type == "6": + with st.container(border=True): + st.selectbox("source:", "APFI0") + st.selectbox("Pause When", options=["Above Level", "Below level"]) + st.number_input("level", value=0.0) + if trigger_type == "7": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." + ) -with right_col: - with st.container(border=True): - acquired_data = panel.get_value("acquired_data", [0.0]) - sample_rate = panel.get_value("sample_rate", 0.0) - acquired_data_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(acquired_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Volts", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": acquired_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", + with st.container(border=True): + acquired_data = panel.get_value("acquired_data", [0.0]) + sample_rate = panel.get_value("sample_rate", 0.0) + acquired_data_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)"]}, + "xAxis": { + "type": "category", + "data": [x / sample_rate for x in range(len(acquired_data))], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, }, - ], - } - st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + "yAxis": { + "type": "value", + "name": "Volts", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": acquired_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], + } + st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") diff --git a/examples/nidaqmx/README.md b/examples/nidaqmx/nidaqmx_continuous_analog_input/README.md similarity index 100% rename from examples/nidaqmx/README.md rename to examples/nidaqmx/nidaqmx_continuous_analog_input/README.md diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py similarity index 97% rename from examples/nidaqmx/nidaqmx_continuous_analog_input.py rename to examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py index bed43eb7..5f2470a0 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py @@ -59,7 +59,7 @@ logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), operation=LoggingOperation.OPEN_OR_CREATE, ) - panel.set_value("sample_rate", task._timing.samp_clk_rate) + panel.set_value("sample_rate", task.timing.samp_clk_rate) try: print(f"Starting data acquisition...") task.start() diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py similarity index 100% rename from examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py rename to examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py diff --git a/examples/nidaqmx_analog_input_filtering/settings_enum.py b/examples/nidaqmx_analog_input_filtering/settings_enum.py deleted file mode 100644 index 6a484b5d..00000000 --- a/examples/nidaqmx_analog_input_filtering/settings_enum.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Enumeration for amplitude values used in the simple graph example.""" - -import enum - - -class PauseWhen(enum.StrEnum): - """Pause When Trigger Setting.""" - - HIGH = "High" - LOW = "Low" - - -class AnalogPause(enum.StrEnum): - """Analog Pause Trigger.""" - - ABOVE = "ABOVE" - BELOW = "BELOW" From 3a22846b8ec313b0bead91400a6ba5eb7efd4b26 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 15:16:21 -0500 Subject: [PATCH 22/68] Fixed panel comments --- .../nidaqmx_analog_input_filtering/README.md | 5 +- .../nidaqmx_analog_input_filtering.py | 34 +- .../nidaqmx_analog_input_filtering_panel.py | 418 +++++++++++++++++ .../README.md | 0 .../nidaqmx_continuous_analog_input.py | 2 +- .../nidaqmx_continuous_analog_input_panel.py | 0 .../nidaqmx_analog_input_filtering_panel.py | 431 ------------------ .../settings_enum.py | 17 - 8 files changed, 445 insertions(+), 462 deletions(-) rename examples/{ => nidaqmx}/nidaqmx_analog_input_filtering/README.md (76%) rename examples/{ => nidaqmx}/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py (88%) create mode 100644 examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/README.md (100%) rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/nidaqmx_continuous_analog_input.py (97%) rename examples/nidaqmx/{ => nidaqmx_continuous_analog_input}/nidaqmx_continuous_analog_input_panel.py (100%) delete mode 100644 examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py delete mode 100644 examples/nidaqmx_analog_input_filtering/settings_enum.py diff --git a/examples/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md similarity index 76% rename from examples/nidaqmx_analog_input_filtering/README.md rename to examples/nidaqmx/nidaqmx_analog_input_filtering/README.md index 6de44432..dcd518a0 100644 --- a/examples/nidaqmx_analog_input_filtering/README.md +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md @@ -16,7 +16,8 @@ Script demonstrates analog input data getting continuously acquired, and being f ### Usage +```pwsh poetry install --with examples -poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py -Run `poetry run examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py` +poetry run python examples/all_types/all_types.py +``` diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py similarity index 88% rename from examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py rename to examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index 17f7643d..a0f608b1 100644 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -1,8 +1,10 @@ """Data acquisition script that continuously acquires analog input data.""" +import time from pathlib import Path import nidaqmx +import nidaqmx.system from nidaqmx.constants import ( AcquisitionType, CurrentShuntResistorLocation, @@ -10,8 +12,6 @@ Edge, ExcitationSource, FilterResponse, - LoggingMode, - LoggingOperation, Slope, StrainGageBridgeType, TerminalConfiguration, @@ -22,6 +22,20 @@ panel_script_path = Path(__file__).with_name("nidaqmx_analog_input_filtering_panel.py") panel = nipanel.create_panel(panel_script_path) panel.set_value("is_running", False) + +system = nidaqmx.system.System.local() + +channel_name = [] +for dev in system.devices: + for chan in dev.ai_physical_chans: + channel_name.append(chan.name) +panel.set_value("channel_name", channel_name) +trigger_sources = [] +for dev in system.devices: + if hasattr(dev, "terminals"): + for term in dev.terminals: + trigger_sources.append(term) +panel.set_value("trigger_sources", trigger_sources) try: print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") @@ -29,16 +43,18 @@ while True: while not panel.get_value("run_button", False): panel.set_value("is_running", False) + # time.sleep(0.1) panel.set_value("is_running", True) panel.set_value("stop_button", False) # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: + chan_type = panel.get_value("chan_type", "1") if chan_type == "2": chan = task.ai_channels.add_ai_current_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), max_val=panel.get_value("max_value_current", 0.01), min_val=panel.get_value("min_value_current", -0.01), ext_shunt_resistor_val=panel.get_value("shunt_resistor_value", 249.0), @@ -50,7 +66,7 @@ elif chan_type == "3": chan = task.ai_channels.add_ai_strain_gage_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), nominal_gage_resistance=panel.get_value("gage_resistance", 350.0), voltage_excit_source=ExcitationSource.EXTERNAL, # Only mode that works max_val=panel.get_value("max_value_strain", 0.001), @@ -66,7 +82,7 @@ ) else: chan = task.ai_channels.add_ai_voltage_chan( - "Mod3/ai10", + panel.get_value("physical_channel", ""), terminal_config=panel.get_value( "terminal_configuration", TerminalConfiguration.DEFAULT ), @@ -79,14 +95,9 @@ sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=panel.get_value("total_samples", 100), ) - panel.set_value("actual_sample_rate", task._timing.samp_clk_rate) + panel.set_value("actual_sample_rate", task.timing.samp_clk_rate) panel.set_value("sample_rate", panel.get_value("rate", 100.0)) - task.in_stream.configure_logging( - file_path=panel.get_value("tdms_file_path", "data.tdms"), - logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), - operation=LoggingOperation.OPEN_OR_CREATE, - ) if panel.get_value("filter", "Filter") == "Filter": chan.ai_filter_enable = True chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) @@ -109,6 +120,7 @@ trigger_slope=panel.get_value("slope", Slope.FALLING), trigger_level=panel.get_value("level", 0.0), ) + if trigger_type == "2": task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source="/Dev2/PFI0", trigger_edge=panel.get_value("edge", Edge.FALLING) diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py new file mode 100644 index 00000000..68116f05 --- /dev/null +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -0,0 +1,418 @@ +"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" + +import extra_streamlit_components as stx # type: ignore[import-untyped] +import streamlit as st +from nidaqmx.constants import ( + CurrentShuntResistorLocation, + CurrentUnits, + Edge, + FilterResponse, + LoggingMode, + Slope, + StrainGageBridgeType, + TerminalConfiguration, +) +from streamlit_echarts import st_echarts + +import nipanel +from nipanel.controls import enum_selectbox + +st.set_page_config(page_title="Analog Input Filtering", page_icon="📈", layout="wide") +st.title("Analog Input - Filtering") +panel = nipanel.get_panel_accessor() + +left_col, right_col = st.columns(2) + + +st.markdown( + """ + + """, + unsafe_allow_html=True, +) + +streamlit_style = """ + + """ +st.markdown(streamlit_style, unsafe_allow_html=True) + + +with left_col: + with st.container(border=True): + is_running = panel.get_value("is_running", True) + if is_running: + st.button("Stop", key="stop_button") + else: + st.button("Run", key="run_button") + + st.title("Channel Settings") + physical_channel = st.selectbox( + options=panel.get_value("channel_name", ["Mod2/ai0"]), + index=0, + label="Physical Channels", + disabled=panel.get_value("is_running", False), + ) + panel.set_value("physical_channel", physical_channel) + enum_selectbox( + panel, + label="Terminal Configuration", + value=TerminalConfiguration.DEFAULT, + disabled=panel.get_value("is_running", False), + key="terminal_configuration", + ) + + st.title("Timing Settings") + + st.selectbox( + "Sample Clock Source", + options=panel.get_value("trigger_sources", [""]), + index=0, + disabled=panel.get_value("is_running", False), + ) + st.number_input( + "Sample Rate", + value=1000.0, + min_value=1.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="rate", + ) + st.number_input( + "Number of Samples", + value=100, + min_value=1, + step=1, + disabled=panel.get_value("is_running", False), + key="total_samples", + ) + st.number_input( + "Actual Sample Rate", + value=panel.get_value("actual_sample_rate", 1000.0), + key="actual_sample_rate", + step=1.0, + disabled=True, + ) + + st.title("Logging Settings") + enum_selectbox( + panel, + label="Logging Mode", + value=LoggingMode.OFF, + disabled=panel.get_value("is_running", False), + key="logging_mode", + ) + tdms_file_path = st.text_input( + label="TDMS File Path", + disabled=panel.get_value("is_running", False), + value="data.tdms", + key="tdms_file_path", + ) + st.title("Filtering Settings") + + filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) + panel.set_value("filter", filter) + enum_selectbox( + panel, + label="Filter Response", + value=FilterResponse.COMB, + disabled=panel.get_value("is_running", False), + key="filter_response", + ) + + filter_freq = st.number_input( + "Filtering Frequency", + value=1000.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + filter_order = st.number_input( + "Filter Order", + min_value=0, + max_value=1, + value=1, + disabled=panel.get_value("is_running", False), + ) + st.selectbox( + "Actual Filter Frequency", + options=[panel.get_value("actual_filter_freq")], + disabled=True, + ) + st.selectbox( + "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True + ) + +with right_col: + st.title("Task Types") + chosen_id = stx.tab_bar( + data=[ + stx.TabBarItemData(id=1, title="Voltage", description=""), + stx.TabBarItemData(id=2, title="Current", description=""), + stx.TabBarItemData(id=3, title="Strain Gage", description=""), + ], + default=1, + ) + + chan_type = chosen_id + panel.set_value("chan_type", chan_type) + + if chosen_id == "1": + with st.container(border=True): + st.title("Voltage Data") + channel_left, channel_right = st.columns(2) + with channel_left: + max_value_voltage = st.number_input( + "Max Value", + value=5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("max_value_voltage", max_value_voltage) + + min_value_voltage = st.number_input( + "Min Value", + value=-5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("min_value_voltage", min_value_voltage) + + if chosen_id == "2": + with st.container(border=True): + st.title("Current Data") + channel_left, channel_right = st.columns(2) + with channel_left: + enum_selectbox( + panel, + label="Shunt Resistor Location", + value=CurrentShuntResistorLocation.EXTERNAL, + disabled=panel.get_value("is_running", False), + key="shunt_location", + ) + enum_selectbox( + panel, + label="Units", + value=CurrentUnits.AMPS, + disabled=panel.get_value("is_running", False), + key="units", + ) + with st.expander("More current info", expanded=False): + min_value_current = st.number_input( + "Min Value", + value=-0.01, + step=0.001, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("min_value_current", min_value_current) + max_value_current = st.number_input( + "Max Value", + value=0.01, + step=1.0, + key="max_value_current", + disabled=panel.get_value("is_running", False), + ) + current = panel.set_value("max_value_current", max_value_current) # type:ignore + shunt_resistor_value = st.number_input( + "Shunt Resistor Value", + value=249.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("shunt_resistor_value", shunt_resistor_value) + if chosen_id == "3": + with st.container(border=True): + st.title("Strain Gage Data") + channel_left, channel_right = st.columns(2) + with channel_left: + min_value_strain = st.number_input( + "Min Value", + value=-0.01, + step=0.01, + ) + panel.set_value("min_value_strain", min_value_strain) + max_value_strain = st.number_input( + "Max Value", value=0.01, step=0.01, max_value=2.0 + ) + panel.set_value("max_value_strain", max_value_strain) + enum_selectbox( + panel, + label="Strain Units", + value=CurrentUnits.AMPS, + disabled=panel.get_value("is_running", False), + key="strain_units", + ) + with st.expander("Strain Gage Information", expanded=False): + st.title("Strain Gage Information") + gage_factor = st.number_input( + "Gage Factor", + value=2.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("gage_factor", gage_factor) + nominal_gage = st.number_input( + "nominal gage resistance", + value=350.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("gage_resistance", nominal_gage) + poisson_ratio = st.number_input( + "poisson ratio", + value=0.3, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("poisson_ratio", poisson_ratio) + with st.expander("Bridge Information", expanded=False): + st.title("Bridge Information") + enum_selectbox( + panel, + label="Strain Configuration", + value=StrainGageBridgeType.FULL_BRIDGE_I, + disabled=panel.get_value("is_running", False), + key="strain_configuration", + ) + wire_resistance = st.number_input( + "lead wire resistance", + value=0.0, + step=1.0, + ) + panel.set_value("wire_resistance", wire_resistance) + initial_voltage = st.number_input( + "initial bridge voltage", + value=0.0, + step=1.0, + disabled=panel.get_value("is_running", False), + ) + panel.set_value("initial_voltage", initial_voltage) + + st.selectbox( + label="voltage excitation source", + key="voltage_excit", + options=["External"], + disabled=True, + ) + panel.set_value("voltage_excitation_source", "voltage_excit") + voltage_excit = st.number_input( + "voltage excitation value", + value=2.5, + step=1.0, + key="voltage_excitation_value", + disabled=panel.get_value("is_running", False), + ) + panel.set_value("voltage_excitation_value", voltage_excit) + + st.title("Trigger Settings") + id = stx.tab_bar( + data=[ + stx.TabBarItemData(id=1, title="No Trigger", description=""), + stx.TabBarItemData(id=2, title="Digital Start", description=""), + stx.TabBarItemData(id=3, title="Digital Pause", description=""), + stx.TabBarItemData(id=4, title="Digital Reference", description=""), + stx.TabBarItemData(id=5, title="Analog Start", description=""), + stx.TabBarItemData(id=6, title="Analog Pause", description=""), + stx.TabBarItemData(id=7, title="Analog Reference", description=""), + ], + default=1, + ) + trigger_type = id + panel.set_value("trigger_type", trigger_type) + + if trigger_type == "1": + with st.container(border=True): + st.write( + "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." + ) + if trigger_type == "2": + with st.container(border=True): + st.selectbox("Source->", " /Dev1/PFI0") + enum_selectbox( + panel, + label="Edge", + value=Edge.FALLING, + disabled=panel.get_value("is_running", False), + key="edge", + ) + if trigger_type == "3": + with st.container(border=True): + st.selectbox("Source-", "/Dev1/PFI0") + st.selectbox("PauseWhen", options=["High", "Low"]) + if trigger_type == "4": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + if trigger_type == "5": + with st.container(border=True): + st.selectbox("Source:", "APFI0") + enum_selectbox( + panel, + label="Slope", + value=Slope.FALLING, + disabled=panel.get_value("is_running", False), + key="slope", + ) + + level = st.number_input("Level") + panel.set_value("level", level) + hysteriesis = st.number_input( + "Hysteriesis", disabled=panel.get_value("is_running", False) + ) + panel.set_value("hysteriesis", hysteriesis) + + if trigger_type == "6": + with st.container(border=True): + st.selectbox("source:", "APFI0") + st.selectbox("Pause When", options=["Above Level", "Below level"]) + st.number_input("level", value=0.0) + if trigger_type == "7": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." + ) + + with st.container(border=True): + acquired_data = panel.get_value("acquired_data", [0.0]) + sample_rate = panel.get_value("sample_rate", 0.0) + acquired_data_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)"]}, + "xAxis": { + "type": "category", + "data": [x / sample_rate for x in range(len(acquired_data))], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Volts", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": acquired_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], + } + st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") diff --git a/examples/nidaqmx/README.md b/examples/nidaqmx/nidaqmx_continuous_analog_input/README.md similarity index 100% rename from examples/nidaqmx/README.md rename to examples/nidaqmx/nidaqmx_continuous_analog_input/README.md diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py similarity index 97% rename from examples/nidaqmx/nidaqmx_continuous_analog_input.py rename to examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py index bed43eb7..5f2470a0 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py @@ -59,7 +59,7 @@ logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), operation=LoggingOperation.OPEN_OR_CREATE, ) - panel.set_value("sample_rate", task._timing.samp_clk_rate) + panel.set_value("sample_rate", task.timing.samp_clk_rate) try: print(f"Starting data acquisition...") task.start() diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py similarity index 100% rename from examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py rename to examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py diff --git a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py deleted file mode 100644 index 1dc6c572..00000000 --- a/examples/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ /dev/null @@ -1,431 +0,0 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" - -import extra_streamlit_components as stx # type: ignore[import-untyped] -import streamlit as st -from nidaqmx.constants import ( - CurrentShuntResistorLocation, - CurrentUnits, - Edge, - FilterResponse, - LoggingMode, - Slope, - StrainGageBridgeType, - TerminalConfiguration, -) -from settings_enum import AnalogPause, PauseWhen -from streamlit_echarts import st_echarts - -import nipanel -from nipanel.controls import enum_selectbox - -st.set_page_config(page_title="Analog Input Filtering", page_icon="📈", layout="wide") -st.title("Analog Input - Filtering") -panel = nipanel.get_panel_accessor() - -left_col, right_col = st.columns(2) - -with right_col: - with st.container(border=True): - st.title("Task Types") - chosen_id = stx.tab_bar( - data=[ - stx.TabBarItemData(id=1, title="Voltage", description=""), - stx.TabBarItemData(id=2, title="Current", description=""), - stx.TabBarItemData(id=3, title="Strain Gage", description=""), - ], - default=1, - ) - tabs = st.tabs(["Voltage", "Current", "Strain Gage"]) - with st.container(border=True): - with tabs[0]: - st.title("Voltage Data") - channel_left, channel_right = st.columns(2) - with channel_left: - max_value_voltage = st.number_input( - "Max Value", - value=5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("max_value_voltage", max_value_voltage) - - min_value_voltage = st.number_input( - "Min Value", - value=-5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("min_value_voltage", min_value_voltage) - - with tabs[1]: - st.title("Current Data") - channel_left, channel_right = st.columns(2) - with channel_left: - enum_selectbox( - panel, - label="Shunt Resistor Location", - value=CurrentShuntResistorLocation.EXTERNAL, - disabled=panel.get_value("is_running", False), - key="shunt_location", - ) - enum_selectbox( - panel, - label="Units", - value=CurrentUnits.AMPS, - disabled=panel.get_value("is_running", False), - key="units", - ) - with st.expander("More current info", expanded=False): - min_value_current = st.number_input( - "Min Value", - value=-0.01, - step=0.001, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("min_value_current", min_value_current) - max_value_current = st.number_input( - "Max Value", - value=0.01, - step=1.0, - key="max_value_current", - disabled=panel.get_value("is_running", False), - ) - current = panel.set_value( - "max_value_current", max_value_current - ) # type:ignore - shunt_resistor_value = st.number_input( - "Shunt Resistor Value", - value=249.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("shunt_resistor_value", shunt_resistor_value) - with tabs[2]: - st.title("Strain Gage Data") - channel_left, channel_right = st.columns(2) - with channel_left: - min_value_strain = st.number_input( - "Min Value", - value=-0.01, - step=0.01, - ) - panel.set_value("min_value_strain", min_value_strain) - max_value_strain = st.number_input( - "Max Value", value=0.01, step=0.01, max_value=2.0 - ) - panel.set_value("max_value_strain", max_value_strain) - enum_selectbox( - panel, - label="Strain Units", - value=CurrentUnits.AMPS, - disabled=panel.get_value("is_running", False), - key="strain_units", - ) - with st.expander("Strain Gage Information", expanded=False): - st.title("Strain Gage Information") - gage_factor = st.number_input( - "Gage Factor", - value=2.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("gage_factor", gage_factor) - nominal_gage = st.number_input( - "nominal gage resistance", - value=350.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("gage_resistance", nominal_gage) - poisson_ratio = st.number_input( - "poisson ratio", - value=0.3, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("poisson_ratio", poisson_ratio) - with st.expander("Bridge Information", expanded=False): - st.title("Bridge Information") - enum_selectbox( - panel, - label="Strain Configuration", - value=StrainGageBridgeType.FULL_BRIDGE_I, - disabled=panel.get_value("is_running", False), - key="strain_configuration", - ) - wire_resistance = st.number_input( - "lead wire resistance", - value=0.0, - step=1.0, - ) - panel.set_value("wire_resistance", wire_resistance) - initial_voltage = st.number_input( - "initial bridge voltage", - value=0.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("initial_voltage", initial_voltage) - - st.selectbox( - label="voltage excitation source", - key="voltage_excit", - options=["External"], - disabled=True, - ) - panel.set_value("voltage_excitation_source", "voltage_excit") - voltage_excit = st.number_input( - "voltage excitation value", - value=2.5, - step=1.0, - key="voltage_excitation_value", - disabled=panel.get_value("is_running", False), - ) - panel.set_value("voltage_excitation_value", voltage_excit) - -panel.set_value("chan_type", "1") - -pages = st.container() -chan_type = chosen_id -panel.set_value("chan_type", chan_type) - -is_running = panel.get_value("is_running", True) -with left_col: - if is_running: - st.button("Stop", key="stop_button") - else: - st.button("Run", key="run_button") - - -st.markdown( - """ - - """, - unsafe_allow_html=True, -) - -streamlit_style = """ - - """ -st.markdown(streamlit_style, unsafe_allow_html=True) - - -with left_col: - with st.container(border=True): - - st.title("Channel Settings") - st.selectbox(options=["Mod3/ai10"], index=0, label="Physical Channels", disabled=True) - - enum_selectbox( - panel, - label="Terminal Configuration", - value=TerminalConfiguration.DEFAULT, - disabled=panel.get_value("is_running", False), - key="terminal_configuration", - ) - - st.title("Timing Settings") - - st.selectbox("Sample Clock Source", options=["Onboard Clock"], index=0, disabled=True) - st.number_input( - "Sample Rate", - value=1000.0, - min_value=1.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="rate", - ) - st.number_input( - "Number of Samples", - value=100, - min_value=1, - step=1, - disabled=panel.get_value("is_running", False), - key="total_samples", - ) - st.number_input( - "Actual Sample Rate", - value=panel.get_value("actual_sample_rate", 1000.0), - key="actual_sample_rate", - step=1.0, - disabled=True, - ) - - st.title("Logging Settings") - enum_selectbox( - panel, - label="Logging Mode", - value=LoggingMode.OFF, - disabled=panel.get_value("is_running", False), - key="logging_mode", - ) - tdms_file_path = st.text_input( - label="TDMS File Path", - disabled=panel.get_value("is_running", False), - value="data.tdms", - key="tdms_file_path", - ) - st.title("Filtering Settings") - - filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) - panel.set_value("filter", filter) - enum_selectbox( - panel, - label="Filter Response", - value=FilterResponse.COMB, - disabled=panel.get_value("is_running", False), - key="filter_response", - ) - - filter_freq = st.number_input( - "Filtering Frequency", - value=1000.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - filter_order = st.number_input( - "Filter Order", - min_value=0, - max_value=1, - value=1, - disabled=panel.get_value("is_running", False), - ) - st.selectbox( - "Actual Filter Frequency", - options=[panel.get_value("actual_filter_freq")], - disabled=True, - ) - st.selectbox( - "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True - ) - - -with right_col: - with st.container(border=True): - st.title("Trigger Settings") - id = stx.tab_bar( - data=[ - stx.TabBarItemData(id=1, title="No Trigger", description=""), - stx.TabBarItemData(id=2, title="Digital Start", description=""), - stx.TabBarItemData(id=3, title="Digital Pause", description=""), - stx.TabBarItemData(id=4, title="Digital Reference", description=""), - stx.TabBarItemData(id=5, title="Analog Start", description=""), - stx.TabBarItemData(id=6, title="Analog Pause", description=""), - stx.TabBarItemData(id=7, title="Analog Reference", description=""), - ], - default=1, - ) - trigger_type = id - panel.set_value("trigger_type", trigger_type) - tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs( - [ - "No Trigger", - "Digital Start", - "Digital Pause", - "Digital Reference", - "Analog Start", - "Analog Pause", - "Analog Reference", - ] - ) - with tab1: - st.write( - "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." - ) - with tab2: - st.selectbox("Source->", " /Dev1/PFI0") - enum_selectbox( - panel, - label="Edge", - value=Edge.FALLING, - disabled=panel.get_value("is_running", False), - key="edge", - ) - with tab3: - st.selectbox("Source-", "/Dev1/PFI0") - pause_when = st.selectbox( - "Pause When", - options=[(e.name, e.value) for e in PauseWhen], - format_func=lambda x: x[0], - index=0, - ) - pause_when = PauseWhen[pause_when[0]] # type: ignore - panel.set_value("pause_when", pause_when) - with tab4: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - with tab5: - st.selectbox("Source:", "APFI0") - enum_selectbox( - panel, - label="Slope", - value=Slope.FALLING, - disabled=panel.get_value("is_running", False), - key="slope", - ) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input( - "Hysteriesis", disabled=panel.get_value("is_running", False) - ) - panel.set_value("hysteriesis", hysteriesis) - - with tab6: - st.selectbox("source:", "APFI0") - analog_pause = st.selectbox( - "analog_pause", - options=[(e.name, e.value) for e in AnalogPause], - format_func=lambda x: x[0], - index=0, - ) - analog_pause = AnalogPause[analog_pause[0]] # type: ignore - panel.set_value("analog_pause", analog_pause) - - with tab7: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) - - -with right_col: - with st.container(border=True): - acquired_data = panel.get_value("acquired_data", [0.0]) - sample_rate = panel.get_value("sample_rate", 0.0) - acquired_data_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(acquired_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Volts", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": acquired_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") diff --git a/examples/nidaqmx_analog_input_filtering/settings_enum.py b/examples/nidaqmx_analog_input_filtering/settings_enum.py deleted file mode 100644 index 6a484b5d..00000000 --- a/examples/nidaqmx_analog_input_filtering/settings_enum.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Enumeration for amplitude values used in the simple graph example.""" - -import enum - - -class PauseWhen(enum.StrEnum): - """Pause When Trigger Setting.""" - - HIGH = "High" - LOW = "Low" - - -class AnalogPause(enum.StrEnum): - """Analog Pause Trigger.""" - - ABOVE = "ABOVE" - BELOW = "BELOW" From 92b3260d3c98b12fe25f06fd7f1c7314de1d0eb5 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 15:29:25 -0500 Subject: [PATCH 23/68] format number input --- .../nidaqmx_analog_input_filtering.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py index a0f608b1..54308903 100644 --- a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py @@ -16,9 +16,10 @@ StrainGageBridgeType, TerminalConfiguration, ) +import time +import nidaqmx.system import nipanel - panel_script_path = Path(__file__).with_name("nidaqmx_analog_input_filtering_panel.py") panel = nipanel.create_panel(panel_script_path) panel.set_value("is_running", False) @@ -89,6 +90,7 @@ max_val=panel.get_value("max_value_voltage", 5.0), min_val=panel.get_value("min_value_voltage", -5.0), ) + task.timing.cfg_samp_clk_timing( rate=panel.get_value("rate", 1000.0), @@ -97,7 +99,7 @@ ) panel.set_value("actual_sample_rate", task.timing.samp_clk_rate) panel.set_value("sample_rate", panel.get_value("rate", 100.0)) - + if panel.get_value("filter", "Filter") == "Filter": chan.ai_filter_enable = True chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) @@ -112,7 +114,7 @@ panel.set_value("actual_filter_freq", 0.0) panel.set_value("actual_filter_response", FilterResponse.COMB) panel.set_value("actual_filter_order", 0) - + trigger_type = panel.get_value("trigger_type") if trigger_type == "5": task.triggers.start_trigger.cfg_anlg_edge_start_trig( @@ -120,6 +122,7 @@ trigger_slope=panel.get_value("slope", Slope.FALLING), trigger_level=panel.get_value("level", 0.0), ) + if trigger_type == "2": task.triggers.start_trigger.cfg_dig_edge_start_trig( From 68db2a411aecc17d53473f01219daa192525eb58 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 18 Jul 2025 15:31:36 -0500 Subject: [PATCH 24/68] adding number format --- .../nidaqmx_analog_input_filtering_panel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py index 68116f05..940d6057 100644 --- a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py @@ -27,12 +27,13 @@ st.markdown( """ + """, + unsafe_allow_html=True, +) + +streamlit_style = """ + + """ +st.markdown(streamlit_style, unsafe_allow_html=True) + + +with left_col: + with st.container(border=True): + is_running = panel.get_value("is_running", True) + if is_running: + st.button("Stop", key="stop_button") + else: + st.button("Run", key="run_button") + st.title("Channel Settings") + physical_channel = st.selectbox( + options=panel.get_value("available_channel_names", ["Mod2/ai0"]), + index=0, + label="Physical Channels", + disabled=panel.get_value("is_running", False), + ) + panel.set_value("physical_channel", physical_channel) + + + max_value_voltage = st.number_input( + "Max Value", + value=5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + key = "max_value_voltage", + ) + + min_value_voltage = st.number_input( + "Min Value", + value=-5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + key = "min_value_voltage", + ) + + st.title("Timing and Buffer Settings") + + st.selectbox( + "Sample Clock Source", + options=panel.get_value("available_trigger_sources", [""]), + index=0, + disabled=panel.get_value("is_running", False), + ) + st.number_input( + "Sample Rate", + value=1000.0, + min_value=1.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="rate", + ) + st.number_input( + "Number of Samples", + value=1000, + min_value=1, + step=1, + disabled=panel.get_value("is_running", False), + key="total_samples", + ) + st.number_input( + "Actual Sample Rate", + value=panel.get_value("actual_sample_rate", 1000.0), + key="actual_sample_rate", + step=1.0, + disabled=True, + ) + st.title("Waveform Settings") + st.number_input( + "Frequency", + value=panel.get_value("frequency", 10.0), + key="frequency", + step=1.0, + disabled=panel.get_value("is_running", False), + ) + st.number_input( + "Amplitude", + value=panel.get_value("amplitude", 1.0), + key="amplitude", + step=1.0, + disabled=panel.get_value("is_running", False), + ) + st.selectbox( + label = "Wave Type", + options = ["Sine Wave", "Triangle Wave", "Square Wave", "Sawtooth Wave"], + key = "wave_type", + ) + + +with right_col: + with st.container(border=True): + + st.title("Trigger Settings") + trigger_type = stx.tab_bar( + data=[ + stx.TabBarItemData(id=1, title="No Trigger", description=""), + stx.TabBarItemData(id=2, title="Digital Start", description=""), + stx.TabBarItemData(id=3, title="Digital Pause", description=""), + stx.TabBarItemData(id=4, title="Digital Reference", description=""), + stx.TabBarItemData(id=5, title="Analog Start", description=""), + stx.TabBarItemData(id=6, title="Analog Pause", description=""), + stx.TabBarItemData(id=7, title="Analog Reference", description=""), + ], + default=1, + ) + panel.set_value("trigger_type", trigger_type) + + if trigger_type == "1": + with st.container(border=True): + st.write( + "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." + ) + if trigger_type == "2": + with st.container(border=True): + source = st.selectbox("Source->", options=panel.get_value("available_trigger_sources", [""])) + panel.set_value("digital_source", source) + enum_selectbox( + panel, + label="Edge", + value=Edge.FALLING, + disabled=panel.get_value("is_running", False), + key="edge", + ) + if trigger_type == "3": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + if trigger_type == "4": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + if trigger_type == "5": + with st.container(border=True): + analog_source = st.text_input("Source:", "APFI0") + panel.set_value("analog_source", analog_source) + enum_selectbox( + panel, + label="Slope", + value=Slope.FALLING, + disabled=panel.get_value("is_running", False), + key="slope", + ) + + level = st.number_input("Level") + panel.set_value("level", level) + hysteriesis = st.number_input( + "Hysteriesis", disabled=panel.get_value("is_running", False), + key = "hysteriesis", + ) + + if trigger_type == "6": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" + ) + if trigger_type == "7": + with st.container(border=True): + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." + ) + + with st.container(border=True): + + acquired_data = panel.get_value("data", [0.0]) + sample_rate = panel.get_value("actual_sample_rate", 1000.0) + time = [x / sample_rate for x in range(len(acquired_data))] + + fig, ax = plt.subplots() + ax.plot(time, acquired_data, label="Line Plot") + ax.set_xlabel("Time (s)") + ax.set_ylabel("Amplitude (V)") + ax.legend() + st.pyplot(fig) + + \ No newline at end of file From 8a70cd0f272284703322fcc1ac58e027e2b12037 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 22 Jul 2025 10:21:59 -0500 Subject: [PATCH 31/68] Voltage - Continuous Output --- .../nidaqmx_analog_output_voltage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index f5ca7269..2ad010b7 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -93,7 +93,6 @@ writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) try: - task.out_stream.output_buf_size = 1000 task.start() while not panel.get_value("stop_button", False): time.sleep(0.1) From 310438416b8670babcd7df776f8c31da07a7de7b Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 22 Jul 2025 10:41:24 -0500 Subject: [PATCH 32/68] Voltage - Continuous Output --- .../nidaqmx_analog_output_voltage.py | 2 +- .../nidaqmx_analog_output_voltage_panel.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 2ad010b7..9f274e91 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -48,7 +48,7 @@ min_val=panel.get_value("min_value_voltage", -5.0), ) sample_rate = panel.get_value("rate", 1000.0) - num_samples = panel.get_value("rate", 1000.0) + num_samples = panel.get_value("total_samples", 1000) frequency = panel.get_value("frequency", 10.0) amplitude = panel.get_value("amplitude", 1.0) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index f3fd34d6..a92b2f43 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -215,7 +215,6 @@ ax.plot(time, acquired_data, label="Line Plot") ax.set_xlabel("Time (s)") ax.set_ylabel("Amplitude (V)") - ax.legend() st.pyplot(fig) \ No newline at end of file From 015a2085c035dc34bf216916b9c5d368cff1bc73 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 22 Jul 2025 14:57:55 -0500 Subject: [PATCH 33/68] formatting changes --- .../nidaqmx_analog_output_voltage.py | 24 ++++++----- .../nidaqmx_analog_output_voltage_panel.py | 43 +++++++------------ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 9f274e91..11ff6e65 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -1,14 +1,14 @@ -"""Data acquisition script that continuously acquires analog input data.""" +"""Data acquisition script that continuously acquires analog output data.""" import time from pathlib import Path -from scipy.signal import sawtooth # type: ignore[import-untyped] import nidaqmx import nidaqmx.stream_writers import nidaqmx.system import numpy as np from nidaqmx.constants import AcquisitionType, Edge, Slope +from scipy.signal import sawtooth # type: ignore[import-untyped] import nipanel @@ -47,13 +47,14 @@ max_val=panel.get_value("max_value_voltage", 5.0), min_val=panel.get_value("min_value_voltage", -5.0), ) + sample_rate = panel.get_value("rate", 1000.0) num_samples = panel.get_value("total_samples", 1000) - frequency = panel.get_value("frequency", 10.0) - amplitude = panel.get_value("amplitude", 1.0) - + frequency = panel.get_value("frequency", 10.0) + amplitude = panel.get_value("amplitude", 1.0) + task.timing.cfg_samp_clk_timing( - rate=panel.get_value("rate", 1000.0), + rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, ) # Not all hardware supports all trigger types. @@ -73,11 +74,12 @@ task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( "hysteresis", 0.0 ) + panel.set_value("sample_rate", task.timing.samp_clk_rate) t = np.arange(num_samples) / sample_rate + wave_type = panel.get_value("wave_type", "Sine Wave") - - + if wave_type == "Sine Wave": waveform = amplitude * np.sin(2 * np.pi * frequency * t) elif wave_type == "Square Wave": @@ -86,9 +88,9 @@ waveform = amplitude * (2 * np.abs(2 * (t * frequency % 1) - 1) - 1) else: waveform = sawtooth(2 * np.pi * frequency * t) - + writer = nidaqmx.stream_writers.AnalogSingleChannelWriter( - task.out_stream, auto_start=False # pyright: ignore[reportArgumentType] + task.out_stream, auto_start=False # pyright: ignore[reportArgumentType] ) writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) @@ -96,7 +98,7 @@ task.start() while not panel.get_value("stop_button", False): time.sleep(0.1) - + except KeyboardInterrupt: break finally: diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index a92b2f43..1e11556c 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -1,18 +1,16 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" +"""Streamlit visualization script to display data acquired by nidaqmx_analog_output_voltage.py.""" import extra_streamlit_components as stx # type: ignore[import-untyped] +import matplotlib.pyplot as plt import streamlit as st from nidaqmx.constants import ( Edge, Slope, ) -import matplotlib.pyplot as plt - import nipanel from nipanel.controls import enum_selectbox - st.set_page_config(page_title="Analog Output Continuous Voltage", page_icon="📈", layout="wide") st.title("Analog Output - Voltage") panel = nipanel.get_panel_accessor() @@ -33,17 +31,12 @@ width: 190px !important; /* Adjust the width as needed */ } - """, - unsafe_allow_html=True, -) - -streamlit_style = """ - """ -st.markdown(streamlit_style, unsafe_allow_html=True) - + """, + unsafe_allow_html=True, +) with left_col: with st.container(border=True): @@ -60,14 +53,13 @@ disabled=panel.get_value("is_running", False), ) panel.set_value("physical_channel", physical_channel) - max_value_voltage = st.number_input( "Max Value", value=5.0, step=0.1, disabled=panel.get_value("is_running", False), - key = "max_value_voltage", + key="max_value_voltage", ) min_value_voltage = st.number_input( @@ -75,9 +67,8 @@ value=-5.0, step=0.1, disabled=panel.get_value("is_running", False), - key = "min_value_voltage", + key="min_value_voltage", ) - st.title("Timing and Buffer Settings") st.selectbox( @@ -125,15 +116,14 @@ disabled=panel.get_value("is_running", False), ) st.selectbox( - label = "Wave Type", - options = ["Sine Wave", "Triangle Wave", "Square Wave", "Sawtooth Wave"], - key = "wave_type", + label="Wave Type", + options=["Sine Wave", "Triangle Wave", "Square Wave", "Sawtooth Wave"], + key="wave_type", ) with right_col: with st.container(border=True): - st.title("Trigger Settings") trigger_type = stx.tab_bar( data=[ @@ -156,7 +146,9 @@ ) if trigger_type == "2": with st.container(border=True): - source = st.selectbox("Source->", options=panel.get_value("available_trigger_sources", [""])) + source = st.selectbox( + "Source:", options=panel.get_value("available_trigger_sources", [""]) + ) panel.set_value("digital_source", source) enum_selectbox( panel, @@ -190,8 +182,9 @@ level = st.number_input("Level") panel.set_value("level", level) hysteriesis = st.number_input( - "Hysteriesis", disabled=panel.get_value("is_running", False), - key = "hysteriesis", + "Hysteriesis", + disabled=panel.get_value("is_running", False), + key="hysteriesis", ) if trigger_type == "6": @@ -206,15 +199,11 @@ ) with st.container(border=True): - acquired_data = panel.get_value("data", [0.0]) sample_rate = panel.get_value("actual_sample_rate", 1000.0) time = [x / sample_rate for x in range(len(acquired_data))] - fig, ax = plt.subplots() ax.plot(time, acquired_data, label="Line Plot") ax.set_xlabel("Time (s)") ax.set_ylabel("Amplitude (V)") st.pyplot(fig) - - \ No newline at end of file From 4add6569e6454899b329f44f9423769a958e0a6f Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 09:01:38 -0500 Subject: [PATCH 34/68] matplotlib to echarts --- .../nidaqmx_analog_output_voltage.py | 9 ++-- .../nidaqmx_analog_output_voltage_panel.py | 49 +++++++++++++------ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 11ff6e65..437689b7 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -8,12 +8,11 @@ import nidaqmx.system import numpy as np from nidaqmx.constants import AcquisitionType, Edge, Slope -from scipy.signal import sawtooth # type: ignore[import-untyped] import nipanel panel_script_path = Path(__file__).with_name("nidaqmx_analog_output_voltage_panel.py") -panel = nipanel.create_panel(panel_script_path) +panel = nipanel.create_streamlit_panel(panel_script_path) system = nidaqmx.system.System.local() @@ -47,7 +46,7 @@ max_val=panel.get_value("max_value_voltage", 5.0), min_val=panel.get_value("min_value_voltage", -5.0), ) - + sample_rate = panel.get_value("rate", 1000.0) num_samples = panel.get_value("total_samples", 1000) frequency = panel.get_value("frequency", 10.0) @@ -84,10 +83,8 @@ waveform = amplitude * np.sin(2 * np.pi * frequency * t) elif wave_type == "Square Wave": waveform = amplitude * np.sign(np.sin(2 * np.pi * frequency * t)) - elif wave_type == "Triangle Wave": - waveform = amplitude * (2 * np.abs(2 * (t * frequency % 1) - 1) - 1) else: - waveform = sawtooth(2 * np.pi * frequency * t) + waveform = amplitude * (2 * np.abs(2 * (t * frequency % 1) - 1) - 1) writer = nidaqmx.stream_writers.AnalogSingleChannelWriter( task.out_stream, auto_start=False # pyright: ignore[reportArgumentType] diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 1e11556c..2ad7b09c 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -1,19 +1,16 @@ """Streamlit visualization script to display data acquired by nidaqmx_analog_output_voltage.py.""" import extra_streamlit_components as stx # type: ignore[import-untyped] -import matplotlib.pyplot as plt import streamlit as st -from nidaqmx.constants import ( - Edge, - Slope, -) +from nidaqmx.constants import Edge, Slope +from streamlit_echarts import st_echarts import nipanel from nipanel.controls import enum_selectbox st.set_page_config(page_title="Analog Output Continuous Voltage", page_icon="📈", layout="wide") st.title("Analog Output - Voltage") -panel = nipanel.get_panel_accessor() +panel = nipanel.get_streamlit_panel_accessor() left_col, right_col = st.columns(2) @@ -117,7 +114,7 @@ ) st.selectbox( label="Wave Type", - options=["Sine Wave", "Triangle Wave", "Square Wave", "Sawtooth Wave"], + options=["Sine Wave", "Triangle Wave", "Square Wave"], key="wave_type", ) @@ -200,10 +197,34 @@ with st.container(border=True): acquired_data = panel.get_value("data", [0.0]) - sample_rate = panel.get_value("actual_sample_rate", 1000.0) - time = [x / sample_rate for x in range(len(acquired_data))] - fig, ax = plt.subplots() - ax.plot(time, acquired_data, label="Line Plot") - ax.set_xlabel("Time (s)") - ax.set_ylabel("Amplitude (V)") - st.pyplot(fig) + sample_rate = panel.get_value("sample_rate", 0.0) + acquired_data_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)"]}, + "xAxis": { + "type": "category", + "data": [x / sample_rate for x in range(len(acquired_data))], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Volts", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": acquired_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], + } + st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") From c41d5efe3d050f43c80b7550be26ad3791400a76 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 09:39:19 -0500 Subject: [PATCH 35/68] changed run button --- examples/nidaqmx/nidaqmx_analog_output_voltage/README.md | 2 +- .../nidaqmx_analog_output_voltage.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md index de7c0158..022a5c37 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md @@ -7,7 +7,7 @@ This is an nipanel example that displays an interactive Streamlit app and update ### Feature -Script demonstrates analog output voltage data getting continuously acquired. +Script demonstrates analog output voltage data getting continuously acquired, and put into different types of waveform graphs. - Supports various data types ### Required Software diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 437689b7..f7dc37aa 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -33,12 +33,9 @@ print(f"Waiting for the 'Run' button to be pressed...") print(f"(Press Ctrl + C to quit)") while True: + panel.set_value("is_running", False) while not panel.get_value("run_button", False): - panel.set_value("is_running", False) time.sleep(0.1) - panel.set_value("is_running", True) - panel.set_value("stop_button", False) - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ with nidaqmx.Task() as task: chan = task.ao_channels.add_ao_voltage_chan( @@ -93,6 +90,8 @@ panel.set_value("data", waveform.tolist()) try: task.start() + panel.set_value("is_running", True) + panel.set_value("stop_button", False) while not panel.get_value("stop_button", False): time.sleep(0.1) @@ -101,7 +100,6 @@ finally: task.stop() panel.set_value("is_running", False) - panel.set_value("run_button", False) except KeyboardInterrupt: From cfdd482f48d144a9afc46a69b6df48c8ec48d7f1 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 10:21:47 -0500 Subject: [PATCH 36/68] resolve sample rate error --- .../nidaqmx_analog_output_voltage.py | 1 + .../nidaqmx_analog_output_voltage_panel.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index f7dc37aa..5a4455a3 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -28,6 +28,7 @@ for term in dev.terminals: available_trigger_sources.append(term) panel.set_value("available_trigger_sources", available_trigger_sources) + try: print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 2ad7b09c..1cb1baf2 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -197,7 +197,7 @@ with st.container(border=True): acquired_data = panel.get_value("data", [0.0]) - sample_rate = panel.get_value("sample_rate", 0.0) + sample_rate = panel.get_value("sample_rate", 1000.0) acquired_data_graph = { "animation": False, "tooltip": {"trigger": "axis"}, From d20cbaa4a0e23139c504bdc885f20d8f02f2a9f2 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 13:16:24 -0500 Subject: [PATCH 37/68] Daq errors (unfinished) --- .../nidaqmx_analog_output_voltage.py | 23 +++++++-------- .../nidaqmx_analog_output_voltage_panel.py | 28 ++++++------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 5a4455a3..a5e70e9f 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -7,8 +7,9 @@ import nidaqmx.stream_writers import nidaqmx.system import numpy as np -from nidaqmx.constants import AcquisitionType, Edge, Slope +from nidaqmx.constants import AcquisitionType, Edge +from nidaqmx.errors import DaqError import nipanel panel_script_path = Path(__file__).with_name("nidaqmx_analog_output_voltage_panel.py") @@ -57,20 +58,13 @@ # Not all hardware supports all trigger types. # Refer to your device documentation for more information. trigger_type = panel.get_value("trigger_type") - if trigger_type == "5": - task.triggers.start_trigger.cfg_anlg_edge_start_trig( - trigger_source=panel.get_value("analog_source", ""), - trigger_slope=panel.get_value("slope", Slope.FALLING), - trigger_level=panel.get_value("level", 0.0), - ) + if trigger_type == "2": task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source=panel.get_value("digital_source", ""), trigger_edge=panel.get_value("edge", Edge.FALLING), ) - task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( - "hysteresis", 0.0 - ) + panel.set_value("sample_rate", task.timing.samp_clk_rate) t = np.arange(num_samples) / sample_rate @@ -89,19 +83,22 @@ ) writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) + try: task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) while not panel.get_value("stop_button", False): time.sleep(0.1) - + except KeyboardInterrupt: break finally: task.stop() panel.set_value("is_running", False) - - +except DaqError as e: + error_message = str(e) + panel.set_value("error_message", error_message) + except KeyboardInterrupt: pass diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 1cb1baf2..ca482b67 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -2,7 +2,7 @@ import extra_streamlit_components as stx # type: ignore[import-untyped] import streamlit as st -from nidaqmx.constants import Edge, Slope +from nidaqmx.constants import Edge from streamlit_echarts import st_echarts import nipanel @@ -54,7 +54,7 @@ max_value_voltage = st.number_input( "Max Value", value=5.0, - step=0.1, + step=1.0, disabled=panel.get_value("is_running", False), key="max_value_voltage", ) @@ -62,7 +62,7 @@ min_value_voltage = st.number_input( "Min Value", value=-5.0, - step=0.1, + step=1.0, disabled=panel.get_value("is_running", False), key="min_value_voltage", ) @@ -116,6 +116,7 @@ label="Wave Type", options=["Sine Wave", "Triangle Wave", "Square Wave"], key="wave_type", + disabled=panel.get_value("is_running", False), ) @@ -166,24 +167,9 @@ ) if trigger_type == "5": with st.container(border=True): - analog_source = st.text_input("Source:", "APFI0") - panel.set_value("analog_source", analog_source) - enum_selectbox( - panel, - label="Slope", - value=Slope.FALLING, - disabled=panel.get_value("is_running", False), - key="slope", - ) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input( - "Hysteriesis", - disabled=panel.get_value("is_running", False), - key="hysteriesis", + st.write( + "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" ) - if trigger_type == "6": with st.container(border=True): st.write( @@ -228,3 +214,5 @@ ], } st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + with st.container(border=True): + st.warning(panel.get_value("error_message", " "), icon="⚠️") From beedfde044a2a815ec33aabacf0eceeadcbbe761 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 13:55:28 -0500 Subject: [PATCH 38/68] daq errors --- .../nidaqmx_analog_output_voltage.py | 10 ++++++---- .../nidaqmx_analog_output_voltage_panel.py | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index a5e70e9f..9b284299 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -29,7 +29,6 @@ for term in dev.terminals: available_trigger_sources.append(term) panel.set_value("available_trigger_sources", available_trigger_sources) - try: print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") @@ -85,6 +84,7 @@ panel.set_value("data", waveform.tolist()) try: + panel.set_value("daq_errors","") task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) @@ -96,9 +96,11 @@ finally: task.stop() panel.set_value("is_running", False) -except DaqError as e: - error_message = str(e) - panel.set_value("error_message", error_message) + +except DaqError as e: + daq_errors = str(e) + panel.set_value("daq_errors",daq_errors) + except KeyboardInterrupt: pass diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index ca482b67..28133d37 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -180,6 +180,7 @@ st.write( "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." ) + with st.container(border=True): acquired_data = panel.get_value("data", [0.0]) @@ -214,5 +215,6 @@ ], } st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + with st.container(border=True): - st.warning(panel.get_value("error_message", " "), icon="⚠️") + st.write(panel.get_value("daq_errors", "")) \ No newline at end of file From eb4ad21f172acd06c608795f29562891b474e8ff Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 23 Jul 2025 14:47:41 -0500 Subject: [PATCH 39/68] updating daq error display --- .../nidaqmx_analog_output_voltage_panel.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 28133d37..cd445574 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -217,4 +217,7 @@ st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") with st.container(border=True): - st.write(panel.get_value("daq_errors", "")) \ No newline at end of file + if panel.get_value("daq_errors", "") == "": + st.write("No DAQ Errors Found") + else: + st.error(panel.get_value("daq_errors", "")) \ No newline at end of file From e0e6c9d1251cb45e6cafa93ab5bb75713b8a55fa Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 07:54:12 -0500 Subject: [PATCH 40/68] README.md change --- examples/nidaqmx/nidaqmx_analog_output_voltage/README.md | 2 +- .../nidaqmx_analog_output_voltage.py | 4 ---- .../nidaqmx_analog_output_voltage_panel.py | 6 +++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md index 022a5c37..5b74796e 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md @@ -18,5 +18,5 @@ Script demonstrates analog output voltage data getting continuously acquired, an ```pwsh poetry install --with examples -poetry run python examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +poetry run python examples\nidaqmx\nidaqmx_analog_output_voltage\nidaqmx_analog_output_voltage.py ``` \ No newline at end of file diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 9b284299..547cfdd9 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -63,11 +63,9 @@ trigger_source=panel.get_value("digital_source", ""), trigger_edge=panel.get_value("edge", Edge.FALLING), ) - panel.set_value("sample_rate", task.timing.samp_clk_rate) t = np.arange(num_samples) / sample_rate - wave_type = panel.get_value("wave_type", "Sine Wave") if wave_type == "Sine Wave": @@ -82,7 +80,6 @@ ) writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) - try: panel.set_value("daq_errors","") task.start() @@ -96,7 +93,6 @@ finally: task.stop() panel.set_value("is_running", False) - except DaqError as e: daq_errors = str(e) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index cd445574..636793ee 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -8,8 +8,8 @@ import nipanel from nipanel.controls import enum_selectbox -st.set_page_config(page_title="Analog Output Continuous Voltage", page_icon="📈", layout="wide") -st.title("Analog Output - Voltage") +st.set_page_config(page_title="Voltage - Continuous Output", page_icon="📈", layout="wide") +st.title("Voltage - Continuous Output") panel = nipanel.get_streamlit_panel_accessor() left_col, right_col = st.columns(2) @@ -198,7 +198,7 @@ }, "yAxis": { "type": "value", - "name": "Volts", + "name": "Amplitude", "nameRotate": 90, "nameLocation": "center", "nameGap": 40, From ea7efdd3b425467d8d7b203cefb9af4605d52882 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 08:00:03 -0500 Subject: [PATCH 41/68] fixing lint errors --- .../nidaqmx_analog_output_voltage.py | 10 +++++----- .../nidaqmx_analog_output_voltage_panel.py | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 547cfdd9..6c064dd7 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -8,8 +8,8 @@ import nidaqmx.system import numpy as np from nidaqmx.constants import AcquisitionType, Edge - from nidaqmx.errors import DaqError + import nipanel panel_script_path = Path(__file__).with_name("nidaqmx_analog_output_voltage_panel.py") @@ -81,22 +81,22 @@ writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) try: - panel.set_value("daq_errors","") + panel.set_value("daq_errors", "") task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) while not panel.get_value("stop_button", False): time.sleep(0.1) - + except KeyboardInterrupt: break finally: task.stop() panel.set_value("is_running", False) - + except DaqError as e: daq_errors = str(e) - panel.set_value("daq_errors",daq_errors) + panel.set_value("daq_errors", daq_errors) except KeyboardInterrupt: pass diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 636793ee..a6dcfc66 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -180,7 +180,6 @@ st.write( "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." ) - with st.container(border=True): acquired_data = panel.get_value("data", [0.0]) @@ -215,9 +214,9 @@ ], } st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") - + with st.container(border=True): if panel.get_value("daq_errors", "") == "": st.write("No DAQ Errors Found") else: - st.error(panel.get_value("daq_errors", "")) \ No newline at end of file + st.error(panel.get_value("daq_errors", "")) From 81b9c7a6a93cbd82c7264fa2282138869c56695a Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 10:23:01 -0500 Subject: [PATCH 42/68] deleted trigger types --- .../nidaqmx_analog_output_voltage_panel.py | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index a6dcfc66..f5dff44c 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -137,11 +137,6 @@ ) panel.set_value("trigger_type", trigger_type) - if trigger_type == "1": - with st.container(border=True): - st.write( - "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." - ) if trigger_type == "2": with st.container(border=True): source = st.selectbox( @@ -155,27 +150,7 @@ disabled=panel.get_value("is_running", False), key="edge", ) - if trigger_type == "3": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - if trigger_type == "4": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - if trigger_type == "5": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - if trigger_type == "6": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - if trigger_type == "7": + else: with st.container(border=True): st.write( "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." From a3680b4c092fc1273edfa6da3c00782cf338a299 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 10:50:29 -0500 Subject: [PATCH 43/68] error handling --- .../nidaqmx_analog_output_voltage.py | 1 + .../nidaqmx_analog_output_voltage_panel.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 6c064dd7..e38bcf45 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -96,6 +96,7 @@ except DaqError as e: daq_errors = str(e) + print(daq_errors) panel.set_value("daq_errors", daq_errors) except KeyboardInterrupt: diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index f5dff44c..c54de0a3 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -42,6 +42,12 @@ st.button("Stop", key="stop_button") else: st.button("Run", key="run_button") + + if panel.get_value("daq_errors", "") == "": + pass + else: + st.error(panel.get_value("daq_errors", "")) + st.title("Channel Settings") physical_channel = st.selectbox( options=panel.get_value("available_channel_names", ["Mod2/ai0"]), @@ -119,7 +125,6 @@ disabled=panel.get_value("is_running", False), ) - with right_col: with st.container(border=True): st.title("Trigger Settings") From 0b858e9215b93c9a801419441289432138f364c4 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 11:38:03 -0500 Subject: [PATCH 44/68] fixing source settings --- .../nidaqmx_analog_output_voltage.py | 9 +++++---- .../nidaqmx_analog_output_voltage_panel.py | 15 ++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index e38bcf45..e6477f20 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -51,6 +51,7 @@ amplitude = panel.get_value("amplitude", 1.0) task.timing.cfg_samp_clk_timing( + source= panel.get_value("source", "/Dev4/PFI0"), rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, ) @@ -81,7 +82,7 @@ writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) try: - panel.set_value("daq_errors", "") + panel.set_value("daq_error", "") task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) @@ -95,9 +96,9 @@ panel.set_value("is_running", False) except DaqError as e: - daq_errors = str(e) - print(daq_errors) - panel.set_value("daq_errors", daq_errors) + daq_error = str(e) + print(daq_error) + panel.set_value("daq_error", daq_error) except KeyboardInterrupt: pass diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index c54de0a3..2e278d73 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -43,11 +43,11 @@ else: st.button("Run", key="run_button") - if panel.get_value("daq_errors", "") == "": + if panel.get_value("daq_error", "") == "": pass else: - st.error(panel.get_value("daq_errors", "")) - + st.error(panel.get_value("daq_error", "")) + st.title("Channel Settings") physical_channel = st.selectbox( options=panel.get_value("available_channel_names", ["Mod2/ai0"]), @@ -74,12 +74,13 @@ ) st.title("Timing and Buffer Settings") - st.selectbox( + source = st.selectbox( "Sample Clock Source", options=panel.get_value("available_trigger_sources", [""]), index=0, disabled=panel.get_value("is_running", False), ) + panel.set_value("source", source) st.number_input( "Sample Rate", value=1000.0, @@ -195,8 +196,4 @@ } st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") - with st.container(border=True): - if panel.get_value("daq_errors", "") == "": - st.write("No DAQ Errors Found") - else: - st.error(panel.get_value("daq_errors", "")) + From 3f5c35f84e7bed8f7ee0598aff2d5689f57891a7 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 11:42:55 -0500 Subject: [PATCH 45/68] fixing lint errors --- .../nidaqmx_analog_output_voltage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index e6477f20..62e764e2 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -51,7 +51,7 @@ amplitude = panel.get_value("amplitude", 1.0) task.timing.cfg_samp_clk_timing( - source= panel.get_value("source", "/Dev4/PFI0"), + source=panel.get_value("source", "/Dev4/PFI0"), rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, ) From da485d6f5057e32335a0d3c5ec044ee8e73180e8 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 11:43:19 -0500 Subject: [PATCH 46/68] lint error --- .../nidaqmx_analog_output_voltage_panel.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 2e278d73..80efcab0 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -195,5 +195,3 @@ ], } st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") - - From 126d3fb7cdbc225d4ffd3d9d9ff8cea5334cf891 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 14:52:32 -0500 Subject: [PATCH 47/68] disable run button --- .../nidaqmx_analog_output_voltage.py | 6 +++--- .../nidaqmx_analog_output_voltage_panel.py | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 62e764e2..9420b449 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -23,13 +23,14 @@ available_channel_names.append(chan.name) panel.set_value("available_channel_names", available_channel_names) -available_trigger_sources = [] +available_trigger_sources = [""] for dev in system.devices: if hasattr(dev, "terminals"): for term in dev.terminals: available_trigger_sources.append(term) panel.set_value("available_trigger_sources", available_trigger_sources) try: + panel.set_value("daq_error", "") print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") print(f"(Press Ctrl + C to quit)") @@ -51,7 +52,7 @@ amplitude = panel.get_value("amplitude", 1.0) task.timing.cfg_samp_clk_timing( - source=panel.get_value("source", "/Dev4/PFI0"), + source=panel.get_value("source", ""), # "" - OnboardClock rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, ) @@ -82,7 +83,6 @@ writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) try: - panel.set_value("daq_error", "") task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 80efcab0..a7898449 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -35,6 +35,21 @@ unsafe_allow_html=True, ) + +def hide_run_button(): + """hide_run_button is used to disable run button when DAQ error pops up.""" + st.markdown( + """ + + """, + unsafe_allow_html=True, + ) + + with left_col: with st.container(border=True): is_running = panel.get_value("is_running", True) @@ -46,7 +61,8 @@ if panel.get_value("daq_error", "") == "": pass else: - st.error(panel.get_value("daq_error", "")) + hide_run_button() + st.error(panel.get_value("daq_error", "") + " Please re-run script") st.title("Channel Settings") physical_channel = st.selectbox( From dd9d95b828bc712b088228bd714748e89c158c0b Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 14:52:32 -0500 Subject: [PATCH 48/68] disable run button --- .../nidaqmx_analog_output_voltage.py | 6 +++--- .../nidaqmx_analog_output_voltage_panel.py | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 62e764e2..9420b449 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -23,13 +23,14 @@ available_channel_names.append(chan.name) panel.set_value("available_channel_names", available_channel_names) -available_trigger_sources = [] +available_trigger_sources = [""] for dev in system.devices: if hasattr(dev, "terminals"): for term in dev.terminals: available_trigger_sources.append(term) panel.set_value("available_trigger_sources", available_trigger_sources) try: + panel.set_value("daq_error", "") print(f"Panel URL: {panel.panel_url}") print(f"Waiting for the 'Run' button to be pressed...") print(f"(Press Ctrl + C to quit)") @@ -51,7 +52,7 @@ amplitude = panel.get_value("amplitude", 1.0) task.timing.cfg_samp_clk_timing( - source=panel.get_value("source", "/Dev4/PFI0"), + source=panel.get_value("source", ""), # "" - OnboardClock rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, ) @@ -82,7 +83,6 @@ writer.write_many_sample(waveform) panel.set_value("data", waveform.tolist()) try: - panel.set_value("daq_error", "") task.start() panel.set_value("is_running", True) panel.set_value("stop_button", False) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 80efcab0..ca0b73f6 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -35,6 +35,21 @@ unsafe_allow_html=True, ) + +def hide_run_button()-> None: + """hide_run_button is used to disable run button when DAQ error pops up.""" + st.markdown( + """ + + """, + unsafe_allow_html=True, + ) + + with left_col: with st.container(border=True): is_running = panel.get_value("is_running", True) @@ -46,7 +61,8 @@ if panel.get_value("daq_error", "") == "": pass else: - st.error(panel.get_value("daq_error", "")) + hide_run_button() + st.error(panel.get_value("daq_error", "") + " Please re-run script") st.title("Channel Settings") physical_channel = st.selectbox( From 6492de65e7cf7af34ac150699f91b4c0ac3077e6 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 24 Jul 2025 15:06:20 -0500 Subject: [PATCH 49/68] delete current example --- examples/nidaqmx_current/nidaqmx_current.py | 95 ------- .../nidaqmx_current/nidaqmx_current_panel.py | 244 ------------------ 2 files changed, 339 deletions(-) delete mode 100644 examples/nidaqmx_current/nidaqmx_current.py delete mode 100644 examples/nidaqmx_current/nidaqmx_current_panel.py diff --git a/examples/nidaqmx_current/nidaqmx_current.py b/examples/nidaqmx_current/nidaqmx_current.py deleted file mode 100644 index e6ea5e07..00000000 --- a/examples/nidaqmx_current/nidaqmx_current.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Data acquisition script that continuously acquires analog input data.""" - -from pathlib import Path - -import nidaqmx -from nidaqmx.constants import ( - AcquisitionType, - CurrentShuntResistorLocation, - CurrentUnits, - Edge, - LoggingMode, - LoggingOperation, - Slope, -) -from settings import AnalogPause, PauseWhen - -import nipanel - -panel_script_path = Path(__file__).with_name("nidaqmx_current_panel.py") -panel = nipanel.create_panel(panel_script_path) -panel.set_value("is_running", False) -try: - print(f"Panel URL: {panel.panel_url}") - print(f"Waiting for the 'Run' button to be pressed...") - print(f"(Press Ctrl + C to quit)") - while True: - while not panel.get_value("run_button", False): - panel.set_value("is_running", False) - panel.set_value("is_running", True) - panel.set_value("stop_button", False) - - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ - with nidaqmx.Task() as task: - - chan = task.ai_channels.add_ai_current_chan( - "Mod3/ai10", - max_val=panel.get_value("max_value_current", 0.01), - min_val=panel.get_value("min_value_current", -0.01), - ext_shunt_resistor_val=panel.get_value("shunt_resistor_value", 249.0), - shunt_resistor_loc=panel.get_value( - "shunt_location", CurrentShuntResistorLocation.EXTERNAL - ), - ) - - task.timing.cfg_samp_clk_timing( - rate=panel.get_value("rate", 1000.0), - sample_mode=AcquisitionType.CONTINUOUS, - samps_per_chan=panel.get_value("num_of_samps", 1000), - ) - panel.set_value("sample_rate", task._timing.samp_clk_rate) - - task.in_stream.configure_logging( - file_path=panel.get_value("tdms_file_path", "data.tdms"), - logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), - operation=LoggingOperation.OPEN_OR_CREATE, - ) - trigger_type = panel.get_value("trigger_type") - - if trigger_type == "5": - task.triggers.start_trigger.cfg_anlg_edge_start_trig( - trigger_source="APFI0", - trigger_slope=panel.get_value("slope", Slope.FALLING), - trigger_level=panel.get_value("level", 0.0), - ) - - if trigger_type == "2": - task.triggers.start_trigger.cfg_dig_edge_start_trig( - trigger_source="/Dev2/PFI0", trigger_edge=panel.get_value("edge", Edge.FALLING) - ) - task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( - "hysteresis", 0.0 - ) - - try: - - task.start() - - while not panel.get_value("stop_button", False): - data = task.read( - number_of_samples_per_channel=1000 - ) # pyright: ignore[reportArgumentType] - panel.set_value("voltage_data", data) - panel.set_value("current_data", data) - panel.set_value("strain_data", data) - - except KeyboardInterrupt: - pass - finally: - task.stop() - panel.set_value("is_running", False) - panel.set_value("run_button", False) - - -except KeyboardInterrupt: - pass diff --git a/examples/nidaqmx_current/nidaqmx_current_panel.py b/examples/nidaqmx_current/nidaqmx_current_panel.py deleted file mode 100644 index d8ba62d9..00000000 --- a/examples/nidaqmx_current/nidaqmx_current_panel.py +++ /dev/null @@ -1,244 +0,0 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" - -import extra_streamlit_components as stx # type: ignore[import-untyped] -import streamlit as st -from nidaqmx.constants import ( - CurrentShuntResistorLocation, - CurrentUnits, - Edge, - FilterResponse, - LoggingMode, - Slope, - StrainGageBridgeType, - TerminalConfiguration, -) -from settings import AnalogPause, PauseWhen -from streamlit_echarts import st_echarts - -import nipanel -from nipanel.controls import enum_selectbox - -st.set_page_config(page_title="Current - Continuous Input", page_icon="📈", layout="wide") -st.title("Current - Continuous Input") -panel = nipanel.get_panel_accessor() - -left_col, right_col = st.columns(2) - - -is_running = panel.get_value("is_running", True) -with left_col: - if is_running: - st.button("Stop", key="stop_button") - else: - st.button("Run", key="run_button") - - -st.markdown( - """ - - """, - unsafe_allow_html=True, -) - -streamlit_style = """ - - """ -st.markdown(streamlit_style, unsafe_allow_html=True) - - -with left_col: - with st.container(border=True): - - st.title("Channel Settings") - st.selectbox(options=["Mod3/ai10"], index=0, label="Physical Channels", disabled=True) - - enum_selectbox( - panel, - label="Shunt Resistor", - value=CurrentShuntResistorLocation.EXTERNAL, - disabled=panel.get_value("is_running", False), - key="shunt_location", - ) - min_value_current = st.number_input( - "Min Current (A)", - value=0.0, - step=0.001, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("min_value_current", min_value_current) - max_value_current = st.number_input( - "Max Current (A)", - value=0.02, - step=1.0, - key="max_value_current", - disabled=panel.get_value("is_running", False), - ) - current = panel.set_value("max_value_current", max_value_current) # type:ignore - shunt_resistor_value = st.number_input( - "Shunt Resistor Value (Ohm)", - value=249.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("shunt_resistor_value", shunt_resistor_value) - - st.title("Timing Settings") - - st.selectbox("Sample Clock Source", options=["Onboard Clock"], index=0, disabled=True) - st.number_input( - "Sample Rate", - value=1000.0, - min_value=1.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="rate", - ) - st.number_input( - "Number of Samples", - value=1000, - min_value=1, - step=1, - disabled=panel.get_value("is_running", False), - key="num_of_samps", - ) - st.selectbox( - "Actual Sample Rate", options=[panel.get_value("sample_rate", 100.0)], disabled=True - ) - - st.title("Logging Settings") - enum_selectbox( - panel, - label="Logging Mode", - value=LoggingMode.OFF, - disabled=panel.get_value("is_running", False), - key="logging_mode", - ) - tdms_file_path = st.text_input( - label="TDMS File Path", - disabled=panel.get_value("is_running", False), - value="data.tdms", - key="tdms_file_path", - ) - -with right_col: - with st.container(border=True): - st.title("Trigger Settings") - id = stx.tab_bar( - data=[ - stx.TabBarItemData(id=1, title="No Trigger", description=""), - stx.TabBarItemData(id=2, title="Digital Start", description=""), - stx.TabBarItemData(id=3, title="Digital Pause", description=""), - stx.TabBarItemData(id=4, title="Digital Reference", description=""), - stx.TabBarItemData(id=5, title="Analog Start", description=""), - stx.TabBarItemData(id=6, title="Analog Pause", description=""), - stx.TabBarItemData(id=7, title="Analog Reference", description=""), - ], - default=1, - ) - trigger_type = id - panel.set_value("trigger_type", trigger_type) - tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs( - [ - "No Trigger", - "Digital Start", - "Digital Pause", - "Digital Reference", - "Analog Start", - "Analog Pause", - "Analog Reference", - ] - ) - with tab1: - st.write( - "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." - ) - with tab2: - st.selectbox("Source->", " /Dev1/PFI0") - enum_selectbox( - panel, - label="Edge", - value=Edge.FALLING, - disabled=panel.get_value("is_running", False), - key="edge", - ) - with tab3: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) - - pause_when = PauseWhen[pause_when[0]] # type: ignore - panel.set_value("pause_when", pause_when) - with tab4: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - with tab5: - st.selectbox("Source:", "APFI0") - enum_selectbox( - panel, - label="Slope", - value=Slope.FALLING, - disabled=panel.get_value("is_running", False), - key="slope", - ) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input( - "Hysteriesis", disabled=panel.get_value("is_running", False) - ) - panel.set_value("hysteriesis", hysteriesis) - - with tab6: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) - - - with tab7: - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) - - -with right_col: - current_data = panel.get_value("current_data", [1.0]) - sample_rate = panel.get_value("sample_rate", 0.0) -with right_col: - with st.container(border=True): - graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Current Data"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(current_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Amps", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": current_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=graph, height="400px", key="graph", width="100%") From 32c6a78e50701c9d9f8ba70761bc51b0b8d07e64 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:26:27 -0500 Subject: [PATCH 50/68] lint errors --- .../nidaqmx_analog_output_voltage_panel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index ca0b73f6..1558fbec 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -36,7 +36,7 @@ ) -def hide_run_button()-> None: +def hide_run_button() -> None: """hide_run_button is used to disable run button when DAQ error pops up.""" st.markdown( """ From 8a3108291fd0a8e7cc937dfbbd0402e84618673c Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:33:03 -0500 Subject: [PATCH 51/68] removing files --- .../nidaqmx_analog_input_filtering/README.md | 23 - .../nidaqmx_analog_input_filtering.py | 150 ------- .../nidaqmx_analog_input_filtering_panel.py | 421 ------------------ .../nidaqmx_analog_output_voltage/README.md | 2 +- .../nidaqmx_continuous_analog_input/README.md | 22 - .../nidaqmx_continuous_analog_input.py | 83 ---- .../nidaqmx_continuous_analog_input_panel.py | 237 ---------- 7 files changed, 1 insertion(+), 937 deletions(-) delete mode 100644 examples/nidaqmx/nidaqmx_analog_input_filtering/README.md delete mode 100644 examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py delete mode 100644 examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py delete mode 100644 examples/nidaqmx/nidaqmx_continuous_analog_input/README.md delete mode 100644 examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py delete mode 100644 examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md deleted file mode 100644 index dcd518a0..00000000 --- a/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md +++ /dev/null @@ -1,23 +0,0 @@ -Prerequisites -=============== -Requires a Physical or Simulated Device. Refer to the [Getting Started Section](https://github.com/ni/nidaqmx-python/blob/master/README.rst) to learn how to create a simulated device. -## Sample - -This is a nipanel example that displays an interactive Streamlit app and updates and fetches data from device. - -### Feature - -Script demonstrates analog input data getting continuously acquired, and being filtered. -- Supports various data types - -### Required Software - -- Python 3.9 or later - -### Usage - -```pwsh -poetry install --with examples -poetry run python examples/all_types/all_types.py -``` - diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py deleted file mode 100644 index 02e0cb7f..00000000 --- a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering.py +++ /dev/null @@ -1,150 +0,0 @@ -"""Data acquisition script that continuously acquires analog input data.""" - -import time -from pathlib import Path - -import nidaqmx -import nidaqmx.system -from nidaqmx.constants import ( - AcquisitionType, - CurrentShuntResistorLocation, - CurrentUnits, - Edge, - ExcitationSource, - FilterResponse, - Slope, - StrainGageBridgeType, - TerminalConfiguration, -) - -import nipanel - -panel_script_path = Path(__file__).with_name("nidaqmx_analog_input_filtering_panel.py") -panel = nipanel.create_panel(panel_script_path) -panel.set_value("is_running", False) - -system = nidaqmx.system.System.local() - -channel_name = [] -for dev in system.devices: - for chan in dev.ai_physical_chans: - channel_name.append(chan.name) -panel.set_value("channel_name", channel_name) - -trigger_sources = [] -for dev in system.devices: - if hasattr(dev, "terminals"): - for term in dev.terminals: - trigger_sources.append(term) -panel.set_value("trigger_sources", trigger_sources) -try: - print(f"Panel URL: {panel.panel_url}") - print(f"Waiting for the 'Run' button to be pressed...") - print(f"(Press Ctrl + C to quit)") - while True: - while not panel.get_value("run_button", False): - panel.set_value("is_running", False) - time.sleep(0.1) - panel.set_value("is_running", True) - panel.set_value("stop_button", False) - - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ - with nidaqmx.Task() as task: - - chan_type = panel.get_value("chan_type", "1") - - if chan_type == "2": - chan = task.ai_channels.add_ai_current_chan( - panel.get_value("physical_channel", ""), - max_val=panel.get_value("max_value_current", 0.01), - min_val=panel.get_value("min_value_current", -0.01), - ext_shunt_resistor_val=panel.get_value("shunt_resistor_value", 249.0), - shunt_resistor_loc=panel.get_value( - "shunt_location", CurrentShuntResistorLocation.EXTERNAL - ), - units=panel.get_value("units", CurrentUnits.AMPS), - ) - - elif chan_type == "3": - chan = task.ai_channels.add_ai_strain_gage_chan( - panel.get_value("physical_channel", ""), - nominal_gage_resistance=panel.get_value("gage_resistance", 350.0), - voltage_excit_source=ExcitationSource.EXTERNAL, # Only mode that works - max_val=panel.get_value("max_value_strain", 0.001), - min_val=panel.get_value("min_value_strain", -0.001), - poisson_ratio=panel.get_value("poisson_ratio", 0.3), - lead_wire_resistance=panel.get_value("wire_resistance", 0.0), - initial_bridge_voltage=panel.get_value("initial_voltage", 0.0), - gage_factor=panel.get_value("gage_factor", 2.0), - voltage_excit_val=panel.get_value("voltage_excitation_value", 0.0), - strain_config=panel.get_value( - "strain_configuration", StrainGageBridgeType.FULL_BRIDGE_I - ), - ) - else: - chan = task.ai_channels.add_ai_voltage_chan( - panel.get_value("physical_channel", ""), - terminal_config=panel.get_value( - "terminal_configuration", TerminalConfiguration.DEFAULT - ), - max_val=panel.get_value("max_value_voltage", 5.0), - min_val=panel.get_value("min_value_voltage", -5.0), - ) - - task.timing.cfg_samp_clk_timing( - rate=panel.get_value("rate", 1000.0), - sample_mode=AcquisitionType.CONTINUOUS, - samps_per_chan=panel.get_value("total_samples", 100), - ) - panel.set_value("actual_sample_rate", task.timing.samp_clk_rate) - panel.set_value("sample_rate", panel.get_value("rate", 100.0)) - - if panel.get_value("filter", "Filter") == "Filter": - chan.ai_filter_enable = True - chan.ai_filter_freq = panel.get_value("filter_freq", 0.0) - chan.ai_filter_response = panel.get_value("filter_response", FilterResponse.COMB) - chan.ai_filter_order = panel.get_value("filter_order", 1) - # Not all hardware supports all filter types. - # Refer to your device documentation for more information. - panel.set_value("actual_filter_freq", chan.ai_filter_freq) - panel.set_value("actual_filter_response", chan.ai_filter_response) - panel.set_value("actual_filter_order", chan.ai_filter_order) - else: - panel.set_value("actual_filter_freq", 0.0) - panel.set_value("actual_filter_response", FilterResponse.COMB) - panel.set_value("actual_filter_order", 0) - - trigger_type = panel.get_value("trigger_type") - if trigger_type == "5": - task.triggers.start_trigger.cfg_anlg_edge_start_trig( - trigger_source=panel.get_value("analog_source", ""), - trigger_slope=panel.get_value("slope", Slope.FALLING), - trigger_level=panel.get_value("level", 0.0), - ) - - if trigger_type == "2": - task.triggers.start_trigger.cfg_dig_edge_start_trig( - trigger_source=panel.get_value("digital_source", ""), - trigger_edge=panel.get_value("edge", Edge.FALLING), - ) - task.triggers.start_trigger.anlg_edge_hyst = hysteresis = panel.get_value( - "hysteresis", 0.0 - ) - - try: - task.start() - while not panel.get_value("stop_button", False): - data = task.read( - number_of_samples_per_channel=100 # pyright: ignore[reportArgumentType] - ) - panel.set_value("acquired_data", data) - except KeyboardInterrupt: - pass - finally: - task.stop() - panel.set_value("is_running", False) - panel.set_value("run_button", False) - - -except KeyboardInterrupt: - pass diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py deleted file mode 100644 index a427e207..00000000 --- a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_input_filtering_panel.py +++ /dev/null @@ -1,421 +0,0 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_analog_input_filtering.py.""" - -import extra_streamlit_components as stx # type: ignore[import-untyped] -import streamlit as st -from nidaqmx.constants import ( - CurrentShuntResistorLocation, - CurrentUnits, - Edge, - FilterResponse, - LoggingMode, - Slope, - StrainGageBridgeType, - TerminalConfiguration, -) -from streamlit_echarts import st_echarts - -import nipanel -from nipanel.controls import enum_selectbox - -st.set_page_config(page_title="Analog Input Filtering", page_icon="📈", layout="wide") -st.title("Analog Input - Filtering") -panel = nipanel.get_panel_accessor() - -left_col, right_col = st.columns(2) - - -st.markdown( - """ - - """, - unsafe_allow_html=True, -) - -streamlit_style = """ - - """ -st.markdown(streamlit_style, unsafe_allow_html=True) - - -with left_col: - with st.container(border=True): - is_running = panel.get_value("is_running", True) - if is_running: - st.button("Stop", key="stop_button") - else: - st.button("Run", key="run_button") - - st.title("Channel Settings") - physical_channel = st.selectbox( - options=panel.get_value("channel_name", ["Mod2/ai0"]), - index=0, - label="Physical Channels", - disabled=panel.get_value("is_running", False), - ) - panel.set_value("physical_channel", physical_channel) - enum_selectbox( - panel, - label="Terminal Configuration", - value=TerminalConfiguration.DEFAULT, - disabled=panel.get_value("is_running", False), - key="terminal_configuration", - ) - - st.title("Timing Settings") - - st.selectbox( - "Sample Clock Source", - options=panel.get_value("trigger_sources", [""]), - index=0, - disabled=panel.get_value("is_running", False), - ) - st.number_input( - "Sample Rate", - value=1000.0, - min_value=1.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="rate", - ) - st.number_input( - "Number of Samples", - value=100, - min_value=1, - step=1, - disabled=panel.get_value("is_running", False), - key="total_samples", - ) - st.number_input( - "Actual Sample Rate", - value=panel.get_value("actual_sample_rate", 1000.0), - key="actual_sample_rate", - step=1.0, - disabled=True, - ) - - st.title("Logging Settings") - enum_selectbox( - panel, - label="Logging Mode", - value=LoggingMode.OFF, - disabled=panel.get_value("is_running", False), - key="logging_mode", - ) - tdms_file_path = st.text_input( - label="TDMS File Path", - disabled=panel.get_value("is_running", False), - value="data.tdms", - key="tdms_file_path", - ) - st.title("Filtering Settings") - - filter = st.selectbox("Filter", options=["No Filtering", "Filter"]) - panel.set_value("filter", filter) - enum_selectbox( - panel, - label="Filter Response", - value=FilterResponse.COMB, - disabled=panel.get_value("is_running", False), - key="filter_response", - ) - - filter_freq = st.number_input( - "Filtering Frequency", - value=1000.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - filter_order = st.number_input( - "Filter Order", - min_value=0, - max_value=1, - value=1, - disabled=panel.get_value("is_running", False), - ) - st.selectbox( - "Actual Filter Frequency", - options=[panel.get_value("actual_filter_freq")], - disabled=True, - ) - st.selectbox( - "Actual Filter Order", options=[panel.get_value("actual_filter_order")], disabled=True - ) - -with right_col: - st.title("Task Types") - chosen_id = stx.tab_bar( - data=[ - stx.TabBarItemData(id=1, title="Voltage", description=""), - stx.TabBarItemData(id=2, title="Current", description=""), - stx.TabBarItemData(id=3, title="Strain Gage", description=""), - ], - default=1, - ) - - chan_type = chosen_id - panel.set_value("chan_type", chan_type) - - if chosen_id == "1": - with st.container(border=True): - st.title("Voltage Data") - channel_left, channel_right = st.columns(2) - with channel_left: - max_value_voltage = st.number_input( - "Max Value", - value=5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("max_value_voltage", max_value_voltage) - - min_value_voltage = st.number_input( - "Min Value", - value=-5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("min_value_voltage", min_value_voltage) - - if chosen_id == "2": - with st.container(border=True): - st.title("Current Data") - channel_left, channel_right = st.columns(2) - with channel_left: - enum_selectbox( - panel, - label="Shunt Resistor Location", - value=CurrentShuntResistorLocation.EXTERNAL, - disabled=panel.get_value("is_running", False), - key="shunt_location", - ) - enum_selectbox( - panel, - label="Units", - value=CurrentUnits.AMPS, - disabled=panel.get_value("is_running", False), - key="units", - ) - with st.expander("More current info", expanded=False): - min_value_current = st.number_input( - "Min Value", - value=-0.01, - step=0.001, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("min_value_current", min_value_current) - max_value_current = st.number_input( - "Max Value", - value=0.01, - step=1.0, - key="max_value_current", - disabled=panel.get_value("is_running", False), - ) - current = panel.set_value("max_value_current", max_value_current) # type:ignore - shunt_resistor_value = st.number_input( - "Shunt Resistor Value", - value=249.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("shunt_resistor_value", shunt_resistor_value) - if chosen_id == "3": - with st.container(border=True): - st.title("Strain Gage Data") - channel_left, channel_right = st.columns(2) - with channel_left: - min_value_strain = st.number_input( - "Min Value", - value=-0.01, - step=0.01, - ) - panel.set_value("min_value_strain", min_value_strain) - max_value_strain = st.number_input( - "Max Value", value=0.01, step=0.01, max_value=2.0 - ) - panel.set_value("max_value_strain", max_value_strain) - enum_selectbox( - panel, - label="Strain Units", - value=CurrentUnits.AMPS, - disabled=panel.get_value("is_running", False), - key="strain_units", - ) - with st.expander("Strain Gage Information", expanded=False): - st.title("Strain Gage Information") - gage_factor = st.number_input( - "Gage Factor", - value=2.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("gage_factor", gage_factor) - nominal_gage = st.number_input( - "nominal gage resistance", - value=350.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("gage_resistance", nominal_gage) - poisson_ratio = st.number_input( - "poisson ratio", - value=0.3, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("poisson_ratio", poisson_ratio) - with st.expander("Bridge Information", expanded=False): - st.title("Bridge Information") - enum_selectbox( - panel, - label="Strain Configuration", - value=StrainGageBridgeType.FULL_BRIDGE_I, - disabled=panel.get_value("is_running", False), - key="strain_configuration", - ) - wire_resistance = st.number_input( - "lead wire resistance", - value=0.0, - step=1.0, - ) - panel.set_value("wire_resistance", wire_resistance) - initial_voltage = st.number_input( - "initial bridge voltage", - value=0.0, - step=1.0, - disabled=panel.get_value("is_running", False), - ) - panel.set_value("initial_voltage", initial_voltage) - - st.selectbox( - label="voltage excitation source", - key="voltage_excit", - options=["External"], - disabled=True, - ) - panel.set_value("voltage_excitation_source", "voltage_excit") - voltage_excit = st.number_input( - "voltage excitation value", - value=2.5, - step=1.0, - key="voltage_excitation_value", - disabled=panel.get_value("is_running", False), - ) - panel.set_value("voltage_excitation_value", voltage_excit) - - st.title("Trigger Settings") - id = stx.tab_bar( - data=[ - stx.TabBarItemData(id=1, title="No Trigger", description=""), - stx.TabBarItemData(id=2, title="Digital Start", description=""), - stx.TabBarItemData(id=3, title="Digital Pause", description=""), - stx.TabBarItemData(id=4, title="Digital Reference", description=""), - stx.TabBarItemData(id=5, title="Analog Start", description=""), - stx.TabBarItemData(id=6, title="Analog Pause", description=""), - stx.TabBarItemData(id=7, title="Analog Reference", description=""), - ], - default=1, - ) - trigger_type = id - panel.set_value("trigger_type", trigger_type) - - if trigger_type == "1": - with st.container(border=True): - st.write( - "To enable triggers, select a tab above, and configure the settings. \n Not all hardware supports all trigger types. Refer to your device documentation for more information." - ) - if trigger_type == "2": - with st.container(border=True): - source = st.selectbox("Source->", options=panel.get_value("trigger_sources", [""])) - panel.set_value("digital_source", source) - enum_selectbox( - panel, - label="Edge", - value=Edge.FALLING, - disabled=panel.get_value("is_running", False), - key="edge", - ) - if trigger_type == "3": - with st.container(border=True): - st.selectbox("Source-", options=panel.get_value("trigger_sources", [""])) - st.selectbox("PauseWhen", options=["High", "Low"]) - if trigger_type == "4": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported" - ) - if trigger_type == "5": - with st.container(border=True): - analog_source = st.text_input("Source:", "APFI0") - panel.set_value("analog_source", analog_source) - enum_selectbox( - panel, - label="Slope", - value=Slope.FALLING, - disabled=panel.get_value("is_running", False), - key="slope", - ) - - level = st.number_input("Level") - panel.set_value("level", level) - hysteriesis = st.number_input( - "Hysteriesis", disabled=panel.get_value("is_running", False) - ) - panel.set_value("hysteriesis", hysteriesis) - - if trigger_type == "6": - with st.container(border=True): - st.text_input("source:", "APFI0") - st.selectbox("Pause When", options=["Above Level", "Below level"]) - st.number_input("level", value=0.0) - if trigger_type == "7": - with st.container(border=True): - st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." - ) - - with st.container(border=True): - acquired_data = panel.get_value("acquired_data", [0.0]) - sample_rate = panel.get_value("sample_rate", 0.0) - acquired_data_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(acquired_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Volts", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": acquired_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md index 5b74796e..d3823b66 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md @@ -3,7 +3,7 @@ Prerequisites Requires a Physical or Simulated Device. Refer to the [Getting Started Section](https://github.com/ni/nidaqmx-python/blob/master/README.rst) to learn how to create a simulated device. ## Sample -This is an nipanel example that displays an interactive Streamlit app and updates and fetches data from device. +This is a nipanel example that displays an interactive Streamlit app and updates continuous analog output examples. ### Feature diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input/README.md b/examples/nidaqmx/nidaqmx_continuous_analog_input/README.md deleted file mode 100644 index fb9adfa9..00000000 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Prerequisites -=============== -Requires a Physical or Simulated Device : https://github.com/ni/nidaqmx-python/blob/master/README.rst (Getting Started Section) - -## Sample - -This is a nipanel example that displays an interactive Streamlit app and updates continuous analog input examples. - -### Feature - -- Supports various data types - -### Required Software - -- Python 3.9 or later - -### Usage - -```pwsh -poetry install --with examples -poetry run examples/nidaqmx/nidaqmx_continuous_analog_input.py -``` diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py deleted file mode 100644 index ec089ad5..00000000 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input.py +++ /dev/null @@ -1,83 +0,0 @@ -"""Data acquisition script that continuously acquires analog input data.""" - -import time -from pathlib import Path - -import nidaqmx -from nidaqmx.constants import ( - AcquisitionType, - TerminalConfiguration, - CJCSource, - TemperatureUnits, - ThermocoupleType, - LoggingMode, - LoggingOperation, -) - -import nipanel - -panel_script_path = Path(__file__).with_name("nidaqmx_continuous_analog_input_panel.py") -panel = nipanel.create_streamlit_panel(panel_script_path) - -try: - print(f"Panel URL: {panel.panel_url}") - print(f"Waiting for the 'Run' button to be pressed...") - print(f"(Press Ctrl + C to quit)") - while True: - panel.set_value("run_button", False) - while not panel.get_value("run_button", False): - time.sleep(0.1) - - # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ - with nidaqmx.Task() as task: - task.ai_channels.add_ai_voltage_chan( - physical_channel="Dev1/ai0", - min_val=panel.get_value("voltage_min_value", -5.0), - max_val=panel.get_value("voltage_max_value", 5.0), - terminal_config=panel.get_value( - "terminal_configuration", TerminalConfiguration.DEFAULT - ), - ) - task.ai_channels.add_ai_thrmcpl_chan( - "Dev1/ai1", - min_val=panel.get_value("thermocouple_min_value", 0.0), - max_val=panel.get_value("thermocouple_max_value", 100.0), - units=panel.get_value("thermocouple_units", TemperatureUnits.DEG_C), - thermocouple_type=panel.get_value("thermocouple_type", ThermocoupleType.K), - cjc_source=panel.get_value( - "thermocouple_cjc_source", CJCSource.CONSTANT_USER_VALUE - ), - cjc_val=panel.get_value("thermocouple_cjc_val", 25.0), - ) - task.timing.cfg_samp_clk_timing( - rate=panel.get_value("sample_rate_input", 1000.0), - sample_mode=AcquisitionType.CONTINUOUS, - samps_per_chan=panel.get_value("samples_per_channel", 3000), - ) - task.in_stream.configure_logging( - file_path=panel.get_value("tdms_file_path", "data.tdms"), - logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), - operation=LoggingOperation.OPEN_OR_CREATE, - ) - panel.set_value("sample_rate", task.timing.samp_clk_rate) - try: - print(f"Starting data acquisition...") - task.start() - panel.set_value("is_running", True) - - panel.set_value("stop_button", False) - while not panel.get_value("stop_button", False): - data = task.read( - number_of_samples_per_channel=1000 # pyright: ignore[reportArgumentType] - ) - panel.set_value("voltage_data", data[0]) - panel.set_value("thermocouple_data", data[1]) - except KeyboardInterrupt: - raise - finally: - print(f"Stopping data acquisition...") - task.stop() - panel.set_value("is_running", False) - -except KeyboardInterrupt: - pass diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py deleted file mode 100644 index 89a22316..00000000 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input/nidaqmx_continuous_analog_input_panel.py +++ /dev/null @@ -1,237 +0,0 @@ -"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py.""" - -import streamlit as st -from nidaqmx.constants import ( - TerminalConfiguration, - CJCSource, - TemperatureUnits, - ThermocoupleType, - LoggingMode, -) -from streamlit_echarts import st_echarts - -import nipanel -from nipanel.controls import enum_selectbox - - -st.set_page_config(page_title="NI-DAQmx Example", page_icon="📈", layout="wide") -st.title("Analog Input - Voltage and Thermocouple in a Single Task") - -st.markdown( - """ - - """, - unsafe_allow_html=True, -) - -panel = nipanel.get_streamlit_panel_accessor() -is_running = panel.get_value("is_running", False) - -if is_running: - st.button(r"⏹️ Stop", key="stop_button") -else: - st.button(r"▶️ Run", key="run_button") - -thermocouple_data = panel.get_value("thermocouple_data", [0.0]) -voltage_data = panel.get_value("voltage_data", [0.0]) -sample_rate = panel.get_value("sample_rate", 0.0) - -# Create two-column layout for the entire interface -left_column, right_column = st.columns([1, 1]) - -# Left column - Channel tabs and Timing Settings -with left_column: - # Channel Settings tabs - with st.container(border=True): - st.header("Channel Settings") - voltage_tab, thermocouple_tab = st.tabs(["Voltage", "Thermocouple"]) - - voltage_tab.header("Voltage") - with voltage_tab: - channel_left_column, channel_right_column = st.columns(2) - with channel_left_column: - st.selectbox(options=["Dev1/ai0"], label="Physical Channels", disabled=True) - st.number_input( - "Min Value", - value=-5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - key="voltage_min_value", - ) - st.number_input( - "Max Value", - value=5.0, - step=0.1, - disabled=panel.get_value("is_running", False), - key="voltage_max_value", - ) - with channel_right_column: - enum_selectbox( - panel, - label="Terminal Configuration", - value=TerminalConfiguration.DEFAULT, - disabled=panel.get_value("is_running", False), - key="terminal_configuration", - ) - - thermocouple_tab.header("Thermocouple") - with thermocouple_tab: - channel_left_column, channel_middle_column, channel_right_column = st.columns(3) - with channel_left_column: - st.selectbox(options=["Dev1/ai1"], label="Physical Channel", disabled=True) - st.number_input( - "Min Value", - value=0.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="thermocouple_min_value", - ) - st.number_input( - "Max Value", - value=100.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="thermocouple_max_value", - ) - with channel_middle_column: - enum_selectbox( - panel, - label="Units", - value=TemperatureUnits.DEG_C, - disabled=panel.get_value("is_running", False), - key="thermocouple_units", - ) - enum_selectbox( - panel, - label="Thermocouple Type", - value=ThermocoupleType.K, - disabled=panel.get_value("is_running", False), - key="thermocouple_type", - ) - with channel_right_column: - enum_selectbox( - panel, - label="CJC Source", - value=CJCSource.CONSTANT_USER_VALUE, - disabled=panel.get_value("is_running", False), - key="thermocouple_cjc_source", - ) - st.number_input( - "CJC Value", - value=25.0, - step=1.0, - disabled=panel.get_value("is_running", False), - key="thermocouple_cjc_val", - ) - - # Timing Settings section in left column - with st.container(border=True): - st.header("Timing Settings") - timing_left_column, timing_right_column = st.columns(2) - with timing_left_column: - st.selectbox( - options=["OnboardClock"], - label="Sample Clock Source", - disabled=True, - ) - st.number_input( - "Sample Rate", - value=1000.0, - step=100.0, - min_value=1.0, - disabled=panel.get_value("is_running", False), - key="sample_rate_input", - ) - with timing_right_column: - st.number_input( - "Samples per Loop", - value=3000, - step=100, - min_value=10, - disabled=panel.get_value("is_running", False), - key="samples_per_channel", - ) - st.text_input( - label="Actual Sample Rate", - value=str(sample_rate) if sample_rate else "", - key="actual_sample_rate_display", - ) - -# Right column - Graph and Logging Settings -with right_column: - with st.container(border=True): - # Graph section - st.header("Voltage & Thermocouple") - voltage_therm_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)", "Temperature (C)"]}, - "xAxis": { - "type": "category", - "data": [ - x / sample_rate if sample_rate > 0.001 else x for x in range(len(voltage_data)) - ], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Measurement", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": voltage_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - { - "name": "thermocouple_amplitude", - "type": "line", - "data": thermocouple_data, - "color": "red", - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=voltage_therm_graph, height="446px", key="voltage_therm_graph") - - # Logging Settings section in right column - with st.container(border=True): - st.header("Logging Settings") - logging_left_column, logging_right_column = st.columns(2) - with logging_left_column: - enum_selectbox( - panel, - label="Logging Mode", - value=LoggingMode.OFF, - disabled=panel.get_value("is_running", False), - key="logging_mode", - ) - with logging_right_column: - left_sub_column, right_sub_column = st.columns([3, 1]) - with left_sub_column: - tdms_file_path = st.text_input( - label="TDMS File Path", - disabled=panel.get_value("is_running", False), - value="data.tdms", - key="tdms_file_path", - ) From 46cf8aec49d1afb61e9a12592fb595e3bd1a8bea Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:44:24 -0500 Subject: [PATCH 52/68] restructure --- .../nidaqmx_analog_output_voltage.py | 0 .../nidaqmx_analog_output_voltage_panel.py | 0 .../nidaqmx_analog_output_voltage/README.md | 22 -- .../nidaqmx/nidaqmx_continous_analog_input.py | 83 ++++++ .../nidaqmx_continuous_analog_input_panel.py | 237 ++++++++++++++++++ 5 files changed, 320 insertions(+), 22 deletions(-) rename examples/nidaqmx/{nidaqmx_analog_output_voltage => nidaqmx_analog_input_filtering}/nidaqmx_analog_output_voltage.py (100%) rename examples/nidaqmx/{nidaqmx_analog_output_voltage => nidaqmx_analog_input_filtering}/nidaqmx_analog_output_voltage_panel.py (100%) delete mode 100644 examples/nidaqmx/nidaqmx_analog_output_voltage/README.md create mode 100644 examples/nidaqmx/nidaqmx_continous_analog_input.py create mode 100644 examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage.py similarity index 100% rename from examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py rename to examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage.py diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage_panel.py similarity index 100% rename from examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py rename to examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage_panel.py diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md deleted file mode 100644 index d3823b66..00000000 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Prerequisites -=============== -Requires a Physical or Simulated Device. Refer to the [Getting Started Section](https://github.com/ni/nidaqmx-python/blob/master/README.rst) to learn how to create a simulated device. -## Sample - -This is a nipanel example that displays an interactive Streamlit app and updates continuous analog output examples. - -### Feature - -Script demonstrates analog output voltage data getting continuously acquired, and put into different types of waveform graphs. -- Supports various data types - -### Required Software - -- Python 3.9 or later - -### Usage - -```pwsh -poetry install --with examples -poetry run python examples\nidaqmx\nidaqmx_analog_output_voltage\nidaqmx_analog_output_voltage.py -``` \ No newline at end of file diff --git a/examples/nidaqmx/nidaqmx_continous_analog_input.py b/examples/nidaqmx/nidaqmx_continous_analog_input.py new file mode 100644 index 00000000..6ba3d0c7 --- /dev/null +++ b/examples/nidaqmx/nidaqmx_continous_analog_input.py @@ -0,0 +1,83 @@ +"""Data acquisition script that continuously acquires analog input data.""" + +import time +from pathlib import Path + +import nidaqmx +from nidaqmx.constants import ( + AcquisitionType, + TerminalConfiguration, + CJCSource, + TemperatureUnits, + ThermocoupleType, + LoggingMode, + LoggingOperation, +) + +import nipanel + +panel_script_path = Path(__file__).with_name("nidaqmx_continuous_analog_input_panel.py") +panel = nipanel.create_streamlit_panel(panel_script_path) + +try: + print(f"Panel URL: {panel.panel_url}") + print(f"Waiting for the 'Run' button to be pressed...") + print(f"(Press Ctrl + C to quit)") + while True: + panel.set_value("run_button", False) + while not panel.get_value("run_button", False): + time.sleep(0.1) + + # How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/ + with nidaqmx.Task() as task: + task.ai_channels.add_ai_voltage_chan( + physical_channel="Dev1/ai0", + min_val=panel.get_value("voltage_min_value", -5.0), + max_val=panel.get_value("voltage_max_value", 5.0), + terminal_config=panel.get_value( + "terminal_configuration", TerminalConfiguration.DEFAULT + ), + ) + task.ai_channels.add_ai_thrmcpl_chan( + "Dev1/ai1", + min_val=panel.get_value("thermocouple_min_value", 0.0), + max_val=panel.get_value("thermocouple_max_value", 100.0), + units=panel.get_value("thermocouple_units", TemperatureUnits.DEG_C), + thermocouple_type=panel.get_value("thermocouple_type", ThermocoupleType.K), + cjc_source=panel.get_value( + "thermocouple_cjc_source", CJCSource.CONSTANT_USER_VALUE + ), + cjc_val=panel.get_value("thermocouple_cjc_val", 25.0), + ) + task.timing.cfg_samp_clk_timing( + rate=panel.get_value("sample_rate_input", 1000.0), + sample_mode=AcquisitionType.CONTINUOUS, + samps_per_chan=panel.get_value("samples_per_channel", 3000), + ) + task.in_stream.configure_logging( + file_path=panel.get_value("tdms_file_path", "data.tdms"), + logging_mode=panel.get_value("logging_mode", LoggingMode.OFF), + operation=LoggingOperation.OPEN_OR_CREATE, + ) + panel.set_value("sample_rate", task._timing.samp_clk_rate) + try: + print(f"Starting data acquisition...") + task.start() + panel.set_value("is_running", True) + + panel.set_value("stop_button", False) + while not panel.get_value("stop_button", False): + data = task.read( + number_of_samples_per_channel=1000 # pyright: ignore[reportArgumentType] + ) + panel.set_value("voltage_data", data[0]) + panel.set_value("thermocouple_data", data[1]) + except KeyboardInterrupt: + raise + finally: + print(f"Stopping data acquisition...") + task.stop() + panel.set_value("is_running", False) + +except KeyboardInterrupt: + pass \ No newline at end of file diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py new file mode 100644 index 00000000..6ee068f4 --- /dev/null +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py @@ -0,0 +1,237 @@ +"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py.""" + +import streamlit as st +from nidaqmx.constants import ( + TerminalConfiguration, + CJCSource, + TemperatureUnits, + ThermocoupleType, + LoggingMode, +) +from streamlit_echarts import st_echarts + +import nipanel +from nipanel.controls import enum_selectbox + + +st.set_page_config(page_title="NI-DAQmx Example", page_icon="📈", layout="wide") +st.title("Analog Input - Voltage and Thermocouple in a Single Task") + +st.markdown( + """ + + """, + unsafe_allow_html=True, +) + +panel = nipanel.get_streamlit_panel_accessor() +is_running = panel.get_value("is_running", False) + +if is_running: + st.button(r"⏹️ Stop", key="stop_button") +else: + st.button(r"▶️ Run", key="run_button") + +thermocouple_data = panel.get_value("thermocouple_data", [0.0]) +voltage_data = panel.get_value("voltage_data", [0.0]) +sample_rate = panel.get_value("sample_rate", 0.0) + +# Create two-column layout for the entire interface +left_column, right_column = st.columns([1, 1]) + +# Left column - Channel tabs and Timing Settings +with left_column: + # Channel Settings tabs + with st.container(border=True): + st.header("Channel Settings") + voltage_tab, thermocouple_tab = st.tabs(["Voltage", "Thermocouple"]) + + voltage_tab.header("Voltage") + with voltage_tab: + channel_left_column, channel_right_column = st.columns(2) + with channel_left_column: + st.selectbox(options=["Dev1/ai0"], label="Physical Channels", disabled=True) + st.number_input( + "Min Value", + value=-5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + key="voltage_min_value", + ) + st.number_input( + "Max Value", + value=5.0, + step=0.1, + disabled=panel.get_value("is_running", False), + key="voltage_max_value", + ) + with channel_right_column: + enum_selectbox( + panel, + label="Terminal Configuration", + value=TerminalConfiguration.DEFAULT, + disabled=panel.get_value("is_running", False), + key="terminal_configuration", + ) + + thermocouple_tab.header("Thermocouple") + with thermocouple_tab: + channel_left_column, channel_middle_column, channel_right_column = st.columns(3) + with channel_left_column: + st.selectbox(options=["Dev1/ai1"], label="Physical Channel", disabled=True) + st.number_input( + "Min Value", + value=0.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="thermocouple_min_value", + ) + st.number_input( + "Max Value", + value=100.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="thermocouple_max_value", + ) + with channel_middle_column: + enum_selectbox( + panel, + label="Units", + value=TemperatureUnits.DEG_C, + disabled=panel.get_value("is_running", False), + key="thermocouple_units", + ) + enum_selectbox( + panel, + label="Thermocouple Type", + value=ThermocoupleType.K, + disabled=panel.get_value("is_running", False), + key="thermocouple_type", + ) + with channel_right_column: + enum_selectbox( + panel, + label="CJC Source", + value=CJCSource.CONSTANT_USER_VALUE, + disabled=panel.get_value("is_running", False), + key="thermocouple_cjc_source", + ) + st.number_input( + "CJC Value", + value=25.0, + step=1.0, + disabled=panel.get_value("is_running", False), + key="thermocouple_cjc_val", + ) + + # Timing Settings section in left column + with st.container(border=True): + st.header("Timing Settings") + timing_left_column, timing_right_column = st.columns(2) + with timing_left_column: + st.selectbox( + options=["OnboardClock"], + label="Sample Clock Source", + disabled=True, + ) + st.number_input( + "Sample Rate", + value=1000.0, + step=100.0, + min_value=1.0, + disabled=panel.get_value("is_running", False), + key="sample_rate_input", + ) + with timing_right_column: + st.number_input( + "Samples per Loop", + value=3000, + step=100, + min_value=10, + disabled=panel.get_value("is_running", False), + key="samples_per_channel", + ) + st.text_input( + label="Actual Sample Rate", + value=str(sample_rate) if sample_rate else "", + key="actual_sample_rate_display", + ) + +# Right column - Graph and Logging Settings +with right_column: + with st.container(border=True): + # Graph section + st.header("Voltage & Thermocouple") + voltage_therm_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)", "Temperature (C)"]}, + "xAxis": { + "type": "category", + "data": [ + x / sample_rate if sample_rate > 0.001 else x for x in range(len(voltage_data)) + ], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Measurement", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": voltage_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + { + "name": "thermocouple_amplitude", + "type": "line", + "data": thermocouple_data, + "color": "red", + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], + } + st_echarts(options=voltage_therm_graph, height="446px", key="voltage_therm_graph") + + # Logging Settings section in right column + with st.container(border=True): + st.header("Logging Settings") + logging_left_column, logging_right_column = st.columns(2) + with logging_left_column: + enum_selectbox( + panel, + label="Logging Mode", + value=LoggingMode.OFF, + disabled=panel.get_value("is_running", False), + key="logging_mode", + ) + with logging_right_column: + left_sub_column, right_sub_column = st.columns([3, 1]) + with left_sub_column: + tdms_file_path = st.text_input( + label="TDMS File Path", + disabled=panel.get_value("is_running", False), + value="data.tdms", + key="tdms_file_path", + ) \ No newline at end of file From b4302cd9027dcabc6b4aa944273a611768a72f84 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:45:21 -0500 Subject: [PATCH 53/68] space --- examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py index 6ee068f4..8276d761 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py @@ -234,4 +234,5 @@ disabled=panel.get_value("is_running", False), value="data.tdms", key="tdms_file_path", - ) \ No newline at end of file + ) + \ No newline at end of file From 667bce1b1314389b0fb4f8805c1f9bf80400bea3 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:47:00 -0500 Subject: [PATCH 54/68] rename --- ...ntinous_analog_input.py => nidaqmx_continuous_analog_input.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/nidaqmx/{nidaqmx_continous_analog_input.py => nidaqmx_continuous_analog_input.py} (100%) diff --git a/examples/nidaqmx/nidaqmx_continous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input.py similarity index 100% rename from examples/nidaqmx/nidaqmx_continous_analog_input.py rename to examples/nidaqmx/nidaqmx_continuous_analog_input.py From 2a00e842937689ef45a3653b3c23e93e10aaaeb7 Mon Sep 17 00:00:00 2001 From: DilmiWickramanayake <155610400+DilmiWickramanayake@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:48:25 -0500 Subject: [PATCH 55/68] Update nidaqmx_continuous_analog_input_panel.py --- examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py index 8276d761..89a22316 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input_panel.py @@ -235,4 +235,3 @@ value="data.tdms", key="tdms_file_path", ) - \ No newline at end of file From 01c58a7f1e2c5d6fb76940659e304b6b0b7531d5 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:49:57 -0500 Subject: [PATCH 56/68] readme --- examples/nidaqmx/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/nidaqmx/README.md diff --git a/examples/nidaqmx/README.md b/examples/nidaqmx/README.md new file mode 100644 index 00000000..db216297 --- /dev/null +++ b/examples/nidaqmx/README.md @@ -0,0 +1,22 @@ +Prerequisites +=============== +Requires a Physical or Simulated Device : https://github.com/ni/nidaqmx-python/blob/master/README.rst (Getting Started Section) + +## Sample + +This is a nipanel example that displays an interactive Streamlit app and updates continuous analog input examples. + +### Feature + +- Supports various data types + +### Required Software + +- Python 3.9 or later + +### Usage + +```pwsh +poetry install --with examples +poetry run examples/nidaqmx/nidaqmx_continuous_analog_input.py +``` \ No newline at end of file From 2def6b29977f62199a692c34fd61ecb6294a0116 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:52:49 -0500 Subject: [PATCH 57/68] poetry lock changes --- poetry.lock | 16 +--------------- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/poetry.lock b/poetry.lock index 74a657d8..71434090 100644 --- a/poetry.lock +++ b/poetry.lock @@ -502,20 +502,6 @@ typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "extra-streamlit-components" -version = "0.1.80" -description = "An all-in-one place, to find complex or just natively unavailable components on streamlit." -optional = false -python-versions = ">=3.6" -files = [ - {file = "extra_streamlit_components-0.1.80-py3-none-any.whl", hash = "sha256:7a8c151da5dcd1f1f97b6c29caa812a1d77928d20fc4bf42a3a4fd788274dd9e"}, - {file = "extra_streamlit_components-0.1.80.tar.gz", hash = "sha256:87d6c38e07381501d8882796adef17d1c1d4e3a79615864d95c1163d2bc136f6"}, -] - -[package.dependencies] -streamlit = ">=1.40.1" - [[package]] name = "flake8" version = "5.0.4" @@ -3277,4 +3263,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "1b4c4105e78ce7eca099f1a45a130c93565d568f2263e70d6389ab59ed3bbe27" +content-hash = "45dc36d0ef51734fbde48be7f49ed705209f3b0d46c827cd0de4115fbf15ce62" diff --git a/pyproject.toml b/pyproject.toml index 41393ee2..199b079b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,6 @@ optional = true [tool.poetry.group.examples.dependencies] streamlit-echarts = ">=0.4.0" -extra-streamlit-components = "^0.1.80" nidaqmx = { version = ">=0.8.0", allow-prereleases = true } niscope = "^1.4.9" From 38b3cc8a42b26f2aee7ad5c0fb0a2f9bdf7305f1 Mon Sep 17 00:00:00 2001 From: DilmiWickramanayake <155610400+DilmiWickramanayake@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:54:01 -0500 Subject: [PATCH 58/68] Update nidaqmx_continuous_analog_input.py --- examples/nidaqmx/nidaqmx_continuous_analog_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nidaqmx/nidaqmx_continuous_analog_input.py b/examples/nidaqmx/nidaqmx_continuous_analog_input.py index 6ba3d0c7..f8210a8a 100644 --- a/examples/nidaqmx/nidaqmx_continuous_analog_input.py +++ b/examples/nidaqmx/nidaqmx_continuous_analog_input.py @@ -80,4 +80,4 @@ panel.set_value("is_running", False) except KeyboardInterrupt: - pass \ No newline at end of file + pass From 8c0bc34ec4a21b73e19447b5a8567337b29f9d49 Mon Sep 17 00:00:00 2001 From: DilmiWickramanayake <155610400+DilmiWickramanayake@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:54:22 -0500 Subject: [PATCH 59/68] Update README.md --- examples/nidaqmx/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nidaqmx/README.md b/examples/nidaqmx/README.md index db216297..fb9adfa9 100644 --- a/examples/nidaqmx/README.md +++ b/examples/nidaqmx/README.md @@ -19,4 +19,4 @@ This is a nipanel example that displays an interactive Streamlit app and updates ```pwsh poetry install --with examples poetry run examples/nidaqmx/nidaqmx_continuous_analog_input.py -``` \ No newline at end of file +``` From 27fb20bc8936fea8276c2586297b32d2aa45187f Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 09:55:44 -0500 Subject: [PATCH 60/68] add readme --- .../nidaqmx_analog_input_filtering/README.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/nidaqmx/nidaqmx_analog_input_filtering/README.md diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md new file mode 100644 index 00000000..f24d917e --- /dev/null +++ b/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md @@ -0,0 +1,22 @@ +Prerequisites +=============== +Requires a Physical or Simulated Device : https://github.com/ni/nidaqmx-python/blob/master/README.rst (Getting Started Section) + +## Sample + +This is a nipanel example that displays an interactive Streamlit app and updates continuous analog output examples. + +### Feature + +- Supports various data types + +### Required Software + +- Python 3.9 or later + +### Usage + +```pwsh +poetry install --with examples +poetry run examples\nidaqmx_analog_output_voltage\nidaqmx_analog_output_voltage.py +``` \ No newline at end of file From 14db8ff4ca9179e172385beb2a4ecf1347daa204 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 10:00:50 -0500 Subject: [PATCH 61/68] rename --- .../README.md | 0 .../nidaqmx_analog_output_voltage.py | 0 .../nidaqmx_analog_output_voltage_panel.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/nidaqmx/{nidaqmx_analog_input_filtering => nidaqmx_analog_output_voltage}/README.md (100%) rename examples/nidaqmx/{nidaqmx_analog_input_filtering => nidaqmx_analog_output_voltage}/nidaqmx_analog_output_voltage.py (100%) rename examples/nidaqmx/{nidaqmx_analog_input_filtering => nidaqmx_analog_output_voltage}/nidaqmx_analog_output_voltage_panel.py (100%) diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md similarity index 100% rename from examples/nidaqmx/nidaqmx_analog_input_filtering/README.md rename to examples/nidaqmx/nidaqmx_analog_output_voltage/README.md diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py similarity index 100% rename from examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage.py rename to examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py diff --git a/examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py similarity index 100% rename from examples/nidaqmx/nidaqmx_analog_input_filtering/nidaqmx_analog_output_voltage_panel.py rename to examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py From 16cdcc55dbff5eb8b102072f48637adc1d04f5af Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 10:28:03 -0500 Subject: [PATCH 62/68] run button change --- .../nidaqmx_analog_output_voltage_panel.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 1558fbec..a515dd5b 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -54,15 +54,13 @@ def hide_run_button() -> None: with st.container(border=True): is_running = panel.get_value("is_running", True) if is_running: - st.button("Stop", key="stop_button") + st.button(r"⏹️ Stop", key="stop_button") + elif not is_running and panel.get_value("daq_error", "") == "": + run_button = st.button(r"▶️ Run", key="run_button") else: - st.button("Run", key="run_button") - - if panel.get_value("daq_error", "") == "": - pass - else: - hide_run_button() - st.error(panel.get_value("daq_error", "") + " Please re-run script") + st.error( + f"There was an error running the script. Fix the issue and re-run nidaqmx_continuous_analog_input.py \n\n {panel.get_value('daq_error', '')}" + ) st.title("Channel Settings") physical_channel = st.selectbox( From 58de63a64e2cc9af55315957bcb612407f556720 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 11:03:30 -0500 Subject: [PATCH 63/68] remove function --- .../nidaqmx_analog_output_voltage_panel.py | 82 ++++++++----------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index a515dd5b..5d8cab5f 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -36,19 +36,6 @@ ) -def hide_run_button() -> None: - """hide_run_button is used to disable run button when DAQ error pops up.""" - st.markdown( - """ - - """, - unsafe_allow_html=True, - ) - with left_col: with st.container(border=True): @@ -141,6 +128,41 @@ def hide_run_button() -> None: ) with right_col: + with st.container(border=True): + st.title("Output") + acquired_data = panel.get_value("data", [0.0]) + sample_rate = panel.get_value("sample_rate", 1000.0) + acquired_data_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)"]}, + "xAxis": { + "type": "category", + "data": [x / sample_rate for x in range(len(acquired_data))], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Amplitude", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": acquired_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", + }, + ], + } + st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + with st.container(border=True): st.title("Trigger Settings") trigger_type = stx.tab_bar( @@ -176,36 +198,4 @@ def hide_run_button() -> None: "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." ) - with st.container(border=True): - acquired_data = panel.get_value("data", [0.0]) - sample_rate = panel.get_value("sample_rate", 1000.0) - acquired_data_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(acquired_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Amplitude", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, - }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": acquired_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + \ No newline at end of file From 2f9aa38232cb6bfaafe53a7bca5f1b89e4447619 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Mon, 28 Jul 2025 11:08:03 -0500 Subject: [PATCH 64/68] lint errors --- .../nidaqmx_analog_output_voltage_panel.py | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 5d8cab5f..2a9ccc51 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -36,14 +36,13 @@ ) - with left_col: with st.container(border=True): is_running = panel.get_value("is_running", True) if is_running: - st.button(r"⏹️ Stop", key="stop_button") + st.button("Stop", key="stop_button") elif not is_running and panel.get_value("daq_error", "") == "": - run_button = st.button(r"▶️ Run", key="run_button") + run_button = st.button("Run", key="run_button") else: st.error( f"There was an error running the script. Fix the issue and re-run nidaqmx_continuous_analog_input.py \n\n {panel.get_value('daq_error', '')}" @@ -129,39 +128,39 @@ with right_col: with st.container(border=True): - st.title("Output") - acquired_data = panel.get_value("data", [0.0]) - sample_rate = panel.get_value("sample_rate", 1000.0) - acquired_data_graph = { - "animation": False, - "tooltip": {"trigger": "axis"}, - "legend": {"data": ["Voltage (V)"]}, - "xAxis": { - "type": "category", - "data": [x / sample_rate for x in range(len(acquired_data))], - "name": "Time", - "nameLocation": "center", - "nameGap": 40, - }, - "yAxis": { - "type": "value", - "name": "Amplitude", - "nameRotate": 90, - "nameLocation": "center", - "nameGap": 40, + st.title("Output") + acquired_data = panel.get_value("data", [0.0]) + sample_rate = panel.get_value("sample_rate", 1000.0) + acquired_data_graph = { + "animation": False, + "tooltip": {"trigger": "axis"}, + "legend": {"data": ["Voltage (V)"]}, + "xAxis": { + "type": "category", + "data": [x / sample_rate for x in range(len(acquired_data))], + "name": "Time", + "nameLocation": "center", + "nameGap": 40, + }, + "yAxis": { + "type": "value", + "name": "Amplitude", + "nameRotate": 90, + "nameLocation": "center", + "nameGap": 40, + }, + "series": [ + { + "name": "voltage_amplitude", + "type": "line", + "data": acquired_data, + "emphasis": {"focus": "series"}, + "smooth": True, + "seriesLayoutBy": "row", }, - "series": [ - { - "name": "voltage_amplitude", - "type": "line", - "data": acquired_data, - "emphasis": {"focus": "series"}, - "smooth": True, - "seriesLayoutBy": "row", - }, - ], - } - st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") + ], + } + st_echarts(options=acquired_data_graph, height="400px", key="graph", width="100%") with st.container(border=True): st.title("Trigger Settings") @@ -197,5 +196,3 @@ st.write( "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." ) - - \ No newline at end of file From 355d3bb39d52033aac01c1cf578d79e99da5ed63 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Tue, 29 Jul 2025 06:42:49 -0500 Subject: [PATCH 65/68] resolve changes --- .../nidaqmx_analog_output_voltage.py | 4 ++-- .../nidaqmx_analog_output_voltage_panel.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 9420b449..a5c51b16 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -1,4 +1,4 @@ -"""Data acquisition script that continuously acquires analog output data.""" +"""Data acquisition script that continuously generates analog output data.""" import time from pathlib import Path @@ -60,7 +60,7 @@ # Refer to your device documentation for more information. trigger_type = panel.get_value("trigger_type") - if trigger_type == "2": + if trigger_type == 2: task.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source=panel.get_value("digital_source", ""), trigger_edge=panel.get_value("edge", Edge.FALLING), diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 2a9ccc51..677e0bdd 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -45,7 +45,7 @@ run_button = st.button("Run", key="run_button") else: st.error( - f"There was an error running the script. Fix the issue and re-run nidaqmx_continuous_analog_input.py \n\n {panel.get_value('daq_error', '')}" + f"There was an error running the script. Fix the issue and re-run nidaqmx_analog_output_voltage.py \n\n {panel.get_value('daq_error', '')}" ) st.title("Channel Settings") @@ -119,12 +119,13 @@ step=1.0, disabled=panel.get_value("is_running", False), ) - st.selectbox( + wave_type = st.selectbox( label="Wave Type", options=["Sine Wave", "Triangle Wave", "Square Wave"], key="wave_type", disabled=panel.get_value("is_running", False), ) + panel.set_value("wave_type", wave_type) with right_col: with st.container(border=True): @@ -176,9 +177,10 @@ ], default=1, ) + trigger_type = int(trigger_type) # pyright: ignore[reportArgumentType] panel.set_value("trigger_type", trigger_type) - if trigger_type == "2": + if trigger_type == 2: with st.container(border=True): source = st.selectbox( "Source:", options=panel.get_value("available_trigger_sources", [""]) From 9c82e5b150793656f0cfcbc1ff83f9c45d1155fa Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Wed, 30 Jul 2025 14:29:31 -0500 Subject: [PATCH 66/68] change triggers --- .../nidaqmx_analog_output_voltage_panel.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 677e0bdd..8e56e451 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -193,8 +193,13 @@ disabled=panel.get_value("is_running", False), key="edge", ) - else: + elif trigger_type == 1: with st.container(border=True): st.write( - "This trigger type is not supported in continuous sample timing. Refer to your device documentation for more information on which triggers are supported." + "To enable triggers, select a tab above, and configure the settings. Not all hardware supports all trigger types. Refer to your device documentation for more information." ) + + else: + st.write( + "This trigger type is not supported in output tasks. Refer to your device documentation for more information on which triggers are supported." + ) From eba2ce88d6a68eb96f1979cdfeea32908e0b5453 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Thu, 31 Jul 2025 07:39:22 -0500 Subject: [PATCH 67/68] changes README.md --- examples/nidaqmx/nidaqmx_analog_output_voltage/README.md | 2 +- .../nidaqmx_analog_output_voltage.py | 2 ++ .../nidaqmx_analog_output_voltage_panel.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md index f24d917e..a25d7ac6 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/README.md @@ -18,5 +18,5 @@ This is a nipanel example that displays an interactive Streamlit app and updates ```pwsh poetry install --with examples -poetry run examples\nidaqmx_analog_output_voltage\nidaqmx_analog_output_voltage.py +poetry run examples\nidaqmx\nidaqmx_analog_output_voltage\nidaqmx_analog_output_voltage.py ``` \ No newline at end of file diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index a5c51b16..398ff536 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -65,6 +65,8 @@ trigger_source=panel.get_value("digital_source", ""), trigger_edge=panel.get_value("edge", Edge.FALLING), ) + else: + pass panel.set_value("sample_rate", task.timing.samp_clk_rate) t = np.arange(num_samples) / sample_rate diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py index 8e56e451..cee0292f 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage_panel.py @@ -38,7 +38,7 @@ with left_col: with st.container(border=True): - is_running = panel.get_value("is_running", True) + is_running = panel.get_value("is_running", False) if is_running: st.button("Stop", key="stop_button") elif not is_running and panel.get_value("daq_error", "") == "": From cc650b561c5804c1cc273a86445ebd31d939d5a3 Mon Sep 17 00:00:00 2001 From: Dilmi Wickramanayake Date: Fri, 1 Aug 2025 07:56:12 -0500 Subject: [PATCH 68/68] set run button to false --- .../nidaqmx_analog_output_voltage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py index 398ff536..e46dfb12 100644 --- a/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py +++ b/examples/nidaqmx/nidaqmx_analog_output_voltage/nidaqmx_analog_output_voltage.py @@ -29,6 +29,7 @@ for term in dev.terminals: available_trigger_sources.append(term) panel.set_value("available_trigger_sources", available_trigger_sources) +panel.set_value("run_button", False) try: panel.set_value("daq_error", "") print(f"Panel URL: {panel.panel_url}")