diff --git a/jet_tracking/context.py b/jet_tracking/context.py index 62c8f9d..da0ecd2 100644 --- a/jet_tracking/context.py +++ b/jet_tracking/context.py @@ -58,6 +58,17 @@ def __init__(self, signals): self.center = 0.03 self.max = 10 self.bg = 0.05 + self.simTracking = False + self.sim_algorithm = "Linear Scan" + self.ratio = 1 + self.dropped = False + self.ave_time = 1 + self.left = -0.1 + self.right = 0.1 + self.step = 0.005 + self.sim_tol = 0.001 + self.thresh = 90 + self.wait = 5 # added while adding simulator def update_motor_position(self, mp): @@ -88,6 +99,34 @@ def update_background(self, bgn): self.bg = bgn self.signals.changeBackground.emit(self.bg) + def update_ave_time(self, at): + self.ave_time = at + self.signals.changeAverageTime.emit(self.ave_time) + + def update_left(self, left): + self.left = left + self.signals.changeLeft.emit(self.left) + + def update_right(self, right): + self.right = right + self.signals.changeRight.emit(self.right) + + def update_step(self, step): + self.step = step + self.signals.changeStep.emit(self.step) + + def update_sim_tol(self, tol): + self.sim_tol = tol + self.signals.changeSimTol.emit(self.sim_tol) + + def update_thresh(self, thresh): + self.thresh = thresh + self.signals.changeThresh.emit(self.thresh) + + def update_wait(self, wait): + self.wait = wait + self.signals.changeWait.emit(self.wait) + def update_live_graphing(self, live): self.live_data = live self.signals.changeRunLive.emit(self.live_data) @@ -96,6 +135,22 @@ def update_calibration_source(self, cal_src): self.calibration_source = cal_src self.signals.changeCalibrationSource.emit(self.calibration_source) + def update_sim_tracking(self, sim_tracking): + self.simTracking = sim_tracking + self.signals.enableSimTracking.emit(self.simTracking) + + def update_sim_algorithm(self, al): + self.sim_algorithm = al + self.signals.changeSimAlgorithm.emit(self.sim_algorithm) + + def update_ratio(self, r): + self.ratio = r + self.signals.changeRatio.emit(self.ratio) + + def update_dropped(self, d): + self.dropped = d + self.signals.changeDropped.emit(self.dropped) + def update_percent(self, p): """ changes the percent threshold and emits a signal to the thread diff --git a/jet_tracking/datastream.py b/jet_tracking/datastream.py index f85b027..d4b8824 100644 --- a/jet_tracking/datastream.py +++ b/jet_tracking/datastream.py @@ -93,7 +93,6 @@ def sim_data_stream(self): self.diff = self.sim_vals["diff"] self.ratio = self.sim_vals["ratio"] self.dropped = self.sim_vals["dropped"] - #self.motor_position = self.sim_vals["motor_position"] def read_value(self): # needs to initialize first maybe using a decorator? if self.context.live_data: @@ -172,6 +171,7 @@ def create_vars(self): self.ave_cycle = self.context.ave_cycle self.x_cycle = self.context.x_cycle self.ave_idx = self.context.ave_idx + #self. def create_value_reader(self): self.reader = ValueReader(self.context, self.signals) diff --git a/jet_tracking/gui/widgets/simControlWidget.py b/jet_tracking/gui/widgets/simControlWidget.py index 7369193..b7bdb7d 100644 --- a/jet_tracking/gui/widgets/simControlWidget.py +++ b/jet_tracking/gui/widgets/simControlWidget.py @@ -2,23 +2,28 @@ from gui.widgets.simControlWidgetUi import Sim_Ui from datastream import StatusThread, MotorThread import logging - +from sketch.sim_motorMoving import SimulatedMotor +import threading log = logging.getLogger(__name__) -class SimWidget(QFrame, Sim_Ui): +class SimWidget(QFrame, Sim_Ui, SimulatedMotor): def __init__(self, context, signals): super(SimWidget, self).__init__() self.signals = signals self.context = context self.setupUi(self) -# self.initialize_threads() + self.initialize_threads() self.make_connections() self.set_sim_options() + self.left = -0.1 + self.right = 0.1 + self.ratio = self.context.ratio + self.ratios = [] -# def initialize_threads(self): -# self.sim_status = StatusThread(self.context, self.signals) + def initialize_threads(self): + self.sim_status = StatusThread(self.context, self.signals) def set_sim_options(self): self.context.update_motor_position(float(self.box_motor_pos.text())) @@ -28,8 +33,15 @@ def set_sim_options(self): self.context.update_jet_center(float(self.box_jet_center.text())) self.context.update_max_intensity(float(self.box_max_int.text())) self.context.update_background(float(self.box_bg.text())) + self.context.update_sim_algorithm(self.cbox_sim_algorithm.currentText()) -# self.context.update_algorithm(self.cbox_algorithm.currentText()) + self.context.update_ave_time(float(self.box_ave_time.text())) + self.context.update_left(float(self.box_left.text())) + self.context.update_right(float(self.box_right.text())) + self.context.update_step(float(self.box_step.text())) + self.context.update_sim_tol(float(self.box_sim_tol.text())) + self.context.update_thresh(float(self.box_thresh.text())) + self.context.update_wait(float(self.box_wait.text())) def make_connections(self): self.box_motor_pos.checkVal.connect(self.context.update_motor_position) @@ -40,16 +52,38 @@ def make_connections(self): self.box_max_int.checkVal.connect(self.context.update_max_intensity) self.box_bg.checkVal.connect(self.context.update_background) -# self.cbox_algorithm.currentTextChanged.connect(self.context.update_algorithm) -# self.bttn_start_tracking.clicked.connect(self._start_sim) + self.box_ave_time.checkVal.connect(self.context.update_ave_time) + self.box_left.checkVal.connect(self.context.update_left) + self.box_right.checkVal.connect(self.context.update_right) + self.box_step.checkVal.connect(self.context.update_step) + self.box_sim_tol.checkVal.connect(self.context.update_sim_tol) + self.box_thresh.checkVal.connect(self.context.update_thresh) + self.box_wait.checkVal.connect(self.context.update_wait) + + self.cbox_sim_algorithm.currentTextChanged.connect(self.context.update_sim_algorithm) + self.bttn_search.clicked.connect(self._start_search) + self.bttn_start_tracking.clicked.connect(self._start_tracking) + self.bttn_stop_tracking.clicked.connect(self._stop_tracking) -# def _start_sim(self): + def _start_search(self): # self.sim_status.start() +# self._start() + thread = threading.Thread(target=self._start, args=()) + thread.start() -# def _enable_tracking(self): + def _start_tracking(self): # self.update_tracking_status("enabled", green) -# self.context.update_tracking(True) -# self._start_motor() + self.context.update_sim_tracking(True) +# self.set_tracking_status('Tracking', 'green') +# self.sim_tracking() + print("started tracking") + thread2 = threading.Thread(target=self.sim_tracking, args=()) + thread2.start() + + def _stop_tracking(self): +# self.update_tracking_status("disabled", red) + self.context.update_sim_tracking(False) + print("stopped tracking") # def set_tracking_status(self, status, color): # self.lbl_tracking_status.setText(status) diff --git a/jet_tracking/gui/widgets/simControlWidgetUi.py b/jet_tracking/gui/widgets/simControlWidgetUi.py index c7e3f9a..b63593f 100644 --- a/jet_tracking/gui/widgets/simControlWidgetUi.py +++ b/jet_tracking/gui/widgets/simControlWidgetUi.py @@ -1,5 +1,5 @@ from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QSlider, QSizePolicy, QButtonGroup, QPushButton -from gui.widgets.basicWidgets import QRangeSlider, Label, LineEdit, ComboBox +from gui.widgets.basicWidgets import CollapsibleBox, QRangeSlider, Label, LineEdit, ComboBox class Sim_Ui(object): @@ -11,6 +11,11 @@ def setupUi(self, obj): obj.layout = QVBoxLayout() obj.setLayout(obj.layout) +# obj.box_jet = CollapsibleBox("Jet and Motor Controls") +# obj.layout.addWidget(obj.box_jet) + obj.lbl_jet = Label("Jet and Motor Controls") + obj.lbl_jet.setTitleStylesheet() + obj.lbl_percent_drop = QLabel("Dropped Shots (%)") obj.box_percent_drop = LineEdit("10") obj.box_percent_drop.valRange(0, 100) @@ -33,10 +38,36 @@ def setupUi(self, obj): obj.box_bg = LineEdit("0.05") obj.box_bg.valRange(0, 1) +# obj.box_search = CollapsibleBox("Search Controls") +# obj.layout.addWidget(obj.box_search) + obj.lbl_search = Label("Search Controls") + obj.lbl_search.setTitleStylesheet() + + obj.lbl_ave_time = QLabel("Averaging Time (s)") + obj.box_ave_time = LineEdit("1") + obj.box_ave_time.valRange(0.01, 100) + obj.lbl_left = QLabel("Left Bound (mm)") + obj.box_left = LineEdit("-0.1") + obj.box_left.valRange(-100, 100) + obj.lbl_right = QLabel("Right Bound (mm)") + obj.box_right = LineEdit("0.1") + obj.box_right.valRange(-100, 100) + obj.lbl_step = QLabel("Motor Step (mm)") + obj.box_step = LineEdit("0.005") + obj.box_step.valRange(0.001, 1) + obj.lbl_sim_tol = QLabel("Convergence Tolerance (mm)") + obj.box_sim_tol = LineEdit("0.001") + obj.box_sim_tol.valRange(0.0001, 1) + obj.lbl_thresh = QLabel("Tracking Threshold (% max)") + obj.box_thresh = LineEdit("90") + obj.box_thresh.valRange(1, 99) + obj.lbl_wait = QLabel("Wait Time (s)") + obj.box_wait = LineEdit("5") + obj.box_wait.valRange(0.01, 100) obj.cbox_sim_algorithm = ComboBox() obj.cbox_sim_algorithm.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - obj.cbox_sim_algorithm.addItem("Ternary Search") obj.cbox_sim_algorithm.addItem("Linear Scan") + obj.cbox_sim_algorithm.addItem("Ternary Search") obj.bttn_start_tracking = QPushButton("Start Tracking") obj.bttn_start_tracking.setStyleSheet("\ background-color: green;\ @@ -47,6 +78,11 @@ def setupUi(self, obj): background-color: red;\ font-size:16px;\ ") + obj.bttn_search = QPushButton("Search") + obj.bttn_search.setStyleSheet("\ + background-color: yellow;\ + font-size:16px;\ + ") obj.layout_percent_drop = QHBoxLayout() obj.layout_percent_drop.addWidget(obj.lbl_percent_drop, 75) @@ -70,13 +106,41 @@ def setupUi(self, obj): obj.layout_bg.addWidget(obj.lbl_bg, 75) obj.layout_bg.addWidget(obj.box_bg) + +# obj.box_jet.setContentLayout(obj.layout) + + obj.layout_ave_time = QHBoxLayout() + obj.layout_ave_time.addWidget(obj.lbl_ave_time, 75) + obj.layout_ave_time.addWidget(obj.box_ave_time) + obj.layout_left = QHBoxLayout() + obj.layout_left.addWidget(obj.lbl_left, 75) + obj.layout_left.addWidget(obj.box_left) + obj.layout_right = QHBoxLayout() + obj.layout_right.addWidget(obj.lbl_right, 75) + obj.layout_right.addWidget(obj.box_right) + obj.layout_step = QHBoxLayout() + obj.layout_step.addWidget(obj.lbl_step, 75) + obj.layout_step.addWidget(obj.box_step) + obj.layout_sim_tol = QHBoxLayout() + obj.layout_sim_tol.addWidget(obj.lbl_sim_tol, 75) + obj.layout_sim_tol.addWidget(obj.box_sim_tol) + obj.layout_thresh = QHBoxLayout() + obj.layout_thresh.addWidget(obj.lbl_thresh, 75) + obj.layout_thresh.addWidget(obj.box_thresh) + obj.layout_wait = QHBoxLayout() + obj.layout_wait.addWidget(obj.lbl_wait, 75) + obj.layout_wait.addWidget(obj.box_wait) + obj.layout_algorithm = QHBoxLayout() obj.layout_algorithm.addWidget(obj.cbox_sim_algorithm) obj.layout_start = QHBoxLayout() obj.layout_start.addWidget(obj.bttn_start_tracking) obj.layout_stop = QHBoxLayout() obj.layout_stop.addWidget(obj.bttn_stop_tracking) + obj.layout_search = QHBoxLayout() + obj.layout_search.addWidget(obj.bttn_search) + obj.layout.addWidget(obj.lbl_jet) obj.layout.addLayout(obj.layout_percent_drop) obj.layout.addLayout(obj.layout_int) obj.layout.addLayout(obj.layout_motor_pos) @@ -84,7 +148,15 @@ def setupUi(self, obj): obj.layout.addLayout(obj.layout_jet_center) obj.layout.addLayout(obj.layout_max_int) obj.layout.addLayout(obj.layout_bg) - + obj.layout.addWidget(obj.lbl_search) + obj.layout.addLayout(obj.layout_ave_time) + obj.layout.addLayout(obj.layout_left) + obj.layout.addLayout(obj.layout_right) + obj.layout.addLayout(obj.layout_step) + obj.layout.addLayout(obj.layout_sim_tol) + obj.layout.addLayout(obj.layout_thresh) + obj.layout.addLayout(obj.layout_wait) obj.layout.addLayout(obj.layout_algorithm) obj.layout.addLayout(obj.layout_start) - obj.layout.addLayout(obj.layout_stop) \ No newline at end of file + obj.layout.addLayout(obj.layout_stop) + obj.layout.addLayout(obj.layout_search) diff --git a/jet_tracking/signals.py b/jet_tracking/signals.py index 213e326..a0266c2 100644 --- a/jet_tracking/signals.py +++ b/jet_tracking/signals.py @@ -106,3 +106,36 @@ class Signals(QtCore.QObject): # emit in editorWidget # connect in jetImageWidget updateImage = QtCore.pyqtSignal(np.ndarray) + # emit in context + # connect in sim_motorMoving + enableSimTracking = QtCore.pyqtSignal(bool) + # emit in context + # connect in sim_motorMoving + changeSimAlgorithm = QtCore.pyqtSignal(str) + # emit in context + # connect in sim_motorMoving + changeRatio = QtCore.pyqtSignal(float) + # emit in context + # connect in sim_motorMoving + changeDropped = QtCore.pyqtSignal(bool) + # emit in context + # connect in SimControlWidget + changeAverageTime = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeLeft = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeRight = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeStep = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeSimTol = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeThresh = QtCore.pyqtSignal(float) + # emit in context + # connect in SimControlWidget + changeWait = QtCore.pyqtSignal(float) diff --git a/jet_tracking/sketch/num_gen.py b/jet_tracking/sketch/num_gen.py index 016cb1e..7aa0de6 100644 --- a/jet_tracking/sketch/num_gen.py +++ b/jet_tracking/sketch/num_gen.py @@ -33,58 +33,12 @@ def __init__(self, context, signals): self.max = 10 self.bg = 0.05 self.percent = 0 - # get current simulated motor position - self.signals.update.connect(self.updateVals) - self.signals.changeMotorPosition.connect(self.change_motor) - self.signals.changeDroppedShots.connect(self.change_dropped) - self.signals.changePeakIntensity.connect(self.change_intensity) - self.signals.changeJetRadius.connect(self.change_radius) - self.signals.changeJetCenter.connect(self.change_center) - self.signals.changeMaxIntensity.connect(self.change_max) - self.signals.changeBackground.connect(self.change_noise) - - def change_motor(self, motor_position): - self.motor_position = motor_position - - def change_dropped(self, percent_dropped): - self.percent_dropped = percent_dropped - - def change_intensity(self, peak_intensity): - self.peak_intensity = peak_intensity - - def change_radius(self, radius): - self.radius = radius - - def change_center(self, center): - self.center = center - - def change_max(self, maxi): - self.max = maxi - - def change_noise(self, bg): - self.bg = bg - - def updateVals(self, name, vals): - if name == "percent": - self.percent_dropped = vals - elif name == "peak": - self.peak_intensity = vals - elif name == "motor_position": - self.motor_position = vals - elif name == "radius": - self.radius = vals - elif name == "center": - self.center = vals - elif name == "max": - self.max = vals - elif name == "background": - self.bg = vals def sim(self): val = {} - val["i0"] = self.peak_intensity - val["diff"] = self.max + val["i0"] = self.context.peak_intensity + val["diff"] = self.context.max val["ratio"] = 1 val["dropped"] = False @@ -92,29 +46,31 @@ def sim(self): # dropped shots. for input percentage of shots, 0 is returned for the scattering intensity b = random.random() c = random.random() - self.percent = self.percent_dropped/100 + self.percent = self.context.percent_dropped/100 # dropped shots if b < self.percent: # val["diff"] = 0 val["dropped"] = True - val["diff"] = (self.bg / 10) * (1 + (a - 0.5)) - val["i0"] = self.bg * (1 + (c - 0.5)) + val["diff"] = (self.context.bg / 10) * (1 + (a - 0.5)) + val["i0"] = self.context.bg * (1 + (c - 0.5)) # on jet else: # calculates length of chord of a circle if on jet or sets diff to 0 (plus noise) if off jet - if abs(self.motor_position - self.center) < self.radius: - val["diff"] = self.max * ((2 * math.sqrt(self.radius ** 2 - abs(self.motor_position - self.center) ** 2)) / (2 * self.radius)) * ( - 1 + self.bg * (a - 0.5)) + if abs(self.context.motor_position - self.context.center) < self.context.radius: + val["diff"] = self.context.max * ((2 * math.sqrt(self.context.radius ** 2 - abs(self.context.motor_position - self.context.center) ** 2)) / (2 * self.context.radius)) * ( + 1 + self.context.bg * (a - 0.5)) val["dropped"] = False - val["i0"] = self.peak_intensity * 1 + self.bg * (c - 0.5) + val["i0"] = self.context.peak_intensity * 1 + self.context.bg * (c - 0.5) -#off jet +# off jet else: - val["diff"] = self.bg * (1 + (a - 0.5)) + val["diff"] = self.context.bg * (1 + (a - 0.5)) val["dropped"] = False - val["i0"] = self.peak_intensity * 1 + self.bg * (c - 0.5) + val["i0"] = self.context.peak_intensity * 1 + self.context.bg * (c - 0.5) val["ratio"] = val["diff"] / val["i0"] + self.context.update_ratio(val["ratio"]) + self.context.update_dropped(val["dropped"]) return val diff --git a/jet_tracking/sketch/sim_motorMoving.py b/jet_tracking/sketch/sim_motorMoving.py index b3bcf13..30dd61d 100644 --- a/jet_tracking/sketch/sim_motorMoving.py +++ b/jet_tracking/sketch/sim_motorMoving.py @@ -4,10 +4,14 @@ import matplotlib.pyplot as plt import time import logging +from datastream import ValueReader +from PyQt5.QtCore import QThread +import threading log = logging.getLogger(__name__) -class SimulatedMotor(object) + +class SimulatedMotor(object): def __init__(self, context, signals): @@ -16,50 +20,149 @@ def __init__(self, context, signals): self.signals = signals self.motor_position = 0 self.i0 = 0 - self.i0_ave = 0 + self.ratio = 0 + self.ratio_ave = 0 + self.ratio_pt = [] + self.positions = [] + self.max_ratio = 0 + self.index_max = 0 + self.max_motor = 0 + self.motor_initial = 0 + self.ratio_initial = 0 + self.t = 0 + self.ratios = [] self.left = -0.1 self.right = 0.1 self.step = 0.01 self.wait = 5 + self.sim_thresh = 90 + self.thresh = 90 + self.sim_algorithm = "Linear Scan" # get current simulated motor position # self.signals.update.connect(self.updateVals) self.signals.changeMotorPosition.connect(self.change_motor) + self.signals.changeSimAlgorithm.connect(self.change_algorithm) # self.make_connections() -# self.set_sim_options() -# -# def set_sim_options(self): -# self.context.update_motor_position(float(self.motor_position)) -# -# def make_connections(self): -# self.box_motor_pos.checkVal.connect(self.context.update_motor_position) + self.set_sim_options() + + def set_sim_options(self): + self.context.update_motor_position(float(self.motor_position)) + self.context.update_sim_algorithm(str(self.sim_algorithm)) def change_motor(self, motor_position): self.motor_position = motor_position - def average_intensity(self, nsamp): - i0 = [] - for i in range(nsamp): - i0.append(self.ratio.get()) - time.sleep(1 / 15) - return statistics.mean(i0) + def change_algorithm(self, al): + self.sim_algorithm = al + + def average_intensity(self, context): + self.t = 0 + self.ave_time = self.context.ave_time * 10 + while self.t < self.ave_time: + if context.dropped is False: + self.ratio_pt = [] + self.ratio_pt.append(context.ratio) + time.sleep(1 / 10) + self.t += 1 + else: + time.sleep(1 / 10) + pass + return statistics.mean(self.ratio_pt) + def _start(self): + self.sim_algorithm = self.context.sim_algorithm + if self.sim_algorithm == "Linear Scan": + self.sim_linear(self.context) + elif self.sim_algorithm == "Ternary Search": + self.sim_ternary(self.context) - def sim_linear(self): + def sim_linear(self, context): + self.left = self.context.left + self.right = self.context.right + self.motor_initial = self.context.motor_position + self.ratio_initial = self.average_intensity(context) self.motor_position = self.left - self.i0_pt = [] + self.ratio_pt = [] + self.t = 0 + self.left = -0.1 + self.right = 0.1 + self.ratios = [] + self.positions = [] + self.max_ratio = 0 + self.index_max = 0 + self.max_motor = 0 while self.motor_position <= self.right: - while t < - self.i0_pt.append(self.i0.get()) - self.i0_ave = + self.ratio_ave = self.average_intensity(context) + self.ratios.append(self.ratio_ave) + self.positions.append(self.motor_position) + self.motor_position += self.context.step + self.context.update_motor_position(self.motor_position) + print('motor position', self.motor_position) + self.max_ratio = max(self.ratios) + self.index_max = self.ratios.index(self.max_ratio) + self.max_motor = self.positions[self.index_max] + if self.max_ratio >= self.ratio_initial: + self.context.update_motor_position(self.max_motor) + else: + self.context.update_motor_position(self.motor_initial) + print("search done") + + def sim_ternary(self, context): + self.left = self.context.left * 3 + self.right = self.context.right * 3 + self.left_third = 0 + self.right_third = 0 + self.tol = self.context.sim_tol + self.motor_position = context.motor_position + self.ratio_left = 0 + self.ratio_right = 0 + self.center = 0 + while abs(self.left - self.right) >= self.tol: + self.left_third = self.left + (self.right - self.left) / 3 + self.motor_position = self.left_third + self.context.update_motor_position(self.motor_position) + self.ratio_left = self.average_intensity(context) + self.right_third = self.right - (self.right - self.left) / 3 + self.motor_position = self.right_third + self.context.update_motor_position(self.motor_position) + self.ratio_right = self.average_intensity(context) + if self.ratio_left < self.ratio_right: + self.left = self.left_third + else: + self.right = self.right_third + self.motor_position = (self.right + self.left) / 2 + self.context.update_motor_position(self.motor_position) + print("search done") + + def sim_golden_section(self): + print("golden section search") + + def sim_coarse_fine(self): + print("coarse then fine linear scan") + + def sim_coarse_ternary(self): + print("coarse linear scan then ternary search") + def sim_ternary_variable(self): + print("ternary search with narrowing window") - def sim_ternary(self): - print("ternary search") + def sim_tracking(self): + self.track(self.context) + def track(self, context): + self.sim_thresh = self.context.thresh / 100 + self.low = self.sim_thresh * self.context.calibration_values['ratio']['mean'] + self.ratio_ave = 1 + while context.simTracking is True: + time.sleep(self.context.wait) + self.ratio_ave = self.average_intensity(context) +# print(self.ratio_ave) + if self.ratio_ave < self.low: + print("starting search") + self._start() + else: + time.sleep(1) + self.ratio_ave = self.average_intensity(context) - def sim_test(self): - print("you are now tracking") - time.sleep(5) - self.motor_position = 0.03