def closeAllModbusConnections(self): '''Close all modbus connections listed in :attr: 'PDPList'. ''' self.disconnectedManually = True for i in range(len(self.PDPList)): self.PDPList[i].modbusConnectionClose() self.PDPList = [] self.ConnectionStatus.set(Timestamp(),5,False) try: print "Closed %r modbus connections at %s." %(i+1,Timestamp().to_string()) except NameError: print "There was no modbus connection at %s."%Timestamp().to_string()
def check_target(OVST, target, tmstmp=None, check=True): ''' :param tar: str or object of class Target if string: searches for the target in catalogue :param antennas: list list of antenna objects of class Antenna :param catalogue: Catalogue :param tmstmp: Timestamp :return: list with position tuples [(az1, el1), (az2, el2), ...] ''' antennas = OVST.active_antennas catalogue = OVST.Catalogue azel = [] if isinstance(target, Target): target = target elif isinstance( target, str ) and ',' in target: # Check if target has format: e.g. 'azel, 30, 60' target = Target(target) elif isinstance(target, str): target = catalogue[target] if not target: raise ValueError("Target not in Catalogue") if isinstance(tmstmp, str): if tmstmp and len(tmstmp) == 5: tmstmp += ':00' if tmstmp and len(tmstmp) == 8: tmstmp = str(datetime.now().date()) + ' ' + tmstmp if isinstance(tmstmp, (int, float)): tmstmp = Timestamp(tmstmp) if not tmstmp: tmstmp = Timestamp() for antenna in antennas: ae = target.azel(timestamp=tmstmp, antenna=antenna) azel.append([rad2deg(ae[0]), rad2deg(ae[1])]) az = [item[0] for item in azel] el = [item[1] for item in azel] if check: if all((OVST.az_limit[1] - 2 < i < OVST.az_limit[0] + 2 for i in az)) or all(i < OVST.el_limit[0] for i in el): raise LookupError( 'target cannot get focused at % s (target at azimuth %.2f and elevation %.2f).\n ' 'Allowed limits: az not in range of 150-173 and elevation > 25' % (tmstmp.local()[11:19], azel[0][0], azel[0][1])) return azel # format: [(az1, el1), (az2, el2), ...]
def writeTask( self, register, value, tmSp=None, ): '''Handles writing tasks. It is sorted intern by timestamp so that it keeps the correct order. params ------ register: The register which will be written. value: The value which is written in the register. tmSp: object of :class: 'Timestamp' It have to be a param because otherwise all commands of a method for instance :meth: 'moveIncrementalAdapter' get the same timestamp. As a result it is sorted by the register in which it writes and it is not a good idea to send first a move command and then set the distance. In less critical commands like :meth: 'enableTelescopes' the default can be used ''' if not isinstance(tmSp, Timestamp): tmSp = Timestamp() PriorityQueue.put(self, (3, tmSp, (register, value))) time.sleep( 0.002) # Makes sure that the next command get another 'Timestamp'
def readTask(self, *args): '''Handles reading tasks. params ------ args: not used ''' PriorityQueue.put(self, (5, Timestamp(), args))
def __init__(self, target, subarray, spectral_window, timestamps): super(MinimalDataSet, self).__init__(name='test', ref_ant='array') num_dumps = len(timestamps) num_chans = spectral_window.num_chans num_corrprods = len(subarray.corr_products) dump_period = timestamps[1] - timestamps[0] def constant_sensor(value): return CategoricalData([value], [0, num_dumps]) self.subarrays = [subarray] self.spectral_windows = [spectral_window] sensors = {} for ant in subarray.ants: sensors['Antennas/%s/antenna' % (ant.name, )] = constant_sensor(ant) az, el = target.azel(timestamps, ant) sensors['Antennas/%s/az' % (ant.name, )] = az sensors['Antennas/%s/el' % (ant.name, )] = el # Extract array reference position as 'array_ant' from last antenna array_ant_fields = ['array'] + ant.description.split(',')[1:5] array_ant = Antenna(','.join(array_ant_fields)) sensors['Antennas/array/antenna'] = constant_sensor(array_ant) sensors['Observation/target'] = constant_sensor(target) for name in ('spw', 'subarray', 'scan', 'compscan', 'target'): sensors['Observation/%s_index' % (name, )] = constant_sensor(0) sensors['Observation/scan_state'] = constant_sensor('track') sensors['Observation/label'] = constant_sensor('track') self._timestamps = timestamps self._time_keep = np.full(num_dumps, True, dtype=np.bool_) self._freq_keep = np.full(num_chans, True, dtype=np.bool_) self._corrprod_keep = np.full(num_corrprods, True, dtype=np.bool_) self.dump_period = dump_period self.start_time = Timestamp(timestamps[0] - 0.5 * dump_period) self.end_time = Timestamp(timestamps[-1] + 0.5 * dump_period) self.sensor = SensorCache(sensors, timestamps, dump_period, keep=self._time_keep, virtual=DEFAULT_VIRTUAL_SENSORS) self.catalogue.add(target) self.catalogue.antenna = array_ant self.select(spw=0, subarray=0)
def __init__(self, start_time=None, warp=False): self.offset = 0.0 if start_time is None else \ Timestamp(start_time).secs - time.time() self.warp = warp self.bed = Bed() self.master_lock = SingleThreadLock() self.slave_lock = SingleThreadLock() self.condition = None self.condition_satisfied = False
def disableTelescopes(self): '''Disables movement of the telescopes ''' i=0 while not self.CurrentSystemStatus.value() == 1 and not self.error: self.PCQ.writeTask(20, 2) i += 1 if i % 10 == 0: # if it does send 10 times it gives the system some time time.sleep(5) else: time.sleep(2) print "Telescopes Disabled at %s."%Timestamp().to_string()
def _updateFunc(self, tbxobj, value, sensor): '''Enables writing to the textboxes, deletes the old value, writes in the new value and disables it for the user again. params ------ tbxobj: object of :class: 'Text' The textbox in which is written in. value: string, float, int The value which is written. status: int Status of the sensor ''' tmSp = Timestamp(float(sensor.read()[0])) if tmSp < Timestamp()-5:# Was not updated the last five seconds status=6 # Time is over sensor.set(tmSp,5,(sensor.read()[2])) else: status = sensor.read()[1] tbxobj.configure(state="normal") tbxobj.delete("1.0",END) tbxobj.insert(END, value) if status == 0: color = "white" elif status == 1: color = "green" elif status == 2: color = "yellow" elif status == 3: color = "red" elif status == 4: color = "magenta" elif status == 5: color = "cyan" elif status == 6: color = "blue" tbxobj.configure(background=color) tbxobj.configure(state="disabled")
def writeImportantTask(self, register, value): '''Handles writing tasks with higher priority. It is sorted intern by timestamp so that it keeps the correct order. It should be used for commands when exceptions occure.# params ------ register: The register which will be written. value: The value which is written in the register. ''' PriorityQueue.put(self, (2, Timestamp(), (register, value)))
def openModbusConnections(self, amount=1): """The defined number of client objects can be defined, opend and append to the 'PDPList' with that method. This does not need to be added to the Queue because it does not write or read anything. Maximum length of the 'PDPList' is 10. params ------ amount: int The amount of objects, which will be opened. The program uses always the first entry in the list. The user could use a second entry """ self.disconnectedManually = False for i in range (amount): self.PDPList.insert(0,PythonDiagnosticProgramm()) connected = self.PDPList[0].modbusConnectionOpen() if connected: self.ConnectionStatus.set(Timestamp(),1,True) else: self.ConnectionStatus.set(Timestamp(),5,False) if len(self.PDPList)>10: for i in range(len(self.PDPList)-10): self.PDPList.pop()
def haltTelescopes(self): """Halts the telescopes. """ i = 0 self.halt=True while not self.CurrentMotionCommand.value() == 0 and not self.error: self.PCQ.writeTask(20, 0) i += 1 if i % 10 == 0: # if it does send 10 times it gives the system some time time.sleep(5) else: time.sleep(2) print "Halt the telescopes at %s."%Timestamp().to_string()
def clearTelescopeFault(self, rollover=None): '''Clear the telescope from faults, when a fault has occured It also clears the software fault param ----- enable: bool Enable the Telescope ''' self.PCQ.writeTask(22,1) self.askRolloverCounter(rollover) self.error = False self.clearTelescopeHalt() print "Telescope Faults cleared at %s."%Timestamp().to_string()
def enableTelescopes(self): '''Enables movement of the telescopes. It also allows automatically reconnection. ''' self.clearTelescopeHalt() self.disconnectedManually = False i =0 while not self.CurrentSystemStatus.value() == 2 and not self.error: self.PCQ.writeTask(20, 1) i += 1 if i%10==0: # if it does send 10 times it gives the system some time time.sleep(5) else: time.sleep(2) print "Telescopes Enabled at %s."%Timestamp().to_string()
def clearTelescopeHalt(self): '''Clear the telescope from faults, when a fault has occured It also clears the software fault param ----- enable: bool Enable the Telescope ''' self.halt =False try: # That also enables the Catalogue Manager self.currentCatalogue.halt = False except AttributeError: pass #There is no Catalogue tracked print "Telescope Halt cleared at %s."%Timestamp().to_string()
def connectionExceptionHandling(self): ''' Handles the event of a 'ConnectionException' with the modbus. It sets the 'ConnectionStatus' on 'False' and try to reconnect. ''' print "Handle connection exception at %s." % Timestamp().to_string() setConnectionStatus(self) while not self.OVST.ConnectionStatus.value( ) == True and not self.OVST.disconnectedManually: #Reconnection if not disconnected manually self.OVST.openModbusConnections( ) #sets OVST.ConnectionStatus.value()=True try: self.OVST.PDPList[0].modbusReadOut( 1) # With default start address ist does not work except AttributeError: setConnectionStatus(self) except ConnectionException: setConnectionStatus(self)
def moveContinuousAdapter(OVST, targetname, tmSp=None, deltaTmSp=None, inTrack=False, mode=ObservationMode(), disableMaxSpeedWarning=False): '''This function allows moving to an continuous position by writing into the PLC. A modbus connection has to be defined in the :object: 'OVST' :attr: 'PDPList' to use the default of modbus. !!Attention!! ------------- :func: 'moveContinuousAdapter' does not check if limit switch will be hit! It belongs to the responsibility of the user. Params ------ OVST: targetname: string, object of :class: 'Target' Name of the target on which will be pointed. If it is a object of :class: 'Target', catalogue value will be skipped. Used in :func: 'check_target' tmSp: object of :class: 'Timestamp' The Timestamp at which the azimuth and elevation cooordinate calculated. deltaTmSp: float The time between the next Timestamp and the current Timestamp. It is used to calculate the speed between two points. Too big values are handled in this class. Too small and also too big values are handled in the PLC to protect it from damage. inTrack: bool If it is true the antennas are not updated during the observation. The value is already writtin in the incremental movement to the start position. mode: object of :class: 'GoOffPointing'. The GoOffPointing Class of the target. It returns the 'currentOff'. disableMaxSpeedWarning ''' # if antenna is not defined, use the first one which is stored in OVST.antennaList antennas = (OVST.active_antennas) # Creates a list of a single antenna if not isinstance(antennas, list): antennas = [antennas] # Initialise axisToMove = 0 current_azEl = check_target(OVST, targetname, tmSp, False) nextAzEl = check_target(OVST, targetname, tmSp + deltaTmSp, False) azElOff = mode.currentOff mode.timeStampToCheck = Timestamp() + deltaTmSp nextAzElOff = mode.currentOff mode.timeStampToCheck = None # It is very important to clear the timestamp for the next check for i in range(len(antennas)): # Calculation of Speed azSpeed = abs( (nextAzEl[i][0] + nextAzElOff[0] - current_azEl[i][0] - azElOff[0]) / deltaTmSp) elSpeed = abs( (elevationDegreeToLength(nextAzEl[i][1] + nextAzElOff[1], antennas[i].azElPos[1].offset) - elevationDegreeToLength(current_azEl[i][1] + azElOff[1], antennas[i].azElPos[1].offset)) / deltaTmSp) if disableMaxSpeedWarning: # Only for RasterDiscrete azSpeed = 5.0 elSpeed = 5.0 # Catches too big speed values if azSpeed > 5: azSpeed = 5.0 if not disableMaxSpeedWarning: print "Azimuth Speed is higher than 5 at %s" % Timestamp( ).to_string() OVST.PCQ.writeTask(antennas[i].azimuthMoveAbsoluteSpeedRegister, float(azSpeed), Timestamp()) if elSpeed > 5: elSpeed = 5.0 if not disableMaxSpeedWarning: print "Elevation Speed is higher than 5 at %s" % Timestamp( ).to_string() OVST.PCQ.writeTask(antennas[i].elevationMoveAbsoluteSpeedRegister, float(elSpeed), Timestamp()) # Positions after speed. Otherwise it uses the old speed from the last writing period. # Write the values in the registers OVST.PCQ.writeTask( antennas[i].azimuthMoveAbsolutePositionRegister, float( azimuthOffset(nextAzEl[i][0] + nextAzElOff[0], antennas[i].azElPos[0].offset)), Timestamp()) print antennas[i].name, float( azimuthOffset(nextAzEl[i][0] + nextAzElOff[0], antennas[i].azElPos[0].offset)) OVST.PCQ.writeTask( antennas[i].elevationMoveAbsolutePositionRegister, float( elevationDegreeToLength(nextAzEl[i][1] + nextAzElOff[1], antennas[i].azElPos[1].offset)), Timestamp()) if not inTrack: # Only called when Track gets started axisToMove += antennas[i].selectValue # Write which axis should move OVST.PCQ.writeTask(OVST.axisToMoveRegister, axisToMove, Timestamp()) # Start move continuous status OVST.PCQ.writeTask(OVST.motionCommandRegister, OVST.moveContinuousValue, Timestamp()) OVST.inSavetyPosition = False OVST.inHomePosition = False
def moveAbsoluteAdapter(OVST, targetname, catalogue=None, antennas=None, modbus=None, tmSp=None, inTrack=False, azElGoOff=[0, 0]): '''This function allows moving to an absolute position by writing into the PLC. A modbus connection has to be defined in the :object: 'OVST' :attr: 'PDPList' to use the default of modbus. Attention --------- :func: 'moveAbsoluteAdapter' does not check if limit switch will be hit! It belongs to the responsibility of the user. Params ------ targetname: string, object of :class: 'Target' Name of the target on which will be pointed. If it is a object of :class: 'Target', catalogue value will be skipped. Used in :func: 'check_target' catalogue: object of :class: 'Catalogue' It should containing an element called 'targetname' Used in :func: 'check_target' antennas: list of object or object of :class: 'Antenna' If there is no antenna specified the antenna(s) defined in 'catalogue' or the antennas defined in the object of :class: 'Target' are used. modbus: object of :class: 'ModbusClient' Necessary for Modbus communication If there is no object defined, the first object of the 'PDPList' in overall settings object 'OVST' is used tmSp: object of :class: 'Timestamp' The Timestamp at which the azimuth and elevation cooordinate calculated. inTrack: bool If it is true the antennas are not updated during the observation. The value is already writtin in the incremental movement to the start position. azElGoOff: list of 2 floats index 0 is the azimuth Off index 1 is the elevation Off it is used to go off the target ''' # if modbus is not defined, use the first one which is stored in OVST.PDPList if (modbus == None): modbus = (OVST.PDPList[0]) # if catalogue is not defined, use the first one which is stored in OVST.Catalogue if (catalogue == None): catalogue = (OVST.Catalogue) # if antenna is not defined, use the first one which is stored in OVST.antennaList if (antennas == None): antennas = (OVST.antennaList) # Creates a list of a single antenna if not isinstance(antennas, list): antennas = [antennas] # Initialise axisToMove = 0 azEl = check_target(OVST, targetname, tmSp) for i in range(len(antennas)): # Write the values in the registers OVST.PCQ.writeTask( antennas[i].azimuthMoveAbsolutePositionRegister, float( azimuthOffset(azEl[i][0] + azElGoOff[0], antennas[i].azElPos[0].offset)), Timestamp()) OVST.PCQ.writeTask( antennas[i].elevationMoveAbsolutePositionRegister, float( elevationDegreeToLength(azEl[i][1] + azElGoOff[1], antennas[i].azElPos[1].offset)), Timestamp()) # Add the axis to the list of axis which move when move command occures axisToMove += antennas[i].selectValue if not inTrack: # Write which axis should move OVST.PCQ.writeTask(OVST.axisToMoveRegister, axisToMove, Timestamp()) # Move to the absolute position OVST.PCQ.writeTask(OVST.motionCommandRegister, OVST.moveAbsoluteValue, Timestamp()) OVST.inSavetyPosition = False OVST.inHomePosition = False
def moveIncrementalAdapter(OVST, targetname, catalogue=None, antennas=None, modbus=None, azTargetRolloverCounter=None, azElOff=[0, 0]): '''This function allows moving for a incremental distance If 'azTargetRolloverCounter' is not None it will use that azimuth values. A modbus connection has to be defined in the :object: 'OVST' :attr: 'PDPList' to use the default of modbus. Params ------ targetname: string, object of :class: 'Target' Name of the target on which will be pointed. If it is a object of :class: 'Target', catalogue value will be skipped. Used in :func: 'check_target'. catalogue: object of :class: 'Catalogue' It should containing an element called 'targetname'. Used in :func: 'check_target'. antennas: list objects of :class: 'Antenna' If there is no antenna specified the antenna(s) defined in 'catalogue' or the antennas defined in the object of :class: 'Target' are used. modbus: object of :class: 'ModbusClient' Necessary for Modbus Communication. azTargetRolloverCounter: array of floats a array of possible azimuth start values for each axis in an absolute coordinate without rollovers It already mention the goOff in azimuth azElOff: list of two floats The first entry is the off in azimuth and the second is the off in elevation. It is necessary for moving to the correct start position, if the goOffPointing does not start at the target itself. Azimuth Off is already mentioned in 'azTargetRolloverCounter ''' # if modbus is not defined, use the first one which is stored in OVST.PDPList if (modbus == None): modbus = (OVST.PDPList[0]) # if catalogue is not defined, use the first one which is stored in OVST.Catalogue if (catalogue == None): catalogue = (OVST.Catalogue) # if antenna is not defined, use the first one which is stored in OVST.antennaList if (antennas == None): antennas = (OVST.antennaList) # Creates a list of a single antenna if not isinstance(antennas, list): antennas = [antennas] # Initialise that only the selected axis move axisToMove = 0 # azEl has to be defined for elevation azEl = check_target(OVST, targetname) if not azTargetRolloverCounter == None: # make sure that it is a list if not isinstance(azTargetRolloverCounter, list): azTargetRolloverCounter = [azTargetRolloverCounter] for i in range(len(antennas)): if (azTargetRolloverCounter == None): # Gives the shortest move distance azMoveDistance = getMoveDistance(azEl[i][0] + azElOff[0], antennas[i].azElPos[0]) else: # Make the add for each axis seperate because the lenght of the sublist must not be of the same length distLst = [] absLst = [] # Get the closest azimuth that is closest to the current possition for azi in range(len(azTargetRolloverCounter[i])): distLst.append(azTargetRolloverCounter[i][azi] - antennas[i].azElPos[0].positionWithoutRollover) absLst.append(abs(distLst[azi])) # take the shortest azimuth distance # a.index(min(a)) index of minimal value azMoveDistance = (distLst[absLst.index(min(absLst))]) # Write the values in the registers OVST.PCQ.writeTask(antennas[i].azimuthMoveIncrementalDistanceRegister, (azMoveDistance), Timestamp()) OVST.PCQ.writeTask( antennas[i].elevationMoveIncrementalDistanceRegister, (getMoveDistance(azEl[i][1] + azElOff[1], antennas[i].azElPos[1])), Timestamp()) # Add the axis to the list of axis which move when move command occures axisToMove += antennas[i].selectValue # Write which axis should move OVST.PCQ.writeTask(OVST.axisToMoveRegister, axisToMove, Timestamp()) # Move to the absolute position OVST.PCQ.writeTask(OVST.motionCommandRegister, OVST.moveIncrementalValue, Timestamp()) OVST.inSavetyPosition = False OVST.inHomePosition = False
def move_to_pos(self, az, el=None, for_track=False, azel_off=[0,0]): ''' moves the telescopes to a specific azel or radec or to a target position :param az: float/int, string if float/int: az if string: ra when in format ('HH:MM:SS') otherwise search for target :param el: float/int, string if float/int: el, if string: declination in degree ''' if self.error: print "Error has occured. Can not move at %s."%Timestamp().to_string() elif self.halt: print "Halt has occured. Can not move at %s."%Timestamp().to_string() # Important if you choose another telescope while another is moving antennas = self.active_antennas # Checks whether azel, radec or a target is given if isinstance(az, (int, float)) and isinstance(el, (int, float)): az = az % 360 target = construct_azel_target(deg2rad(az), deg2rad(el)) target.name = 'Moving to az: %d, el: % d at %s' % (az, el, Timestamp().to_string()) elif isinstance(az, str) and isinstance(el, str): target = construct_radec_target(az, el) target.name = 'Moving to ra: %s, dec: %s at %s' % (az, el, Timestamp().to_string()) elif isinstance(az, str) and not el: if ',' in az: target = Target(az) else: target = self.Catalogue[az] elif isinstance(az, Target): target = az else: raise AttributeError('Wrong format') try: azel = check_target(self, target) except LookupError: return 'Target with position az: %s, el: %s is out of telescope range' % (az, el) self.enableTelescopes() self.inSafetyPosition = False moveIncrementalAdapter(self, target, antennas=antennas, azElOff=azel_off) #inRange = [[False]*2]*len(antennas) inRange = [] for i in antennas: # list of Booleans which show if the antennas are at the right position inRange.append([False, False]) all_inRange = False azel = np.add(azel,azel_off) while ((self.CurrentSystemStatus.value() == 5 or (not all_inRange)) and not self.error and not self.halt): for n, ant in enumerate(antennas): for i, az_el in enumerate(azel[n]): # check if antenna is range if az_el-0.5 <= ant.azElPos[i].value() <= az_el+0.5: inRange[n][i] = True all_inRange = all(i == [True]*2 for i in inRange) time.sleep(1) if (not all_inRange and not self.CurrentMotionCommand.value() == self.moveIncrementalValue and not self.error and not self.halt): moveIncrementalAdapter(self, target, antennas=antennas, azElOff=azel_off) # Get position of all Telescopes pos = self.get_pos() if not for_track: if inRange: print 'Telescopes are in position at %s:'% Timestamp().to_string() for i, azel in enumerate(pos): print '%s \t Azimuth: %s \t Elevation: %s' % (self.antennaList[i].name, azel[1], azel[2]) self.disableTelescopes()
def run(self): """Infinite loop which updates a object of :class: 'Sensor' or sends commands to the PLC. It is called with 'BackgroundUpdaterObject.start()' in the command line. """ while True: # Add a readout command to the Queue if the Queue is not too long. Important for the first loop if self.OVST.PCQ.qsize() < 5: self.OVST.PCQ.readTask() # get the command priority, tmSp, args = self.OVST.PCQ.get() # if it is a reading task, the priority is 5 if priority == 2: successful = False while not successful: try: self.OVST.PDPList[0].modbusWrite(args[0], args[1]) successful = True #print "Send the priority 2 command '%r' to address '%r' at %s" %(args[1],args[0],Timestamp().to_string()) except OverflowError: print "OverflowError 'Writing Priority' at %r " % Timestamp( ) except ConnectionException: connectionExceptionHandling(self) except AttributeError: connectionExceptionHandling(self) except IndexError: # it is disconnected manually setConnectionStatus(self) elif priority == 5: try: # Process the command returnValue = self.OVST.PDPList[0].modbusReadOutAll() self.OVST.ConnectionStatus.set(Timestamp(), 1, True) except OverflowError: print "OverflowError Reading at %r " % Timestamp() except ConnectionException: connectionExceptionHandling(self) except AttributeError: connectionExceptionHandling(self) except IndexError: # it is disconnected manually setConnectionStatus(self) try: #Check if the SUT is finished with working if not self.OVST.SUT.is_alive(): self.OVST.SUT = SensorUpdateThread( returnValue, self.OVST) except AttributeError: # If the name is None try: self.OVST.SUT = SensorUpdateThread( returnValue, self.OVST) except UnboundLocalError: pass #Just do not update: it happens when updating is not possible because of a lost modbus connection if (priority == 3) & (not self.OVST.error): # it is a writing task # The asking for a error makest that it doesnot Move furhter. # It is necessary because even if the telescope will be telescope disabled, the next 'moveAbsoluteCommand' cause it to move. try: self.OVST.PDPList[0].modbusWrite(args[0], args[1]) except OverflowError: print "OverflowError Writing at %r " % Timestamp() print "lenght of PCQ (not reliable)", ( self.OVST.PCQ.qsize()) except ConnectionException: connectionExceptionHandling(self) except AttributeError: connectionExceptionHandling(self) except IndexError: # it is disconnected manually setConnectionStatus(self) if args[0] == self.OVST.antennaList[ 0].azimuthMoveIncrementalDistanceRegister: self.OVST.pointingLog[0].append(args[1]) if args[0] == self.OVST.antennaList[ 0].elevationMoveIncrementalDistanceRegister: self.OVST.pointingLog[1].append(args[1]) # Indicates the Queue that the task is done. self.OVST.PCQ.task_done()
def daq_pos(self, name=None, daq_attrs=None): ''' Creates a hdf5 file for every day and stores the position of the current session in the group 'name' :param name: string name of the datagroup in the hdf file. If None it will use the format "positions_'start Timestamp of record'" ''' # One hdf file for one day: 'positions_YYYY_MM_DD.h5' data_dict = {} for i, ant in enumerate(self.antennaList): data_dict[ant] = [] self.daq = True self.data_saved = False # Start data acquisition while self.daq: pos = self.get_pos() for i, ant in enumerate(self.antennaList): target = construct_azel_target(deg2rad(pos[i][1]), deg2rad(pos[i][2])) radec = target.astrometric_radec(timestamp=pos[i][0], antenna=ant) data_dict[ant].append((pos[i][0], pos[i][1], pos[i][2], radec[0], radec[1])) time.sleep(1) # If task is done, safe the data in an hdf5 file if not name: new_name = '%s_positions' % Timestamp().local()[11:19] # positions_HH:MM:SS else: new_name = name used = True date = datetime.today().date().strftime('%Y_%m_%d') i = 1 # Define column names and data types dtype = np.dtype([ ('Timestamp', np.float), ('Azimuth', np.float), ('Elevation', np.float), ('RA (J2000)', h5py.special_dtype(vlen=str)), ('DEC (J2000)', h5py.special_dtype(vlen=str)) ]) with h5py.File(self.daq_dirpath + '/positions_%s.h5' % date, 'a') as hdf: while used: try: G = hdf.create_group(new_name) used = False except ValueError: new_name = name + '_' + str(i) i += 1 for i, ant in enumerate(self.antennaList): data_array = np.array(data_dict[ant], dtype=dtype) dset = G.create_dataset('%s' % ant.name, data=data_array) dset.attrs.update({ 'Antenna name': ant.name, 'Antenna latitude': ant.observer.lat, 'Antenna longitude': ant.observer.long, 'Antenna altitude': ant.observer.elevation }) if isinstance(daq_attrs, dict): for key, val in daq_attrs.iteritems(): dset.attrs[key] = val print 'Data saved!' self.data_saved = True
def test_timestamps(self): mjd = Timestamp(self.timestamps[0]).to_mjd() assert_equal(self.dataset.mjd[0], mjd) lst = self.array_ant.local_sidereal_time(self.timestamps) # Convert LST from radians (katpoint) to hours (katdal) assert_array_equal(self.dataset.lst, lst * (12 / np.pi))
def setConnectionStatus(self): self.OVST.ConnectionStatus.set(Timestamp(), 5, False)