class ERS(Component): #Parsers.CEOS.CEOSFormat.ceosTypes['text'] = # {'typeCode': 63, 'subtypeCode': [18,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['leaderFile'] = # {'typeCode': 192, 'subtypeCode': [63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['dataSetSummary'] = # {'typeCode': 10, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['platformPositionData'] = # {'typeCode': 30, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['facilityData'] = # {'typeCode': 200, 'subtypeCode': [10,31,50]} #Parsers.CEOS.CEOSFormat.ceosTypes['datafileDescriptor'] = # {'typeCode': 192, 'subtypeCode':[63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['signalData'] = # {'typeCode': 10, 'subtypeCode': [50,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['nullFileDescriptor'] = # {'typeCode': 192, 'subtypeCode': [192,63,18]} logging_name = 'isce.sensor.ers' def __init__(self): Component.__init__(self) self._leaderFile = None self._imageFileList = '' self._leaderFileList = '' self._imageFile = None self._orbitDir = None # Use this for Delft Orbit files self._orbitFile = None # Use this for PDS Orbit files for now self._orbitType = None self.frameList = [] self.output = None self.descriptionOfVariables = {} self.dictionaryOfVariables = { 'ORBIT_TYPE': ['self._orbitType','str','mandatory'], 'ORBIT_DIRECTORY': ['self._orbitDir','str','optional'], 'ORBIT_FILE': ['self._orbitFile','str','optional'], 'LEADERFILE': ['self._leaderFileList','str','mandatory'], 'IMAGEFILE': ['self._imageFileList','str','mandatory'], 'OUTPUT': ['self.output','str','optional']} self.frame = Frame() self.frame.configure() # Constants are from # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = {'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime':6.622e-6, 'iBias': 15.5, 'qBias': 15.5} return None def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() elif (self._orbitType == 'PDS'): self._populatePDSOrbits() else: self._populateHeaderOrbit() def _populatePlatform(self): """ Populate the platform object with metadata """ platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet('Earth')) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() pri = self.imageFile.firstPri rangeSamplingRate = self.constants['rangeSamplingRate'] #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ # 'Range sampling rate']*1e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 4.0/rangeSamplingRate*(pri+2.0) prf = 1.0/pulseInterval instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord.metadata[ 'Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length']*1e-6) instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/ (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']* 1e-6)) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" rangeSamplingRate = self.constants['rangeSamplingRate'] #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ # 'Range sampling rate']*1e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency() frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord.metadata[ 'Scene reference number']) startingRange = (9*pulseInterval + self.imageFile.minSwst*4/rangeSamplingRate-self.constants['delayTime'])*Const.c/2.0 farRange = startingRange + self.imageFile.width*rangePixelSize # Use the Scene center time to get the date, then use the ICU on board time from the image for the rest centerLineTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Scene centre time'],"%Y%m%d%H%M%S%f") first_line_utc = datetime.datetime(year=centerLineTime.year, month=centerLineTime.month, day=centerLineTime.day) if(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'] in ('CRDC_SARDPF','GTS - ERS')): first_line_utc = first_line_utc + datetime.timedelta(milliseconds=self.imageFile.startTime) else: deltaSeconds = (self.imageFile.startTime - self.leaderFile.sceneHeaderRecord.metadata['Satellite encoded binary time code'])* 1/256.0 # Sometimes, the ICU on board clock is corrupt, if the time suggested by the on board clock is more than # 5 days from the satellite clock time, assume its bogus and use the low-precision scene centre time if (math.fabs(deltaSeconds) > 5*86400): self.logger.warn("ICU on board time appears to be corrupt, resorting to low precision clock") first_line_utc = centerLineTime - datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6) else: satelliteClockTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Satellite clock time'],"%Y%m%d%H%M%S%f") first_line_utc = satelliteClockTime + datetime.timedelta(microseconds=int(deltaSeconds*1e6)) mid_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6) last_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*self.imageFile.length*1e6) self.logger.debug("Frame UTC start, mid, end times: %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(mid_line_utc) self.frame.setSensingStop(last_line_utc) def _populateHeaderOrbit(self): """Populate an orbit object with the header orbits""" self.logger.info("Using Header Orbits") orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') orbit.setOrbitQuality('Unknown') t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'] t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]) vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]) orbit.addStateVector(vec) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) odr = ODR(file=os.path.join(self._orbitDir,orbitFile)) #jng it seem that for this tipe of orbit points are separated by 60 sec. In ODR at least 9 state vectors are needed to compute the velocities. add # extra time before and after to allow interpolation, but do not do it for all data points. too slow startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60) odr.parseHeader(startTimePreInterp,stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) orbit = odr.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir,orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePDSOrbits(self): """ Populate an orbit object using the ERS-2 PDS format """ from isceobj.Orbit.PDS import PDS self.logger.info("Using PDS Orbits") pds = PDS(file=self._orbitFile) pds.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = pds.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def extractImage(self): import array import math # just in case there was only one image and it was passed as a str instead of a list with only one element if(isinstance(self._imageFileList,str)): self._imageFileList = [self._imageFileList] self._leaderFileList = [self._leaderFileList] if(len(self._imageFileList) != len(self._leaderFileList)): self.logger.error("Number of leader files different from number of image files.") raise Exception self.frameList = [] for i in range(len(self._imageFileList)): appendStr = "_" + str(i) #if only one file don't change the name if(len(self._imageFileList) == 1): appendStr = '' self.frame = Frame() self.frame.configure() self._leaderFile = self._leaderFileList[i] self._imageFile = self._imageFileList[i] self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) try: outputNow = self.output + appendStr out = open(outputNow,'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) return self.imageFile.extractImage(output=out) out.close() rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(outputNow) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) self.frame.setImage(rawImage) self.populateMetadata() self.frameList.append(self.frame) #jng Howard Z at this point adjusts the sampling starting time for imagery generated from CRDC_SARDPF facility. # for now create the orbit aux file based in starting time and prf prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf)) # the aux files has two entries per line. day of the year and microseconds in the day musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond maxMusec = (24*3600)*10**6#use it to check if we went across a day. very rare day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1 outputArray = array.array('d',[0]*2*numPulses) self.frame.auxFile = outputNow + '.aux' fp = open(self.frame.auxFile,'wb') j = -1 for i1 in range(numPulses): j += 1 musec = round((j/prf)*10**6) + musec0 if musec >= maxMusec: day0 += 1 musec0 = musec%maxMusec musec = musec0 j = 0 outputArray[2*i1] = day0 outputArray[2*i1+1] = musec outputArray.tofile(fp) fp.close() tk = Track() if(len(self._imageFileList) > 1): self.frame = tk.combineFrames(self.output,self.frameList) for i in range(len(self._imageFileList)): try: os.remove(self.output + "_" + str(i)) except OSError: print("Error. Cannot remove temporary file",self.output + "_" + str(i)) raise OSError def _decodeSceneReferenceNumber(self,referenceNumber): frameNumber = referenceNumber.split('=') if (len(frameNumber) > 2): frameNumber = frameNumber[2].strip() else: frameNumber = frameNumber[0] return frameNumber
class UAVSAR_Polsar(Sensor): """ A class representing a UAVSAR Polsar SLC. """ family = 'uavsar_polsar' logging_name = 'isce.Sensor.UAVSAR_Polsar' lookMap = {'RIGHT': -1, 'LEFT': 1} parameter_list = (METADATAFILE, ) + Sensor.parameter_list def __init__(self, name=''): super().__init__(family=self.family, name=name) self.frame = Frame() self.frame.configure() self._elp = None self._peg = None def _populatePlatform(self, **kwargs): platform = self.frame.getInstrument().getPlatform() platform.setMission('UAVSAR') platform.setPointingDirection( self.lookMap[self.metadata['Look Direction'].upper()]) platform.setPlanet(Planet(pname="Earth")) platform.setAntennaLength(1.5) def _populateInstrument(self, **kwargs): fudgefactor = 1.0 # 1.0/1.0735059946800756 instrument = self.frame.getInstrument() instrument.setRadarWavelength(self.metadata['Center Wavelength']) instrument.setPulseRepetitionFrequency( fudgefactor * 1.0 / self.metadata['Average Pulse Repetition Interval']) instrument.setRangePixelSize(self.metadata['slc_mag.col_mult']) instrument.setAzimuthPixelSize(self.metadata['slc_mag.row_mult']) instrument.setPulseLength(self.metadata['Pulse Length']) instrument.setChirpSlope(-self.metadata['Bandwidth'] / self.metadata['Pulse Length']) instrument.setRangeSamplingRate(SPEED_OF_LIGHT / 2.0 / instrument.getRangePixelSize()) def _populateFrame(self, **kwargs): tStart = datetime.datetime.strptime( self.metadata['Start Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z") tStop = datetime.datetime.strptime( self.metadata['Stop Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z") dtMid = DTU.timeDeltaToSeconds(tStop - tStart) / 2. tMid = tStart + datetime.timedelta(microseconds=int(dtMid * 1e6)) frame = self.frame frame.setSensingStart(tStart) frame.setSensingStop(tStop) frame.setSensingMid(tMid) frame.setNumberOfLines(int(self.metadata['slc_mag.set_rows'])) frame.setNumberOfSamples(int(self.metadata['slc_mag.set_cols'])) frame.C0 = self.metadata['slc_mag.col_addr'] frame.S0 = self.metadata['slc_mag.row_addr'] self.extractDoppler() frame.setStartingRange(self.startingRange) frame.platformHeight = self.platformHeight width = frame.getNumberOfSamples() deltaRange = frame.instrument.getRangePixelSize() nearRange = frame.getStartingRange() frame.setFarRange(nearRange + width * deltaRange) frame._ellipsoid = self.elp frame.peg = self.peg frame.procVelocity = self.velocity frame.terrainHeight = self.terrainHeight frame.upperLeftCorner = Coordinate() frame.upperLeftCorner.setLatitude( math.degrees(self.metadata['Approximate Upper Left Latitude'])) frame.upperLeftCorner.setLongitude( math.degrees(self.metadata['Approximate Upper Left Longitude'])) frame.upperLeftCorner.setHeight(self.terrainHeight) frame.upperRightCorner = Coordinate() frame.upperRightCorner.setLatitude( math.degrees(self.metadata['Approximate Upper Right Latitude'])) frame.upperRightCorner.setLongitude( math.degrees(self.metadata['Approximate Upper Right Longitude'])) frame.upperRightCorner.setHeight(self.terrainHeight) frame.lowerRightCorner = Coordinate() frame.lowerRightCorner.setLatitude( math.degrees(self.metadata['Approximate Lower Right Latitude'])) frame.lowerRightCorner.setLongitude( math.degrees(self.metadata['Approximate Lower Right Longitude'])) frame.lowerRightCorner.setHeight(self.terrainHeight) frame.lowerLeftCorner = Coordinate() frame.lowerLeftCorner.setLatitude( math.degrees(self.metadata['Approximate Lower Left Latitude'])) frame.lowerLeftCorner.setLongitude( math.degrees(self.metadata['Approximate Lower Left Longitude'])) frame.lowerLeftCorner.setHeight(self.terrainHeight) def _populateFrameSolo(self): self.logger.info("UAVSAR_Polsar._populateFrameSolo") def _populateExtras(self): pass def _populateOrbit(self, **kwargs): """ Create the orbit as the reference orbit defined by the peg """ numgroup = 1000 prf = self.frame.instrument.getPulseRepetitionFrequency() daz = self.frame.instrument.getAzimuthPixelSize() vel = daz * prf t0 = self.frame.getSensingStart() nlines = int((self.frame.getSensingStop() - t0).total_seconds() * prf) # make sure the elp property has been called elp = self.elp orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') for i in range(-5 * numgroup, int(nlines / numgroup) * numgroup + 5 * numgroup, numgroup): delt = int(i * 1.0e6 / prf) torb = self.frame.getSensingStart() + datetime.timedelta( microseconds=delt) ds = delt * 1.0e-6 * vel vec = OrbitStateVector() posSCH = [self.frame.S0 + ds, 0.0, self.platformHeight] velSCH = [self.velocity, 0., 0.] posXYZ, velXYZ = elp.schdot_to_xyzdot(posSCH, velSCH) vec.setTime(torb) vec.setPosition(posXYZ) vec.setVelocity(velXYZ) orbit.addStateVector(vec) def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() def extractImage(self): from iscesys.Parsers import rdf self.metadata = rdf.parse(self.metadataFile) self.populateMetadata() slcImage = isceobj.createSlcImage() self.slcname = os.path.join( os.path.dirname(os.path.abspath(self.metadataFile)), self.metadata['slc' + self.polarization.upper()]) slcImage.setFilename(self.slcname) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') slcImage.renderHdr() self.frame.setImage(slcImage) def extractDoppler(self): # Recast the Near, Mid, and Far Reskew Doppler values # into three RDF records because they were not parsed # correctly by the RDF parser; it was parsed as a string. # Use the RDF parser on the individual Doppler values to # do the unit conversion properly. # The units, and values parsed from the metadataFile key = 'Reskew Doppler Near Mid Far' u = self.metadata.data[key].units.split(',') v = map(float, self.metadata.data[key].value.split()) k = ["Reskew Doppler " + x for x in ("Near", "Mid", "Far")] # Use the interactive RDF accumulator to create an RDF object # for the near, mid, and far Doppler values from iscesys.Parsers.rdf import iRDF dop = iRDF.RDFAccumulator() for z in zip(k, u, v): dop("%s (%s) = %f" % z) self.dopplerVals = {} for r in dop.record_list: self.dopplerVals[r.key.split()[-1]] = r.field.value # Quadratic model using Near, Mid, Far range doppler values # UAVSAR has a subroutine to compute doppler values at each pixel # that should be used instead. frame = self.frame instrument = frame.getInstrument() width = frame.getNumberOfSamples() nearRangeBin = 0. midRangeBin = float(int((width - 1.0) / 2.0)) farRangeBin = width - 1.0 A = numpy.matrix([[1.0, nearRangeBin, nearRangeBin**2], [1.0, midRangeBin, midRangeBin**2], [1.0, farRangeBin, farRangeBin**2]]) d = numpy.matrix([ self.dopplerVals['Near'], self.dopplerVals['Mid'], self.dopplerVals['Far'] ]).transpose() coefs = (numpy.linalg.inv(A) * d).transpose().tolist()[0] prf = instrument.getPulseRepetitionFrequency() coefs_norm = { 'a': coefs[0] / prf, 'b': coefs[1] / prf, 'c': coefs[2] / prf } self.doppler_coeff = coefs return coefs_norm @property def terrainHeight(self): # The peg point incorporates the actual terrainHeight # return self.metadata['Global Average Terrain Height'] return 0.0 @property def platformHeight(self): # Reduce the platform height by the terrain height because the # peg radius of curvature includes the terrain height h = (self.metadata['Global Average Altitude'] - self.metadata['Global Average Terrain Height']) return h @property def platformStartingAzimuth(self): azimuth = self.frame.S0 return azimuth @property def startingRange(self): return self.metadata['Image Starting Range'] @property def squintAngle(self): """ Update this to use the sphere rather than planar approximation. """ startingRange = self.startingRange h = self.platformHeight v = self.velocity wavelength = self.frame.getInstrument().getRadarWavelength() if h > startingRange: raise ValueError("Spacecraft Height too large (%s>%s)" % (h, startingRange)) sinTheta = math.sqrt(1 - (h / startingRange)**2) fd = self.dopplerVals['Near'] sinSquint = fd / (2.0 * v * sinTheta) * wavelength if sinSquint**2 > 1: raise ValueError( "Error in One or More of the Squint Calculation Values\n" + "Doppler Centroid: %s\nVelocity: %s\nWavelength: %s\n" % (fd, v, wavelength)) self.squint = math.degrees( math.atan2(sinSquint, math.sqrt(1 - sinSquint**2))) # jng squint is also used later on from the frame, just add it here self.frame.squintAngle = math.radians(self.squint) return self.squint @property def heightDt(self): """ Delta(height)/Delta(Time) from frame start-time to mid-time """ return 0.0 @property def velocity(self): platform = self.frame.getInstrument().getPlatform() elp = platform.getPlanet().get_elp() peg = self.peg elp.setSCH(peg.latitude, peg.longitude, peg.heading) scale = (elp.pegRadCur + self.platformHeight) / elp.pegRadCur ds_ground = self.frame.instrument.getAzimuthPixelSize() dt = 1.0 / self.frame.instrument.getPulseRepetitionFrequency() v = scale * ds_ground / dt return v @property def elp(self): if not self._elp: planet = Planet(pname="Earth") self._elp = planet.get_elp() return self._elp @property def peg(self): if not self._peg: peg = [ math.degrees(self.metadata['Peg Latitude']), math.degrees(self.metadata['Peg Longitude']), math.degrees(self.metadata['Peg Heading']) ] th = self.metadata['Global Average Terrain Height'] if self.metadata['Mocomp II Applied'] is 'Y': self.elp.setSCH(peg[0], peg[1], peg[2], th) else: self.elp.setSCH(peg[0], peg[1], peg[2], 0) rc = self.elp.pegRadCur from isceobj.Location.Peg import Peg self._peg = Peg(latitude=peg[0], longitude=peg[1], heading=peg[2], radiusOfCurvature=rc) self.logger.info( "UAVSAR_Polsar: peg radius of curvature = {}".format( self.elp.pegRadCur)) self.logger.info("UAVSAR_Polsar: terrain height = {}".format(th)) self.logger.info("UAVSAR_Polsar: mocomp II applied = {}".format( self.metadata['Mocomp II Applied'])) return self._peg
class Sentinel1A(Component): """ A Class representing RadarSAT 2 data """ def __init__(self): Component.__init__(self) self.xml = None self.tiff = None self.orbitfile = None self.output = None self.frame = Frame() self.frame.configure() self._xml_root = None self.descriptionOfVariables = {} self.dictionaryOfVariables = { 'XML': ['self.xml', 'str', 'mandatory'], 'TIFF': ['self.tiff', 'str', 'mandatory'], 'ORBITFILE': ['self.orbitfile', 'str', 'optional'], 'OUTPUT': ['self.output', 'str', 'optional'] } def getFrame(self): return self.frame def parse(self): try: fp = open(self.xml, 'r') except IOError as strerr: print("IOError: %s" % strerr) return self._xml_root = ElementTree(file=fp).getroot() # self.product.set_from_etnode(self._xml_root) self.populateMetadata() fp.close() def grab_from_xml(self, path): try: res = self._xml_root.find(path).text except: raise Exception('Tag= %s not found' % (path)) if res is None: raise Exception('Tag = %s not found' % (path)) return res def convertToDateTime(self, string): dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f") return dt def populateMetadata(self): """ Create metadata objects from the metadata files """ ####Set each parameter one - by - one mission = self.grab_from_xml('adsHeader/missionId') swath = self.grab_from_xml('adsHeader/swath') polarization = self.grab_from_xml('adsHeader/polarisation') frequency = float( self.grab_from_xml( 'generalAnnotation/productInformation/radarFrequency')) passDirection = self.grab_from_xml( 'generalAnnotation/productInformation/pass') rangePixelSize = float( self.grab_from_xml( 'imageAnnotation/imageInformation/rangePixelSpacing')) azimuthPixelSize = float( self.grab_from_xml( 'imageAnnotation/imageInformation/azimuthPixelSpacing')) rangeSamplingRate = Const.c / (2.0 * rangePixelSize) prf = 1.0 / float( self.grab_from_xml( 'imageAnnotation/imageInformation/azimuthTimeInterval')) lines = int( self.grab_from_xml( 'imageAnnotation/imageInformation/numberOfLines')) samples = int( self.grab_from_xml( 'imageAnnotation/imageInformation/numberOfSamples')) startingRange = float( self.grab_from_xml( 'imageAnnotation/imageInformation/slantRangeTime') ) * Const.c / 2.0 incidenceAngle = float( self.grab_from_xml( 'imageAnnotation/imageInformation/incidenceAngleMidSwath')) dataStartTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productFirstLineUtcTime')) dataStopTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productLastLineUtcTime')) pulseLength = float( self.grab_from_xml( 'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseLength' )) chirpSlope = float( self.grab_from_xml( 'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseRampRate' )) pulseBandwidth = pulseLength * chirpSlope ####Sentinel is always right looking lookSide = -1 facility = 'EU' version = '1.0' # height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight ####Populate platform platform = self.frame.getInstrument().getPlatform() platform.setPlanet(Planet(pname="Earth")) platform.setMission(mission) platform.setPointingDirection(lookSide) platform.setAntennaLength(2 * azimuthPixelSize) ####Populate instrument instrument = self.frame.getInstrument() instrument.setRadarFrequency(frequency) instrument.setPulseRepetitionFrequency(prf) instrument.setPulseLength(pulseLength) instrument.setChirpSlope(pulseBandwidth / pulseLength) instrument.setIncidenceAngle(incidenceAngle) #self.frame.getInstrument().setRangeBias(0) instrument.setRangePixelSize(rangePixelSize) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setBeamNumber(swath) instrument.setPulseLength(pulseLength) #Populate Frame #self.frame.setSatelliteHeight(height) self.frame.setSensingStart(dataStartTime) self.frame.setSensingStop(dataStopTime) diffTime = DTUtil.timeDeltaToSeconds(dataStopTime - dataStartTime) / 2.0 sensingMid = dataStartTime + datetime.timedelta( microseconds=int(diffTime * 1e6)) self.frame.setSensingMid(sensingMid) self.frame.setPassDirection(passDirection) self.frame.setPolarization(polarization) self.frame.setStartingRange(startingRange) self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize) self.frame.setNumberOfLines(lines) self.frame.setNumberOfSamples(samples) self.frame.setProcessingFacility(facility) self.frame.setProcessingSoftwareVersion(version) self.frame.setPassDirection(passDirection) ResOrbFlag = self.extractResOrbit() if ResOrbFlag == 0: print( "cannot find POD Restituted Orbit, using orbit coming along with SLC" ) self.extractOrbit() ###################################################################################### def extractResOrbit(self): #read ESA's POD Restituted Orbit by Cunren Liang, APR. 2, 2015. import pathlib useResOrbFlag = 0 ResOrbDir = os.environ.get('RESORB') if ResOrbDir != None: print("Trying to find POD Restituted Orbit...") #get start time and stop time of the SLC data from data xml file dataStartTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productFirstLineUtcTime') ) dataStopTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productLastLineUtcTime')) #RESORB has an orbit every 10 sec, extend the start and stop time by 50 sec. dataStartTimeExt = dataStartTime - datetime.timedelta(0, 50) dataStopTimeExt = dataStopTime + datetime.timedelta(0, 50) ########################### #deal with orbit directory ########################### orbList = pathlib.Path(ResOrbDir).glob('**/*.EOF') for orb in orbList: #save full path orb = str(orb) orbx = orb #get orbit file name orb = os.path.basename(os.path.normpath(orb)) #print("{0}".format(orb)) #get start and stop time of the orbit file orbStartTime = datetime.datetime.strptime( orb[42:57], "%Y%m%dT%H%M%S") orbStopTime = datetime.datetime.strptime( orb[58:73], "%Y%m%dT%H%M%S") #print("{0}, {1}".format(orbStartTime, orbStopTime)) if dataStartTimeExt >= orbStartTime and dataStopTimeExt <= orbStopTime: try: orbfp = open(orbx, 'r') except IOError as strerr: print("IOError: %s" % strerr) return useResOrbFlag orbxml = ElementTree(file=orbfp).getroot() print('using orbit file: {0}'.format(orbx)) frameOrbit = Orbit() frameOrbit.setOrbitSource('Restituted') #find the orbit data from the file, and use them node = orbxml.find('Data_Block/List_of_OSVs' ) #note upper case and lower case for child in node.getchildren(): timestamp = self.convertToDateTime( child.find('UTC').text[4:]) if timestamp < dataStartTimeExt: continue if timestamp > dataStopTimeExt: break pos = [] vel = [] for tag in ['X', 'Y', 'Z']: pos.append(float(child.find(tag).text)) vel.append(float(child.find('V' + tag).text)) vec = StateVector() vec.setTime(timestamp) vec.setPosition(pos) vec.setVelocity(vel) frameOrbit.addStateVector(vec) #there is no need to extend the orbit any longer #planet = self.frame.instrument.platform.planet #orbExt = OrbitExtender(planet=planet) #orbExt.configure() #newOrb = orbExt.extendOrbit(frameOrbit) self.frame.getOrbit().setOrbitSource('Restituted') for sv in frameOrbit: self.frame.getOrbit().addStateVector(sv) orbfp.close() useResOrbFlag = 1 break return useResOrbFlag ###################################################################################### def extractOrbit(self): ''' Extract orbit information from xml node. ''' node = self._xml_root.find('generalAnnotation/orbitList') frameOrbit = Orbit() frameOrbit.setOrbitSource('Header') for child in node.getchildren(): timestamp = self.convertToDateTime(child.find('time').text) pos = [] vel = [] posnode = child.find('position') velnode = child.find('velocity') for tag in ['x', 'y', 'z']: pos.append(float(posnode.find(tag).text)) for tag in ['x', 'y', 'z']: vel.append(float(velnode.find(tag).text)) vec = StateVector() vec.setTime(timestamp) vec.setPosition(pos) vec.setVelocity(vel) frameOrbit.addStateVector(vec) planet = self.frame.instrument.platform.planet orbExt = OrbitExtender(planet=planet) orbExt.configure() newOrb = orbExt.extendOrbit(frameOrbit) self.frame.getOrbit().setOrbitSource('Header') for sv in newOrb: self.frame.getOrbit().addStateVector(sv) return def extractPreciseOrbit(self): ''' Extract precise orbit from given Orbit file. ''' try: fp = open(self.orbitfile, 'r') except IOError as strerr: print("IOError: %s" % strerr) return _xml_root = ElementTree(file=fp).getroot() node = _xml_root.find('Data_Block/List_of_OSVs') orb = Orbit() orb.configure() margin = datetime.timedelta(seconds=40.0) tstart = self.frame.getSensingStart() - margin tend = self.frame.getSensingStop() + margin for child in node.getchildren(): timestamp = self.convertToDateTime(child.find('UTC').text[4:]) if (timestamp >= tstart) and (timestamp < tend): pos = [] vel = [] for tag in ['VX', 'VY', 'VZ']: vel.append(float(child.find(tag).text)) for tag in ['X', 'Y', 'Z']: pos.append(float(child.find(tag).text)) vec = StateVector() vec.setTime(timestamp) vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) fp.close() self.frame.getOrbit().setOrbitSource('Header') for sv in orb: self.frame.getOrbit().addStateVector(sv) return def extractImage(self): """ Use gdal python bindings to extract image """ try: from osgeo import gdal except ImportError: raise Exception( 'GDAL python bindings not found. Need this for RSAT2/ TandemX / Sentinel1A.' ) self.parse() width = self.frame.getNumberOfSamples() lgth = self.frame.getNumberOfLines() src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly) band = src.GetRasterBand(1) fid = open(self.output, 'wb') for ii in range(lgth): data = band.ReadAsArray(0, ii, width, 1) data.tofile(fid) fid.close() src = None band = None #### slcImage = isceobj.createSlcImage() slcImage.setByteOrder('l') slcImage.setFilename(self.output) slcImage.setAccessMode('read') slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setLength(self.frame.getNumberOfLines()) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) self.frame.setImage(slcImage) def extractDoppler(self): ''' self.parse() Extract doppler information as needed by mocomp ''' # ins = self.frame.getInstrument() # dc = self.product.imageGenerationParameters.dopplerCentroid quadratic = {} # r0 = self.frame.startingRange # fs = ins.getRangeSamplingRate() # tNear = 2*r0/Const.c # tMid = tNear + 0.5*self.frame.getNumberOfSamples()/fs # t0 = dc.dopplerCentroidReferenceTime # poly = dc.dopplerCentroidCoefficients # fd_mid = 0.0 # for kk in range(len(poly)): # fd_mid += poly[kk] * (tMid - t0)**kk # quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency() quadratic['a'] = 0. quadratic['b'] = 0. quadratic['c'] = 0. return quadratic
class ERS_EnviSAT_SLC(Sensor): parameter_list = (ORBIT_TYPE, ORBIT_DIRECTORY, ORBITFILE, IMAGEFILE) + Sensor.parameter_list """ A Class for parsing ERS instrument and imagery files (Envisat format) """ family = 'ers' logging_name = 'isce.sensor.ers_envisat_slc' def __init__(self,family='',name=''): super(ERS_EnviSAT_SLC, self).__init__(family if family else self.__class__.family, name=name) self._imageFile = None #self._instrumentFileData = None #none for ERS self._imageryFileData = None self.dopplerRangeTime = None self.rangeRefTime = None self.logger = logging.getLogger("isce.sensor.ERS_EnviSAT_SLC") self.frame = None self.frameList = [] #NOTE: copied from ERS_SLC.py... only antennaLength used? -SH # Constants are from # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = {'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime':6.622e-6, 'iBias': 15.5, 'qBias': 15.5} def getFrame(self): return self.frame def parse(self): """ Parse both imagery and create objects representing the platform, instrument and scene """ self.frame = Frame() self.frame.configure() self._imageFile = ImageryFile(fileName=self._imageFileName) self._imageryFileData = self._imageFile.parse() self.populateMetadata() def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() #self._populateOrbit() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() elif (self._orbitType == 'PDS'): self._populatePDSOrbits() #else: # self._populateHeaderOrbit() #NOTE: No leader file #NOTE: remove? self.dopplerRangeTime = self._imageryFileData['doppler'] self.rangeRefTime = self._imageryFileData['dopplerOrigin'][0] * 1.0e-9 # print('Doppler confidence: ', 100.0 * self._imageryFileData['dopplerConfidence'][0]) def _populatePlatform(self): """Populate the platform object with metadata""" platform = self.frame.getInstrument().getPlatform() # Populate the Platform and Scene objects platform.setMission("ERS") platform.setPointingDirection(-1) platform.setAntennaLength(self.constants['antennaLength']) platform.setPlanet(Planet(pname="Earth")) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() rangeSampleSpacing = Const.c/(2*self._imageryFileData['rangeSamplingRate']) pri = self._imageryFileData['pri'] ####These shouldnt matter for SLC data since data is already focused. txPulseLength = 512 / 19207680.000000 chirpPulseBandwidth = 16.0e6 chirpSlope = chirpPulseBandwidth/txPulseLength instrument.setRangePixelSize(rangeSampleSpacing) instrument.setPulseLength(txPulseLength) #instrument.setSwath(imageryFileData['SWATH']) instrument.setRadarFrequency(self._imageryFileData['radarFrequency']) instrument.setChirpSlope(chirpSlope) instrument.setRangeSamplingRate(self._imageryFileData['rangeSamplingRate']) instrument.setPulseRepetitionFrequency(1.0/pri) #instrument.setRangeBias(rangeBias) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" numberOfLines = self._imageryFileData['numLines'] numberOfSamples = self._imageryFileData['numSamples'] pri = self._imageryFileData['pri'] startingRange = Const.c * float(self._imageryFileData['timeToFirstSample']) * 1.0e-9 / 2.0 rangeSampleSpacing = Const.c/(2*self._imageryFileData['rangeSamplingRate']) farRange = startingRange + numberOfSamples*rangeSampleSpacing first_line_utc = datetime.datetime.strptime(self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') center_line_utc = datetime.datetime.strptime(self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') last_line_utc = datetime.datetime.strptime(self._imageryFileData['LAST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') centerTime = DTUtil.timeDeltaToSeconds(last_line_utc-first_line_utc)/2.0 center_line_utc = center_line_utc + datetime.timedelta(microseconds=int(centerTime*1e6)) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self._imageryFileData['PROC_CENTER']) self.frame.setProcessingSystem(self._imageryFileData['SOFTWARE_VER']) self.frame.setTrackNumber(int(self._imageryFileData['REL_ORBIT'])) self.frame.setOrbitNumber(int(self._imageryFileData['ABS_ORBIT'])) self.frame.setPolarization(self._imageryFileData['MDS1_TX_RX_POLAR']) self.frame.setNumberOfSamples(numberOfSamples) self.frame.setNumberOfLines(numberOfLines) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(center_line_utc) self.frame.setSensingStop(last_line_utc) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() print(self.frame.getSensingStart()) print(arclist) orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) #print(orbitFile) odr = ODR(file=os.path.join(self._orbitDir,orbitFile)) startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60) odr.parseHeader(startTimePreInterp,stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) orbit = odr.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir,orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePDSOrbits(self): """ Populate an orbit object using the ERS-2 PDS format """ from isceobj.Orbit.PDS import PDS self.logger.info("Using PDS Orbits") pds = PDS(file=self._orbitFile) pds.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = pds.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populateImage(self,outname,width,length): #farRange = self.frame.getStartingRange() + width*self.frame.getInstrument().getRangeSamplingRate() # Update the NumberOfSamples and NumberOfLines in the Frame object self.frame.setNumberOfSamples(width) self.frame.setNumberOfLines(length) #self.frame.setFarRange(farRange) # Create a RawImage object rawImage = createSlcImage() rawImage.setFilename(outname) rawImage.setAccessMode('read') rawImage.setByteOrder('l') rawImage.setXmin(0) rawImage.setXmax(width) rawImage.setWidth(width) self.frame.setImage(rawImage) def extractImage(self): from datetime import datetime as dt import tempfile as tf self.parse() width = self._imageryFileData['numSamples'] length = self._imageryFileData['numLines'] self._imageFile.extractImage(self.output, width, length) self._populateImage(self.output, width, length) pass def extractDoppler(self): """ Return the doppler centroid as defined in the ASAR file. """ quadratic = {} r0 = self.frame.getStartingRange() dr = self.frame.instrument.getRangePixelSize() width = self.frame.getNumberOfSamples() midr = r0 + (width/2.0) * dr midtime = 2 * midr/ Const.c - self.rangeRefTime fd_mid = 0.0 tpow = midtime for kk in self.dopplerRangeTime: fd_mid += kk * tpow tpow *= midtime ####For insarApp quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate from isceobj.Util import Poly1D coeffs = self.dopplerRangeTime dr = self.frame.getInstrument().getRangePixelSize() rref = 0.5 * Const.c * self.rangeRefTime r0 = self.frame.getStartingRange() norm = 0.5*Const.c/dr dcoeffs = [] for ind, val in enumerate(coeffs): dcoeffs.append( val / (norm**ind)) poly = Poly1D.Poly1D() poly.initPoly(order=len(coeffs)-1) poly.setMean( (rref - r0)/dr - 1.0) poly.setCoeffs(dcoeffs) pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(coeffs)+1) evals = poly(pix) fit = np.polyfit(pix,evals, len(coeffs)-1) self.frame._dopplerVsPixel = list(fit[::-1]) print('Doppler Fit: ', fit[::-1]) return quadratic
class EnviSAT_SLC(Sensor): parameter_list = (ORBIT_DIRECTORY, ORBITFILE, INSTRUMENTFILE, INSTRUMENT_DIRECTORY, IMAGEFILE) + Sensor.parameter_list """ A Class for parsing EnviSAT instrument and imagery files """ family = 'envisat' def __init__(self, family='', name=''): super(EnviSAT_SLC, self).__init__(family if family else self.__class__.family, name=name) self._imageFile = None self._instrumentFileData = None self._imageryFileData = None self.dopplerRangeTime = None self.rangeRefTime = None self.logger = logging.getLogger("isce.sensor.EnviSAT_SLC") self.frame = None self.frameList = [] self.constants = {'antennaLength': 10.0, 'iBias': 128, 'qBias': 128} def getFrame(self): return self.frame def parse(self): """ Parse both imagery and instrument files and create objects representing the platform, instrument and scene """ self.frame = Frame() self.frame.configure() self._imageFile = ImageryFile(fileName=self._imageFileName) self._imageryFileData = self._imageFile.parse() if self.instrumentFile in [None, '']: self.findInstrumentFile() instrumentFileParser = InstrumentFile(fileName=self.instrumentFile) self._instrumentFileData = instrumentFileParser.parse() self.populateMetadata() def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() self.dopplerRangeTime = self._imageryFileData['doppler'] self.rangeRefTime = self._imageryFileData['dopplerOrigin'][0] * 1.0e-9 # print('Doppler confidence: ', 100.0 * self._imageryFileData['dopplerConfidence'][0]) def _populatePlatform(self): """Populate the platform object with metadata""" platform = self.frame.getInstrument().getPlatform() # Populate the Platform and Scene objects platform.setMission("Envisat") platform.setPointingDirection(-1) platform.setAntennaLength(self.constants['antennaLength']) platform.setPlanet(Planet(pname="Earth")) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() rangeSampleSpacing = Const.c / ( 2 * self._imageryFileData['rangeSamplingRate']) pri = self._imageryFileData['pri'] ####These shouldnt matter for SLC data since data is already focused. txPulseLength = 512 / 19207680.000000 chirpPulseBandwidth = 16.0e6 chirpSlope = chirpPulseBandwidth / txPulseLength instrument.setRangePixelSize(rangeSampleSpacing) instrument.setPulseLength(txPulseLength) #instrument.setSwath(imageryFileData['SWATH']) instrument.setRadarFrequency(self._instrumentFileData['frequency']) instrument.setChirpSlope(chirpSlope) instrument.setRangeSamplingRate( self._imageryFileData['rangeSamplingRate']) instrument.setPulseRepetitionFrequency(1.0 / pri) #instrument.setRangeBias(rangeBias) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" numberOfLines = self._imageryFileData['numLines'] numberOfSamples = self._imageryFileData['numSamples'] pri = self._imageryFileData['pri'] startingRange = Const.c * float( self._imageryFileData['timeToFirstSample']) * 1.0e-9 / 2.0 rangeSampleSpacing = Const.c / ( 2 * self._imageryFileData['rangeSamplingRate']) farRange = startingRange + numberOfSamples * rangeSampleSpacing first_line_utc = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') center_line_utc = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') last_line_utc = datetime.datetime.strptime( self._imageryFileData['LAST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') centerTime = DTUtil.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 center_line_utc = center_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self._imageryFileData['PROC_CENTER']) self.frame.setProcessingSystem(self._imageryFileData['SOFTWARE_VER']) self.frame.setTrackNumber(int(self._imageryFileData['REL_ORBIT'])) self.frame.setOrbitNumber(int(self._imageryFileData['ABS_ORBIT'])) self.frame.setPolarization(self._imageryFileData['MDS1_TX_RX_POLAR']) self.frame.setNumberOfSamples(numberOfSamples) self.frame.setNumberOfLines(numberOfLines) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(center_line_utc) self.frame.setSensingStop(last_line_utc) def _populateOrbit(self): if self.orbitFile in [None, '']: self.findOrbitFile() dorParser = DOR(fileName=self.orbitFile) dorParser.parse() startTime = self.frame.getSensingStart() - datetime.timedelta( minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.frame.setOrbit(dorParser.orbit.trimOrbit(startTime, stopTime)) def _populateImage(self, outname, width, length): #farRange = self.frame.getStartingRange() + width*self.frame.getInstrument().getRangeSamplingRate() # Update the NumberOfSamples and NumberOfLines in the Frame object self.frame.setNumberOfSamples(width) self.frame.setNumberOfLines(length) #self.frame.setFarRange(farRange) # Create a RawImage object rawImage = createSlcImage() rawImage.setFilename(outname) rawImage.setAccessMode('read') rawImage.setByteOrder('l') rawImage.setXmin(0) rawImage.setXmax(width) rawImage.setWidth(width) self.frame.setImage(rawImage) def extractImage(self): from datetime import datetime as dt import tempfile as tf self.parse() width = self._imageryFileData['numSamples'] length = self._imageryFileData['numLines'] self._imageFile.extractImage(self.output, width, length) self._populateImage(self.output, width, length) pass def findOrbitFile(self): datefmt = '%Y%m%d%H%M%S' # sensingStart = self.frame.getSensingStart() sensingStart = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') outFile = None if self.orbitDir in [None, '']: raise Exception( 'No Envisat Orbit File or Orbit Directory specified') try: for fname in os.listdir(self.orbitDir): if not os.path.isfile(os.path.join(self.orbitDir, fname)): continue if not fname.startswith('DOR'): continue fields = fname.split('_') procdate = datetime.datetime.strptime( fields[-6][-8:] + fields[-5], datefmt) startdate = datetime.datetime.strptime(fields[-4] + fields[-3], datefmt) enddate = datetime.datetime.strptime(fields[-2] + fields[-1], datefmt) if (sensingStart > startdate) and (sensingStart < enddate): outFile = os.path.join(self.orbitDir, fname) break except: raise Exception( 'Error occured when trying to find orbit file in %s' % (self.orbitDir)) if not outFile: raise Exception('Envisat orbit file could not be found in %s' % (self.orbitDir)) self.orbitFile = outFile return def findInstrumentFile(self): datefmt = '%Y%m%d%H%M%S' sensingStart = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') print('sens: ', sensingStart) outFile = None if self.instrumentDir in [None, '']: raise Exception( 'No Envisat Instrument File or Instrument Directory specified') try: for fname in os.listdir(self.instrumentDir): if not os.path.isfile(os.path.join(self.instrumentDir, fname)): continue if not fname.startswith('ASA_INS'): continue fields = fname.split('_') procdate = datetime.datetime.strptime( fields[-6][-8:] + fields[-5], datefmt) startdate = datetime.datetime.strptime(fields[-4] + fields[-3], datefmt) enddate = datetime.datetime.strptime(fields[-2] + fields[-1], datefmt) if (sensingStart > startdate) and (sensingStart < enddate): outFile = os.path.join(self.instrumentDir, fname) break except: raise Exception( 'Error occured when trying to find instrument file in %s' % (self.instrumentDir)) if not outFile: raise Exception( 'Envisat instrument file could not be found in %s' % (self.instrumentDir)) self.instrumentFile = outFile return def extractDoppler(self): """ Return the doppler centroid as defined in the ASAR file. """ quadratic = {} r0 = self.frame.getStartingRange() dr = self.frame.instrument.getRangePixelSize() width = self.frame.getNumberOfSamples() midr = r0 + (width / 2.0) * dr midtime = 2 * midr / Const.c - self.rangeRefTime fd_mid = 0.0 tpow = midtime for kk in self.dopplerRangeTime: fd_mid += kk * tpow tpow *= midtime ####For insarApp quadratic['a'] = fd_mid / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate from isceobj.Util import Poly1D coeffs = self.dopplerRangeTime dr = self.frame.getInstrument().getRangePixelSize() rref = 0.5 * Const.c * self.rangeRefTime r0 = self.frame.getStartingRange() norm = 0.5 * Const.c / dr dcoeffs = [] for ind, val in enumerate(coeffs): dcoeffs.append(val / (norm**ind)) poly = Poly1D.Poly1D() poly.initPoly(order=len(coeffs) - 1) poly.setMean((rref - r0) / dr - 1.0) poly.setCoeffs(dcoeffs) pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(coeffs) + 1) evals = poly(pix) fit = np.polyfit(pix, evals, len(coeffs) - 1) self.frame._dopplerVsPixel = list(fit[::-1]) print('Doppler Fit: ', fit[::-1]) return quadratic
class ERS_EnviSAT(Sensor): parameter_list = (IMAGEFILE, ORBIT_TYPE, ORBIT_DIRECTORY, ORBIT_FILE) + Sensor.parameter_list """ A Class for parsing ERS_EnviSAT_format image files There is no LEADERFILE file, which was required for old ERS [disk image] raw data, i.e. [ERS.py] sensor. There is also no INSTRUMENT file. All required default headers/parameters are stored in the image data file itself """ family = 'ers_envisat' def __init__(self, family='', name=''): super(ERS_EnviSAT, self).__init__(family if family else self.__class__.family, name=name) self.imageFile = None self._imageFileData = None self.logger = logging.getLogger("isce.sensor.ERA_EnviSAT") self.frame = None self.frameList = [] # Constants are from the paper below: # J. J. Mohr and Soren. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = { 'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime': 6.622e-6, 'iBias': 15.5, 'qBias': 15.5, 'chirp': 0.419137466e12, 'waveLength': 0.0565646, 'pulseLength': 37.10e-06, 'SEC_PER_PRI_COUNT': 210.943006e-9, 'numberOfSamples': 11232 } return None def getFrame(self): return self.frame def populateMetadata(self): """Create the appropriate metadata objects from ERS Envisat-type metadata""" print("Debug Flag: start populate Metadata") self._populatePlatform() self._populateInstrument() self._populateFrame() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() else: self.logger.error("ERROR: no orbit type (ODR or PRC") def _populatePlatform(self): """Populate the platform object with metadata""" platform = self.frame.getInstrument().getPlatform() platform.setMission("ERS" + str(self._imageFileData['PRODUCT'][61])) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet(pname='Earth')) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() pri = (self._imageFileData['pri_counter'] + 2.0) * self.constants['SEC_PER_PRI_COUNT'] print("Debug: pri = ", pri) rangeSamplingRate = self.constants['rangeSamplingRate'] rangePixelSize = Const.c / (2.0 * rangeSamplingRate) prf = 1.0 / pri self._imageFileData['prf'] = prf instrument.setRadarWavelength(self.constants['waveLength']) # instrument.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre']) # comment out +HB, need to check instrument.setPulseRepetitionFrequency(prf) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(self.constants['pulseLength']) instrument.setChirpSlope(self.constants['chirp']) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) print("Debug Flag Populate Instrument Done") def _populateFrame(self): """Populate the scene object with metadata""" numberOfLines = self._imageFileData[ 'length'] # updated the value after findSwst and extractIQ numberOfSamples = self._imageFileData[ 'width'] # updated value after findSwst and extractIQ frame = 0 # ERS in Envisat format header does not contain frame number! pulseInterval = (self._imageFileData['pri_counter'] + 2.0) * self.constants['SEC_PER_PRI_COUNT'] rangeSamplingRate = self.constants['rangeSamplingRate'] rangePixelSize = Const.c / (2.0 * rangeSamplingRate) startingRange = (9 * pulseInterval + self._imageFileData['minSwst'] * 4 / rangeSamplingRate - self.constants['delayTime']) * Const.c / 2.0 farRange = startingRange + self._imageFileData['width'] * rangePixelSize first_line_utc = datetime.datetime.strptime( self._imageFileData['SENSING_START'], '%d-%b-%Y %H:%M:%S.%f') mid_line_utc = datetime.datetime.strptime( self._imageFileData['SENSING_START'], '%d-%b-%Y %H:%M:%S.%f') last_line_utc = datetime.datetime.strptime( self._imageFileData['SENSING_STOP'], '%d-%b-%Y %H:%M:%S.%f') centerTime = DTU.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 mid_line_utc = mid_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) print("Debug Print: Frame UTC start, mid, end times: %s %s %s" % (first_line_utc, mid_line_utc, last_line_utc)) self.frame.setFrameNumber(frame) self.frame.setProcessingFacility(self._imageFileData['PROC_CENTER']) self.frame.setProcessingSystem(self._imageFileData['SOFTWARE_VER']) self.frame.setTrackNumber(int(self._imageFileData['REL_ORBIT'])) self.frame.setOrbitNumber(int(self._imageFileData['ABS_ORBIT'])) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfSamples(numberOfSamples) self.frame.setNumberOfLines(numberOfLines) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(mid_line_utc) self.frame.setSensingStop(last_line_utc) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir, 'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.info('Using ODR file: ' + orbitFile) odr = ODR(file=os.path.join(self._orbitDir, orbitFile)) # It seem that for this tipe of orbit points are separated by 60 sec. In ODR at # least 9 state vectors are needed to compute the velocities. add extra time before # and after to allow interpolation, but do not do it for all data points. too slow startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta( minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta( minutes=60) odr.parseHeader(startTimePreInterp, stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta( minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime, stopTime)) orbit = odr.trimOrbit(startTime, stopTime) self.frame.setOrbit(orbit) print("Debug populate Delft Orbits Done") print(startTime, stopTime) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir, 'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir, orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta( minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime, stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime, stopTime) self.frame.setOrbit(orbit) def _populateImage(self, outname): width = self._imageFileData['width'] # Create a RawImage object rawImage = isceobj.createRawImage() rawImage.setFilename(outname) rawImage.setAccessMode('read') rawImage.setByteOrder('l') rawImage.setXmin(0) rawImage.setXmax(width) rawImage.setWidth(width) self.frame.setImage(rawImage) def extractImage(self): import array import math self.frameList = [] for i in range(len(self._imageFileList)): appendStr = "_" + str(i) #intermediate raw files suffix if (len(self._imageFileList) == 1): appendStr = '' #if only one file don't change the name outputNow = self.output + appendStr auxImage = isceobj.createImage() # unused widthAux = 2 # unused auxName = outputNow + '.aux' self.imageFile = self._imageFileList[i] self.frame = Frame() self.frame.configure() self.frame.auxFile = auxName #add the auxFile as part of the frame and diring the stitching create also a combined aux file # HB: added from Envisat.py imageFileParser = ImageFile(fileName=self.imageFile) self._imageFileData = imageFileParser.parse( ) # parse image and get swst values and new width try: outputNow = self.output + appendStr out = open(outputNow, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) return imageFileParser.extractIQ( output=out) # IMPORTANT for ERS Envisat-type data out.close() self.populateMetadata( ) # populate Platform, Instrument, Frame, and Orbit self._populateImage(outputNow) self.frameList.append(self.frame) ### Below: create a aux file # for now create the orbit aux file based in starting time and prf prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = int( math.ceil( DTU.timeDeltaToSeconds(self.frame.getSensingStop() - senStart) * prf)) # the aux files has two entries per line. day of the year and microseconds in the day musec0 = (senStart.hour * 3600 + senStart.minute * 60 + senStart.second) * 10**6 + senStart.microsecond maxMusec = ( 24 * 3600 ) * 10**6 # use it to check if we went across a day. very rare day0 = (datetime.datetime(senStart.year, senStart.month, senStart.day) - datetime.datetime(senStart.year, 1, 1)).days + 1 outputArray = array.array('d', [0] * 2 * numPulses) self.frame.auxFile = outputNow + '.aux' fp = open(self.frame.auxFile, 'wb') j = -1 for i1 in range(numPulses): j += 1 musec = round((j / prf) * 10**6) + musec0 if musec >= maxMusec: day0 += 1 musec0 = musec % maxMusec musec = musec0 j = 0 outputArray[2 * i1] = day0 outputArray[2 * i1 + 1] = musec outputArray.tofile(fp) fp.close() ## refactor this with __init__.tkfunc tk = Track() if (len(self._imageFileList) > 1): self.frame = tk.combineFrames(self.output, self.frameList) for i in range(len(self._imageFileList)): try: os.remove(self.output + "_" + str(i)) except OSError: print("Error. Cannot remove temporary file", self.output + "_" + str(i)) raise OSError
class Generic(Component): """ A class to parse generic SAR data stored in the HDF5 format """ logging_name = 'isce.sensor.Generic' def __init__(self): super(Generic, self).__init__() self._hdf5File = None self.output = None self.frame = Frame() self.frame.configure() self.logger = logging.getLogger('isce.sensor.Generic') self.descriptionOfVariables = {} self.dictionaryOfVariables = { 'HDF5': ['self._hdf5File', 'str', 'mandatory'], 'OUTPUT': ['self.output', 'str', 'optional'] } return None def getFrame(self): return self.frame def parse(self): try: fp = h5py.File(self._hdf5File, 'r') except Exception as strerror: self.logger.error("IOError: %s" % strerror) return self.populateMetadata(fp) fp.close() def populateMetadata(self, file): """ Create the appropriate metadata objects from our HDF5 file """ self._populatePlatform(file) self._populateInstrument(file) self._populateFrame(file) self._populateOrbit(file) def _populatePlatform(self, file): platform = self.frame.getInstrument().getPlatform() platform.setMission(file['Platform'].attrs['Mission']) platform.setPlanet(Planet(pname='Earth')) platform.setAntennaLength(file['Platform'].attrs['Antenna Length']) def _populateInstrument(self, file): instrument = self.frame.getInstrument() instrument.setRadarWavelength(file['Instrument'].attrs['Wavelength']) instrument.setPulseRepetitionFrequency( file['Instrument'].attrs['Pulse Repetition Frequency']) instrument.setRangePixelSize( file['Instrument'].attrs['Range Pixel Size']) instrument.setPulseLength(file['Instrument'].attrs['Pulse Length']) instrument.setChirpSlope(file['Instrument'].attrs['Chirp Slope']) instrument.setRangeSamplingRate( file['Instrument'].attrs['Range Sampling Frequency']) instrument.setInPhaseValue(file['Frame'].attrs['In Phase Bias']) instrument.setQuadratureValue(file['Frame'].attrs['Quadrature Bias']) def _populateFrame(self, file): size = file['Frame'].shape start = DTU.parseIsoDateTime(file['Frame'].attrs['Sensing Start']) stop = DTU.parseIsoDateTime(file['Frame'].attrs['Sensing Stop']) deltaT = DTU.timeDeltaToSeconds(stop - start) mid = start + datetime.timedelta(microseconds=int(deltaT / 2.0 * 1e6)) startingRange = file['Frame'].attrs['Starting Range'] rangePixelSize = file['Instrument'].attrs['Range Pixel Size'] farRange = startingRange + size[1] * rangePixelSize self.frame.setStartingRange(file['Frame'].attrs['Starting Range']) self.frame.setFarRange(farRange) self.frame.setNumberOfLines(size[0]) self.frame.setNumberOfSamples(2 * size[1]) self.frame.setSensingStart(start) self.frame.setSensingMid(mid) self.frame.setSensingStop(stop) def _populateOrbit(self, file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource(file['Orbit'].attrs['Source']) for i in range(len(file['Orbit']['Time'])): vec = StateVector() time = DTU.parseIsoDateTime(file['Orbit']['Time'][i]) vec.setTime(time) vec.setPosition(list(file['Orbit']['Position'][i])) vec.setVelocity(list(file['Orbit']['Velocity'][i])) orbit.addStateVector(vec) def extractImage(self): try: file = h5py.File(self._hdf5File, 'r') except Exception as strerror: self.logger.error("IOError: %s" % strerror) return size = file['Frame'].shape dtype = self._translateDataType(file['Frame'].attrs['Image Type']) length = size[0] width = size[1] data = numpy.memmap(self.output, dtype=dtype, mode='w+', shape=(length, width, 2)) data[:, :, :] = file['Frame'][:, :, :] del data rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('r') rawImage.setFilename(self.output) rawImage.setWidth(2 * width) rawImage.setXmin(0) rawImage.setXmax(2 * width) self.frame.setImage(rawImage) self.populateMetadata(file) file.close() def write(self, output, compression=None): """ Given a frame object (appropriately populated) and an image, create an HDF5 from those objects. """ if (not self.frame): self.logger.error("Frame not set") raise AttributeError("Frame not set") h5file = h5py.File(output, 'w') self._writeMetadata(h5file, compression) def _writeMetadata(self, h5file, compression=None): self._writePlatform(h5file) self._writeInstrument(h5file) self._writeFrame(h5file, compression) self._writeOrbit(h5file) def _writePlatform(self, h5file): platform = self.frame.getInstrument().getPlatform() if (not platform): self.logger.error("Platform not set") raise AttributeError("Platform not set") group = h5file.create_group('Platform') group.attrs['Mission'] = platform.getMission() group.attrs['Planet'] = platform.getPlanet().name group.attrs['Antenna Length'] = platform.getAntennaLength() def _writeInstrument(self, h5file): instrument = self.frame.getInstrument() if (not instrument): self.logger.error("Instrument not set") raise AttributeError("Instrument not set") group = h5file.create_group('Instrument') group.attrs['Wavelength'] = instrument.getRadarWavelength() group.attrs[ 'Pulse Repetition Frequency'] = instrument.getPulseRepetitionFrequency( ) group.attrs['Range Pixel Size'] = instrument.getRangePixelSize() group.attrs['Pulse Length'] = instrument.getPulseLength() group.attrs['Chirp Slope'] = instrument.getChirpSlope() group.attrs[ 'Range Sampling Frequency'] = instrument.getRangeSamplingRate() group.attrs['In Phase Bias'] = instrument.getInPhaseValue() group.attrs['Quadrature Bias'] = instrument.getQuadratureValue() def _writeFrame(self, h5file, compression=None): group = self._writeImage(h5file, compression) group.attrs['Starting Range'] = self.frame.getStartingRange() group.attrs['Sensing Start'] = self.frame.getSensingStart().isoformat() group.attrs['Sensing Stop'] = self.frame.getSensingStop().isoformat() def _writeImage(self, h5file, compression=None): image = self.frame.getImage() if (not image): self.logger.error("Image not set") raise AttributeError("Image not set") filename = image.getFilename() length = image.getLength() width = image.getWidth() dtype = self._translateDataType(image.dataType) if (image.dataType == 'BYTE'): width = int(width / 2) self.logger.debug("Width: %s" % (width)) self.logger.debug("Length: %s" % (length)) data = numpy.memmap(filename, dtype=dtype, mode='r', shape=(length, 2 * width)) dset = h5file.create_dataset("Frame", (length, width, 2), dtype=dtype, compression=compression) dset.attrs['Image Type'] = image.dataType dset[:, :, 0] = data[:, ::2] dset[:, :, 1] = data[:, 1::2] del data return dset def _writeOrbit(self, h5file): # Add orbit information (time, position, velocity) = self._orbitToArray() group = h5file.create_group("Orbit") group.attrs['Source'] = self.frame.getOrbit().getOrbitSource() group.attrs['Reference Frame'] = self.frame.getOrbit( ).getReferenceFrame() timedset = h5file.create_dataset("Orbit/Time", time.shape, dtype=time.dtype) posdset = h5file.create_dataset("Orbit/Position", position.shape, dtype=numpy.float64) veldset = h5file.create_dataset("Orbit/Velocity", velocity.shape, dtype=numpy.float64) timedset[...] = time posdset[...] = position veldset[...] = velocity def _orbitToArray(self): orbit = self.frame.getOrbit() if (not orbit): self.logger.error("Orbit not set") raise AttributeError("Orbit not set") time = [] position = [] velocity = [] for sv in orbit: timeString = sv.getTime().isoformat() time.append(timeString) position.append(sv.getPosition()) velocity.append(sv.getVelocity()) return numpy.array(time), numpy.array(position), numpy.array(velocity) def _translateDataType(self, imageType): dtype = '' if (imageType == 'BYTE'): dtype = 'int8' elif (imageType == 'CFLOAT'): dtype = 'float32' elif (imageType == 'SHORT'): dtype = 'int16' else: self.logger.error("Unknown data type %s" % (imageType)) raise ValueError("Unknown data type %s" % (imageType)) return dtype
class UAVSAR_Stack(Component): """ A class representing a UAVSAR SLC. """ family = 'uavsar_stack' logging_name = 'isce.Sensor.UAVSAR_Stack' lookMap = {'RIGHT': -1, 'LEFT': 1} parameter_list = (METADATAFILE, SEGMENT_INDEX) @logged def __init__(self, name=''): super().__init__(family=self.family, name=name) self.frame = Frame() self.frame.configure() self._elp = None self._peg = None elp = self.elp return def _populatePlatform(self, **kwargs): platform = self.frame.getInstrument().getPlatform() platform.setMission('UAVSAR') platform.setPointingDirection( self.lookMap[self.metadata['Look Direction'].upper()]) platform.setPlanet(Planet(pname="Earth")) platform.setAntennaLength(self.metadata['Antenna Length']) return def _populateInstrument(self, **kwargs): instrument = self.frame.getInstrument() instrument.setRadarWavelength(self.metadata['Center Wavelength']) instrument.setPulseRepetitionFrequency( 1.0 / self.metadata['Average Pulse Repetition Interval']) instrument.setRangePixelSize( self.metadata['1x1 SLC Range Pixel Spacing']) instrument.setAzimuthPixelSize( self.metadata['1x1 SLC Azimuth Pixel Spacing']) instrument.setPulseLength(self.metadata['Pulse Length']) instrument.setChirpSlope(-self.metadata['Bandwidth'] / self.metadata['Pulse Length']) from isceobj.Constants.Constants import SPEED_OF_LIGHT instrument.setRangeSamplingRate(SPEED_OF_LIGHT / 2.0 / instrument.getRangePixelSize()) instrument.setIncidenceAngle(0.5 * (self.metadata['Minimum Look Angle'] + self.metadata['Maximum Look Angle'])) return def _populateFrame(self): #Get the Start, Mid, and Stop times import datetime tStart = datetime.datetime.strptime( self.metadata['Start Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z") tStop = datetime.datetime.strptime( self.metadata['Stop Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z") dtMid = DTU.timeDeltaToSeconds(tStop - tStart) / 2. tMid = tStart + datetime.timedelta(microseconds=int(dtMid * 1e6)) frame = self.frame frame._frameNumber = 1 frame._trackNumber = 1 frame.setSensingStart(tStart) frame.setSensingStop(tStop) frame.setSensingMid(tMid) frame.setNumberOfLines(int(self.metadata['slc_1_1x1_mag.set_rows'])) frame.setNumberOfSamples(int(self.metadata['slc_1_1x1_mag.set_cols'])) frame.setPolarization(self.metadata['Polarization']) frame.C0 = self.metadata['slc_1_1x1_mag.col_addr'] frame.S0 = self.metadata['Segment {} Data Starting Azimuth'.format( self.segment_index)] frame.nearLookAngle = self.metadata['Minimum Look Angle'] frame.farLookAngle = self.metadata['Maximum Look Angle'] frame.setStartingRange(self.startingRange) frame.platformHeight = self.platformHeight width = frame.getNumberOfSamples() deltaRange = frame.instrument.getRangePixelSize() nearRange = frame.getStartingRange() midRange = nearRange + (width / 2.) * deltaRange frame.setFarRange(nearRange + width * deltaRange) self.extractDoppler() frame._ellipsoid = self.elp frame.peg = self.peg frame.procVelocity = self.velocity from isceobj.Location.Coordinate import Coordinate frame.upperLeftCorner = Coordinate() #The corner latitude, longitudes are given as a pair #of values in degrees at each corner (without rdf unit specified) llC = [] for ic in range(1, 5): key = 'Segment {0} Data Approximate Corner {1}'.format( self.segment_index, ic) self.logger.info("key = {}".format(key)) self.logger.info("metadata[key] = {}".format( self.metadata[key], type(self.metadata[key]))) llC.append(list(map(float, self.metadata[key].split(',')))) frame.terrainHeight = self.terrainHeight frame.upperLeftCorner.setLatitude(llC[0][0]) frame.upperLeftCorner.setLongitude(llC[0][1]) frame.upperLeftCorner.setHeight(self.terrainHeight) frame.upperRightCorner = Coordinate() frame.upperRightCorner.setLatitude(llC[1][0]) frame.upperRightCorner.setLongitude(llC[1][1]) frame.upperRightCorner.setHeight(self.terrainHeight) frame.lowerRightCorner = Coordinate() frame.lowerRightCorner.setLatitude(llC[2][0]) frame.lowerRightCorner.setLongitude(llC[2][1]) frame.lowerRightCorner.setHeight(self.terrainHeight) frame.lowerLeftCorner = Coordinate() frame.lowerLeftCorner.setLatitude(llC[3][0]) frame.lowerLeftCorner.setLongitude(llC[3][1]) frame.lowerLeftCorner.setHeight(self.terrainHeight) frame.nearLookAngle = math.degrees(self.metadata['Minimum Look Angle']) frame.farLookAngle = math.degrees(self.metadata['Maximum Look Angle']) return def _populateFrameSolo(self): self.logger.info("UAVSAR_Stack._populateFrameSolo") def _populateExtras(self): pass def _populateOrbit(self, **kwargs): """ Create the orbit as the reference orbit defined by the peg """ numgroup = 1000 prf = self.frame.instrument.getPulseRepetitionFrequency() daz = self.frame.instrument.getAzimuthPixelSize() vel = daz * prf t0 = self.frame.getSensingStart() nlines = int((self.frame.getSensingStop() - t0).total_seconds() * prf) #make sure the elp property has been called elp = self.elp orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') for i in range(-5 * numgroup, int(nlines / numgroup) * numgroup + 5 * numgroup, numgroup): delt = int(i * 1.0e6 / prf) torb = self.frame.getSensingStart() + datetime.timedelta( microseconds=delt) ###Need to compute offset ###While taking into account, rounding off in time ds = delt * 1.0e-6 * vel vec = OrbitStateVector() vec.setTime(torb) posSCH = [self.frame.S0 + ds, 0.0, self.platformHeight] velSCH = [self.velocity, 0., 0.] posXYZ, velXYZ = elp.schdot_to_xyzdot(posSCH, velSCH) vec.setPosition(posXYZ) vec.setVelocity(velXYZ) orbit.addStateVector(vec) return #t0 = (self.frame.getSensingStart() - #datetime.timedelta(microseconds=delta)) #ds = deltaFactor*self.frame.instrument.getAzimuthPixelSize() #s0 = self.platformStartingAzimuth - numExtra*ds #self.logger.info("populateOrbit: frame.sensingStart, frame.sensingStop = ", self.frame.getSensingStart(), #self.frame.getSensingStop()) #self.logger.info("populateOrbit: deltaFactor, numExtra, dt = ", deltaFactor, numExtra, dt) #self.logger.info("populateOrbit: t0, startingAzimuth, platformStartingAzimuth, s0, ds = ", #t0, self.frame.S0, self.platformStartingAzimuth, s0, ds) #h = self.platformHeight #v = [self.velocity, 0., 0.] #self.logger.info("t0, dt = ", t0, dt) #self.logger.info("s0, ds, h = ", s0, ds, h) #self.logger.info("elp.pegRadCur = ", self.elp.pegRadCur) #self.logger.info("v = ", v[0]) #platform = self.frame.getInstrument().getPlatform() #elp = self.elp #make sure the elp property has been called #orbit = self.frame.getOrbit() #orbit.setOrbitSource('Header') #for i in range(int(self.frame.getNumberOfLines()/deltaFactor)+1000*numExtra+1): #vec = OrbitStateVector() #t = t0 + datetime.timedelta(microseconds=int(i*dt*1e6)) #vec.setTime(t) #posSCH = [s0 + i*ds , 0., h] #velSCH = v #posXYZ, velXYZ = self.elp.schdot_to_xyzdot(posSCH, velSCH) #sch_pos, sch_vel = elp.xyzdot_to_schdot(posXYZ, velXYZ) #vec.setPosition(posXYZ) #vec.setVelocity(velXYZ) #orbit.addStateVector(vec) #return def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() #self.extractDoppler() self._populateOrbit() def parse(self): from iscesys.Parsers import rdf self.metadata = rdf.parse(self.metadataFile) self.populateMetadata() def extractImage(self): self.parse() slcImage = isceobj.createSlcImage() self.slcname = self.metadata['slc_{}_1x1'.format(self.segment_index)] slcImage.setFilename(self.slcname) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') self.frame.setImage(slcImage) return def extractDoppler(self): """ Read doppler values from the doppler file and fit a polynomial """ frame = self.frame instrument = frame.getInstrument() rho0 = frame.getStartingRange() drho = instrument.getRangePixelSize( ) #full res value, not spacing in the dop file prf = instrument.getPulseRepetitionFrequency() self.logger.info("extractDoppler: rho0, drho, prf = {}, {}, {}".format( rho0, drho, prf)) dopfile = self.metadata['dop'] f = open(dopfile, 'r') x = f.readlines() #first line is a header import numpy z = numpy.array( [list(map(float, e)) for e in list(map(str.split, x[1:]))]) rho = z[:, 0] dop = z[:, 1] #rho0 = rho[0] #drho = (rho[1] - rho[0])/2.0 rhoi = [(r - rho0) / drho for r in rho] polydeg = 6 #2 #Quadratic is built in for now fit = numpy.polynomial.polynomial.polyfit(rhoi, dop, polydeg, rcond=1.e-9, full=True) coefs = fit[0] res2 = fit[1][0] #sum of squared residuals self.logger.info("coeffs = {}".format(coefs)) self.logger.info("rms residual = {}".format(numpy.sqrt(res2 / len(dop)))) o = open("dop.txt", 'w') for i, d in zip(rhoi, dop): val = polyval(coefs, i) res = d - val o.write("{0} {1} {2} {3}\n".format(i, d, val, res)) dopfile = self.metadata['dop'] self.dopplerVals = { 'Near': polyval(coefs, 0) } #need this temporarily in this module self.logger.info( "UAVSAR_Stack.extractDoppler: self.dopplerVals = {}".format( self.dopplerVals)) self.logger.info("UAVSAR_Stack.extractDoppler: prf = {}".format(prf)) #The doppler file values are in units rad/m. divide by 2*pi rad/cycle to convert #to cycle/m. Then multiply by velocity to get Hz and divide by prf for dimensionless #doppler coefficients dop_scale = self.velocity / 2.0 / math.pi coefs = [x * dop_scale for x in coefs] #Set the coefs in frame._dopplerVsPixel because that is where DefaultDopp looks for them self.frame._dopplerVsPixel = coefs return coefs @property def terrainHeight(self): #The peg point incorporates the actual terrainHeight return 0.0 @property def platformHeight(self): h = self.metadata['Global Average Altitude'] #Reduce the platform height by the terrain height because the #peg radius of curvature includes the terrain height h -= self.metadata['Global Average Terrain Height'] return h @property def platformStartingAzimuth(self): azimuth = self.frame.S0 return azimuth @property def startingRange(self): return self.metadata['Image Starting Slant Range'] @property def squintAngle(self): """ Update this to use the sphere rather than planar approximation. """ startingRange = self.startingRange h = self.platformHeight v = self.velocity prf = self.frame.getInstrument().getPulseRepetitionFrequency() wavelength = self.frame.getInstrument().getRadarWavelength() if h > startingRange: raise ValueError("Spacecraft Height too large (%s>%s)" % (h, startingRange)) sinTheta = math.sqrt(1 - (h / startingRange)**2) fd = self.dopplerVals['Near'] sinSquint = fd / (2.0 * v * sinTheta) * wavelength if sinSquint**2 > 1: raise ValueError( "Error in One or More of the Squint Calculation Values\n" + "Doppler Centroid: %s\nVelocity: %s\nWavelength: %s\n" % (fd, v, wavelength)) self.squint = math.degrees( math.atan2(sinSquint, math.sqrt(1 - sinSquint**2))) #squint is also required in the frame. self.frame.squintAngle = math.radians(self.squint) return self.squint @property def heightDt(self): """ Delta(height)/Delta(Time) from frame start-time to mid-time """ return 0.0 @property def velocity(self): v = self.metadata['Average Along Track Velocity'] platform = self.frame.getInstrument().getPlatform() elp = self.elp peg = self.peg scale = (elp.pegRadCur + self.platformHeight) / elp.pegRadCur ds_ground = self.frame.instrument.getAzimuthPixelSize() dt = 1.0 / self.frame.instrument.getPulseRepetitionFrequency() v1 = scale * ds_ground / dt return v1 @property def elp(self): if not self._elp: planet = Planet(pname="Earth") self._elp = planet.get_elp() return self._elp @property def peg(self): if not self._peg: peg = [ math.degrees(self.metadata['Peg Latitude']), math.degrees(self.metadata['Peg Longitude']), math.degrees(self.metadata['Peg Heading']) ] th = self.metadata['Global Average Terrain Height'] platform = self.frame.getInstrument().getPlatform() self.elp.setSCH(peg[0], peg[1], peg[2], th) rc = self.elp.pegRadCur from isceobj.Location.Peg import Peg self._peg = Peg(latitude=peg[0], longitude=peg[1], heading=peg[2], radiusOfCurvature=rc) self.logger.info( "UAVSAR_Stack: peg radius of curvature = {}".format( self.elp.pegRadCur)) self.logger.info("UAVSAR_Stack: terrain height = {}".format(th)) return self._peg
class ERS_SLC(Sensor): family = 'ers_slc' logging_name = 'isce.sensor.ers_slc' parameter_list = (IMAGEFILE, LEADERFILE, ORBIT_TYPE, ORBIT_DIRECTORY, ORBIT_FILE) + Sensor.parameter_list @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.frame = Frame() self.frame.configure() self.dopplerRangeTime = None # Constants are from # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = {'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime':6.622e-6, 'iBias': 15.5, 'qBias': 15.5} return None def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() elif (self._orbitType == 'PDS'): self._populatePDSOrbits() else: self._populateHeaderOrbit() self._populateDoppler() def _populatePlatform(self): """ Populate the platform object with metadata """ platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet(pname='Earth')) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() prf = self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency'] rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1.0e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord.metadata[ 'Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length']*1e-6) instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/ (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']* 1e-6)) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" rangeSamplingRate = self.constants['rangeSamplingRate'] rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency() frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord.metadata[ 'Scene reference number']) prf = self.frame.instrument.getPulseRepetitionFrequency() tau0 = self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler range time of first range pixel']*1.0e-3 startingRange = tau0*Const.c/2.0 farRange = startingRange + self.imageFile.width*rangePixelSize first_line_utc = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler azimuth time of first azimuth pixel'], "%d-%b-%Y %H:%M:%S.%f") mid_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1) * 0.5 / prf) last_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1)/prf) self.logger.debug("Frame UTC start, mid, end times: %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(mid_line_utc) self.frame.setSensingStop(last_line_utc) def _populateHeaderOrbit(self): """Populate an orbit object with the header orbits""" self.logger.info("Using Header Orbits") orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') orbit.setOrbitQuality('Unknown') t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'] t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]) vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]) orbit.addStateVector(vec) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) odr = ODR(file=os.path.join(self._orbitDir,orbitFile)) startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60) odr.parseHeader(startTimePreInterp,stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) orbit = odr.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir,orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePDSOrbits(self): """ Populate an orbit object using the ERS-2 PDS format """ from isceobj.Orbit.PDS import PDS self.logger.info("Using PDS Orbits") pds = PDS(file=self._orbitFile) pds.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = pds.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populateDoppler(self): ''' Extract doppler from the CEOS file. ''' prf = self.frame.instrument.getPulseRepetitionFrequency() #####ERS provides doppler as a function of slant range time in seconds d0 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term'] d1 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term'] d2 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term'] self.dopplerRangeTime = [d0, d1, d2] return def extractDoppler(self): width = self.frame.getNumberOfSamples() prf = self.frame.instrument.getPulseRepetitionFrequency() midtime = 0.5*width/self.frame.instrument.getRangeSamplingRate() fd_mid = 0.0 x = 1.0 for ind, coeff in enumerate(self.dopplerRangeTime): fd_mid += coeff * x x *= midtime ####For insarApp quadratic = {} quadratic['a'] = fd_mid / prf quadratic['b'] = 0.0 quadratic['c'] = 0.0 ###For roiApp more accurate ####Convert stuff to pixel wise coefficients dr = self.frame.getInstrument().getRangePixelSize() norm = 0.5*Const.c/dr dcoeffs = [] for ind, val in enumerate(self.dopplerRangeTime): dcoeffs.append( val / (norm**ind)) self.frame._dopplerVsPixel = dcoeffs print('Doppler Fit: ', fit[::-1]) return quadratic def extractImage(self): import array import math self.parse() try: out = open(self.output, 'wb') except: raise Exception('Cannot open output file: %s'%(self.output)) self.imageFile.extractImage(output=out) out.close() rawImage = isceobj.createSlcImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) self.frame.setImage(rawImage) prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf)) musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond maxMusec = (24*3600)*10**6#use it to check if we went across a day. very rare day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1 outputArray = array.array('d',[0]*2*numPulses) self.frame.auxFile = self.output + '.aux' fp = open(self.frame.auxFile,'wb') j = -1 for i1 in range(numPulses): j += 1 musec = round((j/prf)*10**6) + musec0 if musec >= maxMusec: day0 += 1 musec0 = musec%maxMusec musec = musec0 j = 0 outputArray[2*i1] = day0 outputArray[2*i1+1] = musec outputArray.tofile(fp) fp.close() def _decodeSceneReferenceNumber(self,referenceNumber): frameNumber = referenceNumber.split('=') if (len(frameNumber) > 2): frameNumber = frameNumber[2].strip() else: frameNumber = frameNumber[0] return frameNumber
class Sentinel1(Sensor): """ A Class representing Sentinel1 StripMap data """ family = 's1sm' logging = 'isce.sensor.S1_SM' parameter_list = ( XML, TIFF, MANIFEST, SAFE, ORBIT_FILE, ORBIT_DIR, POLARIZATION, ) + Sensor.parameter_list def __init__(self, family='', name=''): super(Sentinel1, self).__init__(family if family else self.__class__.family, name=name) self.frame = Frame() self.frame.configure() self._xml_root = None def validateUserInputs(self): ''' Validate inputs from user. Populate tiff and xml from SAFE folder name. ''' import fnmatch import zipfile if not self.xml: if not self.safe: raise Exception('SAFE directory is not provided') ####First find annotation file ####Dont need swath number when driving with xml and tiff file if not self.xml: swathid = 's1?-s?-slc-{}'.format(self.polarization) dirname = self.safe if not self.xml: match = None if dirname.endswith('.zip'): pattern = os.path.join('*SAFE', 'annotation', swathid) + '*.xml' zf = zipfile.ZipFile(dirname, 'r') match = fnmatch.filter(zf.namelist(), pattern) zf.close() if (len(match) == 0): raise Exception( 'No annotation xml file found in zip file: {0}'.format( dirname)) ####Add /vsizip at the start to make it a zip file self.xml = '/vsizip/' + os.path.join(dirname, match[0]) else: pattern = os.path.join('annotation', swathid) + '*.xml' match = glob.glob(os.path.join(dirname, pattern)) if (len(match) == 0): raise Exception( 'No annotation xml file found in {0}'.format(dirname)) self.xml = match[0] if not self.xml: raise Exception('No annotation files found') print('Input XML file: ', self.xml) ####Find TIFF file if (not self.tiff) and (self.safe): match = None if dirname.endswith('.zip'): pattern = os.path.join('*SAFE', 'measurement', swathid) + '*.tiff' zf = zipfile.ZipFile(dirname, 'r') match = fnmatch.filter(zf.namelist(), pattern) zf.close() if (len(match) == 0): raise Exception( 'No tiff file found in zip file: {0}'.format(dirname)) ####Add /vsizip at the start to make it a zip file self.tiff = '/vsizip/' + os.path.join(dirname, match[0]) else: pattern = os.path.join('measurement', swathid) + '*.tiff' match = glob.glob(os.path.join(dirname, pattern)) if len(match) == 0: raise Exception( 'No tiff file found in directory: {0}'.format(dirname)) self.tiff = match[0] print('Input TIFF files: ', self.tiff) ####Find manifest files if self.safe: if dirname.endswith('.zip'): pattern = '*SAFE/manifest.safe' zf = zipfile.ZipFile(dirname, 'r') match = fnmatch.filter(zf.namelist(), pattern) zf.close() self.manifest = '/vsizip/' + os.path.join(dirname, match[0]) else: self.manifest = os.path.join(dirname, 'manifest.safe') print('Manifest files: ', self.manifest) return def getFrame(self): return self.frame def parse(self): ''' Actual parsing of the metadata for the product. ''' from isceobj.Sensor.TOPS.Sentinel1 import s1_findOrbitFile ###Check user inputs self.validateUserInputs() if self.xml.startswith('/vsizip'): import zipfile parts = self.xml.split(os.path.sep) if parts[2] == '': parts[2] = os.path.sep zipname = os.path.join(*(parts[2:-3])) fname = os.path.join(*(parts[-3:])) zf = zipfile.ZipFile(zipname, 'r') xmlstr = zf.read(fname) zf.close() else: with open(self.xml, 'r') as fid: xmlstr = fid.read() self._xml_root = ET.fromstring(xmlstr) self.populateMetadata() if self.manifest: self.populateIPFVersion() else: self.frame.setProcessingFacility('ESA') self.frame.setProcessingSoftwareVersion('IPFx.xx') if not self.orbitFile: if self.orbitDir: self.orbitFile = s1_findOrbitFile( self.orbitDir, self.frame.sensingStart, self.frame.sensingStop, mission=self.frame.getInstrument().getPlatform( ).getMission()) if self.orbitFile: orb = self.extractPreciseOrbit() self.frame.orbit.setOrbitSource(os.path.basename(self.orbitFile)) else: orb = self.extractOrbitFromAnnotation() self.frame.orbit.setOrbitSource('Annotation') for sv in orb: self.frame.orbit.addStateVector(sv) def grab_from_xml(self, path): try: res = self._xml_root.find(path).text except: raise Exception('Tag= %s not found' % (path)) if res is None: raise Exception('Tag = %s not found' % (path)) return res def convertToDateTime(self, string): dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f") return dt def populateMetadata(self): """ Create metadata objects from the metadata files """ ####Set each parameter one - by - one mission = self.grab_from_xml('adsHeader/missionId') swath = self.grab_from_xml('adsHeader/swath') polarization = self.grab_from_xml('adsHeader/polarisation') frequency = float( self.grab_from_xml( 'generalAnnotation/productInformation/radarFrequency')) passDirection = self.grab_from_xml( 'generalAnnotation/productInformation/pass') rangePixelSize = float( self.grab_from_xml( 'imageAnnotation/imageInformation/rangePixelSpacing')) azimuthPixelSize = float( self.grab_from_xml( 'imageAnnotation/imageInformation/azimuthPixelSpacing')) rangeSamplingRate = Const.c / (2.0 * rangePixelSize) prf = 1.0 / float( self.grab_from_xml( 'imageAnnotation/imageInformation/azimuthTimeInterval')) lines = int( self.grab_from_xml( 'imageAnnotation/imageInformation/numberOfLines')) samples = int( self.grab_from_xml( 'imageAnnotation/imageInformation/numberOfSamples')) startingRange = float( self.grab_from_xml( 'imageAnnotation/imageInformation/slantRangeTime') ) * Const.c / 2.0 incidenceAngle = float( self.grab_from_xml( 'imageAnnotation/imageInformation/incidenceAngleMidSwath')) dataStartTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productFirstLineUtcTime')) dataStopTime = self.convertToDateTime( self.grab_from_xml( 'imageAnnotation/imageInformation/productLastLineUtcTime')) pulseLength = float( self.grab_from_xml( 'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseLength' )) chirpSlope = float( self.grab_from_xml( 'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseRampRate' )) pulseBandwidth = pulseLength * chirpSlope ####Sentinel is always right looking lookSide = -1 # height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight ####Populate platform platform = self.frame.getInstrument().getPlatform() platform.setPlanet(Planet(pname="Earth")) platform.setMission(mission) platform.setPointingDirection(lookSide) platform.setAntennaLength(2 * azimuthPixelSize) ####Populate instrument instrument = self.frame.getInstrument() instrument.setRadarFrequency(frequency) instrument.setPulseRepetitionFrequency(prf) instrument.setPulseLength(pulseLength) instrument.setChirpSlope(pulseBandwidth / pulseLength) instrument.setIncidenceAngle(incidenceAngle) #self.frame.getInstrument().setRangeBias(0) instrument.setRangePixelSize(rangePixelSize) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setBeamNumber(swath) instrument.setPulseLength(pulseLength) #Populate Frame #self.frame.setSatelliteHeight(height) self.frame.setSensingStart(dataStartTime) self.frame.setSensingStop(dataStopTime) diffTime = DTUtil.timeDeltaToSeconds(dataStopTime - dataStartTime) / 2.0 sensingMid = dataStartTime + datetime.timedelta( microseconds=int(diffTime * 1e6)) self.frame.setSensingMid(sensingMid) self.frame.setPassDirection(passDirection) self.frame.setPolarization(polarization) self.frame.setStartingRange(startingRange) self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize) self.frame.setNumberOfLines(lines) self.frame.setNumberOfSamples(samples) self.frame.setPassDirection(passDirection) def extractOrbitFromAnnotation(self): ''' Extract orbit information from xml node. ''' node = self._xml_root.find('generalAnnotation/orbitList') frameOrbit = Orbit() frameOrbit.setOrbitSource('Header') for child in node: timestamp = self.convertToDateTime(child.find('time').text) pos = [] vel = [] posnode = child.find('position') velnode = child.find('velocity') for tag in ['x', 'y', 'z']: pos.append(float(posnode.find(tag).text)) for tag in ['x', 'y', 'z']: vel.append(float(velnode.find(tag).text)) vec = StateVector() vec.setTime(timestamp) vec.setPosition(pos) vec.setVelocity(vel) frameOrbit.addStateVector(vec) planet = self.frame.instrument.platform.planet orbExt = OrbitExtender(planet=planet) orbExt.configure() newOrb = orbExt.extendOrbit(frameOrbit) return newOrb def extractPreciseOrbit(self): ''' Extract precise orbit from given Orbit file. ''' try: fp = open(self.orbitFile, 'r') except IOError as strerr: print("IOError: %s" % strerr) return _xml_root = ET.ElementTree(file=fp).getroot() node = _xml_root.find('Data_Block/List_of_OSVs') orb = Orbit() orb.configure() margin = datetime.timedelta(seconds=40.0) tstart = self.frame.getSensingStart() - margin tend = self.frame.getSensingStop() + margin for child in node: timestamp = self.convertToDateTime(child.find('UTC').text[4:]) if (timestamp >= tstart) and (timestamp < tend): pos = [] vel = [] for tag in ['VX', 'VY', 'VZ']: vel.append(float(child.find(tag).text)) for tag in ['X', 'Y', 'Z']: pos.append(float(child.find(tag).text)) vec = StateVector() vec.setTime(timestamp) vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) fp.close() return orb def extractImage(self): """ Use gdal python bindings to extract image """ try: from osgeo import gdal except ImportError: raise Exception( 'GDAL python bindings not found. Need this for RSAT2/ TandemX / Sentinel1A.' ) self.parse() width = self.frame.getNumberOfSamples() lgth = self.frame.getNumberOfLines() src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly) band = src.GetRasterBand(1) fid = open(self.output, 'wb') for ii in range(lgth): data = band.ReadAsArray(0, ii, width, 1) data.tofile(fid) fid.close() src = None band = None #### slcImage = isceobj.createSlcImage() slcImage.setByteOrder('l') slcImage.setFilename(self.output) slcImage.setAccessMode('read') slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setLength(self.frame.getNumberOfLines()) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) self.frame.setImage(slcImage) def extractDoppler(self): ''' self.parse() Extract doppler information as needed by mocomp ''' from isceobj.Util import Poly1D node = self._xml_root.find('dopplerCentroid/dcEstimateList') tdiff = 1.0e9 dpoly = None for index, burst in enumerate(node): refTime = self.convertToDateTime(burst.find('azimuthTime').text) delta = abs((refTime - self.frame.sensingMid).total_seconds()) if delta < tdiff: tdiff = delta r0 = 0.5 * Const.c * float(burst.find('t0').text) coeffs = [ float(val) for val in burst.find('dataDcPolynomial').text.split() ] poly = Poly1D.Poly1D() poly.initPoly(order=len(coeffs) - 1) poly.setMean(r0) poly.setNorm(0.5 * Const.c) poly.setCoeffs(coeffs) dpoly = poly if dpoly is None: raise Exception( 'Could not extract Doppler information for S1 scene') ###Part for insarApp ###Should be removed in the future rmid = self.frame.startingRange + 0.5 * self.frame.getNumberOfSamples( ) * self.frame.getInstrument().getRangePixelSize() quadratic = {} quadratic['a'] = dpoly( rmid) / self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ###Actual Doppler Polynomial for accurate processing ###Will be used in roiApp pix = np.linspace(0, self.frame.getNumberOfSamples(), num=dpoly._order + 2) rngs = self.frame.startingRange + pix * self.frame.getInstrument( ).getRangePixelSize() evals = dpoly(rngs) fit = np.polyfit(pix, evals, dpoly._order) self.frame._dopplerVsPixel = list(fit[::-1]) print('Doppler Fit : ', fit[::-1]) return quadratic def populateIPFVersion(self): ''' Get IPF version from the manifest file. ''' try: if self.manifest.startswith('/vsizip'): import zipfile parts = self.manifest.split(os.path.sep) if parts[2] == '': parts[2] = os.path.sep zipname = os.path.join(*(parts[2:-2])) fname = os.path.join(*(parts[-2:])) print('MANS: ', zipname, fname) zf = zipfile.ZipFile(zipname, 'r') xmlstr = zf.read(fname) else: with open(self.manifest, 'r') as fid: xmlstr = fid.read() ####Setup namespace nsp = "{http://www.esa.int/safe/sentinel-1.0}" root = ET.fromstring(xmlstr) elem = root.find('.//metadataObject[@ID="processing"]') rdict = elem.find('.//xmlData/' + nsp + 'processing/' + nsp + 'facility').attrib self.frame.setProcessingFacility(rdict['site'] + ', ' + rdict['country']) rdict = elem.find('.//xmlData/' + nsp + 'processing/' + nsp + 'facility/' + nsp + 'software').attrib self.frame.setProcessingSoftwareVersion(rdict['name'] + ' ' + rdict['version']) except: ###Not a critical error ... continuing print( 'Could not read version number successfully from manifest file: ', self.manifest) pass return