# Data Acquisition Interval and Slowness

Hello guys. I am pretty new on Python, and I have been doing a project where I am collecting some data from a NI DAQ system, and getting some outputs. Within my code, I have two graphic user interface windows: the first one is to start the data acquisition (after pressing the button, it closes and I go to the second GUI) and the second one has the live outputs I am generating (plus a Figure window where I am able to see the graphs being updated). The issue that I have with my code is that the second GUI window (and the Figure window) appear in my screen pretty slow (it take around 15 - 20 seconds for the Figure window to appear an another 10 - 20 seconds to start recording and updating data). I tried to incorporate a time.sleep function since I want my data to have a uniform interval among recorded points (instead of being random), but this did not work out. At this point, I just want to optimize and make my code more time efficient (aka faster). I will leave my code below to see if you have any suggestions:

‘’’
import os
import time
import openpyxl
import math
import nidaqmx
import matplotlib.pyplot as plt
from datetime import datetime
import tkinter as tk
from tkinter import ttk

class StopDataCollection(Exception):
pass

# Constants (you can modify these values if needed)

sampling_and_refresh_interval = 5.0 # Update data every 5.0 seconds
max_time = 5400
voltage_high = 5.0
voltage_low_E = 3.0
voltage_low_O = 0.0
pressure_high = 25.0
pressure_low = 0
max_flowrate = 8.0
min_flowrate = 0.5

# Function to control the output voltage

def control_output(value):

# Function to read voltage and calculate pressure for both devices

``````with nidaqmx.Task() as task:

pressure_omega = (12.5 * voltage_omega) - 37.5
pressure_edwards = (5.3652 * voltage_edwards) + 0.0145

return voltage_omega, pressure_omega, voltage_edwards, pressure_edwards
``````

# Dictionary to store device-specific values

device_values = {
‘Omega’: {
‘max_voltage’: voltage_high,
‘min_voltage’: voltage_low_O,
‘max_pressure’: pressure_high,
‘min_pressure’: pressure_low,
},
‘Edwards’: {
‘max_voltage’: voltage_high,
‘min_voltage’: voltage_low_E,
‘max_pressure’: pressure_high,
‘min_pressure’: pressure_low,
‘max_flowrate’: max_flowrate,
‘min_flowrate’: min_flowrate,
}
}

# Function to get the device-specific values based on the user’s choice

def get_device_specific_values(device_choice):
return device_values[device_choice][‘max_voltage’], device_values[device_choice][‘min_voltage’],
device_values[device_choice][‘max_pressure’], device_values[device_choice][‘min_pressure’]

# Function to create or load an Excel sheet for data storage

if os.path.exists(‘output_data.xlsx’):
sheet_name = f’Sheet_{datetime.now().strftime(“%Y%m%d_%H%M%S”)}’
data_sheet = workbook.create_sheet(title=sheet_name)
else:
workbook = openpyxl.Workbook()
data_sheet = workbook.active
data_sheet.title = f’Sheet_{datetime.now().strftime(“%Y%m%d_%H%M%S”)}’
return workbook, data_sheet

# Function to append data to the Excel sheet

def append_data_to_sheet(data_sheet, timestamp, elapsed_time, pressure_omega, voltage_omega, pressure_edwards, voltage_edwards, volumetric_flow_rate):
data_sheet.append([timestamp, elapsed_time, pressure_omega, voltage_omega, pressure_edwards, voltage_edwards, volumetric_flow_rate])

# Function to save the Excel file

def save_excel_file(workbook):
workbook.save(‘output_data.xlsx’)

# Function to update the pressure plot

def update_pressure_plot(ax1, time_data, pressure_data_omega, pressure_data_edwards):
ax1.clear()
ax1.plot(time_data, pressure_data_omega, ‘r’, label=‘Pressure Omega’)
ax1.plot(time_data, pressure_data_edwards, ‘b’, label=‘Pressure Edwards’)
ax1.set_title(‘Pressure across Flowmeter’)
ax1.set_xlabel(‘Time (seconds)’)
ax1.set_ylabel(‘Pressure (in H2O)’)
ax1.grid()
ax1.legend()

