"""
This script is intended to be used with a quadrant diode. It averages a
certain amount of samples and displays a dot with its standard deviation
on a grid. The position of the dot can be resetted via a reset button.
The outputs of the quadrant diodes were connected to an National
Instruments ADC which can communicate with the nidaqmx library of
python.
"""
import nidaqmx
from nidaqmx import task as ni_task
from nidaqmx._task_modules import in_stream
from nidaqmx.stream_readers import AnalogMultiChannelReader
import numpy as np
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QRunnable, QThreadPool, pyqtSignal, QObject
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys # We need sys so that we can pass argv to QApplication
import os
[docs]class MainWindow(QtWidgets.QMainWindow):
[docs] class Signals(QObject):
acquisition_done = pyqtSignal()
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.signals = self.Signals()
self.layout = QtWidgets.QVBoxLayout()
self.graphWidget = pg.PlotWidget()
self.graphWidget.showGrid(x=True, y=True)
self.layout.addWidget(self.graphWidget)
self.button = QtWidgets.QPushButton("Reset Position")
self.button.clicked.connect(self.reset_position)
self.layout.addWidget(self.button)
self.widget = QtWidgets.QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
self.offset = np.array([0, 0])
self.s1 = pg.ScatterPlotItem(
size=5, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 255)
)
pos = np.array([0, 0])
spots = [{"pos": pos, "data": 1}]
self.s1.addPoints(spots)
self.graphWidget.addItem(self.s1)
device = "Dev1"
sampling_freq = 25000 # Hz
samples_to_acquire = 1000
refresh_time = 1000 / 25000
self.task = ni_task.Task()
# Add x-Coordinate
self.task.ai_channels.add_ai_voltage_chan(
device + "/ai0", name_to_assign_to_channel="dX", min_val=0, max_val=5
)
# Add y-Coordinate
self.task.ai_channels.add_ai_voltage_chan(
device + "/ai1", name_to_assign_to_channel="dY", min_val=0, max_val=5
)
# Add SUM
self.task.ai_channels.add_ai_voltage_chan(
device + "/ai2", name_to_assign_to_channel="SUM", min_val=0, max_val=5
)
self.task.timing.cfg_samp_clk_timing(
sampling_freq, samps_per_chan=samples_to_acquire
)
self.data = np.empty((self.task.number_of_channels, samples_to_acquire))
# Put task 'into stream' this is done so that data can be read
# directly into numpy array.
self.stream = in_stream.InStream(self.task)
# Setup AnalogMultiChannelReader this is done so that data can
# be read directly into numpy array.
self.channel_reader = AnalogMultiChannelReader(self.stream)
self.timer = QtCore.QTimer()
self.timer.setInterval(refresh_time * 1.2)
self.timer.timeout.connect(self.run)
self.timer.start()
[docs] def run(self):
self.channel_reader.read_many_sample(self.data)
# Normalize positions
self.rel_pos = self.data[(0, 1), :] / self.data[2, :]
# Average positions and subtract offset
self.avg_rel_pos = np.average(self.rel_pos, axis=-1)
self.avg_rel_pos_minus_offset = self.avg_rel_pos - self.offset
# Compute standard deviation to set as point size
self.std_rel_pos = np.average(np.std(self.rel_pos, axis=-1))
self.spots = [
{
"pos": self.avg_rel_pos_minus_offset,
"data": 1,
"size": 2000 * self.std_rel_pos,
"brush": pg.mkBrush(255, 0, 0, 255),
},
{
"pos": self.avg_rel_pos_minus_offset,
"data": 1,
"size": 10,
"brush": pg.mkBrush(255, 255, 255, 255),
},
]
self.s1.setData(self.spots)
[docs] def reset_position(self):
self.offset = self.avg_rel_pos.copy()
[docs]def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
main.task.close()
if __name__ == "__main__":
main()