Skip to content

Commit 46cf8ae

Browse files
author
Dilmi Wickramanayake
committed
restructure
1 parent 8a31082 commit 46cf8ae

File tree

5 files changed

+320
-22
lines changed

5 files changed

+320
-22
lines changed

examples/nidaqmx/nidaqmx_analog_output_voltage/README.md

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Data acquisition script that continuously acquires analog input data."""
2+
3+
import time
4+
from pathlib import Path
5+
6+
import nidaqmx
7+
from nidaqmx.constants import (
8+
AcquisitionType,
9+
TerminalConfiguration,
10+
CJCSource,
11+
TemperatureUnits,
12+
ThermocoupleType,
13+
LoggingMode,
14+
LoggingOperation,
15+
)
16+
17+
import nipanel
18+
19+
panel_script_path = Path(__file__).with_name("nidaqmx_continuous_analog_input_panel.py")
20+
panel = nipanel.create_streamlit_panel(panel_script_path)
21+
22+
try:
23+
print(f"Panel URL: {panel.panel_url}")
24+
print(f"Waiting for the 'Run' button to be pressed...")
25+
print(f"(Press Ctrl + C to quit)")
26+
while True:
27+
panel.set_value("run_button", False)
28+
while not panel.get_value("run_button", False):
29+
time.sleep(0.1)
30+
31+
# How to use nidaqmx: https://nidaqmx-python.readthedocs.io/en/stable/
32+
with nidaqmx.Task() as task:
33+
task.ai_channels.add_ai_voltage_chan(
34+
physical_channel="Dev1/ai0",
35+
min_val=panel.get_value("voltage_min_value", -5.0),
36+
max_val=panel.get_value("voltage_max_value", 5.0),
37+
terminal_config=panel.get_value(
38+
"terminal_configuration", TerminalConfiguration.DEFAULT
39+
),
40+
)
41+
task.ai_channels.add_ai_thrmcpl_chan(
42+
"Dev1/ai1",
43+
min_val=panel.get_value("thermocouple_min_value", 0.0),
44+
max_val=panel.get_value("thermocouple_max_value", 100.0),
45+
units=panel.get_value("thermocouple_units", TemperatureUnits.DEG_C),
46+
thermocouple_type=panel.get_value("thermocouple_type", ThermocoupleType.K),
47+
cjc_source=panel.get_value(
48+
"thermocouple_cjc_source", CJCSource.CONSTANT_USER_VALUE
49+
),
50+
cjc_val=panel.get_value("thermocouple_cjc_val", 25.0),
51+
)
52+
task.timing.cfg_samp_clk_timing(
53+
rate=panel.get_value("sample_rate_input", 1000.0),
54+
sample_mode=AcquisitionType.CONTINUOUS,
55+
samps_per_chan=panel.get_value("samples_per_channel", 3000),
56+
)
57+
task.in_stream.configure_logging(
58+
file_path=panel.get_value("tdms_file_path", "data.tdms"),
59+
logging_mode=panel.get_value("logging_mode", LoggingMode.OFF),
60+
operation=LoggingOperation.OPEN_OR_CREATE,
61+
)
62+
panel.set_value("sample_rate", task._timing.samp_clk_rate)
63+
try:
64+
print(f"Starting data acquisition...")
65+
task.start()
66+
panel.set_value("is_running", True)
67+
68+
panel.set_value("stop_button", False)
69+
while not panel.get_value("stop_button", False):
70+
data = task.read(
71+
number_of_samples_per_channel=1000 # pyright: ignore[reportArgumentType]
72+
)
73+
panel.set_value("voltage_data", data[0])
74+
panel.set_value("thermocouple_data", data[1])
75+
except KeyboardInterrupt:
76+
raise
77+
finally:
78+
print(f"Stopping data acquisition...")
79+
task.stop()
80+
panel.set_value("is_running", False)
81+
82+
except KeyboardInterrupt:
83+
pass
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py."""
2+
3+
import streamlit as st
4+
from nidaqmx.constants import (
5+
TerminalConfiguration,
6+
CJCSource,
7+
TemperatureUnits,
8+
ThermocoupleType,
9+
LoggingMode,
10+
)
11+
from streamlit_echarts import st_echarts
12+
13+
import nipanel
14+
from nipanel.controls import enum_selectbox
15+
16+
17+
st.set_page_config(page_title="NI-DAQmx Example", page_icon="📈", layout="wide")
18+
st.title("Analog Input - Voltage and Thermocouple in a Single Task")
19+
20+
st.markdown(
21+
"""
22+
<style>
23+
div[data-baseweb="select"] {
24+
max-width: 250px !important;
25+
}
26+
div.stNumberInput {
27+
max-width: 250px !important;
28+
}
29+
div.stTextInput {
30+
max-width: 250px !important;
31+
}
32+
</style>
33+
""",
34+
unsafe_allow_html=True,
35+
)
36+
37+
panel = nipanel.get_streamlit_panel_accessor()
38+
is_running = panel.get_value("is_running", False)
39+
40+
if is_running:
41+
st.button(r"⏹️ Stop", key="stop_button")
42+
else:
43+
st.button(r"▶️ Run", key="run_button")
44+
45+
thermocouple_data = panel.get_value("thermocouple_data", [0.0])
46+
voltage_data = panel.get_value("voltage_data", [0.0])
47+
sample_rate = panel.get_value("sample_rate", 0.0)
48+
49+
# Create two-column layout for the entire interface
50+
left_column, right_column = st.columns([1, 1])
51+
52+
# Left column - Channel tabs and Timing Settings
53+
with left_column:
54+
# Channel Settings tabs
55+
with st.container(border=True):
56+
st.header("Channel Settings")
57+
voltage_tab, thermocouple_tab = st.tabs(["Voltage", "Thermocouple"])
58+
59+
voltage_tab.header("Voltage")
60+
with voltage_tab:
61+
channel_left_column, channel_right_column = st.columns(2)
62+
with channel_left_column:
63+
st.selectbox(options=["Dev1/ai0"], label="Physical Channels", disabled=True)
64+
st.number_input(
65+
"Min Value",
66+
value=-5.0,
67+
step=0.1,
68+
disabled=panel.get_value("is_running", False),
69+
key="voltage_min_value",
70+
)
71+
st.number_input(
72+
"Max Value",
73+
value=5.0,
74+
step=0.1,
75+
disabled=panel.get_value("is_running", False),
76+
key="voltage_max_value",
77+
)
78+
with channel_right_column:
79+
enum_selectbox(
80+
panel,
81+
label="Terminal Configuration",
82+
value=TerminalConfiguration.DEFAULT,
83+
disabled=panel.get_value("is_running", False),
84+
key="terminal_configuration",
85+
)
86+
87+
thermocouple_tab.header("Thermocouple")
88+
with thermocouple_tab:
89+
channel_left_column, channel_middle_column, channel_right_column = st.columns(3)
90+
with channel_left_column:
91+
st.selectbox(options=["Dev1/ai1"], label="Physical Channel", disabled=True)
92+
st.number_input(
93+
"Min Value",
94+
value=0.0,
95+
step=1.0,
96+
disabled=panel.get_value("is_running", False),
97+
key="thermocouple_min_value",
98+
)
99+
st.number_input(
100+
"Max Value",
101+
value=100.0,
102+
step=1.0,
103+
disabled=panel.get_value("is_running", False),
104+
key="thermocouple_max_value",
105+
)
106+
with channel_middle_column:
107+
enum_selectbox(
108+
panel,
109+
label="Units",
110+
value=TemperatureUnits.DEG_C,
111+
disabled=panel.get_value("is_running", False),
112+
key="thermocouple_units",
113+
)
114+
enum_selectbox(
115+
panel,
116+
label="Thermocouple Type",
117+
value=ThermocoupleType.K,
118+
disabled=panel.get_value("is_running", False),
119+
key="thermocouple_type",
120+
)
121+
with channel_right_column:
122+
enum_selectbox(
123+
panel,
124+
label="CJC Source",
125+
value=CJCSource.CONSTANT_USER_VALUE,
126+
disabled=panel.get_value("is_running", False),
127+
key="thermocouple_cjc_source",
128+
)
129+
st.number_input(
130+
"CJC Value",
131+
value=25.0,
132+
step=1.0,
133+
disabled=panel.get_value("is_running", False),
134+
key="thermocouple_cjc_val",
135+
)
136+
137+
# Timing Settings section in left column
138+
with st.container(border=True):
139+
st.header("Timing Settings")
140+
timing_left_column, timing_right_column = st.columns(2)
141+
with timing_left_column:
142+
st.selectbox(
143+
options=["OnboardClock"],
144+
label="Sample Clock Source",
145+
disabled=True,
146+
)
147+
st.number_input(
148+
"Sample Rate",
149+
value=1000.0,
150+
step=100.0,
151+
min_value=1.0,
152+
disabled=panel.get_value("is_running", False),
153+
key="sample_rate_input",
154+
)
155+
with timing_right_column:
156+
st.number_input(
157+
"Samples per Loop",
158+
value=3000,
159+
step=100,
160+
min_value=10,
161+
disabled=panel.get_value("is_running", False),
162+
key="samples_per_channel",
163+
)
164+
st.text_input(
165+
label="Actual Sample Rate",
166+
value=str(sample_rate) if sample_rate else "",
167+
key="actual_sample_rate_display",
168+
)
169+
170+
# Right column - Graph and Logging Settings
171+
with right_column:
172+
with st.container(border=True):
173+
# Graph section
174+
st.header("Voltage & Thermocouple")
175+
voltage_therm_graph = {
176+
"animation": False,
177+
"tooltip": {"trigger": "axis"},
178+
"legend": {"data": ["Voltage (V)", "Temperature (C)"]},
179+
"xAxis": {
180+
"type": "category",
181+
"data": [
182+
x / sample_rate if sample_rate > 0.001 else x for x in range(len(voltage_data))
183+
],
184+
"name": "Time",
185+
"nameLocation": "center",
186+
"nameGap": 40,
187+
},
188+
"yAxis": {
189+
"type": "value",
190+
"name": "Measurement",
191+
"nameRotate": 90,
192+
"nameLocation": "center",
193+
"nameGap": 40,
194+
},
195+
"series": [
196+
{
197+
"name": "voltage_amplitude",
198+
"type": "line",
199+
"data": voltage_data,
200+
"emphasis": {"focus": "series"},
201+
"smooth": True,
202+
"seriesLayoutBy": "row",
203+
},
204+
{
205+
"name": "thermocouple_amplitude",
206+
"type": "line",
207+
"data": thermocouple_data,
208+
"color": "red",
209+
"emphasis": {"focus": "series"},
210+
"smooth": True,
211+
"seriesLayoutBy": "row",
212+
},
213+
],
214+
}
215+
st_echarts(options=voltage_therm_graph, height="446px", key="voltage_therm_graph")
216+
217+
# Logging Settings section in right column
218+
with st.container(border=True):
219+
st.header("Logging Settings")
220+
logging_left_column, logging_right_column = st.columns(2)
221+
with logging_left_column:
222+
enum_selectbox(
223+
panel,
224+
label="Logging Mode",
225+
value=LoggingMode.OFF,
226+
disabled=panel.get_value("is_running", False),
227+
key="logging_mode",
228+
)
229+
with logging_right_column:
230+
left_sub_column, right_sub_column = st.columns([3, 1])
231+
with left_sub_column:
232+
tdms_file_path = st.text_input(
233+
label="TDMS File Path",
234+
disabled=panel.get_value("is_running", False),
235+
value="data.tdms",
236+
key="tdms_file_path",
237+
)

0 commit comments

Comments
 (0)