start multiprocessing
This commit is contained in:
parent
dbf1f0b4c2
commit
76e0a4e64a
@ -19,6 +19,8 @@ from os import path, makedirs
|
||||
import pickle as pkl
|
||||
import json
|
||||
import atexit
|
||||
import multiprocessing as mp
|
||||
from multiprocessing.managers import BaseManager
|
||||
|
||||
import argparse
|
||||
|
||||
@ -47,7 +49,7 @@ from .led_control_device.base import LedControlDevice
|
||||
from .led_control_device.impl import thorlabs_ledd1b as _led
|
||||
from .led_script import LedScript
|
||||
|
||||
from .measurement import Measurement
|
||||
from .measurement import measure as _measure
|
||||
from .utility.data import DataCollector
|
||||
|
||||
|
||||
@ -72,13 +74,14 @@ settings = {
|
||||
|
||||
test = False
|
||||
|
||||
BaseManager.register('LedControlDevice', LedControlDevice)
|
||||
# global variable for the instrument/client returned by pyvisa/bleak
|
||||
dev: VoltageMeasurementDevice|None = None
|
||||
led: LedControlDevice|None = None
|
||||
data = DataCollector(data_path=settings["datadir"], data_name="interactive", dirname="interactive_test", dir_exists_is_ok=True)
|
||||
t0 = 0
|
||||
|
||||
def monitor(interval=None, max_measurements=None, max_points_shown=160):
|
||||
def monitor(script: str|int=0, interval=None, flush_after=None, max_measurements=None, max_points_shown=400):
|
||||
"""
|
||||
Monitor the voltage with matplotlib.
|
||||
|
||||
@ -91,21 +94,27 @@ def monitor(interval=None, max_measurements=None, max_points_shown=160):
|
||||
@param max_points_shown : how many points should be shown at once. None means infinite
|
||||
@param max_measurements : maximum number of measurements. None means infinite
|
||||
"""
|
||||
global _runtime_vars
|
||||
global _runtime_vars, data, dev, led
|
||||
_runtime_vars["last_measurement"] = dtime.now().isoformat()
|
||||
if not interval: interval = settings["interval"]
|
||||
print(f"Starting measurement with:\n\tinterval = {interval}s\nUse <C-c> to stop. Save the data using 'save_csv()' afterwards.")
|
||||
print(f"Starting measurement with:\n\tinterval = {interval}s\nUse <C-c> to stop. Save the data using 'data.save_csv()' afterwards.")
|
||||
plt_monitor = _Monitor(use_print=True, max_points_shown=max_points_shown)
|
||||
led_script = LedScript(script=script)
|
||||
data.clear()
|
||||
def update_func(i, t, v):
|
||||
global t0
|
||||
if i == 0:
|
||||
t0 = t
|
||||
t -= t0
|
||||
data.add_data(i, t, v, 0)
|
||||
plt_monitor.update(i, t, v)
|
||||
# update_led()
|
||||
dev.measure(interval=interval, max_measurements=max_measurements, update_func=update_func)
|
||||
queue = mp.Queue()
|
||||
pipe_send, pipe_recv = mp.Pipe()
|
||||
# TODO: pass instruments
|
||||
proc_measure = mp.Process(target=_measure, args=(None, None, led_script, data, interval, flush_after, max_measurements, False, pipe_recv, queue))
|
||||
proc_measure.start()
|
||||
try:
|
||||
while True:
|
||||
data = queue.get(block=True, timeout=30)
|
||||
i, tval, vval, led_val = data
|
||||
plt_monitor.update(i, tval, vval, led_val)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
pipe_send.send("stop")
|
||||
proc_measure.join()
|
||||
|
||||
def measure(interval=None, max_measurements=None):
|
||||
"""
|
||||
@ -276,8 +285,13 @@ Enter 'help()' for a list of commands""")
|
||||
makedirs(settings["datadir"])
|
||||
|
||||
try:
|
||||
dev = _volt.init("GPIB0::22::INSTR")
|
||||
led = _led.LEDD1B()
|
||||
pass
|
||||
# dev = _volt.init("GPIB0::22::INSTR")
|
||||
# TODO
|
||||
# manager = BaseManager()
|
||||
# manager.start()
|
||||
# led = manager._led.LEDD1B()
|
||||
# led = _led.LEDD1B()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
exit(1)
|
||||
|
@ -5,62 +5,90 @@ Created on Fri Jan 24 15:18:31 2025
|
||||
@author: Matthias Quintern
|
||||
"""
|
||||
from cpdctrl.voltage_measurement_device.base import VoltageMeasurementDevice
|
||||
from cpdctrl.voltage_measurement_device.impl.keithley2700 import init
|
||||
from cpdctrl.led_control_device.base import LedControlDevice
|
||||
from cpdctrl.led_control_device.impl.thorlabs_ledd1b import LEDD1B # TODO: remove!
|
||||
from cpdctrl.led_script import LedScript
|
||||
from cpdctrl.utility.data import DataCollector
|
||||
|
||||
import time
|
||||
import datetime
|
||||
from multiprocessing import Pipe
|
||||
from multiprocessing.connection import Connection
|
||||
from queue import Queue
|
||||
|
||||
class Measurement:
|
||||
def __init__(self,
|
||||
vm_dev: VoltageMeasurementDevice,
|
||||
led_dev: LedControlDevice,
|
||||
led_script: LedScript,
|
||||
data: DataCollector,
|
||||
|
||||
):
|
||||
self.vm_dev = vm_dev
|
||||
self.led_dev = led_dev
|
||||
self.led_script = led_script
|
||||
self.data = data
|
||||
|
||||
def measure_finite(self, delta_t: 0.1, flush_after:int|None=None, max_measurements=None, verbose=False):
|
||||
# if no "time" in header, set the current local time in ISO 8601 format
|
||||
# and without microseconds
|
||||
if not "time" in self.data.header:
|
||||
self.data.header["time"] = datetime.datetime.now().replace(microsecond=0).isoformat()
|
||||
self.vm_dev.reset(True)
|
||||
try:
|
||||
i = 0
|
||||
led_val = self.led_script.start()
|
||||
def measure(
|
||||
vm_dev: VoltageMeasurementDevice,
|
||||
led_dev: LedControlDevice,
|
||||
led_script: LedScript,
|
||||
data: DataCollector,
|
||||
delta_t: float=0.1,
|
||||
flush_after:int|None=None,
|
||||
max_measurements: int=None,
|
||||
verbose: bool=False,
|
||||
pipe: None|Connection=None,
|
||||
queue: None|Queue=None
|
||||
):
|
||||
# TODO: find a way to move inherited objects into a process
|
||||
if led_dev is None:
|
||||
led_dev = LEDD1B()
|
||||
if vm_dev is None:
|
||||
vm_dev = init("GPIB0::22::INSTR")
|
||||
# if no "time" in header, set the current local time in ISO 8601 format
|
||||
# and without microseconds
|
||||
if not "time" in data.header:
|
||||
data.header["time"] = datetime.datetime.now().replace(microsecond=0).isoformat()
|
||||
vm_dev.reset(True)
|
||||
try:
|
||||
i = 0
|
||||
led_val = led_script.start()
|
||||
t_iter_start = time.time()
|
||||
while max_measurements is None or i < max_measurements:
|
||||
# 1) read value
|
||||
tval, vval = vm_dev.read_value()
|
||||
if i == 0:
|
||||
t0 = tval
|
||||
tval -= t0
|
||||
current_data = (i, tval, vval, led_val)
|
||||
data.add_data(*current_data)
|
||||
# 2) write data
|
||||
print(f"n = {i:6d}, t = {tval: .2f} s, U = {vval: .5f} V, LED = {led_val:03}%" + " "*10, end='\r')
|
||||
if flush_after is not None and (i+1) % flush_after == 0:
|
||||
data.flush(verbose=verbose)
|
||||
# if a queue was given, put the data
|
||||
if queue is not None:
|
||||
queue.put(current_data)
|
||||
# if a pipe was given, check for messages
|
||||
if pipe is not None and pipe.poll(0):
|
||||
recv = pipe.recv()
|
||||
if recv == "stop":
|
||||
break
|
||||
elif type(recv) == tuple and recv[0] == "led_script":
|
||||
led_script = recv[1]
|
||||
else:
|
||||
print(f"Received invalid message: '{recv}'")
|
||||
# 3) sleep
|
||||
# substract the execution time from the sleep time for a more
|
||||
# acurate frequency
|
||||
dt_sleep = delta_t - (time.time() - t_iter_start)
|
||||
if dt_sleep > 0:
|
||||
# print(f"Sleeping for {dt_sleep}")
|
||||
time.sleep(dt_sleep)
|
||||
t_iter_start = time.time()
|
||||
while max_measurements is None or i < max_measurements:
|
||||
tval, vval = self.vm_dev.read_value()
|
||||
if i == 0:
|
||||
t0 = tval
|
||||
tval -= t0
|
||||
self.data.add_data(i, tval, vval, led_val)
|
||||
print(f"n = {i:6d}, t = {tval: .2f} s, U = {vval: .5f} V, LED = {led_val:03}%" + " "*10, end='\r')
|
||||
if flush_after is not None and (i+1) % flush_after == 0:
|
||||
self.data.flush(verbose=verbose)
|
||||
# substract the execution time from the sleep time for a more
|
||||
# acurate frequency
|
||||
dt_sleep = delta_t - (time.time() - t_iter_start)
|
||||
if dt_sleep > 0:
|
||||
# print(f"Sleeping for {dt_sleep}")
|
||||
time.sleep(dt_sleep)
|
||||
t_iter_start = time.time()
|
||||
new_led_val = self.led_script.get_state()
|
||||
if new_led_val != led_val:
|
||||
try:
|
||||
self.led_dev.set_level(new_led_val)
|
||||
led_val = new_led_val
|
||||
except Exception as e:
|
||||
print(f"Error setting led to {new_led_val}%:")
|
||||
print(e)
|
||||
i += 1
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
self.data.flush(verbose=verbose)
|
||||
print("Measurement stopped" + " "*50)
|
||||
# 4) update LED
|
||||
new_led_val = led_script.get_state()
|
||||
if new_led_val != led_val:
|
||||
try:
|
||||
led_dev.set_level(new_led_val)
|
||||
led_val = new_led_val
|
||||
except Exception as e:
|
||||
print(f"Error setting led to {new_led_val}%:")
|
||||
print(e)
|
||||
i += 1
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
data.flush(verbose=verbose)
|
||||
led_dev.off()
|
||||
print("Measurement stopped" + " "*50)
|
@ -8,35 +8,45 @@ class _Monitor:
|
||||
"""
|
||||
Monitor v and i data in a matplotlib window
|
||||
"""
|
||||
def __init__(self, max_points_shown=None, use_print=False):
|
||||
def __init__(self, led_data=True, max_points_shown=None, use_print=False):
|
||||
self.max_points_shown = max_points_shown
|
||||
self.use_print = use_print
|
||||
self.index = []
|
||||
self.vdata = []
|
||||
self.tdata = []
|
||||
self.ldata = []
|
||||
|
||||
plt.ion()
|
||||
self.fig1, self.vax = plt.subplots(1, 1, figsize=(8, 5))
|
||||
|
||||
self.vline, = self.vax.plot(self.tdata, self.vdata, color="g")
|
||||
self.led_data = led_data
|
||||
if self.led_data:
|
||||
self.lax = self.vax.twinx()
|
||||
self.lax.set_ylabel("LED [%]")
|
||||
self.lline, = self.lax.plot(self.tdata, self.ldata, color="orange")
|
||||
self.lax.set_ylim(-0.5, 100.5)
|
||||
self.vline, = self.vax.plot(self.tdata, self.vdata, color="blue")
|
||||
self.vax.set_xlabel("time [s]")
|
||||
self.vax.set_ylabel("Voltage [V]")
|
||||
self.vax.grid(True)
|
||||
|
||||
|
||||
def update(self, i, tval, vval):
|
||||
def update(self, i, tval, vval, led_val=-1):
|
||||
if self.use_print:
|
||||
_update_print(i, tval, vval)
|
||||
self.index.append(i)
|
||||
self.tdata.append(tval)
|
||||
self.vdata.append(vval)
|
||||
if self.led_data:
|
||||
self.ldata.append(led_val)
|
||||
self.lline.set_xdata(self.tdata)
|
||||
self.lline.set_ydata(self.ldata)
|
||||
# update data
|
||||
self.vline.set_xdata(self.tdata)
|
||||
self.vline.set_ydata(self.vdata)
|
||||
# recalculate limits and set them for the view
|
||||
self.vax.relim()
|
||||
if self.max_points_shown and i > self.max_points_shown:
|
||||
self.vax.set_xlim(i - self.max_points_shown, i)
|
||||
self.vax.set_xlim(self.tdata[i-self.max_points_shown], self.tdata[i])
|
||||
self.vax.autoscale_view()
|
||||
# update plot
|
||||
self.fig1.canvas.draw()
|
||||
|
Loading…
x
Reference in New Issue
Block a user