def read(self): self.init() data_arr = numpy.zeros(self.io_length, uInt8) samples_per_chan = int32() num_bytes_per_sample = int32() DAQmxReadDigitalLines(self.task, 1, # Samples per channel 2.0, # Timeout DAQmx_Val_GroupByScanNumber, # Interleaved data_arr, len(data_arr), byref(samples_per_chan), byref(num_bytes_per_sample), None) return data_arr
def setupNICard(self): ## create the NI task that reads data from the NI card. #self.taskHandle = TaskHandle() #DAQmxCreateTask("pyEnvDAQ",byref(self.taskHandle)) ## (see http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxcreatetask/ ) ##[DAQmxCreateAIVoltageChan(self.taskHandle, "Dev1/ai"+str(self.channelAddresses[i]), self.channelNames[i+1], DAQmx_Val_Cfg_Default, int(self.channelMins[i+1]), \ ## int(self.channelMaxes[i+1]), DAQmx_Val_Volts, None) for i in range(self.numOfRecordedChannels)] # we use i+1 instead of i to skip the time channel ##print("numOfNIChannels: ",self.numOfNIChannels) #channelIndices = ["Dev1/ai"+str(self.channelIndex[i]) for i in range(self.numOfNIChannels)] # note that this also contains the time channel ##[print("channel index: ",channelIndices[i]," name: ",self.channelNames[i]," min ",int(self.channelMins[i]), \ ## "max ",int(self.channelMaxes[i]),"\n") for i in range(1,self.numOfNIChannels)] #[DAQmxCreateAIVoltageChan(self.taskHandle, channelIndices[i], self.channelNames[i], DAQmx_Val_Cfg_Default, int(self.channelMins[i]), \ # int(self.channelMaxes[i]), DAQmx_Val_Volts, None) for i in range(1,self.numOfNIChannels)] # we start from 1 to skip the time channel # #DAQmxCfgSampClkTiming(self.taskHandle,"",1/self.MEASUREMENT_PERIOD_s,DAQmx_Val_Rising,DAQmx_Val_ContSamps,self.numOfNIChannels-1) # -1 because we don't actually record the time channel ## (see http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxcfgsampclktiming/ ) ## #try: # DAQmxStartTask(self.taskHandle) #except DAQError: # self.printError("execution of DAQmxStartTask failed - THe-Monitor is probably on \"Run\". Try \"Pause\"ing it and restarting PyEnvDAQ.") self.taskHandle = TaskHandle() #DAQmxLoadTask("enviroment_measurement",byref(self.taskHandle)) DAQmxLoadTask("PyEnvDAQTask", byref(self.taskHandle)) DAQmxStartTask(self.taskHandle)
def init(self): if self.task_state == "": self.task = TaskHandle() DAQmxCreateTask(b"", byref(self.task)) DAQmxCreateDOChan(self.task, self.task_string, b"", DAQmx_Val_ChanPerLine) self.task_state = "init"
def _read(self): try: DAQmxReadCounterScalarF64(self.task, float64(self._thread_timeout), byref(self._data), None) except Exception as e: self._error_queue.put(ThreadError(e)) return
def init(self): if self.task_state == "": self.task = TaskHandle() DAQmxCreateTask(b"", byref(self.task)) DAQmxCreateDIChan(self.task, self.task_string, b"", DAQmx_Val_ChanPerLine) self.task_state = "init" if self.task_state in ["init", "stopped"]: self.start()
def finish_count(pulse, ctr): """ finish counting events and return the result. """ # initialize memory for readout count = uInt32() # wait for pulse to be done pulse.WaitUntilTaskDone(10.) # timeout, ref to output value, reserved ctr.ReadCounterScalarU32(10., byref(count), None) pulse.StopTask() ctr.StopTask() return count.value
def port_supports_buffered(device_name, port, clock_terminal=None): """Empirically determines if the digital port supports buffered output. Args: device_name (str): NI-MAX device name port (int): Which port to intro-spect clock_terminal (str, optional): String that specifies the clock terminal. Returns: bool: True if `port` supports buffered output. """ all_terminals = DAQmxGetDevTerminals(device_name) if clock_terminal is None: clock_terminal = all_terminals[0] npts = 16 task = Task() clock_terminal_full = '/' + device_name + '/' + clock_terminal data = np.zeros(npts, dtype=np.uint32) task.CreateDOChan(device_name + "/" + port, "", c.DAQmx_Val_ChanForAllLines) task.CfgSampClkTiming( clock_terminal_full, 100, c.DAQmx_Val_Rising, c.DAQmx_Val_FiniteSamps, npts ) written = int32() try: task.WriteDigitalU32( npts, False, 10.0, c.DAQmx_Val_GroupByScanNumber, data, byref(written), None ) except ( PyDAQmx.DAQmxFunctions.BufferedOperationsNotSupportedOnSelectedLinesError, PyDAQmx.DAQmxFunctions.PhysicalChanNotSupportedGivenSampTimingType653xError, ): return False except ( PyDAQmx.DAQmxFunctions.CantUsePort3AloneGivenSampTimingTypeOn653xError, PyDAQmx.DAQmxFunctions.CantUsePort1AloneGivenSampTimingTypeOn653xError, ): # Ports that throw this error on 653x devices do support buffered output, though # there are requirements that multiple ports be used together. return True except PyDAQmx.DAQmxFunctions.RouteNotSupportedByHW_RoutingError: # Try again with a different terminal current_terminal_index = all_terminals.index(clock_terminal) if current_terminal_index == len(all_terminals) - 1: # There are no more terminals. No terminals can be used as clocks, # therefore we cannot do externally clocked buffered output. return False next_terminal_to_try = all_terminals[current_terminal_index + 1] return port_supports_buffered(device_name, port, next_terminal_to_try) else: return True finally: task.ClearTask()
def wrapped(name): import warnings with warnings.catch_warnings(): # PyDAQmx warns about a positive return value, but actually this is how you # are supposed to figure out the size of the array required. warnings.simplefilter("ignore") # Pass in null pointer and 0 len to ask for what array size is needed: npts = func(name, byref(float64()), 0) # Create that array result = (float64 * npts)() func(name, result, npts) result = [result[i] for i in range(npts)] return result
def init(self): if self.task_state == "": self.task = TaskHandle() DAQmxCreateTask(b"", byref(self.task)) DAQmxCreateCITwoEdgeSepChan(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), b"", float64(self.min_val), float64(self.max_val), DAQmx_Val_Seconds, self.first_edge_type, self.second_edge_type, b"") if self.source_terminal: tmp_data = c_char_p(self.source_terminal.encode()) DAQmxSetCITwoEdgeSepFirstTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), tmp_data) if self.validate_terminals: tmp_data = c_char_p("".encode()) DAQmxGetCITwoEdgeSepFirstTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), tmp_data, uInt32(16)) if self.destination_terminal not in tmp_data.value.decode('utf-8'): raise InstrumentError( "Destination terminal is set to {}, should be /{}/{}".format(tmp_data.value.decode('utf-8'), self.device_name, self.destination_terminal)) if self.destination_terminal: tmp_data = c_char_p(self.destination_terminal.encode()) DAQmxSetCITwoEdgeSepSecondTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), tmp_data) if self.validate_terminals: tmp_data = c_char_p("".encode()) DAQmxGetCITwoEdgeSepSecondTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), tmp_data, uInt32(16)) if self.destination_terminal not in tmp_data.value.decode('utf-8'): raise InstrumentError( "Destination terminal is set to {}, should be /{}/{}".format(tmp_data.value.decode('utf-8'), self.device_name, self.destination_terminal)) self.task_state = "init"
def wrapped(name): result = float64() func(name, byref(result)) return result.value
def wrapped(name): result = int32() func(name, byref(result)) return result.value
def wrapped(name): result = bool32() func(name, byref(result)) return bool(result.value)
def _read(self): self.init() return DAQmxReadCounterScalarF64(self.task, float64(10), byref(self._data), None)
def measure(self): """ Acquire once using the created task. """ if len(self.data.cols) == 0: return BaseDriver.measure(self) ### measure ########################################################### # unpack inputs ------------------------------------------------------- self.running = True #self.update_ui.emit() if not self.task_created: return start_time = time.time() # collect samples array ----------------------------------------------- try: self.thread self.read = int32() if True: DAQmxStartTask(self.task_handle) DAQmxReadAnalogF64(self.task_handle, # task handle int(self.shots), # number of samples per channel 10.0, # timeout (seconds) for each read operation DAQmx_Val_GroupByScanNumber, # fill mode (specifies whether or not the samples are interleaved) self.samples, # read array self.samples_len, # size of the array, in samples, into which samples are read byref(self.read), # reference of thread None) # reserved by NI, pass NULL (?) DAQmxStopTask(self.task_handle) else: self.samples = np.random.normal(size=self.samples_len) except DAQError as err: print("DAQmx Error: %s"%err) g.logger.log('error', 'Error in timing definition', err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) # export samples samples.write(self.samples) ### process ########################################################### # calculate shot values for each channel, chopper --------------------- active_channels = [channel for channel in channels.read() if channel.active.read()] active_choppers = [chopper for chopper in choppers.read() if chopper.active.read()] shots_array = np.full((len(active_channels)+len(active_choppers), int(self.shots)), np.nan) folded_samples = self.samples.copy().reshape((nsamples.read(), -1), order='F') index = 0 # channels for channel_index, channel in enumerate(active_channels): # get signal points signal_index_possibilities = range(int(channel.signal_start_index.read()), int(channel.signal_stop_index.read()) + 1) signal_indicies = [i for i in signal_index_possibilities if sample_correspondances.read()[i] == channel_index + 1] signal_indicies = signal_indicies[int(channel.signal_pre_index.read()):] # remove pre points signal_samples = folded_samples[signal_indicies] # process signal if channel.signal_method.read() == 'Average': signal = np.mean(signal_samples, axis=0) elif channel.signal_method.read() == 'Sum': signal = np.sum(signal_samples, axis=0) elif channel.signal_method.read() == 'Min': signal = np.min(signal_samples, axis=0) elif channel.signal_method.read() == 'Max': signal = np.max(signal_samples, axis=0) # baseline if channel.use_baseline.read(): # get baseline points baseline_index_possibilities = range(int(channel.baseline_start_index.read()), int(channel.baseline_stop_index.read()) + 1) baseline_indicies = [i for i in baseline_index_possibilities if sample_correspondances.read()[i] == channel_index + 1] baseline_indicies = baseline_indicies[int(channel.baseline_pre_index.read()):] # remove pre points baseline_samples = folded_samples[baseline_indicies] # process baseline if channel.baseline_method.read() == 'Average': baseline = np.mean(baseline_samples, axis=0) elif channel.baseline_method.read() == 'Sum': baseline = np.sum(baseline_samples, axis=0) elif channel.baseline_method.read() == 'Min': baseline = np.min(baseline_samples, axis=0) elif channel.baseline_method.read() == 'Max': baseline = np.max(baseline_samples, axis=0) else: baseline = 0 out = signal - baseline # invert if channel.invert.read(): out *= -1 # finish shots_array[index] = out index += 1 # choppers for chopper in active_choppers: cutoff = 1. # volts out = folded_samples[int(chopper.index.read())] out[out<=cutoff] = -1. out[out>cutoff] = 1. if chopper.invert.read(): out *= -1 shots_array[index] = out index += 1 # export shots channel_names = [channel.name.read() for channel in active_channels] chopper_names = [chopper.name.read() for chopper in active_choppers] shots.write(shots_array) # TODO: can I remove this? shots.write_properties((1,), channel_names+chopper_names, shots_array) # do math ------------------------------------------------------------- # pass through shots processing module with self.processing_timer: path = shots_processing_module_path.read() name = os.path.basename(path).split('.')[0] directory = os.path.dirname(path) f, p, d = imp.find_module(name, [directory]) processing_module = imp.load_module(name, f, p, d) kinds = ['channel' for _ in channel_names] + ['chopper' for _ in chopper_names] names = channel_names + chopper_names out = processing_module.process(shots_array, names, kinds) if len(out) == 3: out, out_names, out_signed = out else: out, out_names = out out_signed = False seconds_for_shots_processing.write(self.processing_timer.interval) # export last data self.data.write_properties((1,), out_names, out, out_signed) self.update_ui.emit() ### finish ############################################################ seconds_since_last_task.write(time.time() - self.previous_time) self.previous_time = time.time() self.running = False stop_time = time.time() seconds_for_acquisition.write(stop_time - start_time) self.measure_time.write(seconds_for_acquisition.read())
def create_task(self): ''' Define a new DAQ task. This needs to be run once every time the parameters of the aquisition (channel correspondance, shots, etc.) change. No inputs ''' # ensure previous task closed ----------------------------------------- if self.task_created: DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) self.task_created = False # import -------------------------------------------------------------- self.shots = nshots.read() # calculate the number of 'virtual samples' to take ------------------- self.virtual_samples = nsamples.read() # create task --------------------------------------------------------- try: self.task_handle = TaskHandle() self.read = int32() # ??? --BJT 2017-06-03 DAQmxCreateTask('', byref(self.task_handle)) except DAQError as err: print("DAQmx Error: %s"%err) g.logger.log('error', 'Error in task creation', err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # initialize channels ------------------------------------------------- # The daq is addressed in a somewhat non-standard way. A total of ~1000 # virtual channels are initialized (depends on DAQ speed and laser rep # rate). These virtual channels are evenly distributed over the physical # channels addressed by the software. When the task is run, it round # robins over all the virtual channels, essentially oversampling the # analog physical channels. # # self.virtual_samples contains the oversampling factor. # # Each virtual channel must have a unique name. # # The sample clock is supplied by the laser output trigger. # name_index = 0 # something to keep channel names unique try: # sample correspondances holds an array of integers # zero : rest sample # positive : channel # negative : chopper for correspondance in sample_correspondances.read(): if correspondance == 0: physical_channel = rest_channel.read() min_voltage = -10. max_voltage = 10. elif correspondance > 0: channel = channels.read()[correspondance-1] physical_channel = channel.physical_correspondance.read() min_voltage, max_voltage = channel.get_range() elif correspondance < 0: physical_channel = choppers.read()[-correspondance-1].physical_correspondance.read() min_voltage = -10. max_voltage = 10. channel_name = 'sample_' + str(name_index).zfill(3) DAQmxCreateAIVoltageChan(self.task_handle, # task handle DAQ_device_name + '/ai%i'%physical_channel, # physical chanel channel_name, # name to assign to channel DAQmx_Val_Diff, # the input terminal configuration min_voltage, max_voltage, # minVal, maxVal DAQmx_Val_Volts, # units None) # custom scale name_index += 1 except DAQError as err: print("DAQmx Error: %s"%err) g.logger.log('error', 'Error in virtual channel creation', err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # define timing ------------------------------------------------------- try: DAQmxCfgSampClkTiming(self.task_handle, # task handle '/' + DAQ_device_name + '/PFI0', # sorce terminal 1000.0, # sampling rate (samples per second per channel) (float 64) (in externally clocked mode, only used to initialize buffer) DAQmx_Val_Rising, # acquire samples on the rising edges of the sample clock DAQmx_Val_FiniteSamps, # acquire a finite number of samples int(self.shots)) # samples per channel to acquire (unsigned integer 64) except DAQError as err: print("DAQmx Error: %s"%err) g.logger.log('error', 'Error in timing definition', err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # create arrays for task to fill -------------------------------------- self.samples = np.zeros(int(self.shots*nsamples.read()), dtype=np.float64) self.samples_len = len(self.samples) # do not want to call for every acquisition # finish -------------------------------------------------------------- self.task_created = True self.task_changed.emit()
def readEnvData(self): print("started readEnvData \n" ) # commenting this out stops the program from working. why? dataForTable = zeros( self.numOfChannels + 1, dtype=float64 ) # this will hold the data to update the table with. (+1 to include the time channel) # setup NI card-related parameters dataNI = zeros( (self.numOfNIChannels, ), dtype=float64 ) # this will hold the data gathered in a single measurement. -1 because we don't record the time. timeOut = 10 # 10s timeout limit? read = int32() # the type of data read is 32int? session = requests.Session() session.trust_env = False while self.isRunning == True: # retrieve the data from the MSC box (which is saved after the data from the NI card) # setup MCS box-related parameters res = session.get( 'http://tritium-remotemcs/cgi-bin/volt.cgi' ) # we also get something if we replace "volt" with "temp", but I don't get the values there content = str( res.content, "windows-1252") # get the whole HTML code for that page content = content[ 419:] # delete some bullshit before the first value content = content.replace( "</td><td>", "," ) # separate the values with commas instead of with bullshit content = content.replace( "</td></tr></table><br><table border=1><colgroup width=200 span=4></colgroup><tr><td><b>channel 5</b>,<b>channel 6</b>,<b>channel 7</b>,<b>channel 8</b></td></tr><tr><td>", ",") # remove bullshit content = content[:-22] # get rid of some last bullshit content = content.split(",") dataMCS = [int(i, 16) for i in content ] # convert the data from hexadecimal to decimal format # (note that there are 8 values here but we only save the first 4 cause we don't know what the other 4 are for) # retrieve data from NI card's channels. # see http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxreadanalogf64/ try: DAQmxReadAnalogF64(self.taskHandle, 1, timeOut, 0, dataNI, self.numOfNIChannels, byref(read), None) except DAQError as err: self.printError( "execution of DAQmxReadAnalogF64 failed. Maybe THe-Monitor is running? If so \"Pause\" it and try again." ) self.pauseMeasurement() else: # this is only executed if no DAQError was raised during execution of the code in the "try:" block # self.checkForWarnings(dataNI) # check if some of the values are suspicious and should be reported timestamp = round(time()) # the time in units of s # save the flow data self.previousHeFlowMeterValue = self.currentHeFlowMeterValue self.previousN2FlowMeterValue = self.currentN2FlowMeterValue self.currentHeFlowMeterValue = dataNI[ self.HE_FLOW_METER_CHANNEL_INDEX] self.currentN2FlowMeterValue = dataNI[ self.N2_FLOW_METER_CHANNEL_INDEX] self.currentDataTimeStamp = timestamp # get MKS flow data# #resultMKSflow = self.clientMKSflow.read_input_registers(0x0001, 2) #i1MKSflow = resultMKSflow.registers[0] #i2MKSflow = resultMKSflow.registers[1] #dataMKSflow = struct.unpack('l',struct.pack('<HH',i1MKSflow,i2MKSflow))[0]/10000 dataMKSflow = 0 # merge the data from the NI card and from the MCS box data = [] for blah in dataNI: data.append(blah) for j in range(self.numOfMCSChannels): data.append(dataMCS[j]) data.append(dataMKSflow) # data = append(dataNI,dataMCS) # data = append(data,dataMKSflow) dataForTable[0] = timestamp for j in range(self.numOfChannels): dataForTable[j + 1] = data[ j] # +1 to skip [0] which holds the time channel dataPrecisionFormat = "{0:." + str(self.DATA_PRECISION) + "f}" writeMeIntoFile = str(timestamp) + "\t" + "\t".join([ dataPrecisionFormat.format(data[j]) for j in range(self.numOfChannels) ]) + "\n" # writeMeIntoFile = str(timestamp)+"\t" + "\t".join([str(data[j]) for j in range(self.numOfNIChannels-1+self.numOfMCSChannels)]) +"\n" # (note that we save up to DATA_PRECISION=4 digits after the decimal point instead of 6 like in the original program) self.comDataRecording.signalNewData.emit( dataForTable, writeMeIntoFile ) # emit a signal in order to trigger updatePyEnvFileAndGUI # (see http://stackoverflow.com/questions/7127075/what-exactly-the-pythons-file-flush-is-doing ) sleep( self.MEASUREMENT_PERIOD_s - 0.1 ) # read at a higher rate than the card's to make sure the buffer is cleared