Skip to content

Commit f1395d6

Browse files
author
Dilmi Wickramanayake
committed
Merge branch 'users/DilmiWickramanayake/niscope_ex_fetch_forever' of https://github.com/ni/nipanel-python into users/DilmiWickramanayake/niscope_ex_fetch_forever
2 parents 2056cf3 + a80d753 commit f1395d6

File tree

6 files changed

+391
-19
lines changed

6 files changed

+391
-19
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""Data acquisition script that continuously acquires analog input data."""
2+
3+
from pathlib import Path
4+
5+
6+
import nidaqmx
7+
from nidaqmx.constants import AcquisitionType, ExcitationSource, Edge, Slope
8+
from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause
9+
import nipanel
10+
import time
11+
12+
panel_script_path = Path(__file__).with_name("nidaqmx_analog_input_filtering_panel.py")
13+
panel = nipanel.create_panel(panel_script_path)
14+
15+
16+
17+
with nidaqmx.Task() as task:
18+
chan_voltage = task.ai_channels.add_ai_voltage_chan("Mod3/ai10")
19+
chan_strain_gage = task.ai_channels.add_ai_strain_gage_chan("Mod3/ai7", voltage_excit_source=ExcitationSource.EXTERNAL)
20+
chan_current = task.ai_channels.add_ai_current_chan("Mod3/ai9")
21+
task.timing.cfg_samp_clk_timing(
22+
rate = 1000.0, sample_mode = AcquisitionType.CONTINUOUS, samps_per_chan = 3000
23+
)
24+
25+
task.timing.samp_clk_dig_fltr_min_pulse_width = 20.0e-6
26+
task.timing.samp_clk_dig_fltr_enable = True
27+
chan_voltage.ai_filter_response
28+
29+
panel.set_value("source", [task.triggers.pause_trigger.dig_lvl_src])
30+
panel.set_value("analog_source", [task.triggers.start_trigger.anlg_edge_src])
31+
32+
panel.set_value("sample_rate", task._timing.samp_clk_rate)
33+
34+
slope = Slopes(panel.get_value("slope",Slopes.FALLING.value))
35+
36+
if slope == "Rising":
37+
task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=0, trigger_slope= Slope.RISING)
38+
else:
39+
task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=0, trigger_slope= Slope.FALLING)
40+
41+
digital_edge = DigitalEdge(panel.get_value("edge_digital", DigitalEdge.FALLING.value))
42+
if digital_edge == "RISING":
43+
task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/PFI0", trigger_edge=Edge.RISING)
44+
else:
45+
task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/PFI0", trigger_edge=Edge.FALLING)
46+
task.start()
47+
48+
try:
49+
print(f"Press Ctrl + C to stop")
50+
51+
while True:
52+
53+
level = panel.get_value("level", 0.0)
54+
new_slope = Slopes(panel.get_value("slope",Slopes.FALLING.value))
55+
if slope != new_slope:
56+
task.stop()
57+
58+
if new_slope == "Rising":
59+
task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=level, trigger_slope= Slope.RISING)
60+
else:
61+
task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0", trigger_level=level, trigger_slope= Slope.FALLING)
62+
task.start()
63+
slope = new_slope
64+
65+
analog_pause = AnalogPause(panel.get_value("analog_pause", AnalogPause.ABOVE.value))
66+
67+
if analog_pause == "ABOVE":
68+
task.triggers.pause_trigger.anlg_lvl_when.ABOVE
69+
else:
70+
task.triggers.pause_trigger.anlg_lvl_when.BELOW
71+
72+
73+
pause_when = PauseWhen(panel.get_value("pause_when",PauseWhen.HIGH.value))
74+
if pause_when == "High":
75+
task.triggers.pause_trigger.dig_lvl_when.HIGH
76+
else:
77+
task.triggers.pause_trigger.dig_lvl_when.LOW
78+
79+
new_edge = DigitalEdge(panel.get_value("edge_digital", DigitalEdge.FALLING.value))
80+
if new_edge != digital_edge:
81+
task.stop()
82+
if new_edge == "RISING":
83+
task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/PFI0", trigger_edge=Edge.RISING)
84+
else:
85+
task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/PFI0", trigger_edge=Edge.FALLING)
86+
task.start()
87+
digital_edge = new_edge
88+
89+
90+
task.triggers.start_trigger.cfg_dig_edge_start_trig
91+
# task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source="/Dev2/te1/SampleClock")
92+
# task.triggers.start_trigger.cfg_time_start_trig(10)
93+
# task.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source="APFI0")
94+
# Configure a digital pause trigger (example)
95+
# Replace "PFI0" with your actual trigger source if needed
96+
97+
# task.triggers.pause_trigger.trig_type = TriggerType.DIGITAL_LEVEL
98+
# task.triggers.pause_trigger.dig_lvl_src = "/Dev2/PFI0"
99+
100+
# task.triggers.pause_trigger.dig_lvl_when
101+
# task.triggers.pause_trigger.trig_type = TriggerType.ANALOG_LEVEL
102+
# task.triggers.pause_trigger.anlg_lvl_src
103+
# task.triggers.pause_trigger.anlg_lvl_when
104+
105+
106+
data = task.read(number_of_samples_per_channel=100)
107+
panel.set_value("voltage_data", data[0])
108+
panel.set_value("current_data", data[2])
109+
panel.set_value("strain_data", data[1])
110+
111+
except KeyboardInterrupt:
112+
pass
113+
finally:
114+
task.stop()
115+
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
"""Streamlit visualization script to display data acquired by nidaqmx_continuous_analog_input.py."""
2+
3+
import streamlit as st
4+
from streamlit_echarts import st_echarts
5+
from settings_enum import DigitalEdge, PauseWhen, Slopes, AnalogPause
6+
import time
7+
import nipanel
8+
9+
10+
st.set_page_config(page_title="Analog Input Filtering", page_icon="📈", layout="wide")
11+
st.title("Analog Input - Filtering")
12+
13+
panel = nipanel.get_panel_accessor()
14+
15+
16+
tabs = st.tabs(["Voltage", "Current", "Strain Gage"])
17+
18+
st.markdown(
19+
"""
20+
<style>
21+
div[data-baseweb="select"] {
22+
width: 190px !important; /* Adjust the width as needed */
23+
}
24+
</style>
25+
""",
26+
unsafe_allow_html=True,
27+
)
28+
29+
streamlit_style = """
30+
<style>
31+
iframe[title="streamlit_echarts.st_echarts"]{ height: 400px; width:75%;}
32+
</style>
33+
"""
34+
st.markdown(streamlit_style, unsafe_allow_html=True)
35+
36+
37+
source = panel.get_value("source", [])
38+
analog_source = panel.get_value("analog_source", [])
39+
40+
voltage_data = panel.get_value("voltage_data", [0.0])
41+
current_data = panel.get_value("current_data", [0.0])
42+
strain_data = panel.get_value("strain_data", [0.0])
43+
44+
sample_rate = panel.get_value("sample_rate", 0.0)
45+
46+
col_chart, settings = st.columns([1,1.5]) # Chart wider than buttons
47+
with settings:
48+
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"])
49+
with tab1:
50+
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.")
51+
with tab2:
52+
nipanel.enum_selectbox(
53+
54+
)
55+
# st.selectbox("Source->", source)
56+
# edge_digital = st.selectbox(
57+
# "Edge",
58+
# options=[(e.name, e.value) for e in DigitalEdge],
59+
# format_func=lambda x: x[0],
60+
# index=0,
61+
# )
62+
# edge_digital = DigitalEdge[edge_digital[0]]
63+
# panel.set_value("edge_digital", edge_digital)
64+
65+
with tab3:
66+
st.selectbox("Source-", source)
67+
pause_when = st.selectbox(
68+
"Pause When",
69+
options=[(e.name, e.value) for e in PauseWhen],
70+
format_func=lambda x: x[0],
71+
index=0,
72+
)
73+
pause_when = PauseWhen[pause_when[0]]
74+
panel.set_value("pause_when", pause_when)
75+
with tab4:
76+
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")
77+
with tab5:
78+
st.selectbox("Source:", analog_source)
79+
slope = st.selectbox(
80+
"Slope",
81+
options=[(e.name, e.value) for e in Slopes],
82+
format_func=lambda x: x[0],
83+
index=0,
84+
)
85+
slope = Slopes[slope[0]]
86+
panel.set_value("slope", slope)
87+
88+
level = st.number_input("Level")
89+
panel.set_value("level", level)
90+
hysteriesis = st.number_input("Hysteriesis")
91+
panel.set_value("hysteriesis", hysteriesis)
92+
93+
with tab6:
94+
st.selectbox("source:", analog_source)
95+
analog_pause = st.selectbox(
96+
"analog_pause",
97+
options=[(e.name, e.value) for e in AnalogPause],
98+
format_func=lambda x: x[0],
99+
index=0,
100+
)
101+
analog_pause = AnalogPause[analog_pause[0]]
102+
panel.set_value("analog_pause", analog_pause)
103+
104+
with tab7:
105+
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.")
106+
with tab8:
107+
if st.button("Select time Manually"):
108+
time = st.time_input("When?")
109+
st.write(time)
110+
st.write("If time is not manually set, task will begin after 10 seconds")
111+
112+
113+
with tabs[0]:
114+
graph = {
115+
"animation": False,
116+
"tooltip": {"trigger": "axis"},
117+
"legend": {"data": ["Voltage (V)"]},
118+
"xAxis": {
119+
"type": "category",
120+
"data": [x / sample_rate for x in range(len(voltage_data))],
121+
"name": "Time",
122+
"nameLocation": "center",
123+
"nameGap": 40,
124+
},
125+
"yAxis": {
126+
"type": "value",
127+
"name": "Measurement",
128+
"nameRotate": 90,
129+
"nameLocation": "center",
130+
"nameGap": 40,
131+
},
132+
"series": [
133+
{
134+
"name": "voltage_amplitude",
135+
"type": "line",
136+
"data": voltage_data,
137+
"emphasis": {"focus": "series"},
138+
"smooth": True,
139+
"seriesLayoutBy": "row",
140+
},
141+
],
142+
}
143+
st_echarts(options=graph, height="400px", key="graph", width="50%")
144+
with tabs[1]:
145+
graph_2= {
146+
"animation": False,
147+
"tooltip": {"trigger": "axis"},
148+
"legend": {"data": ["Voltage (V)"]},
149+
"xAxis": {
150+
"type": "category",
151+
"data": [x / sample_rate for x in range(len(current_data))],
152+
"name": "Time",
153+
"nameLocation": "center",
154+
"nameGap": 40,
155+
},
156+
"yAxis": {
157+
"type": "value",
158+
"name": "Measurement",
159+
"nameRotate": 90,
160+
"nameLocation": "center",
161+
"nameGap": 40,
162+
},
163+
"series": [
164+
{
165+
"name": "voltage_amplitude",
166+
"type": "line",
167+
"data": current_data,
168+
"emphasis": {"focus": "series"},
169+
"smooth": True,
170+
"seriesLayoutBy": "row",
171+
},
172+
],
173+
}
174+
st_echarts(options=graph, height="400px", key="graph_2", width="50%")
175+
176+
with tabs[2]:
177+
graph_3 = {
178+
"animation": False,
179+
"tooltip": {"trigger": "axis"},
180+
"legend": {"data": ["Voltage (V)"]},
181+
"xAxis": {
182+
"type": "category",
183+
"data": [x / sample_rate for x in range(len(strain_data))],
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": strain_data,
200+
"emphasis": {"focus": "series"},
201+
"smooth": True,
202+
"seriesLayoutBy": "row",
203+
},
204+
],
205+
}
206+
st_echarts(options=graph_3, height="400px", key="graph_3", width="50%")
207+
208+
209+
210+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Enumeration for amplitude values used in the simple graph example."""
2+
3+
import enum
4+
5+
class DigitalEdge(enum.StrEnum):
6+
FALLING = "FALLING"
7+
RISING = "RISING"
8+
9+
class PauseWhen(enum.StrEnum):
10+
HIGH = "High"
11+
LOW = "Low"
12+
13+
class Slopes(enum.StrEnum):
14+
FALLING = "Falling"
15+
RISING = "Rising"
16+
17+
class AnalogPause(enum.StrEnum):
18+
ABOVE = "ABOVE"
19+
BELOW = "BELOW"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Enumeration for amplitude values used in the simple graph example."""
2+
3+
import enum
4+
5+
6+
class AmplitudeEnum(enum.IntEnum):
7+
"""Enumeration for amplitude values."""
8+
9+
SMALL = 1
10+
MEDIUM = 5
11+
BIG = 10

examples/simple_graph/simple_graph.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pathlib import Path
66

77
import numpy as np
8+
from amplitude_enum import AmplitudeEnum
89

910
import nipanel
1011

@@ -22,17 +23,24 @@
2223

2324
# Generate and update the sine wave data periodically
2425
while True:
26+
amplitude_enum = AmplitudeEnum(panel.get_value("amplitude_enum", AmplitudeEnum.SMALL.value))
27+
base_frequency = panel.get_value("base_frequency", 1.0)
28+
29+
30+
31+
# Slowly vary the total frequency for a more dynamic visualization
32+
frequency = base_frequency + 0.5 * math.sin(time.time() / 5.0)
2533
time_points = np.linspace(0, num_points, num_points)
26-
sine_values = amplitude * np.sin(frequency * time_points)
34+
sine_values = amplitude_enum.value * np.sin(frequency * time_points)
35+
36+
panel.set_value("frequency", frequency)
2737

2838
panel.set_value("time_points", time_points.tolist())
2939
panel.set_value("sine_values", sine_values.tolist())
30-
panel.set_value("amplitude", amplitude)
31-
panel.set_value("frequency", frequency)
40+
3241

3342
# Slowly vary the frequency for a more dynamic visualization
34-
frequency = 1.0 + 0.5 * math.sin(time.time() / 5.0)
35-
time.sleep(1)
43+
time.sleep(0.1)
3644

3745
except KeyboardInterrupt:
3846
print("Exiting...")

0 commit comments

Comments
 (0)