# Function to update the voltage plot

def update_voltage_plot(ax2, time_data, voltage_data_omega, voltage_data_edwards):
ax2.clear()
ax2.plot(time_data, voltage_data_omega, ‘r’, label=‘Voltage Omega’)
ax2.plot(time_data, voltage_data_edwards, ‘b’, label=‘Voltage Edwards’)
ax2.set_title(‘Voltage across Flowmeter’)
ax2.set_xlabel(‘Time (seconds)’)
ax2.set_ylabel(‘Voltage (V)’)
ax2.grid()
ax2.legend()

# Function to update the volumetric flow rate plot

def update_flowrate_plot(ax3, time_data, volumetric_flow_rate_data):
ax3.clear()
ax3.plot(time_data, volumetric_flow_rate_data, ‘g’)
ax3.set_title(‘Volumetric Flowrate across Flowmeter’)
ax3.set_xlabel(‘Time (seconds)’)
ax3.set_ylabel(‘Volumetric Flowrate (cfm)’)
ax3.grid()

``````plt.tight_layout()
``````

# Global variables

data_acquisition_running = False
second_gui = None # Initialize second_gui as None

# Function to stop data acquisition and quit the root window

def stop_data_acquisition():
global data_acquisition_running, btn_stop, root
data_acquisition_running = False
btn_stop.config(state=tk.DISABLED) # Disable the button to prevent multiple clicks
root.quit()

# Function to update the second GUI with elapsed time

def update_second_gui(start_time):
global entry_seconds

``````# Calculate the elapsed time since the start of data acquisition
current_time = time.time()
elapsed_time = current_time - start_time

# Update the time (in seconds) label in the second GUI
entry_seconds.delete(0, tk.END)
entry_seconds.insert(0, f"{elapsed_time:.2f}")

# Schedule the update of the GUI again after 100 milliseconds
second_gui.after(100, update_second_gui, start_time)
``````

# Function to calculate volumetric flow rate based on Edwards sensor’s pressure

def calculate_volumetric_flow_rate(pressure_edwards):
volumetric_flow_rate = 0.1038*(pressure_edwards**2) + 0.0034*(pressure_edwards)
return volumetric_flow_rate

# Function to update the second GUI with pressure, voltage, and volumetric flow rate values

def update_second_gui_values(voltage_edwards, voltage_omega, pressure_edwards, pressure_omega, volumetric_flow_rate, time_seconds):
global entry_edwards_voltage, entry_omega_voltage, entry_edwards_pressure, entry_omega_pressure, entry_volumetric_flow_rate, entry_seconds

``````entry_edwards_voltage.delete(0, tk.END)
entry_edwards_voltage.insert(0, f"{voltage_edwards:.3f} V")

entry_omega_voltage.delete(0, tk.END)
entry_omega_voltage.insert(0, f"{voltage_omega:.3f} V")

entry_edwards_pressure.delete(0, tk.END)
entry_edwards_pressure.insert(0, f"{pressure_edwards:.3f} in H2O")

entry_omega_pressure.delete(0, tk.END)
entry_omega_pressure.insert(0, f"{pressure_omega:.3f} in H2O")

entry_volumetric_flow_rate.delete(0, tk.END)
entry_volumetric_flow_rate.insert(0, f"{volumetric_flow_rate:.4f} cfm")

entry_seconds.delete(0, tk.END)
entry_seconds.insert(0, f"{time_seconds:.2f} s")
``````

# Main function for data acquisition and plotting

def main():
global root, entry_edwards_voltage, entry_omega_voltage, entry_edwards_pressure, entry_omega_pressure, entry_volumetric_flow_rate, entry_seconds, btn_stop, data_acquisition_running

