Introduction
I encountered issues with extracting data using NI-DAQmx Python algorithms (using Python 3.11 on Anaconda, with Spyder as the IDE). The data remains unchanged when I alter the settings, yielding a constant, incorrect value. This question outlines my troubleshooting process and the steps taken to resolve the issue.
Checking the Device Connected to the National Instruments (NI-DAQmx)
MAX
Initially, I utilized MAX (Measurement and Automation Explorer) to verify the device's functionality. The device appeared to operate correctly, and test panel readings matched expected theoretical values :
NI SignalExpress 2015
Further testing with NI SignalExpress 2015 confirmed that the software could accurately retrieve the expected values, indicating no issues at this stage.
Code Implementation in NI-DAQmx Python
Despite anticipating seamless integration with the NI-DAQmx Python API, problems emerged: The values returned by basic algorithms were static and inconsistent with both expected fluctuations and previous measurements, displaying values such as 5.3, which were incongruent with prior results. Below, I detailed the algorithms attempted and their respective outcomes.
First Algorithms and Results
import nidaqmx
task = nidaqmx.Task()
task.ai_channels.add_ai_voltage_chan("Dev1/ai10")
task.start()
value = task.read()
print(round(value,1))
task.stop()
task.close()
$ python script_1.py
5.4
Second Algorithms and Results
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
import nidaqmx
from nidaqmx.constants import AcquisitionType
import pdb
# Configuration de l'appareil NI-DAQmx pour deux canaux
device_name = "Dev1" # Le nom de votre dispositif
sample_rate = 1000 # Taux d'échantillonnage en échantillons par seconde
samples_per_read = 1 # Nombre d'échantillons à lire à chaque itération
# Initialisation des données de graphique
xdata, ydata1, ydata2 = [], [], []
fig, ax = plt.subplots()
line1, = plt.plot([], [], '-', label='Canal ai9')
line2, = plt.plot([], [], '-', label='Canal ai10')
plt.title('Données NI-DAQmx en temps réel')
plt.xlabel('Échantillons')
plt.ylabel('Voltage (V)')
plt.legend()
def init():
ax.set_xlim(0, 100)
ax.set_ylim(1, 6.5) # Ajustez les limites pour refléter la nouvelle plage de tension
return line1, line2
def update(frame):
with nidaqmx.Task() as task:
# Ajoutez ici les deux canaux à la tâche
for ch in channels:
task.ai_channels.add_ai_voltage_chan(f"{device_name}/{ch}")
task.timing.cfg_samp_clk_timing(rate=sample_rate, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=samples_per_read)
data = task.read(number_of_samples_per_channel=samples_per_read)
xdata.append(frame)
# Mettez à jour les données pour les deux canaux
ydata1.append(data[0])
ydata2.append(data[1])
line1.set_data(xdata, ydata1)
line2.set_data(xdata, ydata2)
if len(xdata) > 100: # Défilement de l'axe x pour garder les 100 derniers points visibles
ax.set_xlim(xdata[-100], xdata[-1] + 1)
return line1, line2
# Animation
ani = FuncAnimation(fig, update, frames=np.arange(0, 1000), init_func=init, blit=False, interval=50)
plt.show()
Bug Resolution attempt
I verified the device name and ports, ensuring accuracy in their specification. Additionally, I regularly cleared the device of any residual data to prevent issues related to data overflow or corruption.
Conclusion
I am at a loss regarding the cause of these discrepancies between NI SignalExpress 2015 and NI-DAQmx or how to rectify them. Any assistance or guidance would be greatly appreciated.
ANSWER (provided in the question until it is reopen to accept answers)
Here is the solution provided in github (https://github.com/ni/nidaqmx-python/issues/543#event-12171891209)
n MAX and SignalExpress, you are acquiring data with a +/-10 V range, but the Python add_ai_voltage_channel method sets `min_val=-5.0 `and `max_val=5.0` by default:
def add_ai_voltage_chan(
self, physical_channel, name_to_assign_to_channel="",
terminal_config=TerminalConfiguration.DEFAULT, min_val=-5.0,
max_val=5.0, units=VoltageUnits.VOLTS, custom_scale_name=""):
This is clipping your data to approximately a +/-5 V range. The reason it reads 5.3 V rather than 5 V is that X Series devices have a small amount of overrange so that software calibration doesn't reduce the usable range.
Try specifying min_val=-10.0 and max_val=10.0.
And this is the following working script
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
import nidaqmx
from nidaqmx.constants import (AcquisitionType, TerminalConfiguration)
import csv
import os
import time
# Ask the user for desired units
units = input("Enter the desired units (bar or mmHg): ").lower()
# Conversion function
def voltage_to_pressure(voltage, units):
pressure_bar = (voltage / 10) * 1.6 # 0-10 V -> 0-1.6 bar
if units == "bar":
return pressure_bar # Directly in bar
elif units == "mmhg":
return ( pressure_bar * 750.0616827 )-7 # 1 bar = 750.0616827 mmHg
else:
return None
# Configuration
device_name = "Dev1"
channel = "ai10"
Tstop = 60 # Logging Time [seconds]
Ts = 2 # Sampling Time [seconds]
N = int(Tstop/Ts)
data = []
c_hg = 750.0616827
# CSV setup
csv_file_name = input("Enter the name for the CSV file (without extension): ") + ".csv"
csv_file_path = os.path.join(os.path.expanduser("~"), "Desktop", csv_file_name)
# Initialize CSV
with open(csv_file_path, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['Sample Number', 'ai10 (' + units + ')'])
fig, ax = plt.subplots()
# Correctly unpack the list returned by ax.plot to get the Line2D object for animation
line, = ax.plot([], [], 'r-', label='Channel ai10') # Use comma to unpack
ax.set_xlim(0, 100) # Set the x-axis limit
# Set y-axis based on units
if units == 'bar':
ax.set_ylim(0.9, 1.11) # For 'bar' units
else:
ax.set_ylim(0.9*c_hg, 1.11*c_hg) # For 'mmHg' units, using the conversion constant
ax.legend()
ax.set_title('NI-DAQmx Real-time Data')
ax.set_xlabel('Time (s)')
ax.set_ylabel(f'Pressure ({units})')
xdata, ydata = [], []
def init():
line.set_data([], [])
return (line,)
def update(frame):
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan(f"{device_name}/{channel}", terminal_config=TerminalConfiguration.RSE, min_val=-10, max_val=10)
voltage_reading = task.read() # Ensure this returns a single reading directly
pressure = voltage_to_pressure(voltage_reading, units) # Convert directly
ydata.append(pressure)
xdata.append(frame * Ts) # Assuming each frame represents a time step of Ts seconds
line.set_data(xdata, ydata)
if len(xdata) > 100:
ax.set_xlim(xdata[-100], xdata[-1]+1)
with open(csv_file_path, mode='a', newline='') as file:
writer = csv.writer(file)
writer.writerow([frame, pressure])
return line,
ani = FuncAnimation(fig, update, frames=np.arange(1, 1000), init_func=init, blit=True, interval=50)
plt.show()

