@@ -68,8 +68,14 @@ def __init__(self, microscope_name, device_connection, configuration: Dict[str,
6868
6969 Parameters
7070 ----------
71+ microscope_name : str
72+ Name of the microscope.
73+ device_connection : Any
74+ Connection to the Tiger Controller.
7175 configuration : Dict[str, Any]
72- Configuration dictionary.
76+ Dictionary of configuration parameters.
77+ device_id : int
78+ Parameter necessary for start_device but not used here.
7379 """
7480 super ().__init__ (configuration )
7581
@@ -96,8 +102,10 @@ def __init__(self, microscope_name, device_connection, configuration: Dict[str,
96102
97103 #: str: microscope name
98104 self .microscope_name = microscope_name
105+
99106 #: str: zoom
100107 self .zoom = self .configuration ["experiment" ]["MicroscopeState" ]["zoom" ]
108+
101109 # retrieves galvo ListProxy/DictProxy from config file
102110 galvos_raw = self .configuration ["configuration" ]['microscopes' ][self .microscope_name ]['galvo' ]
103111
@@ -109,7 +117,7 @@ def __init__(self, microscope_name, device_connection, configuration: Dict[str,
109117 else :
110118 raise TypeError ("Unexpected type for galvos: {}" .format (type (galvos_raw )))
111119
112- # update analog outputs with galvo numbers and associated axes
120+ # update analog outputs with galvo IDs and associated axes
113121 i = 0
114122 for g in self .galvos :
115123 self .analog_outputs [f"galvo { i } " ] = g ['hardware' ]['axis' ]
@@ -119,17 +127,18 @@ def __init__(self, microscope_name, device_connection, configuration: Dict[str,
119127 self .phases = [
120128 galvo ["phase" ] for galvo in self .galvos
121129 ]
122- print ( self . phases )
130+
123131 # update analog outputs with rfvc and associated axis
124132 remote_focus_channel = self .configuration ["configuration" ]["microscopes" ][self .microscope_name ]["remote_focus" ]["hardware" ]["axis" ]
125133 self .analog_outputs ["remote_focus" ] = remote_focus_channel
126- # sets up initial PLC configuration with default delay (ms), sweep time (ms), and analog outputs dict
134+
135+ # sets up initial PLC configuration with default delay (ms), camera delay, rfvc delay, sweep time (ms), and analog outputs dict
127136 self .daq .setup_control_loop ([200 ], 0 , 0 , 120 , self .analog_outputs )
128137
129138
130139 @classmethod
131140 def connect (cls , port , baudrate = 115200 , timeout = 0.25 ):
132- """Build ASILaser Serial Port connection
141+ """Build ASIDaq Serial Port connection
133142
134143 Parameters
135144 ----------
@@ -153,129 +162,101 @@ def connect(cls, port, baudrate=115200, timeout=0.25):
153162 raise Exception ("ASI stage connection failed." )
154163 return tiger_controller
155164
156- def create_camera_task (self , channel_key : str ) -> None :
157- """
158- Set up the camera trigger pulse using ASI Tiger Controller.
165+ def prepare_acquisition (self , channel_key : str ) -> None :
166+ """Prepare the acquisition.
167+
168+ Creates and configures the DAQ tasks.
169+ Writes the waveforms to each task.
159170
160171 Parameters
161172 ----------
162173 channel_key : str
163174 Channel key for current channel.
164175 """
165- camera_waveform_repeat_num = self .waveform_repeat_num * self .waveform_expand_num
166-
167- if self .analog_outputs :
168- camera_high_time = 4 # ms
169- elif camera_waveform_repeat_num == 1 :
170- camera_high_time = (self .sweep_times [channel_key ] * 1000 ) - (self .camera_delay * 1000 )
171- else :
172- camera_high_time = (self .sweep_times [channel_key ] * 1000 ) - 4
173-
174- camera_delay_ms = int (self .camera_delay * 1000 )
175-
176- ttl_channel = int (self .configuration ["configuration" ]["microscopes" ][self .microscope_name ]["daq" ]["camera_trigger_out_line" ])
177-
178- try :
179- response = TigerController .send_ttl_pulse (
180- channel = ttl_channel ,
181- pulse_width_ms = int (camera_high_time ),
182- delay_ms = camera_delay_ms
183- )
184- logger .info (f"Sent TTL command to ASI: { response } " )
185- except Exception :
186- logger .exception ("Failed to send TTL command to ASI." )
187-
188- def prepare_acquisition (self , channel_key : str ) -> None :
189- # self.create_analog_output_tasks(channel_key)
190- # self.create_camera_task(channel_key)
191-
192- # Gets appropriate sweep_time for the current channel
176+ # Get appropriate sweep_time for the current channel
193177 sweep_time = self .sweep_times [channel_key ]
194178
195- # loops through galvo phases to calculate time delays
196- # delays[i] corresponds to the time between the triggering of the ith galvo and the master trigger
197- # delay between consecutive triggers must be greater than 175 ms (limitation of TG-1000)
179+ # loop through galvo phases to calculate time delays
180+ # delays[i] corresponds to the time between the ith galvo trigger and the master trigger
198181 n = len (self .galvos )
199182 i = 0
200183 delays = []
201184 for phase in self .phases :
202185 frequency = self .waveform_constants ["galvo_constants" ][f"Galvo { i } " ][self .microscope_name ][self .zoom ]["frequency" ]
203186 period = self .exposure_times [channel_key ]* 1000 / float (frequency )
204- # rounds period for triangle waveform to even number, as the TG-1000 can only generate triangle waveforms with even-number-of-ms periods
187+
188+ # round period for triangle waveform to even number, as the TG-1000 can only generate triangle waveforms with even-number-of-ms periods
205189 if self .galvos [i ]['waveform' ] == 'sawtooth' :
206190 rising_ramp = float (self .waveform_constants ["galvo_constants" ][f"Galvo { i } " ][self .microscope_name ][self .zoom ].get ("rising_ramp" , 50 ))
207191 if (rising_ramp == 50 ):
208192 period = 2 * round (period / 2 )
209- # rounds period to closest number of ms, as TG-1000 can only generate waveforms with whole number of ms periods
193+
194+ # round period to closest number of ms, as TG-1000 can only generate waveforms with whole-number-of-ms periods
210195 period = int (round (period ))
196+
197+ # save first period to sync control loop with first galvo
211198 if (i == 0 ):
212- period1 = period # saves first period to sync loop with first galvo
199+ period0 = period
200+
201+ # calculate time delay corresponding to phase offset
213202 t = period * phase / (2 * 3.14159265 )
214- # n39 = ((n-i)*0 + t) // period + 1
215203 delays .append (period * (n - i ) - t )
216204 i += 1
217- # modify sweep time to sync with first galvo if there are asi galvos in config
205+
206+ # modify sweep time to sync with the first galvo if there are asi galvos in config
218207 if (len (delays ) > 0 ):
219- n7 = 1000 * sweep_time // period1 + 1
220- sweep_time = period1 * n7
208+ n7 = 1000 * sweep_time // period0 + 1
209+ sweep_time = period0 * n7
221210
222211 self .camera_delay = (
223212 float (self .waveform_constants ["other_constants" ].get ("camera_delay" , 5 ))
224213 )
225214 rfvc_delay = (
226215 float (self .waveform_constants ["other_constants" ].get ("remote_focus_delay" , 5 ))
227216 )
228-
229- self .daq .setup_control_loop (delays , self .camera_delay , rfvc_delay , sweep_time , self .analog_outputs ) # delay (ms), sweep_time (ms)
217+ # sets up control loop with all parameters (all times in ms)
218+ self .daq .setup_control_loop (delays , self .camera_delay , rfvc_delay , sweep_time , self .analog_outputs )
230219
231220 self .current_channel_key = channel_key
232221 self .is_updating_analog_task = False
233222 # if self.wait_to_run_lock.locked():
234223 # self.wait_to_run_lock.release()
235224
236225 def run_acquisition (self ) -> None :
226+ """Run DAQ Acquisition.
237227
228+ Run the tasks for triggering, analog and counter outputs.
229+ The master trigger initiates all other waveforms via a shared trigger
230+ For this to work, all analog output and counter tasks have to be primed so that
231+ they are waiting for the trigger signal.
232+ """
238233 # if self.is_updating_analog_task:
239234 # self.wait_to_run_lock.acquire()
240235 # self.wait_to_run_lock.release()
241236
242- # try:
243- #send logic card on to cell 1
244- self .daq .logic_cell_on ("1" )
245- # self.daq.trigger_acquisition()
246- # except Exception:
247- # logger.debug("DAQ cannot turn on")
248- # pass
237+ # turn on PLC cell 1 (Master Trigger)
238+ try :
239+ self .daq .logic_cell_on ("1" )
240+ except Exception :
241+ logger .debug ("DAQ cannot turn on" )
242+ pass
249243
250244 def stop_acquisition (self ) -> None :
251- #send logic card off to cell 1
245+ """Stop Acquisition.
246+
247+ Stop control loop.
248+ """
249+ # turn on PLC cell 8 (kills control loop)
250+ # reset PLC cell 1 (Master Trigger)
252251 try :
253252 self .daq .logic_cell_on ("8" )
254- self .daq .logic_cell_off ("1" )
255- # self.daq.send_command("3 sam a = 0")
256- # self.daq.read_response()
257- # self.daq.send_command("3 sam c = 0")
258- # self.daq.read_response()
253+ self .daq .logic_cell_off ("1" )
259254 except Exception :
260255 logger .debug ("DAQ cannot turn off" )
261256 pass
262257
263258 # if self.wait_to_run_lock.locked():
264259 # self.wait_to_run_lock.release()
265260
266- # def create_analog_output_tasks(self, channel_key: str) -> None:
267- # galvo_channel = self.configuration["configuration"]["microscopes"][self.microscope_name]["galvo"][0]["hardware"]["axis"]
268- # if isinstance(galvo_channel, list):
269- # for channel in galvo_channel:
270- # self.analog_outputs.update({channel: "galvo"})
271- # self.galvo.move(self.exposure_times,self.sweep_times,offset=None)
272- # else:
273- # self.analog_outputs.update({galvo_channel: "galvo"})
274- # remote_focus_channel = self.configuration["configuration"]["microscopes"][self.microscope_name]["remote_focus"]["hardware"]["axis"]
275- # self.analog_outputs.update({remote_focus_channel: "remote_focus"})
276- # print(self.exposure_times)
277- # print(self.sweep_times)
278- # self.remote_focus.move(self.exposure_times, self.sweep_times)
279-
280261
281262
0 commit comments