Source code for utils.quadrant_diode

"""
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()