``````data_acquisition_running = True
last_refresh_time = time.time()  # Initialize the time for the first refresh
last_acquisition_time = last_refresh_time  # Initialize the time for the first acquisition

workbook = None  # Initialize workbook outside the try-except block

try:
print("Data acquisition started.")  # Debug print
max_voltage, min_voltage, max_pressure, min_pressure = get_device_specific_values('Omega')
workbook, data_sheet = create_or_load_excel_sheet()

data_sheet.append(['Timestamp', 'Time (seconds)', 'Pressure Omega (in H2O)', 'Voltage Omega (V)',
'Pressure Edwards (in H2O)', 'Voltage Edwards (V)', 'Volumetric Flowrate (cfm)'])

time_data = []
pressure_data_omega = []
pressure_data_edwards = []
voltage_data_omega = []
voltage_data_edwards = []
volumetric_flow_rate_data = []

# Update the figsize parameter to make the plots larger
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True, figsize=(9, 9))

start_time = time.time()

while data_acquisition_running:
current_time = time.time()

# Check if we have reached the max_time
elapsed_time = current_time - start_time
if elapsed_time >= max_time:
print("Reached max_time.")
data_acquisition_running = False
break

if not plt.get_fignums():
print("Figure window closed. Stopping.")
data_acquisition_running = False
break

# Only acquire data and update plots every 5 seconds
if current_time - last_acquisition_time >= sampling_and_refresh_interval:
voltage_omega, pressure_omega, voltage_edwards, pressure_edwards = readdaq()

timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]

if voltage_omega < min_voltage or voltage_omega > max_voltage:
control_output(0.0)
print("Omega Voltage out of range. Stopping.")
data_acquisition_running = False
break

if pressure_omega < min_pressure or pressure_omega > max_pressure:
control_output(0.0)
print("Omega Pressure out of range. Stopping.")
data_acquisition_running = False
break

if voltage_edwards < min_voltage or voltage_edwards > max_voltage:
control_output(0.0)
print("Edwards Voltage out of range. Stopping.")
data_acquisition_running = False
break

if pressure_edwards < min_pressure or pressure_edwards > max_pressure:
control_output(0.0)
print("Edwards Pressure out of range. Stopping.")
data_acquisition_running = False
break

volumetric_flow_rate = calculate_volumetric_flow_rate(pressure_edwards)

# Check volumetric flow rate range for the selected device
if volumetric_flow_rate < min_flowrate or volumetric_flow_rate > max_flowrate:
control_output(0.0)
print("Volumetric Flow Rate out of range. Stopping.")
data_acquisition_running = False
break

append_data_to_sheet(data_sheet, timestamp, elapsed_time, pressure_omega, voltage_omega, pressure_edwards, voltage_edwards, volumetric_flow_rate)
save_excel_file(workbook)

time_data.append(elapsed_time)
pressure_data_omega.append(pressure_omega)
pressure_data_edwards.append(pressure_edwards)
voltage_data_omega.append(voltage_omega)
voltage_data_edwards.append(voltage_edwards)
volumetric_flow_rate_data.append(volumetric_flow_rate)

last_acquisition_time = current_time  # Update the last acquisition time

# Update plots and refresh the GUI every 5 seconds
if current_time - last_refresh_time >= sampling_and_refresh_interval:
update_pressure_plot(ax1, time_data, pressure_data_omega, pressure_data_edwards)
update_voltage_plot(ax2, time_data, voltage_data_omega, voltage_data_edwards)
update_flowrate_plot(ax3, time_data, volumetric_flow_rate_data)

root.update()
plt.pause(0.01)  # Small pause to allow GUI updates

last_refresh_time = current_time  # Update the last refresh time

print("Timestamp:", timestamp)
print("T =", round(elapsed_time, 2), "(s)")
print("Pressure Omega =", round(pressure_omega, 3), "(in H2O)")
print("Voltage Omega =", round(voltage_omega, 3), "(V)")
print("Pressure Edwards =", round(pressure_edwards, 3), "(in H2O)")
print("Voltage Edwards =", round(voltage_edwards, 3), "(V)")
print("Volumetric Flow Rate =", round(volumetric_flow_rate, 3), "(cfm)")

second_gui.after(100, update_second_gui_values, voltage_edwards, voltage_omega, pressure_edwards, pressure_omega, volumetric_flow_rate, elapsed_time)

print("Data acquisition loop ended.")  # Debug print

except KeyboardInterrupt:
print("KeyboardInterrupt: Stopping the data collection.")
except StopDataCollection:
print("Data collection stopped.")
except Exception as e:
print("An error occurred:", str(e))

finally:
control_output(0.0)
if output_task is not None:
if workbook is not None:
save_excel_file(workbook)  # Save the workbook before closing
workbook.close()  # Close the workbook
print("Data collection stopped.")  # Debug print
if second_gui:
second_gui.destroy()

os._exit(0)
``````

# Function to create the second GUI window

def create_second_gui():
global root, entry_edwards_voltage, entry_omega_voltage, entry_edwards_pressure, entry_omega_pressure, entry_volumetric_flow_rate, entry_seconds, btn_stop, second_gui

``````print("Creating second GUI")  # Debug print

root.withdraw()

second_gui = tk.Tk()
second_gui.title("Data Acquisition")
second_gui.geometry("500x300")  # Set the size to 500x300

lbl_edwards_voltage = ttk.Label(second_gui, text="Edwards Voltage:")

entry_edwards_voltage = ttk.Entry(second_gui)

lbl_omega_voltage = ttk.Label(second_gui, text="Omega Voltage:")

entry_omega_voltage = ttk.Entry(second_gui)

lbl_edwards_pressure = ttk.Label(second_gui, text="Edwards Pressure:")

entry_edwards_pressure = ttk.Entry(second_gui)

lbl_omega_pressure = ttk.Label(second_gui, text="Omega Pressure:")

entry_omega_pressure = ttk.Entry(second_gui)

lbl_volumetric_flow_rate = ttk.Label(second_gui, text="Volumetric Flow Rate:")

entry_volumetric_flow_rate = ttk.Entry(second_gui)

lbl_seconds = ttk.Label(second_gui, text="Time:")

entry_seconds = ttk.Entry(second_gui)

# Add the "Stop Data Acquisition" button
btn_stop = ttk.Button(second_gui, text="Stop Data Acquisition", command=stop_data_acquisition)

# Handle the WM_DELETE_WINDOW event of the second GUI window
second_gui.protocol("WM_DELETE_WINDOW", stop_data_acquisition)

second_gui.after(100, main)  # Start the data acquisition

second_gui.after(100, update_second_gui, time.time())  # Start the time update loop

second_gui.mainloop()
``````

# Function to start data acquisition

def start_data_acquisition():
global root
print(“Starting data acquisition”) # Debug print
create_second_gui()

# First GUI window to choose the pressure device

root = tk.Tk()
root.title(“Data Acquisition”)
root.geometry(“400x150”)

label_instruction = ttk.Label(root, text=“Click the button to start data acquisition.”)
label_instruction.pack()

# Handle the WM_DELETE_WINDOW event of the first GUI window

root.protocol(“WM_DELETE_WINDOW”, stop_data_acquisition)

# Add the “Start Data Acquisition” button

btn_start_acquisition = ttk.Button(root, text=“Start Data Acquisition”, command=start_data_acquisition)
btn_start_acquisition.pack()

root.mainloop()
‘’’

Did you try removing parts of the functionality, to try to figure out which parts are causing the slowdown?

No. The only thing I tried out was to stop printing the output values in each iteration. How can I do what you are suggesting?