class COSMO_SkyMed(Sensor): """ A class to parse COSMO-SkyMed metadata """ parameter_list = (HDF5, ) + Sensor.parameter_list logging_name = "isce.sensor.COSMO_SkyMed" family = 'cosmo_skymed' def __init__(self, family='', name=''): super().__init__(family if family else self.__class__.family, name=name) self.hdf5 = None #used to allow refactoring on tkfunc self._imageFileList = None ###Specific doppler functions for CSK self.dopplerRangeTime = [] self.dopplerAzimuthTime = [] self.azimuthRefTime = None self.rangeRefTime = None self.rangeFirstTime = None self.rangeLastTime = None ## make this a class attribute, and a Sensor.Constant--not a dictionary. self.constants = {'iBias': 127.5, 'qBias': 127.5} return None ## Note: this breaks the ISCE convention of getters. def getFrame(self): return self.frame #jng parse or parse_context never used def parse(self): try: fp = h5py.File(self.hdf5, 'r') except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return None self.populateMetadata(file=fp) fp.close() ## Use h5's context management-- TODO: debug and install as 'parse' def parse_context(self): try: with h5py.File(self.hdf5, 'r') as fp: self.populateMetadata(file=fp) except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return None def _populatePlatform(self, file=None): platform = self.frame.getInstrument().getPlatform() if np.isnan(file['S01'].attrs['Equivalent First Column Time']) and ( len(file['S01/B001'].attrs['Range First Times']) > 1): raise NotImplementedError( 'Current CSK reader does not handle RAW data not adjusted for SWST shifts' ) platform.setMission( file.attrs['Satellite ID']) # Could use Mission ID as well platform.setPlanet(Planet(pname="Earth")) platform.setPointingDirection( self.lookMap[file.attrs['Look Side'].decode('utf-8')]) platform.setAntennaLength(file.attrs['Antenna Length']) def _populateInstrument(self, file): instrument = self.frame.getInstrument() rangePixelSize = Const.c / (2 * file['S01'].attrs['Sampling Rate']) instrument.setRadarWavelength(file.attrs['Radar Wavelength']) instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF']) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(file['S01'].attrs['Range Chirp Length']) instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate']) instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate']) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) instrument.setBeamNumber(file.attrs['Multi-Beam ID']) def _populateFrame(self, file): rft = file['S01']['B001'].attrs['Range First Times'][0] slantRange = rft * Const.c / 2.0 sensingStart = self._parseNanoSecondTimeStamp( file.attrs['Scene Sensing Start UTC']) sensingStop = self._parseNanoSecondTimeStamp( file.attrs['Scene Sensing Stop UTC']) centerTime = DTUtil.timeDeltaToSeconds(sensingStop - sensingStart) / 2.0 sensingMid = sensingStart + datetime.timedelta( microseconds=int(centerTime * 1e6)) self.frame.setStartingRange(slantRange) self.frame.setPassDirection(file.attrs['Orbit Direction']) self.frame.setOrbitNumber(file.attrs['Orbit Number']) self.frame.setProcessingFacility(file.attrs['Processing Centre']) self.frame.setProcessingSoftwareVersion( file.attrs['L0 Software Version']) self.frame.setPolarization(file['S01'].attrs['Polarisation']) self.frame.setNumberOfLines(file['S01']['B001'].shape[0]) self.frame.setNumberOfSamples(file['S01']['B001'].shape[1]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = slantRange + self.frame.getNumberOfSamples() * rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self, file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t0 = datetime.datetime.strptime( file.attrs['Reference UTC'].decode('utf-8'), '%Y-%m-%d %H:%M:%S.%f000') t = file.attrs['State Vectors Times'] position = file.attrs['ECEF Satellite Position'] velocity = file.attrs['ECEF Satellite Velocity'] for i in range(len(position)): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i, 0], position[i, 1], position[i, 2]]) vec.setVelocity([velocity[i, 0], velocity[i, 1], velocity[i, 2]]) orbit.addStateVector(vec) def populateImage(self, filename): rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setFilename(filename) rawImage.setAccessMode('read') rawImage.setWidth(2 * self.frame.getNumberOfSamples()) rawImage.setXmax(2 * self.frame.getNumberOfSamples()) rawImage.setXmin(0) self.getFrame().setImage(rawImage) def _populateExtras(self, file): """ Populate some extra fields. """ self.dopplerRangeTime = file.attrs['Centroid vs Range Time Polynomial'] self.dopplerAzimuthTime = file.attrs[ 'Centroid vs Azimuth Time Polynomial'] self.rangeRefTime = file.attrs['Range Polynomial Reference Time'] self.azimuthRefTime = file.attrs['Azimuth Polynomial Reference Time'] self.rangeFirstTime = file['S01']['B001'].attrs['Range First Times'][0] self.rangeLastTime = self.rangeFirstTime + ( self.frame.getNumberOfSamples() - 1) / self.frame.instrument.getRangeSamplingRate() def extractImage(self): """Extract the raw image data""" import os from ctypes import cdll, c_char_p extract_csk = cdll.LoadLibrary(os.path.dirname(__file__) + '/csk.so') # Prepare and run the C-based extractor for i in range(len(self.hdf5FileList)): #need to create a new instance every time self.frame = Frame() self.frame.configure() appendStr = '_' + str(i) # if more than one file to contatenate that create different outputs # but suffixing _i if (len(self.hdf5FileList) == 1): appendStr = '' outputNow = self.output + appendStr self.hdf5 = self.hdf5FileList[i] inFile_c = c_char_p(bytes(self.hdf5, 'utf-8')) outFile_c = c_char_p(bytes(outputNow, 'utf-8')) extract_csk.extract_csk(inFile_c, outFile_c) # Now, populate the metadata try: fp = h5py.File(self.hdf5, 'r') except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return self.populateMetadata(file=fp) self.populateImage(outputNow) self._populateExtras(fp) fp.close() self.frameList.append(self.frame) createAuxFile(self.frame, outputNow + '.aux') self._imageFileList = self.hdf5FileList return tkfunc(self) def _parseNanoSecondTimeStamp(self, timestamp): """Parse a date-time string with nanosecond precision and return a datetime object """ dateTime, nanoSeconds = timestamp.decode('utf-8').split('.') microsec = float(nanoSeconds) * 1e-3 dt = datetime.datetime.strptime(dateTime, '%Y-%m-%d %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ quadratic = {} midtime = (self.rangeLastTime + self.rangeFirstTime) * 0.5 - self.rangeRefTime fd_mid = 0.0 x = 1.0 for ind, coeff in enumerate(self.dopplerRangeTime): fd_mid += coeff * x x *= midtime ####insarApp style quadratic['a'] = fd_mid / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ###For roiApp more accurate ####Convert stuff to pixel wise coefficients 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 ALOS2(Sensor): """ Code to read CEOSFormat leader files for ALOS2 SLC data. """ family = 'alos2' parameter_list = (WAVELENGTH, LEADERFILE, IMAGEFILE) + Sensor.parameter_list fsampConst = { 104: 1.047915957140240E+08, 52: 5.239579785701190E+07, 34: 3.493053190467460E+07, 17: 1.746526595233730E+07 } #Orbital Elements (Quality) Designator #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description #PALSAR-2_xx_Format_CEOS_E_r.pdf orbitElementsDesignator = { '0': 'preliminary', '1': 'decision', '2': 'high precision' } def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.leaderFile = None self.imageFile = None #####Soecific doppler functions for ALOS2 self.doppler_coeff = None self.azfmrate_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 10} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) fsamplookup = int(self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate in MHz']) rangePixelSize = Const.c / (2 * self.fsampConst[fsamplookup]) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(1) platform.setPlanet(Planet(pname='Earth')) if self.wavelength: ins.setRadarWavelength(float(self.wavelength)) # print('ins.radarWavelength = ', ins.getRadarWavelength(), # type(ins.getRadarWavelength())) else: ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency( self.leaderFile.sceneHeaderRecord. metadata['Pulse Repetition Frequency in mHz'] * 1.0e-3) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate(self.fsampConst[fsamplookup]) ins.setPulseLength(self.leaderFile.sceneHeaderRecord. metadata['Range pulse length in microsec'] * 1.0e-6) chirpSlope = self.leaderFile.sceneHeaderRecord.metadata[ 'Nominal range pulse (chirp) amplitude coefficient linear term'] chirpPulseBandwidth = abs( chirpSlope * self.leaderFile.sceneHeaderRecord. metadata['Range pulse length in microsec'] * 1.0e-6) ins.setChirpSlope(chirpSlope) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along pixel direction'].strip() ######ALOS2 includes this information in clock angle clockAngle = self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor clock angle'] if clockAngle == 90.0: platform.setPointingDirection(-1) elif clockAngle == -90.0: platform.setPointingDirection(1) else: raise Exception( 'Unknown look side. Clock Angle = {0}'.format(clockAngle)) # print(self.leaderFile.sceneHeaderRecord.metadata["Sensor ID and mode of operation for this channel"]) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) 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.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) ###### orb = self.frame.getOrbit() orb.setOrbitSource('Header') orb.setOrbitQuality(self.orbitElementsDesignator[ self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']]) 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates deltaT = self.leaderFile.platformPositionRecord.metadata[ 'Time interval between data points'] numPts = self.leaderFile.platformPositionRecord.metadata[ 'Number of data points'] orb = self.frame.getOrbit() for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i * deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata[ 'Positional Data Points'][i] pos = [ dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z'] ] vel = [ dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z'] ] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) self.doppler_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid quadratic term'] ] self.azfmrate_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate quadratic term'] ] # print('Terrain height: ', self.leaderFile.sceneHeaderRecord.metadata['Average terrain ellipsoid height']) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() # rangeGate = self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6 # delt = datetime.timedelta(seconds=rangeGate) delt = datetime.timedelta(seconds=0.0) self.frame.setSensingStart(self.imageFile.sensingStart + delt) self.frame.setSensingStop(self.imageFile.sensingStop + delt) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) + delt self.frame.setSensingMid(sensingMid) self.frame.setStartingRange(self.imageFile.nearRange) self.frame.getInstrument().setPulseRepetitionFrequency( self.imageFile.prf) pixelSize = self.frame.getInstrument().getRangePixelSize() farRange = self.imageFile.nearRange + (pixelSize - 1) * self.imageFile.width self.frame.setFarRange(farRange) 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) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' midwidth = self.frame.getNumberOfSamples() / 2.0 dop = 0.0 prod = 1.0 for ind, kk in enumerate(self.doppler_coeff): dop += kk * prod prod *= midwidth print('Average Doppler: {0}'.format(dop)) ####For insarApp quadratic = {} quadratic['a'] = dop / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate ####CEOS already provides function vs pixel self.frame._dopplerVsPixel = self.doppler_coeff return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
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 KOMPSAT5(Component): """ A class representing a Level1Product meta data. Level1Product(hdf5=h5filename) will parse the hdf5 file and produce an object with attributes for metadata. """ logging_name = 'isce.Sensor.KOMPSAT5' def __init__(self): super(KOMPSAT5,self).__init__() self.hdf5 = None self.output = None self.frame = Frame() self.frame.configure() # Some extra processing parameters unique to CSK SLC (currently) self.dopplerCoeffs = [] self.rangeFirstTime = None self.rangeLastTime = None self.rangeRefTime = None self.refUTC = None self.descriptionOfVariables = {} self.dictionaryOfVariables = {'HDF5': ['self.hdf5','str','mandatory'], 'OUTPUT': ['self.output','str','optional']} self.lookMap = {'RIGHT': -1, 'LEFT': 1} return def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self,d): self.__dict__.update(d) self.logger = logging.getLogger('isce.Sensor.COSMO_SkyMed_SLC') return def getFrame(self): return self.frame def parse(self): try: fp = h5py.File(self.hdf5,'r') except Exception as strerr: self.logger.error("IOError: %s" % strerr) return None self.populateMetadata(fp) fp.close() def populateMetadata(self, file): """ Populate our Metadata objects """ self._populatePlatform(file) self._populateInstrument(file) self._populateFrame(file) self._populateOrbit(file) self._populateExtras(file) def _populatePlatform(self, file): platform = self.frame.getInstrument().getPlatform() platform.setMission(file.attrs['Satellite ID']) platform.setPointingDirection(self.lookMap[file.attrs['Look Side'].decode('utf-8')]) platform.setPlanet(Planet("Earth")) ####This is an approximation for spotlight mode ####In spotlight mode, antenna length changes with azimuth position platform.setAntennaLength(file.attrs['Antenna Length']) try: if file.attrs['Multi-Beam ID'].startswith('ES'): platform.setAntennaLength(16000.0/file['S01/SBI'].attrs['Line Time Interval']) except: pass def _populateInstrument(self, file): instrument = self.frame.getInstrument() # rangePixelSize = Const.c/(2*file['S01'].attrs['Sampling Rate']) rangePixelSize = file['S01/SBI'].attrs['Column Spacing'] instrument.setRadarWavelength(file.attrs['Radar Wavelength']) # instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF']) instrument.setPulseRepetitionFrequency(1.0/file['S01/SBI'].attrs['Line Time Interval']) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(file['S01'].attrs['Range Chirp Length']) instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate']) # instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate']) instrument.setRangeSamplingRate(1.0/file['S01/SBI'].attrs['Column Time Interval']) incangle = 0.5*(file['S01/SBI'].attrs['Far Incidence Angle'] + file['S01/SBI'].attrs['Near Incidence Angle']) instrument.setIncidenceAngle(incangle) def _populateFrame(self, file): rft = file['S01/SBI'].attrs['Zero Doppler Range First Time'] slantRange = rft*Const.c/2.0 self.frame.setStartingRange(slantRange) referenceUTC = self._parseNanoSecondTimeStamp(file.attrs['Reference UTC']) relStart = file['S01/SBI'].attrs['Zero Doppler Azimuth First Time'] relEnd = file['S01/SBI'].attrs['Zero Doppler Azimuth Last Time'] relMid = 0.5*(relStart + relEnd) sensingStart = self._combineDateTime(referenceUTC, relStart) sensingStop = self._combineDateTime(referenceUTC, relEnd) sensingMid = self._combineDateTime(referenceUTC, relMid) self.frame.setPassDirection(file.attrs['Orbit Direction']) self.frame.setOrbitNumber(file.attrs['Orbit Number']) self.frame.setProcessingFacility(file.attrs['Processing Centre']) self.frame.setProcessingSoftwareVersion(file.attrs['L0 Software Version']) self.frame.setPolarization(file['S01'].attrs['Polarisation']) self.frame.setNumberOfLines(file['S01/SBI'].shape[0]) self.frame.setNumberOfSamples(file['S01/SBI'].shape[1]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = slantRange + (self.frame.getNumberOfSamples()-1)*rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self,file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t0 = datetime.datetime.strptime(file.attrs['Reference UTC'].decode('utf-8'),'%Y-%m-%d %H:%M:%S.%f000') t = file.attrs['State Vectors Times'] position = file.attrs['ECEF Satellite Position'] velocity = file.attrs['ECEF Satellite Velocity'] for i in range(len(position)): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i,0],position[i,1],position[i,2]]) vec.setVelocity([velocity[i,0],velocity[i,1],velocity[i,2]]) orbit.addStateVector(vec) def _populateExtras(self, file): """ Populate some of the extra fields unique to processing TSX data. In the future, other sensors may need this information as well, and a re-organization may be necessary. """ from isceobj.Doppler.Doppler import Doppler scale = file['S01'].attrs['PRF'] * file['S01/SBI'].attrs['Line Time Interval'] self.dopplerCoeffs = file.attrs['Centroid vs Range Time Polynomial']*scale self.rangeRefTime = file.attrs['Range Polynomial Reference Time'] self.rangeFirstTime = file['S01/SBI'].attrs['Zero Doppler Range First Time'] self.rangeLastTime = file['S01/SBI'].attrs['Zero Doppler Range Last Time'] def extractImage(self): import os from ctypes import cdll, c_char_p extract_csk = cdll.LoadLibrary(os.path.dirname(__file__)+'/csk.so') inFile_c = c_char_p(bytes(self.hdf5, 'utf-8')) outFile_c = c_char_p(bytes(self.output, 'utf-8')) extract_csk.extract_csk_slc(inFile_c, outFile_c) self.parse() slcImage = isceobj.createSlcImage() slcImage.setFilename(self.output) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') self.frame.setImage(slcImage) def _parseNanoSecondTimeStamp(self,timestamp): """ Parse a date-time string with nanosecond precision and return a datetime object """ dateTime,nanoSeconds = timestamp.decode('utf-8').split('.') microsec = float(nanoSeconds)*1e-3 dt = datetime.datetime.strptime(dateTime,'%Y-%m-%d %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def _combineDateTime(self,dobj, secsstr): '''Takes the date from dobj and time from secs to spit out a date time object. ''' sec = float(secsstr) dt = datetime.timedelta(seconds = sec) return dobj + dt def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ quadratic = {} midtime = (self.rangeLastTime + self.rangeFirstTime)*0.5 - self.rangeRefTime fd_mid = self.dopplerCoeffs[0] + self.dopplerCoeffs[1]*midtime + self.dopplerCoeffs[2]*midtime*midtime quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. 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 Radarsat1(Sensor): """ Code to read CEOSFormat leader files for Radarsat-1 SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ family = 'radarsat1' logging_name = 'isce.sensor.radarsat1' parameter_list = (LEADERFILE, IMAGEFILE, PARFILE) + Sensor.parameter_list auxLength = 50 @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.imageFile = None self.leaderFile = None #####Soecific doppler functions for RSAT1 self.doppler_ref_range = None self.doppler_ref_azi = None self.doppler_predict = None self.doppler_DAR = None self.doppler_coeff = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 15} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() if self._parFile: self.parseParFile() else: self.populateCEOSOrbit() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate'] * 1e6) except ZeroDivisionError: rangePixelSize = 0 ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet(pname='Earth')) ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) ##RSAT-1 does not have PRF for raw data in leader file. # self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency']) ins.setRangePixelSize(rangePixelSize) ins.setPulseLength( self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] * 1e-6) chirpPulseBandwidth = 15.50829e6 # Is this really not in the CEOSFormat Header? ins.setChirpSlope( chirpPulseBandwidth / (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] * 1e-6)) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) 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.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) self.frame.getOrbit().setOrbitSource('Header') self.frame.getOrbit().setOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) def populateCEOSOrbit(self): from isceobj.Orbit.Inertial import ECI2ECR 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates orb = Orbit() for i in range(self.leaderFile.platformPositionRecord. metadata['Number of data points']): vec = StateVector() t = t0 + datetime.timedelta( seconds=(i * self.leaderFile.platformPositionRecord. metadata['Time interval between DATA points'])) 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'] / 1000., dataPoints['Velocity vector Y'] / 1000., dataPoints['Velocity vector Z'] / 1000. ]) orb.addStateVector(vec) #####Convert orbits from ECI to ECEF frame. t0 = orb._stateVectors[0]._time ang = self.leaderFile.platformPositionRecord.metadata[ 'Greenwich mean hour angle'] cOrb = ECI2ECR(orb, GAST=ang, epoch=t0) wgsorb = cOrb.convert() orb = self.frame.getOrbit() for sv in wgsorb: orb.addStateVector(sv) print(sv) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() ####RSAT1 is weird. Contains all useful info in RAW data and not leader. ins = self.frame.getInstrument() ins.setPulseRepetitionFrequency(self.imageFile.prf) ins.setPulseLength(self.imageFile.pulseLength) ins.setRangeSamplingRate(self.imageFile.rangeSamplingRate) ins.setRangePixelSize(Const.c / (2 * self.imageFile.rangeSamplingRate)) ins.setChirpSlope(self.imageFile.chirpSlope) ###### self.frame.setSensingStart(self.imageFile.sensingStart) sensingStop = self.imageFile.sensingStart + datetime.timedelta( seconds=((self.frame.getNumberOfLines() - 1) / self.imageFile.prf)) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingStop(sensingStop) self.frame.setSensingMid(sensingMid) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setStartingRange(self.imageFile.startingRange) farRange = self.imageFile.startingRange + ins.getRangePixelSize( ) * self.imageFile.width * 0.5 self.frame.setFarRange(farRange) rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) rawImage.renderHdr() self.frame.setImage(rawImage) def parseParFile(self): '''Parse the par file if any is available.''' if self._parFile not in (None, ''): par = ParFile(self._parFile) ####Update orbit svs = par['prep_block']['sensor']['ephemeris']['sv_block'][ 'state_vector'] datefmt = '%Y%m%d%H%M%S%f' for entry in svs: sv = StateVector() sv.setPosition( [float(entry['x']), float(entry['y']), float(entry['z'])]) sv.setVelocity([ float(entry['xv']), float(entry['yv']), float(entry['zv']) ]) sv.setTime(datetime.datetime.strptime(entry['Date'], datefmt)) self.frame.orbit.addStateVector(sv) self.frame.orbit._stateVectors = sorted( self.frame.orbit._stateVectors, key=lambda x: x.getTime()) doppinfo = par['prep_block']['sensor']['beam'][ 'DopplerCentroidParameters'] #######Selectively update some values. #######Currently used only for doppler centroids. self.doppler_ref_range = float(doppinfo['reference_range']) self.doppler_ref_azi = datetime.datetime.strptime( doppinfo['reference_date'], '%Y%m%d%H%M%S%f') self.doppler_predict = float(doppinfo['Predict_doppler']) self.doppler_DAR = float(doppinfo['DAR_doppler']) coeff = doppinfo['doppler_centroid_coefficients'] rngOrder = int(coeff['number_of_coefficients_first_dimension']) - 1 azOrder = int(coeff['number_of_coefficients_second_dimension']) - 1 self.doppler_coeff = Poly2D.Poly2D() self.doppler_coeff.initPoly(rangeOrder=rngOrder, azimuthOrder=azOrder) self.doppler_coeff.setMeanRange(self.doppler_ref_range) self.doppler_coeff.setMeanAzimuth( secondsSinceMidnight(self.doppler_ref_azi)) parms = [] for ii in range(azOrder + 1): row = [] for jj in range(rngOrder + 1): key = 'a%d%d' % (ii, jj) val = float(coeff[key]) row.append(val) parms.append(row) self.doppler_coeff.setCoeffs(parms) def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' rmin = self.frame.getStartingRange() rmax = self.frame.getFarRange() rmid = 0.5 * (rmin + rmax) delr = Const.c / (2 * self.frame.instrument.rangeSamplingRate) azmid = secondsSinceMidnight(self.frame.getSensingMid()) print(rmid, self.doppler_coeff.getMeanRange()) print(azmid, self.doppler_coeff.getMeanAzimuth()) if self.doppler_coeff is None: raise Exception( 'ASF PARFILE was not provided. Cannot determine default doppler.' ) dopav = self.doppler_coeff(azmid, rmid) prf = self.frame.getInstrument().getPulseRepetitionFrequency() quadratic = {} quadratic['a'] = dopav / prf quadratic['b'] = 0. quadratic['c'] = 0. ######Set up the doppler centroid computation just like CSK at mid azimuth order = self.doppler_coeff._rangeOrder rng = np.linspace(rmin, rmax, num=(order + 2)) pix = (rng - rmin) / delr val = [self.doppler_coeff(azmid, x) for x in rng] print(rng, val) print(delr, pix) fit = np.polyfit(pix, val, order) self.frame._dopplerVsPixel = list(fit[::-1]) # self.frame._dopplerVsPixel = [dopav,0.,0.,0.] return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
class COSMO_SkyMed_SLC(Sensor): """ A class representing a Level1Product meta data. Level1Product(hdf5=h5filename) will parse the hdf5 file and produce an object with attributes for metadata. """ parameter_list = (HDF5, ) + Sensor.parameter_list logging_name = 'isce.Sensor.COSMO_SkyMed_SLC' family = 'cosmo_skymed_slc' def __init__(self, family='', name=''): super(COSMO_SkyMed_SLC, self).__init__(family if family else self.__class__.family, name=name) self.frame = Frame() self.frame.configure() # Some extra processing parameters unique to CSK SLC (currently) self.dopplerRangeTime = [] self.dopplerAzimuthTime = [] self.azimuthRefTime = None self.rangeRefTime = None self.rangeFirstTime = None self.rangeLastTime = None self.lookMap = {'RIGHT': -1, 'LEFT': 1} return def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self, d): self.__dict__.update(d) self.logger = logging.getLogger('isce.Sensor.COSMO_SkyMed_SLC') return def getFrame(self): return self.frame def parse(self): try: fp = h5py.File(self.hdf5, 'r') except Exception as strerr: self.logger.error("IOError: %s" % strerr) return None self.populateMetadata(fp) fp.close() def populateMetadata(self, file): """ Populate our Metadata objects """ self._populatePlatform(file) self._populateInstrument(file) self._populateFrame(file) self._populateOrbit(file) self._populateExtras(file) def _populatePlatform(self, file): platform = self.frame.getInstrument().getPlatform() platform.setMission(file.attrs['Satellite ID']) platform.setPointingDirection( self.lookMap[file.attrs['Look Side'].decode('utf-8')]) platform.setPlanet(Planet(pname="Earth")) ####This is an approximation for spotlight mode ####In spotlight mode, antenna length changes with azimuth position platform.setAntennaLength(file.attrs['Antenna Length']) try: if file.attrs['Multi-Beam ID'].startswith('ES'): platform.setAntennaLength( 16000.0 / file['S01/SBI'].attrs['Line Time Interval']) except: pass def _populateInstrument(self, file): instrument = self.frame.getInstrument() # rangePixelSize = Const.c/(2*file['S01'].attrs['Sampling Rate']) rangePixelSize = file['S01/SBI'].attrs['Column Spacing'] instrument.setRadarWavelength(file.attrs['Radar Wavelength']) # instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF']) instrument.setPulseRepetitionFrequency( 1.0 / file['S01/SBI'].attrs['Line Time Interval']) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(file['S01'].attrs['Range Chirp Length']) instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate']) # instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate']) instrument.setRangeSamplingRate( 1.0 / file['S01/SBI'].attrs['Column Time Interval']) incangle = 0.5 * (file['S01/SBI'].attrs['Far Incidence Angle'] + file['S01/SBI'].attrs['Near Incidence Angle']) instrument.setIncidenceAngle(incangle) def _populateFrame(self, file): rft = file['S01/SBI'].attrs['Zero Doppler Range First Time'] slantRange = rft * Const.c / 2.0 self.frame.setStartingRange(slantRange) referenceUTC = self._parseNanoSecondTimeStamp( file.attrs['Reference UTC']) relStart = file['S01/SBI'].attrs['Zero Doppler Azimuth First Time'] relEnd = file['S01/SBI'].attrs['Zero Doppler Azimuth Last Time'] relMid = 0.5 * (relStart + relEnd) sensingStart = self._combineDateTime(referenceUTC, relStart) sensingStop = self._combineDateTime(referenceUTC, relEnd) sensingMid = self._combineDateTime(referenceUTC, relMid) self.frame.setPassDirection(file.attrs['Orbit Direction']) self.frame.setOrbitNumber(file.attrs['Orbit Number']) self.frame.setProcessingFacility(file.attrs['Processing Centre']) self.frame.setProcessingSoftwareVersion( file.attrs['L0 Software Version']) self.frame.setPolarization(file['S01'].attrs['Polarisation']) self.frame.setNumberOfLines(file['S01/SBI'].shape[0]) self.frame.setNumberOfSamples(file['S01/SBI'].shape[1]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = slantRange + (self.frame.getNumberOfSamples() - 1) * rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self, file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t0 = datetime.datetime.strptime( file.attrs['Reference UTC'].decode('utf-8'), '%Y-%m-%d %H:%M:%S.%f000') t = file.attrs['State Vectors Times'] position = file.attrs['ECEF Satellite Position'] velocity = file.attrs['ECEF Satellite Velocity'] for i in range(len(position)): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i, 0], position[i, 1], position[i, 2]]) vec.setVelocity([velocity[i, 0], velocity[i, 1], velocity[i, 2]]) orbit.addStateVector(vec) def _populateExtras(self, file): """ Populate some of the extra fields unique to processing TSX data. In the future, other sensors may need this information as well, and a re-organization may be necessary. """ from isceobj.Doppler.Doppler import Doppler self.dopplerRangeTime = file.attrs['Centroid vs Range Time Polynomial'] self.dopplerAzimuthTime = file.attrs[ 'Centroid vs Azimuth Time Polynomial'] self.rangeRefTime = file.attrs['Range Polynomial Reference Time'] self.azimuthRefTime = file.attrs['Azimuth Polynomial Reference Time'] self.rangeFirstTime = file['S01/SBI'].attrs[ 'Zero Doppler Range First Time'] self.rangeLastTime = file['S01/SBI'].attrs[ 'Zero Doppler Range Last Time'] # get Doppler rate information, vs. azimuth first EJF 2015/00/05 # guessing that same scale applies as for Doppler centroid self.dopplerRateCoeffs = file.attrs[ 'Doppler Rate vs Azimuth Time Polynomial'] def extractImage(self): import os from ctypes import cdll, c_char_p extract_csk = cdll.LoadLibrary(os.path.dirname(__file__) + '/csk.so') inFile_c = c_char_p(bytes(self.hdf5, 'utf-8')) outFile_c = c_char_p(bytes(self.output, 'utf-8')) extract_csk.extract_csk_slc(inFile_c, outFile_c) self.parse() slcImage = isceobj.createSlcImage() slcImage.setFilename(self.output) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') self.frame.setImage(slcImage) def _parseNanoSecondTimeStamp(self, timestamp): """ Parse a date-time string with nanosecond precision and return a datetime object """ dateTime, nanoSeconds = timestamp.decode('utf-8').split('.') microsec = float(nanoSeconds) * 1e-3 dt = datetime.datetime.strptime(dateTime, '%Y-%m-%d %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def _combineDateTime(self, dobj, secsstr): '''Takes the date from dobj and time from secs to spit out a date time object. ''' sec = float(secsstr) dt = datetime.timedelta(seconds=sec) return datetime.datetime.combine(dobj.date(), datetime.time(0, 0)) + dt def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ import numpy as np quadratic = {} midtime = (self.rangeLastTime + self.rangeFirstTime) * 0.5 - self.rangeRefTime fd_mid = 0.0 x = 1.0 for ind, coeff in enumerate(self.dopplerRangeTime): fd_mid += coeff * x x *= midtime ####insarApp style quadratic['a'] = fd_mid / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp more accurate ####Convert stuff to pixel wise coefficients 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]) #EMG - 20160420 This section was introduced in the populateMetadata method by EJF in r2022 #Its pupose seems to be to set self.doppler_coeff and self.azfmrate_coeff, which don't seem #to be used anywhere in ISCE. Need to take time to understand the need for this and consult #with EJF. # ## save the Doppler centroid coefficients, converting units from .h5 file ## units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2) ## ISCE expects Hz, Hz/(range sample), Hz/(range sample)^2 ## note that RS2 Doppler values are estimated at time dc.dopplerCentroidReferenceTime, ## so the values might need to be adjusted for ISCE usage ## adapted from RS2 version EJF 2015/09/05 # poly = self.frame._dopplerVsPixel # rangeSamplingRate = self.frame.getInstrument().getPulseRepetitionFrequency() # # need to convert units # poly[1] = poly[1]/rangeSamplingRate # poly[2] = poly[2]/rangeSamplingRate**2 # self.doppler_coeff = poly # ## similarly save Doppler azimuth fm rate values, converting units ## units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2) ## units are already converted below ## Guessing that ISCE expects Hz, Hz/(azimuth line), Hz/(azimuth line)^2 ## note that RS2 Doppler values are estimated at time dc.dopplerRateReferenceTime, ## so the values might need to be adjusted for ISCE usage ## modified from RS2 version EJF 2015/09/05 ## CSK Doppler azimuth FM rate not yet implemented in reading section, set to zero for now # # fmpoly = self.dopplerRateCoeffs # # don't need to convert units ## fmpoly[1] = fmpoly[1]/rangeSamplingRate ## fmpoly[2] = fmpoly[2]/rangeSamplingRate**2 # self.azfmrate_coeff = fmpoly #EMG - 20160420 return quadratic
class EnviSAT(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, self).__init__(family if family else self.__class__.family, name=name) self.imageryFile = None self._instrumentFileData = None self._imageryFileData = None self.logger = logging.getLogger("isce.sensor.EnviSAT") 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 """ imageryFileParser = ImageryFile(fileName=self.imageryFile) self._imageryFileData = imageryFileParser.parse() first_line_utc = datetime.datetime.strptime( self._imageryFileData['SENSING_START'], '%d-%b-%Y %H:%M:%S.%f') if self.instrumentFile in [None, '']: self.findInstrumentFile(first_line_utc) instrumentFileParser = InstrumentFile(fileName=self.instrumentFile) self._instrumentFileData = instrumentFileParser.parse() self.populateMetadata() def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() 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._instrumentFileData['sampleRate']) txPulseLength = self._imageryFileData[ 'TxPulseLengthCodeword'] / self._instrumentFileData['sampleRate'] pri = self._imageryFileData['priCodeword'] / self._instrumentFileData[ 'sampleRate'] chirpPulseBandwidth = self._imageryFileData[ 'chirpPulseBandwidthCodeword'] * 16.0e6 / 255.0 chirpSlope = chirpPulseBandwidth / txPulseLength ####ChirpSlope from GADS index = self._imageryFileData['antennaBeamSetNumber'] - 1 chirpSlope = 2.0 * self._instrumentFileData['nom_chirp_{0}'.format( index)][6] if (chirpSlope * txPulseLength) > chirpPulseBandwidth: print('Warning: Chirp Bandwidth > Slope * Pulse length') print('Check parser again .....') instrument.setRangePixelSize(rangeSampleSpacing) instrument.setPulseLength(txPulseLength) #instrument.setSwath(imageryFileData['SWATH']) instrument.setRadarFrequency(self._instrumentFileData['frequency']) instrument.setChirpSlope(chirpSlope) instrument.setRangeSamplingRate(self._instrumentFileData['sampleRate']) instrument.setPulseRepetitionFrequency(1 / pri) #instrument.setRangeBias(rangeBias) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" # Decode some code words, and calculate some parameters numberOfLines = None for dataSet in self._imageryFileData['dataSets']: if (dataSet['DS_NAME'] == 'ASAR_SOURCE_PACKETS'): numberOfLines = int(dataSet['NUM_DSR']) numberOfSamples = self._imageryFileData['numberOfSamples'] pri = self._imageryFileData['priCodeword'] / self._instrumentFileData[ 'sampleRate'] windowStartTime = self._imageryFileData[ 'windowStartTimeCodeword'] / self._instrumentFileData['sampleRate'] rangeSampleSpacing = Const.c / (2 * self._instrumentFileData['sampleRate']) index = self._imageryFileData['antennaBeamSetNumber'] - 1 startingRange = (self._instrumentFileData['r_values'][index] * pri + windowStartTime) * Const.c / 2.0 farRange = startingRange + numberOfSamples * rangeSampleSpacing rangeBias = self._instrumentFileData['rangeGateBias'] * Const.c / 2 # The %b in the next lines strptime read the abbreviated month of the year by locale and could # present a problem for people with a different locale set. first_line_utc = datetime.datetime.strptime( self._imageryFileData['SENSING_START'], '%d-%b-%Y %H:%M:%S.%f') center_line_utc = datetime.datetime.strptime( self._imageryFileData['SENSING_START'], '%d-%b-%Y %H:%M:%S.%f') last_line_utc = datetime.datetime.strptime( self._imageryFileData['SENSING_STOP'], '%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 - rangeBias) self.frame.setFarRange(farRange - rangeBias) 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['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, outStruct, outname): width = outStruct.samples length = outStruct.lines #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 = createRawImage() rawImage.setFilename(outname) rawImage.setAccessMode('read') rawImage.setByteOrder('l') rawImage.setXmin(0) rawImage.setXmax(2 * width) rawImage.setWidth(2 * width) self.frame.setImage(rawImage) def extractImage(self): from datetime import datetime as dt import tempfile as tf lib = ctypes.cdll.LoadLibrary( os.path.dirname(__file__) + '/envisat.so') #check if input file is a string or a list (then do concatenation) #ussume that one orbit and one instrument is enough for all the frame in the list # if isinstance(self._imageryFileList,str): # self._imageryFileList = [self._imageryFileList] self.frameList = [] for i in range(len(self._imageryFileList)): appendStr = '_' + str(i) #intermediate raw files suffix if len(self._imageryFileList) == 1: appendStr = '' # no suffix if only one file outputNow = self.output + appendStr auxImage = isceobj.createImage() widthAux = 2 auxName = outputNow + '.aux' self.imageryFile = self._imageryFileList[i] self.frame = Frame() self.frame.configure() #add the auxFile as part of the frame and diring the stitching create also a combined aux file self.frame.auxFile = auxName self.parse() #Declare the types of the arguments to asa_im_decode lib.asa_im_decode.argtypes = [ ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_ushort, ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int) ] #Set the daysToRemove variable for the call to asa_im_decode sensingYear = self.frame.getSensingStart().year daysToRemove = ctypes.c_int( (dt(sensingYear - 1, 12, 31) - dt(2000, 1, 1)).days) #Create memory for pointers nsamps and nlines to be set by #asa_im_decode a = 1 b = 2 nsamps = ctypes.pointer(ctypes.c_int(a)) nlines = ctypes.pointer(ctypes.c_int(b)) #Variables for outType and windowStartTimeCodeword0 passed to #asa_im_decode c = 1 d = 0 lib.asa_im_decode( ctypes.c_char_p(bytes(self.imageryFile, 'utf-8')), ctypes.c_char_p(bytes(self.instrumentFile, 'utf-8')), ctypes.c_char_p(bytes(outputNow, 'utf-8')), ctypes.c_char_p(bytes(auxName, 'utf-8')), ctypes.c_int(c), ctypes.c_ushort(d), daysToRemove, nsamps, nlines) #Create the outStruct for the call to populateImage outStruct = ImageOutput(nsamps[0], nlines[0]) self._populateImage(outStruct, outputNow) self.frameList.append(self.frame) pass ## refactor this with __init__.tkfunc tk = Track() if (len(self._imageryFileList) > 1): self.frame = tk.combineFrames(self.output, self.frameList) for i in range(len(self._imageryFileList)): try: os.remove(self.output + "_" + str(i)) except OSError: print("Error. Cannot remove temporary file", self.output + "_" + str(i)) raise OSError pass pass pass def findOrbitFile(self): datefmt = '%Y%m%d%H%M%S' sensingStart = self.frame.getSensingStart() 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 outFile def findInstrumentFile(self, sensingStart): datefmt = '%Y%m%d%H%M%S' if sensingStart is None: raise Exception('Image data not read in yet') 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 outFile
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
class Radarsat2(Component): """ A Class representing RadarSAT 2 data """ def __init__(self): Component.__init__(self) self.xml = None self.tiff = None self.output = None self.product = _Product() self.frame = Frame() self.frame.configure() self.descriptionOfVariables = {} self.dictionaryOfVariables = {'XML': ['self.xml','str','mandatory'], 'TIFF': ['self.tiff','str','mandatory'], '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 populateMetadata(self): """ Create metadata objects from the metadata files """ mission = self.product.sourceAttributes.satellite swath = self.product.sourceAttributes.radarParameters.beams frequency = self.product.sourceAttributes.radarParameters.radarCenterFrequency prf = self.product.sourceAttributes.radarParameters.prf rangePixelSize = self.product.imageAttributes.rasterAttributes.sampledPixelSpacing rangeSamplingRate = Const.c/(2*rangePixelSize) pulseLength = self.product.sourceAttributes.radarParameters.pulseLengths[0] pulseBandwidth = self.product.sourceAttributes.radarParameters.pulseBandwidths[0] polarization = self.product.sourceAttributes.radarParameters.polarizations lookSide = lookMap[self.product.sourceAttributes.radarParameters.antennaPointing.upper()] facility = self.product.imageGenerationParameters.generalProcessingInformation._processingFacility version = self.product.imageGenerationParameters.generalProcessingInformation.softwareVersion lines = self.product.imageAttributes.rasterAttributes.numberOfLines samples = self.product.imageAttributes.rasterAttributes.numberOfSamplesPerLine startingRange = self.product.imageGenerationParameters.slantRangeToGroundRange.slantRangeTimeToFirstRangeSample * (Const.c/2) incidenceAngle = (self.product.imageGenerationParameters.sarProcessingInformation.incidenceAngleNearRange + self.product.imageGenerationParameters.sarProcessingInformation.incidenceAngleFarRange)/2 lineFlip = (self.product.imageAttributes.rasterAttributes.lineTimeOrdering.upper() == 'DECREASING') if lineFlip: dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine else: dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine passDirection = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.passDirection height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight ####Populate platform platform = self.frame.getInstrument().getPlatform() platform.setPlanet(Planet("Earth")) platform.setMission(mission) platform.setPointingDirection(lookSide) platform.setAntennaLength(15.0) ####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) # Initialize orbit objects # Read into temp orbit first. # Radarsat 2 needs orbit extensions. tempOrbit = Orbit() self.frame.getOrbit().setOrbitSource('Header: ' + self.product.sourceAttributes.orbitAndAttitude.orbitInformation.orbitDataFile) self.frame.setPassDirection(passDirection) stateVectors = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.stateVectors for i in range(len(stateVectors)): position = [stateVectors[i].xPosition, stateVectors[i].yPosition, stateVectors[i].zPosition] velocity = [stateVectors[i].xVelocity, stateVectors[i].yVelocity, stateVectors[i].zVelocity] vec = StateVector() vec.setTime(stateVectors[i].timeStamp) vec.setPosition(position) vec.setVelocity(velocity) tempOrbit.addStateVector(vec) planet = self.frame.instrument.platform.planet orbExt = OrbitExtender(planet=planet) orbExt.configure() newOrb = orbExt.extendOrbit(tempOrbit) for sv in newOrb: self.frame.getOrbit().addStateVector(sv) def extractImage(self, verbose=True): ''' Use gdal to extract the slc. ''' 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() lineFlip = (self.product.imageAttributes.rasterAttributes.lineTimeOrdering.upper() == 'DECREASING') pixFlip = (self.product.imageAttributes.rasterAttributes.pixelTimeOrdering.upper() == 'DECREASING') src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly) cJ = np.complex64(1.0j) ####Images are small enough that we can do it all in one go - Piyush real = src.GetRasterBand(1).ReadAsArray(0,0,width,lgth) imag = src.GetRasterBand(2).ReadAsArray(0,0,width,lgth) if (real is None) or (imag is None): raise Exception('Input Radarsat2 SLC seems to not be a 2 band Int16 image.') data = real+cJ*imag real = None imag = None src = None if lineFlip: if verbose: print('Vertically Flipping data') data = np.flipud(data) if pixFlip: if verbose: print('Horizontally Flipping data') data = np.fliplr(data) data.tofile(self.output) #### slcImage = isceobj.createSlcImage() slcImage.setByteOrder('l') slcImage.setFilename(self.output) slcImage.setAccessMode('read') slcImage.setWidth(width) slcImage.setLength(lgth) slcImage.setXmin(0) slcImage.setXmax(width) # slcImage.renderHdr() 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['b'] = 0. quadratic['c'] = 0. return quadratic
class UAVSAR_HDF5_SLC(Sensor): """ A class representing a Level1Product meta data. Level1Product(hdf5=h5filename) will parse the hdf5 file and produce an object with attributes for metadata. """ parameter_list = (HDF5, FREQUENCY, POLARIZATION) + Sensor.parameter_list logging_name = 'isce.Sensor.UAVSAR_HDF5_SLC' family = 'uavsar_hdf5_slc' def __init__(self, family='', name=''): # , frequency='frequencyA', polarization='HH'): super(UAVSAR_HDF5_SLC, self).__init__(family if family else self.__class__.family, name=name) self.frame = Frame() self.frame.configure() # Some extra processing parameters unique to UAVSAR HDF5 SLC (currently) self.dopplerRangeTime = [] self.dopplerAzimuthTime = [] self.azimuthRefTime = None self.rangeRefTime = None self.rangeFirstTime = None self.rangeLastTime = None #self.frequency = frequency #self.polarization = polarization self.lookMap = {'right': -1, 'left': 1} return def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self, d): self.__dict__.update(d) self.logger = logging.getLogger('isce.Sensor.UAVSAR_HDF5_SLC') return def getFrame(self): return self.frame def parse(self): try: fp = h5py.File(self.hdf5, 'r') except Exception as strerr: self.logger.error("IOError: %s" % strerr) return None self.populateMetadata(fp) fp.close() def populateMetadata(self, file): """ Populate our Metadata objects """ self._populatePlatform(file) self._populateInstrument(file) self._populateFrame(file) self._populateOrbit(file) def _populatePlatform(self, file): platform = self.frame.getInstrument().getPlatform() platform.setMission( file['/science/LSAR/identification'].get('missionId')[( )].decode('utf-8')) platform.setPointingDirection( self.lookMap[file['/science/LSAR/identification'].get( 'lookDirection')[()].decode('utf-8')]) platform.setPlanet(Planet(pname="Earth")) # We are not using this value anywhere. Let's fix it for now. platform.setAntennaLength(12.0) def _populateInstrument(self, file): instrument = self.frame.getInstrument() rangePixelSize = file['/science/LSAR/SLC/swaths/' + self.frequency + '/slantRangeSpacing'][()] wvl = SPEED_OF_LIGHT / file['/science/LSAR/SLC/swaths/' + self.frequency + '/processedCenterFrequency'][()] instrument.setRadarWavelength(wvl) instrument.setPulseRepetitionFrequency( 1.0 / file['/science/LSAR/SLC/swaths/zeroDopplerTimeSpacing'][()]) rangePixelSize = file['/science/LSAR/SLC/swaths/' + self.frequency + '/slantRangeSpacing'][()] instrument.setRangePixelSize(rangePixelSize) # Chrip slope and length only are used in the split spectrum workflow to compute the bandwidth. # Therefore fixing it to 1.0 won't breack anything Chirp_slope = 1.0 rangeBandwidth = file['/science/LSAR/SLC/swaths/' + self.frequency + '/processedRangeBandwidth'][()] Chirp_length = rangeBandwidth / Chirp_slope instrument.setPulseLength(Chirp_length) instrument.setChirpSlope(Chirp_slope) rangeSamplingFrequency = SPEED_OF_LIGHT / 2. / rangePixelSize instrument.setRangeSamplingRate(rangeSamplingFrequency) incangle = 0.0 instrument.setIncidenceAngle(incangle) def _populateFrame(self, file): slantRange = file['/science/LSAR/SLC/swaths/' + self.frequency + '/slantRange'][0] self.frame.setStartingRange(slantRange) referenceUTC = file['/science/LSAR/SLC/swaths/zeroDopplerTime'].attrs[ 'units'].decode('utf-8') referenceUTC = referenceUTC.replace('seconds since ', '') format_str = '%Y-%m-%d %H:%M:%S' if '.' in referenceUTC: format_str += '.%f' referenceUTC = datetime.datetime.strptime(referenceUTC, format_str) relStart = file['/science/LSAR/SLC/swaths/zeroDopplerTime'][0] relEnd = file['/science/LSAR/SLC/swaths/zeroDopplerTime'][-1] relMid = 0.5 * (relStart + relEnd) sensingStart = self._combineDateTime(referenceUTC, relStart) sensingStop = self._combineDateTime(referenceUTC, relEnd) sensingMid = self._combineDateTime(referenceUTC, relMid) self.frame.setPassDirection( file['/science/LSAR/identification'].get('orbitPassDirection')[( )].decode('utf-8')) self.frame.setOrbitNumber( file['/science/LSAR/identification'].get('trackNumber')[()]) self.frame.setProcessingFacility('JPL') self.frame.setProcessingSoftwareVersion( file['/science/LSAR/SLC/metadata/processingInformation/algorithms'] .get('ISCEVersion')[()].decode('utf-8')) self.frame.setPolarization(self.polarization) self.frame.setNumberOfLines( file['/science/LSAR/SLC/swaths/' + self.frequency + '/' + self.polarization].shape[0]) self.frame.setNumberOfSamples( file['/science/LSAR/SLC/swaths/' + self.frequency + '/' + self.polarization].shape[1]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.instrument.rangePixelSize farRange = slantRange + (self.frame.getNumberOfSamples() - 1) * rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self, file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') referenceUTC = file['/science/LSAR/SLC/swaths/zeroDopplerTime'].attrs[ 'units'].decode('utf-8') referenceUTC = referenceUTC.replace('seconds since ', '') format_str = '%Y-%m-%d %H:%M:%S' if '.' in referenceUTC: format_str += '.%f' t0 = datetime.datetime.strptime(referenceUTC, format_str) t = file['/science/LSAR/SLC/metadata/orbit/time'] position = file['/science/LSAR/SLC/metadata/orbit/position'] velocity = file['/science/LSAR/SLC/metadata/orbit/velocity'] for i in range(len(position)): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i, 0], position[i, 1], position[i, 2]]) vec.setVelocity([velocity[i, 0], velocity[i, 1], velocity[i, 2]]) orbit.addStateVector(vec) def extractImage(self): import numpy as np import h5py self.parse() fid = h5py.File(self.hdf5, 'r') ds = fid['/science/LSAR/SLC/swaths/' + self.frequency + '/' + self.polarization] nLines = ds.shape[0] # force casting to complex64 with ds.astype(np.complex64): with open(self.output, 'wb') as fout: for ii in range(nLines): ds[ii, :].tofile(fout) fid.close() slcImage = isceobj.createSlcImage() slcImage.setFilename(self.output) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') slcImage.renderHdr() self.frame.setImage(slcImage) def _parseNanoSecondTimeStamp(self, timestamp): """ Parse a date-time string with nanosecond precision and return a datetime object """ dateTime, nanoSeconds = timestamp.decode('utf-8').split('.') microsec = float(nanoSeconds) * 1e-3 dt = datetime.datetime.strptime(dateTime, '%Y-%m-%d %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def _combineDateTime(self, dobj, secsstr): '''Takes the date from dobj and time from secs to spit out a date time object. ''' sec = float(secsstr) dt = datetime.timedelta(seconds=sec) return dobj + dt def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ import h5py from scipy.interpolate import UnivariateSpline import numpy as np h5 = h5py.File(self.hdf5, 'r') # extract the 2D LUT of Doppler and choose only one range line as the data duplicates for other range lines dop = h5['/science/LSAR/SLC/metadata/processingInformation/parameters/' + self.frequency + '/dopplerCentroid'][0, :] rng = h5[ '/science/LSAR/SLC/metadata/processingInformation/parameters/slantRange'] # extract the slant range of the image grid imgRng = h5['/science/LSAR/SLC/swaths/' + self.frequency + '/slantRange'] # use only part of the slant range that closely covers image ranges and ignore the rest ind0 = np.argmin(np.abs(rng - imgRng[0])) - 1 ind0 = np.max([0, ind0]) ind1 = np.argmin(np.abs(rng - imgRng[-1])) + 1 ind1 = np.min([ind1, rng.shape[0]]) dop = dop[ind0:ind1] rng = rng[ind0:ind1] f = UnivariateSpline(rng, dop) imgDop = f(imgRng) dr = imgRng[1] - imgRng[0] pix = (imgRng - imgRng[0]) / dr fit = np.polyfit(pix, imgDop, 41) self.frame._dopplerVsPixel = list(fit[::-1]) ####insarApp style (doesn't get used for stripmapApp). A fixed Doppler at the middle of the scene quadratic = {} quadratic['a'] = imgDop[int( imgDop.shape[0] / 2)] / self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. 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 S1toFrame(object): ''' Create a traditional ISCE Frame object from S1 container. ''' def __init__(self, sar, obj): self.sar = sar self.obj = obj self.missionId = self.obj.xpath('.//missionId/text()')[0] self.missionId_char = MISSION_RE.search(self.missionId).group(1) self.frame = Frame() self.frame.configure() self.parse() def parse(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() self._populateExtras() def _populatePlatform(self): platform = self.frame.getInstrument().getPlatform() platform.setMission(self.missionId) platform.setPlanet(Planet(pname='Earth')) platform.setPointingDirection(-1) platform.setAntennaLength(40.0) def _populateInstrument(self): ins = self.frame.getInstrument() b0 = self.sar.bursts[0] b1 = self.sar.bursts[-1] ins.setRadarWavelength(b0.radarWavelength) ins.setPulseRepetitionFrequency(1.0 / b0.azimuthTimeInterval) ins.setRangePixelSize(b0.rangePixelSize) tau = self.obj.generalAnnotation.replicaInformationList.replicaInformation.referenceReplica.timeDelay ins.setPulseLength(float(tau)) slope = str( self.obj.generalAnnotation.replicaInformationList. replicaInformation.referenceReplica.phaseCoefficients).split()[2] ins.setChirpSlope(float(slope)) fsamp = Const.c / (2.0 * b0.rangePixelSize) ins.setRangeSamplingRate(fsamp) ins.setInPhaseValue(127.5) ins.setQuadratureValue(127.5) ins.setBeamNumber(self.obj.adsHeader.swath) def _populateFrame(self): frame = self.frame b0 = self.sar.bursts[0] b1 = self.sar.bursts[-1] hdg = self.obj.generalAnnotation.productInformation.platformHeading if hdg < -90: frame.setPassDirection('Descending') else: frame.setPassDirection('Ascending') frame.setStartingRange(b0.startingRange) frame.setOrbitNumber(int(self.obj.adsHeader.absoluteOrbitNumber)) frame.setProcessingFacility('Sentinel 1%s' % self.missionId_char) frame.setProcessingSoftwareVersion('IPF') frame.setPolarization(self.obj.adsHeader.polarisation) frame.setNumberOfSamples( int(self.obj.imageAnnotation.imageInformation.numberOfSamples)) frame.setNumberOfLines( int(self.obj.imageAnnotation.imageInformation.numberOfLines)) frame.setSensingStart(b0.sensingStart) frame.setSensingStop(b1.sensingStop) tmid = b0.sensingStart + 0.5 * (b1.sensingStop - b0.sensingStart) frame.setSensingMid(tmid) farRange = b0.startingRange + frame.getNumberOfSamples( ) * b0.rangePixelSize frame.setFarRange(farRange) def _populateOrbit(self): b0 = self.sar.bursts[0] self.frame.orbit = b0.orbit def _populateExtras(self): b0 = self.sar.bursts[0] self.frame._squintAngle = 0.0 self.frame.doppler = b0.doppler._coeffs[0] match = DATASETTYPE_RE.search(self.sar.xml) if match: self.frame.datasetType = 'slc' else: self.frame.datasetType = ''
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 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 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 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 JERS(Component): """ Code to read CEOSFormat leader files for ERS-1/2 SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ #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]} def __init__(self): Component.__init__(self) self._leaderFile = None self._imageFile = None self.output = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 12} self.descriptionOfVariables = {} self.dictionaryOfVariables = {'LEADERFILE': ['self._leaderFile','str','mandatory'], 'IMAGEFILE': ['self._imageFile','str','mandatory'], 'OUTPUT': ['self.output','str','optional']} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self.leaderFile.sceneHeaderRecord.metadata['Scene reference number'].strip() frame = self._decodeSceneReferenceNumber(frame) rangePixelSize = Constants.SPEED_OF_LIGHT/(2*self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1e6) self.frame.getInstrument().getPlatform().setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier']) self.frame.getInstrument().getPlatform().setPlanet(Planet(pname='Earth')) self.frame.getInstrument().setWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) self.frame.getInstrument().setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency']) self.frame.getInstrument().setRangePixelSize(rangePixelSize) self.frame.getInstrument().setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6) chirpPulseBandwidth = 15.50829e6 # Is this really not in the CEOSFormat Header? self.frame.getInstrument().setChirpSlope(chirpPulseBandwidth/(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) #self.frame.setStartingRange(self.leaderFile.facilityRecord.metadata['Slant range reference']) 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('HH') self.frame.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel']) self.frame.getOrbit().setOrbitSource('Header') 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(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() t = t0 + datetime.timedelta(seconds=(i*self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'])) 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']]) self.frame.getOrbit().addStateVector(vec) def extractImage(self): raise NotImplementedError() def _decodeSceneReferenceNumber(self,referenceNumber): return referenceNumber
class SAOCOM_SLC(Sensor): parameter_list = (IMAGEFILE, XEMTFILE, XMLFILE) + Sensor.parameter_list """ A Class for parsing SAOCOM instrument and imagery files """ family = 'saocom_slc' def __init__(self,family='',name=''): super(SAOCOM_SLC, self).__init__(family if family else self.__class__.family, name=name) self._imageFile = None self._xemtFileParser = None self._xmlFileParser = None self._instrumentFileData = None self._imageryFileData = None self.dopplerRangeTime = None self.rangeRefTime = None self.azimuthRefTime = None self.rangeFirstTime = None self.rangeLastTime = None self.logger = logging.getLogger("isce.sensor.SAOCOM_SLC") self.frame = None self.frameList = [] self.lookMap = {'RIGHT': -1, 'LEFT': 1} self.nearIncidenceAngle = {'S1DP': 20.7, 'S2DP': 24.9, 'S3DP': 29.1, 'S4DP': 33.7, 'S5DP': 38.2, 'S6DP': 41.3, 'S7DP': 44.6, 'S8DP': 47.2, 'S9DP': 48.8, 'S1QP': 17.6, 'S2QP': 19.5, 'S3QP': 21.4, 'S4QP': 23.2, 'S5QP': 25.3, 'S6QP': 27.2, 'S7QP': 29.6, 'S8QP': 31.2, 'S9QP': 33.0, 'S10QP': 34.6} self.farIncidenceAngle = {'S1DP': 25.0, 'S2DP': 29.2, 'S3DP': 33.8, 'S4DP': 38.3, 'S5DP': 41.3, 'S6DP': 44.5, 'S7DP': 47.1, 'S8DP': 48.7, 'S9DP': 50.2, 'S1QP': 19.6, 'S2QP': 21.5, 'S3QP': 23.3, 'S4QP': 25.4, 'S5QP': 27.3, 'S6QP': 29.6, 'S7QP': 31.2, 'S8QP': 33.0, 'S9QP': 34.6, 'S10QP': 35.5} 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._xemtFileParser = XEMTFile(fileName=self.xemtFile) self._xemtFileParser.parse() self._xmlFileParser = XMLFile(fileName=self.xmlFile) self._xmlFileParser.parse() self.populateMetadata() def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() self._populateExtras() def _populatePlatform(self): """Populate the platform object with metadata""" platform = self.frame.getInstrument().getPlatform() # Populate the Platform and Scene objects platform.setMission(self._xmlFileParser.sensorName) platform.setPointingDirection(self.lookMap[self._xmlFileParser.sideLooking]) platform.setAntennaLength(9.968) platform.setPlanet(Planet(pname="Earth")) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() rangePixelSize = self._xmlFileParser.PSRng azimuthPixelSize = self._xmlFileParser.PSAz radarWavelength = Const.c/float(self._xmlFileParser.fc_hz) instrument.setRadarWavelength(radarWavelength) instrument.setPulseRepetitionFrequency(self._xmlFileParser.prf) instrument.setRangePixelSize(rangePixelSize) instrument.setAzimuthPixelSize(azimuthPixelSize) instrument.setPulseLength(self._xmlFileParser.pulseLength) instrument.setChirpSlope(float(self._xmlFileParser.pulseBandwidth)/float(self._xmlFileParser.pulseLength)) instrument.setRangeSamplingRate(self._xmlFileParser.frg) incAngle = 0.5*(self.nearIncidenceAngle[self._xemtFileParser.beamID] + self.farIncidenceAngle[self._xemtFileParser.beamID]) instrument.setIncidenceAngle(incAngle) def _populateFrame(self): """Populate the scene object with metadata""" rft = self._xmlFileParser.rangeStartTime slantRange = float(rft)*Const.c/2.0 self.frame.setStartingRange(slantRange) sensingStart = self._parseNanoSecondTimeStamp(self._xmlFileParser.azimuthStartTime) sensingTime = self._xmlFileParser.lines/self._xmlFileParser.prf sensingStop = sensingStart + datetime.timedelta(seconds=sensingTime) sensingMid = sensingStart + datetime.timedelta(seconds=0.5*sensingTime) self.frame.setPassDirection(self._xmlFileParser.orbitDirection) self.frame.setProcessingFacility(self._xemtFileParser.facilityID) self.frame.setProcessingSoftwareVersion(self._xemtFileParser.softVersion) self.frame.setPolarization(self._xmlFileParser.polarization) self.frame.setNumberOfLines(self._xmlFileParser.lines) self.frame.setNumberOfSamples(self._xmlFileParser.samples) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = slantRange + (self.frame.getNumberOfSamples()-1)*rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t0 = self._parseNanoSecondTimeStamp(self._xmlFileParser.orbitStartTime) t = np.arange(self._xmlFileParser.numberSV)*self._xmlFileParser.deltaTimeSV position = self._xmlFileParser.orbitPositionXYZ velocity = self._xmlFileParser.orbitVelocityXYZ for i in range(0,self._xmlFileParser.numberSV): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i*3],position[i*3+1],position[i*3+2]]) vec.setVelocity([velocity[i*3],velocity[i*3+1],velocity[i*3+2]]) orbit.addStateVector(vec) print("valor "+str(i)+": "+str(dt)) def _populateExtras(self): from isceobj.Doppler.Doppler import Doppler self.dopplerRangeTime = self._xmlFileParser.dopRngTime self.rangeRefTime = self._xmlFileParser.trg self.rangeFirstTime = self._xmlFileParser.rangeStartTime def extractImage(self): """ Exports GeoTiff to ISCE format. """ from osgeo import gdal ds = gdal.Open(self._imageFileName) metadata = ds.GetMetadata() geoTs = ds.GetGeoTransform() #GeoTransform prj = ds.GetProjection() #Projection dataType = ds.GetRasterBand(1).DataType gcps = ds.GetGCPs() sds = ds.ReadAsArray() # Output raster array to ISCE file driver = gdal.GetDriverByName('ISCE') export = driver.Create(self.output, ds.RasterXSize, ds.RasterYSize, 1, dataType) band = export.GetRasterBand(1) band.WriteArray(sds) export.SetGeoTransform(geoTs) export.SetMetadata(metadata) export.SetProjection(prj) export.SetGCPs(gcps,prj) band.FlushCache() export.FlushCache() self.parse() slcImage = isceobj.createSlcImage() slcImage.setFilename(self.output) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') self.frame.setImage(slcImage) def _parseNanoSecondTimeStamp(self,timestamp): """ Parse a date-time string with microsecond precision and return a datetime object """ dateTime,decSeconds = timestamp.split('.') microsec = float("0."+decSeconds)*1e6 dt = datetime.datetime.strptime(dateTime,'%d-%b-%Y %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def extractDoppler(self): """ Return the doppler centroid. """ 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 ALOS(Component): """Code to read CEOSFormat leader files for ALOS SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ family = 'alos' logging_name = 'isce.sensor.ALOS' parameter_list = (IMAGEFILE, LEADERFILE, OUTPUT, RESAMPLE_FLAG) # polarizationMap = ['H','V','H+V'] ## This is manifestly better than a method complete the lazy instantation ## of an instance attribute transmit = Distortion(complex(2.427029e-3, 1.293019e-2), complex(-1.147240e-2, -6.228230e-3), complex(9.572169e-1, 3.829563e-1)) receive = Distortion(complex(-6.263392e-3, 7.082863e-3), complex(-6.297074e-3, 8.026685e-3), complex(7.217117e-1, -2.367683e-2)) constants = Constants(iBias=15.5, qBias=15.5, pointingDirection=-1, antennaLength=8.9) HEADER_LINES = 720 RESAMPLE_FLAG = { '': 'do Nothing', 'single2dual': 'resample from single to dual pole', 'dual2single': 'resample from dual to single' } @logged def __init__(self, name=''): super(ALOS, self).__init__(family=self.__class__.family, name=name) self._leaderFile = None self._imageFile = None self.frame = None return None #2013-06-03 Kosal: the functions below overwrite the transmit property #initiated above ''' @property def transmit(self): return self.__class__.transmit @transmit.setter def transmit(self, x): raise TypeError( "ALOS.transmit is a protected class attribute and cannot be set" ) @property def receive(self): return self.__class__.receive @receive.setter def receive(self, x): raise TypeError( "ALOS.receive is a protected class attribute and cannot be set" ) ''' #Kosal def getFrame(self): return self.frame def setLeaderFile(self, ldr): self._leaderFile = ldr return def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.imageFile = ImageFile(self) try: self.leaderFile.parse() self.imageFile.parse() except IOError: return self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() # Header orbits self._populateOrbit() self._populateAttitude() self._populateDistortions() pass def _populatePlatform(self): platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setPointingDirection(self.constants.pointing_direction) platform.setAntennaLength(self.constants.antenna_length) platform.setPlanet(Planet('Earth')) def _populateInstrument(self): instrument = self.frame.getInstrument() rangePixelSize = None rangeSamplingRate = None chirpSlope = None bandwidth = None prf = None try: rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ 'Range sampling rate'] * 1e6 pulseLength = self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length'] * 1e-6 rangePixelSize = SPEED_OF_LIGHT / (2.0 * rangeSamplingRate) prf = self.leaderFile.sceneHeaderRecord.metadata[ 'Pulse Repetition Frequency'] beamNumber = self.leaderFile.sceneHeaderRecord.metadata[ 'Antenna beam number'] if self.imageFile.prf: prf = self.imageFile.prf else: self.logger.info("Using nominal PRF") bandwidth = self.leaderFile.calibrationRecord.metadata[ 'Band width'] * 1e6 #if (not bandwidth): # bandwidth = self.leaderFile.sceneHeaderRecord.metadata[ # 'Bandwidth per look in range'] chirpSlope = -(bandwidth / pulseLength) except AttributeError: self.logger.info("Some of the instrument parameters were not set") self.logger.debug("PRF: %s" % prf) self.logger.debug("Bandwidth: %s" % bandwidth) self.logger.debug("Pulse Length: %s" % pulseLength) self.logger.debug("Chirp Slope: %s" % chirpSlope) self.logger.debug("Range Pixel Size: %s" % rangePixelSize) self.logger.debug("Range Sampling Rate: %s" % rangeSamplingRate) self.logger.debug("Beam Number: %s" % beamNumber) instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangePixelSize(rangePixelSize) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setPulseLength(pulseLength) instrument.setChirpSlope(chirpSlope) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) instrument.setBeamNumber(beamNumber) return None def _populateFrame(self, polarization='HH', farRange=None): frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: first_line_utc = self.imageFile.start_time last_line_utc = self.imageFile.stop_time centerTime = DTUtil.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 center_line_utc = first_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(center_line_utc) self.frame.setSensingStop(last_line_utc) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = (self.imageFile.startingRange + self.imageFile.width * rangePixelSize) except TypeError as strerr: self.logger.warn(strerr) self.frame.frameNumber = frame self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(self.imageFile.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(polarization) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) def _populateOrbit(self): orbit = self.frame.getOrbit() velocityScale = 1.0 if (self.leaderFile.sceneHeaderRecord. metadata['Processing facility identifier'] == 'ERSDAC'): # The ERSDAC header orbits are in mm/s velocityScale = 1000.0 orbit.setReferenceFrame(self.leaderFile.platformPositionRecord. metadata['Reference coordinate system']) orbit.setOrbitSource('Header') orbitQuality = self._decodeOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) orbit.setOrbitQuality(orbitQuality) 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) for i in range(self.leaderFile.platformPositionRecord. metadata['Number of data points']): vec = OrbitStateVector() t = t0 + datetime.timedelta( seconds=i * self.leaderFile.platformPositionRecord. metadata['Time interval between DATA points']) 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'] / velocityScale, dataPoints['Velocity vector Y'] / velocityScale, dataPoints['Velocity vector Z'] / velocityScale ]) orbit.addStateVector(vec) def _populateAttitude(self): if (self.leaderFile.leaderFDR. metadata['Number of attitude data records'] != 1): return attitude = self.frame.getAttitude() attitude.setAttitudeSource("Header") year = int( self.leaderFile.sceneHeaderRecord.metadata['Scene centre time'] [0:4]) t0 = datetime.datetime(year=year, month=1, day=1) for i in range(self.leaderFile.platformAttitudeRecord. metadata['Number of attitude data points']): vec = AttitudeStateVector() dataPoints = self.leaderFile.platformAttitudeRecord.metadata[ 'Attitude Data Points'][i] t = t0 + datetime.timedelta( days=(dataPoints['Day of the year'] - 1), milliseconds=dataPoints['Millisecond of day']) vec.setTime(t) vec.setPitch(dataPoints['Pitch']) vec.setRoll(dataPoints['Roll']) vec.setYaw(dataPoints['Yaw']) attitude.addStateVector(vec) def _populateDistortions(self): return None def readOrbitPulse(self, leader, raw, width): from isceobj.Sensor import readOrbitPulse as ROP rawImage = isceobj.createRawImage() leaImage = isceobj.createStreamImage() auxImage = isceobj.createImage() rawImage.initImage(raw, 'read', width) rawImage.createImage() rawAccessor = rawImage.getImagePointer() leaImage.initImage(leader, 'read') leaImage.createImage() leaAccessor = leaImage.getImagePointer() widthAux = 2 auxName = raw + '.aux' self.frame.auxFile = auxName auxImage.initImage(auxName, 'write', widthAux, type='DOUBLE') auxImage.createImage() auxAccessor = auxImage.getImagePointer() length = rawImage.getLength() ROP.setNumberBitesPerLine_Py(width) ROP.setNumberLines_Py(length) ROP.readOrbitPulse_Py(leaAccessor, rawAccessor, auxAccessor) rawImage.finalizeImage() leaImage.finalizeImage() auxImage.finalizeImage() return None ## Can this even be done/ ## should the pointer be an __Int__? def readOrbitPulseDevelopement(self, leader, raw, width): from isceobj.Sensor import readOrbitPulse as ROP with isceobj.contextRawImage( width=width, accessMode='read', ) as rawImage: with isceobj.contextStreamImage( width=width, accessMode='read', ) as leaImage: with isceobj.contextImage( width=width, accessMode='write', ) as auxImage: rawAccessor = rawImage.getImagePointer() leaAccessor = leaImage.getImagePointer() widthAux = 2 auxName = raw + '.aux' self.frame.auxFile = auxName auxImage.initImage(auxName, 'write', widthAux, type='DOUBLE') auxImage.createImage() auxAccessor = auxImage.getImagePointer() length = rawImage.getLength() ROP.setNumberBitesPerLine_Py(width) ROP.setNumberLines_Py(length) ROP.readOrbitPulse_Py(leaAccessor, rawAccessor, auxAccessor) pass #rawImage.finalizeImage() pass #leaImage.finalizeImage() pass #auxImage.finalizeImage() return None def extractImage(self): # 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 RuntimeError 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.imageFile = ImageFile(self) try: self.leaderFile.parse() self.imageFile.parse(calculateRawDimensions=False) outputNow = self.output + appendStr if not (self._resampleFlag == ''): filein = self.output + '__tmp__' self.imageFile.extractImage(filein) self.populateMetadata() objResample = None if (self._resampleFlag == 'single2dual'): objResample = ALOS_fbs2fbdPy() else: objResample = ALOS_fbd2fbsPy() objResample.wireInputPort('frame', object=self.frame) objResample.setInputFilename(filein) objResample.setOutputFilename(outputNow) objResample.run() objResample.updateFrame(self.frame) os.remove(filein) else: self.imageFile.extractImage(outputNow) self.populateMetadata() width = self.frame.getImage().getWidth() self.readOrbitPulse(self._leaderFile, outputNow, width) self.frameList.append(self.frame) except IOError: return pass ## refactor this with __init__.tkfunc return tkfunc(self) def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber def _decodeOrbitQuality(self, quality): try: quality = int(quality) except ValueError: quality = None qualityString = '' if (quality == 0): qualityString = 'Preliminary' elif (quality == 1): qualityString = 'Decision' elif (quality == 2): qualityString = 'High Precision' else: qualityString = 'Unknown' return qualityString
class ALOS_SLC(Sensor): """ Code to read CEOSFormat leader files for ALOS SLC data. """ parameter_list = (WAVELENGTH, LEADERFILE, IMAGEFILE) + Sensor.parameter_list family = 'alos_slc' logging_name = 'isce.sensor.ALOS_SLC' #Orbital Elements (Quality) Designator #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description #PALSAR-2_xx_Format_CEOS_E_r.pdf orbitElementsDesignator = {'0': 'preliminary', '1': 'decision', '2': 'high precision'} def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.imageFile = None self.leaderFile = None # Specific doppler functions for ALOS self.doppler_coeff = None self.azfmrate_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = {'antennaLength': 15} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() self._populateExtras() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber(self.leaderFile.sceneHeaderRecord.metadata['Scene reference number']) fsamplookup = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate in MHz']*1.0e6 rangePixelSize = Const.c/(2*fsamplookup) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(1) platform.setPlanet(Planet(pname='Earth')) if self.wavelength: ins.setRadarWavelength(float(self.wavelength)) else: ins.setRadarWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency in mHz']*1.0e-3) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate(fsamplookup) ins.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6) chirpSlope = self.leaderFile.sceneHeaderRecord.metadata['Nominal range pulse (chirp) amplitude coefficient linear term'] chirpPulseBandwidth = abs(chirpSlope * self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6) ins.setChirpSlope(chirpSlope) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along pixel direction'].strip() ######ALOS includes this information in clock angle clockAngle = self.leaderFile.sceneHeaderRecord.metadata['Sensor clock angle'] if clockAngle == 90.0: platform.setPointingDirection(-1) elif clockAngle == -90.0: platform.setPointingDirection(1) else: raise Exception('Unknown look side. Clock Angle = {0}'.format(clockAngle)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) 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.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel']) self.frame.instrument.setAzimuthPixelSize(self.leaderFile.dataQualitySummaryRecord.metadata['Azimuth resolution']) ###### orb = self.frame.getOrbit() orb.setOrbitSource('Header') orb.setOrbitQuality( self.orbitElementsDesignator[ self.leaderFile.platformPositionRecord.metadata['Orbital elements designator'] ] ) 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(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']) #####Read in orbit in inertial coordinates deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between data points'] numPts = self.leaderFile.platformPositionRecord.metadata['Number of data points'] orb = self.frame.getOrbit() for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i*deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] pos = [dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']] vel = [dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) self.doppler_coeff = [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term']] self.azfmrate_coeff = [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate constant term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate linear term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate quadratic term']] def _populateExtras(self): dataset = self.leaderFile.radiometricRecord.metadata print("Record Number: %d" % (dataset["Record Number"])) print("First Record Subtype: %d" % (dataset["First Record Subtype"])) print("Record Type Code: %d" % (dataset["Record Type Code"])) print("Second Record Subtype: %d" % (dataset["Second Record Subtype"])) print("Third Record Subtype: %d" % (dataset["Third Record Subtype"])) print("Record Length: %d" % (dataset["Record Length"])) print("SAR channel indicator: %d" % (dataset["SAR channel indicator"])) print("Number of data sets: %d" % (dataset["Number of data sets"])) numPts = dataset['Number of data sets'] for i in range(numPts): if i > 1: break print('Radiometric record field: %d' % (i+1)) dataset = self.leaderFile.radiometricRecord.metadata[ 'Radiometric data sets'][i] DT11 = complex(dataset['Real part of DT 1,1'], dataset['Imaginary part of DT 1,1']) DT12 = complex(dataset['Real part of DT 1,2'], dataset['Imaginary part of DT 1,2']) DT21 = complex(dataset['Real part of DT 2,1'], dataset['Imaginary part of DT 2,1']) DT22 = complex(dataset['Real part of DT 2,2'], dataset['Imaginary part of DT 2,2']) DR11 = complex(dataset['Real part of DR 1,1'], dataset['Imaginary part of DR 1,1']) DR12 = complex(dataset['Real part of DR 1,2'], dataset['Imaginary part of DR 1,2']) DR21 = complex(dataset['Real part of DR 2,1'], dataset['Imaginary part of DR 2,1']) DR22 = complex(dataset['Real part of DR 2,2'], dataset['Imaginary part of DR 2,2']) print("Calibration factor [dB]: %f" % (dataset["Calibration factor"])) print('Distortion matrix Trasmission [DT11, DT12, DT21, DT22]: ' '[%s, %s, %s, %s]' % (str(DT11), str(DT12), str(DT21), str(DT22))) print('Distortion matrix Reception [DR11, DR12, DR21, DR22]: ' '[%s, %s, %s, %s]' % (str(DR11), str(DR12), str(DR21), str(DR22))) self.transmit = Distortion(DT12, DT21, DT22) self.receive = Distortion(DR12, DR21, DR22) self.calibrationFactor = float( dataset['Calibration factor']) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() self.frame.setSensingStart(self.imageFile.sensingStart) self.frame.setSensingStop(self.imageFile.sensingStop) sensingMid = self.imageFile.sensingStart + datetime.timedelta(seconds = 0.5* (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingMid(sensingMid) try: rngGate= Const.c*0.5*self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6 except: rngGate = None if (rngGate is None) or (rngGate == 0.0): rngGate = self.imageFile.nearRange self.frame.setStartingRange(rngGate) self.frame.getInstrument().setPulseRepetitionFrequency(self.imageFile.prf) pixelSize = self.frame.getInstrument().getRangePixelSize() farRange = self.imageFile.nearRange + (pixelSize-1) * self.imageFile.width self.frame.setFarRange(farRange) self.frame.setPolarization(self.imageFile.current_polarization) 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) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' midwidth = self.frame.getNumberOfSamples() / 2.0 dop = 0.0 prod = 1.0 for ind, kk in enumerate(self.doppler_coeff): dop += kk * prod prod *= midwidth print ('Average Doppler: {0}'.format(dop)) ####For insarApp quadratic = {} quadratic['a'] = dop / self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate ####CEOS already provides function vs pixel self.frame._dopplerVsPixel = self.doppler_coeff return quadratic def _decodeSceneReferenceNumber(self,referenceNumber): return referenceNumber
class COSMO_SkyMed(Sensor): """ A class to parse COSMO-SkyMed metadata """ logging_name = "isce.sensor.COSMO_SkyMed" def __init__(self): super(COSMO_SkyMed,self).__init__() self.hdf5 = None self.hdf5FileList = None #used to allow refactoring on tkfunc self._imageFileList = None ###Specific doppler functions for CSK self.dopplerRangeTime = [] self.dopplerAzimuthTime = [] self.azimuthRefTime = None self.rangeRefTime = None self.rangeFirstTime = None self.rangeLastTime = None self.dictionaryOfVariables = { 'HDF5': ['hdf5FileList','str','mandatory'], 'OUTPUT': ['output','str','optional'] } ## make this a class attribute, and a Sensor.Constant--not a dictionary. self.constants = {'iBias': 127.5, 'qBias': 127.5} return None ## Note: this breaks the ISCE convention of getters. def getFrame(self): return self.frame #jng parse or parse_context never used def parse(self): try: fp = h5py.File(self.hdf5, 'r') except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return None self.populateMetadata(file=fp) fp.close() ## Use h5's context management-- TODO: debug and install as 'parse' def parse_context(self): try: with h5py.File(self.hdf5, 'r') as fp: self.populateMetadata(file=fp) except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return None def _populatePlatform(self, file=None): platform = self.frame.getInstrument().getPlatform() platform.setMission(file.attrs['Satellite ID']) # Could use Mission ID as well platform.setPlanet(Planet("Earth")) platform.setPointingDirection(self.lookMap[file.attrs['Look Side'].decode('utf-8')]) platform.setAntennaLength(file.attrs['Antenna Length']) def _populateInstrument(self,file): instrument = self.frame.getInstrument() rangePixelSize = Const.c/(2*file['S01'].attrs['Sampling Rate']) instrument.setRadarWavelength(file.attrs['Radar Wavelength']) instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF']) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(file['S01'].attrs['Range Chirp Length']) instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate']) instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate']) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) instrument.setBeamNumber(file.attrs['Multi-Beam ID']) def _populateFrame(self,file): rft = file['S01']['B001'].attrs['Range First Times'][0] slantRange = rft*Const.c/2.0 sensingStart = self._parseNanoSecondTimeStamp(file.attrs['Scene Sensing Start UTC']) sensingStop = self._parseNanoSecondTimeStamp(file.attrs['Scene Sensing Stop UTC']) centerTime = DTUtil.timeDeltaToSeconds(sensingStop - sensingStart)/2.0 sensingMid = sensingStart + datetime.timedelta(microseconds=int(centerTime*1e6)) self.frame.setStartingRange(slantRange) self.frame.setPassDirection(file.attrs['Orbit Direction']) self.frame.setOrbitNumber(file.attrs['Orbit Number']) self.frame.setProcessingFacility(file.attrs['Processing Centre']) self.frame.setProcessingSoftwareVersion(file.attrs['L0 Software Version']) self.frame.setPolarization(file['S01'].attrs['Polarisation']) self.frame.setNumberOfLines(file['S01']['B001'].shape[0]) self.frame.setNumberOfSamples(file['S01']['B001'].shape[1]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() #Spurious factor of 2 removed - PSA farRange = slantRange + self.frame.getNumberOfSamples()*rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self,file): orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t0 = datetime.datetime.strptime(file.attrs['Reference UTC'].decode('utf-8'),'%Y-%m-%d %H:%M:%S.%f000') t = file.attrs['State Vectors Times'] position = file.attrs['ECEF Satellite Position'] velocity = file.attrs['ECEF Satellite Velocity'] for i in range(len(position)): vec = StateVector() dt = t0 + datetime.timedelta(seconds=t[i]) vec.setTime(dt) vec.setPosition([position[i,0],position[i,1],position[i,2]]) vec.setVelocity([velocity[i,0],velocity[i,1],velocity[i,2]]) orbit.addStateVector(vec) def populateImage(self,filename): rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setFilename(filename) rawImage.setAccessMode('read') rawImage.setWidth(2*self.frame.getNumberOfSamples()) rawImage.setXmax(2*self.frame.getNumberOfSamples()) rawImage.setXmin(0) self.getFrame().setImage(rawImage) def _populateExtras(self, file): """ Populate some extra fields. """ self.dopplerRangeTime = file.attrs['Centroid vs Range Time Polynomial'] self.dopplerAzimuthTime = file.attrs['Centroid vs Azimuth Time Polynomial'] self.rangeRefTime = file.attrs['Range Polynomial Reference Time'] self.azimuthRefTime = file.attrs['Azimuth Polynomial Reference Time'] ####Lazy fix for testing - PSA self.rangeFirstTime = self.rangeRefTime self.rangeLastTime = self.rangeRefTime def extractImage(self): """Extract the raw image data""" import os from ctypes import cdll, c_char_p extract_csk = cdll.LoadLibrary(os.path.dirname(__file__)+'/csk.so') # Prepare and run the C-based extractor #check if the input is a string. if so put it into one element list if(isinstance(self.hdf5FileList,str)): self.hdf5FileList = [self.hdf5FileList] for i in range(len(self.hdf5FileList)): #need to create a new instance every time self.frame = Frame() self.frame.configure() appendStr = '_' + str(i) # if more than one file to contatenate that create different outputs # but suffixing _i if(len(self.hdf5FileList) == 1): appendStr = '' outputNow = self.output + appendStr self.hdf5 = self.hdf5FileList[i] inFile_c = c_char_p(bytes(self.hdf5,'utf-8')) outFile_c = c_char_p(bytes(outputNow,'utf-8')) extract_csk.extract_csk(inFile_c,outFile_c) # Now, populate the metadata try: fp = h5py.File(self.hdf5,'r') except Exception as strerror: self.logger.error("IOError: %s\n" % strerror) return self.populateMetadata(file=fp) self.populateImage(outputNow) self._populateExtras(fp) fp.close() self.frameList.append(self.frame) createAuxFile(self.frame,outputNow + '.aux') self._imageFileList = self.hdf5FileList return tkfunc(self) def _parseNanoSecondTimeStamp(self,timestamp): """Parse a date-time string with nanosecond precision and return a datetime object """ dateTime,nanoSeconds = timestamp.decode('utf-8').split('.') microsec = float(nanoSeconds)*1e-3 dt = datetime.datetime.strptime(dateTime,'%Y-%m-%d %H:%M:%S') dt = dt + datetime.timedelta(microseconds=microsec) return dt def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ quadratic = {} midtime = (self.rangeLastTime + self.rangeFirstTime)*0.5 - self.rangeRefTime fd_mid = self.dopplerRangeTime[0] + self.dopplerRangeTime[1]*midtime + self.dopplerRangeTime[2]*midtime*midtime quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. return quadratic
class UAVSAR_RPI(Sensor): """ A class representing a UAVSAR SLC. """ family = 'uavsar_rpi' logging_name = 'isce.Sensor.UAVSAR_RPI' lookMap = {'RIGHT': -1, 'LEFT': 1} parameter_list = (METADATAFILE, ) + Sensor.parameter_list def __init__(self, name=''): # print("UAVSAR_RPI: self.family, name = ", self.family, name) super().__init__(family=self.family, name=name) self.frame = Frame() self.frame.configure() return def _populatePlatform(self, **kwargs): # print("UAVSAR_RPI._populatePlatform") platform = self.frame.getInstrument().getPlatform() platform.setMission('UAVSAR') platform.setPointingDirection( self.lookMap[self.metadata['Radar Look Direction'].upper()]) platform.setPlanet(Planet(pname="Earth")) platform.setAntennaLength(1.5) # Thierry Michel return def _populateInstrument(self, **kwargs): # print("UAVSAR_RPI._populateInstrument") instrument = self.frame.getInstrument() instrument.setRadarWavelength(self.metadata['Center Wavelength']) fudgefactor = 1.0 / 1.0735059946800756 instrument.setPulseRepetitionFrequency( fudgefactor * 1.0 / self.metadata['Average Pulse Repetition Interval']) # print("instrument.getPulseRepetitionFrequency() = ", # instrument.getPulseRepetitionFrequency(), # type(instrument.getPulseRepetitionFrequency())) instrument.setRangePixelSize( self.metadata['Single Look Complex Data Range Spacing']) instrument.setAzimuthPixelSize( self.metadata['Single Look Complex Data Azimuth 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['Average Look Angle in Near Range'] + self.metadata['Average Look Angle in Far Range'])) return def _populateFrame(self, **kwargs): # print("UAVSAR_RPI._populateFrame") if self.metadata['UAVSAR RPI Annotation File Version Number']: # print("UAVSAR_RPI._populateFrame, pair = True") if self.name.lower() == 'reference': sip1 = str(1) else: sip1 = str(2) print("UAVSAR_RPI._populateFrame, 1-based index = ", sip1) self._populateFrameFromPair(sip1) else: # print("UAVSAR_RPI._populateFrame, pair = False") self._populateFrameSolo() pass def _populateFrameFromPair(self, sip1): # print("UAVSAR_RPI._populateFrameFromPair: metadatafile = ", # self.metadataFile) #Get the Start, Mid, and Stop times import datetime tStart = datetime.datetime.strptime( self.metadata['Start Time of Acquisition for Pass ' + sip1], "%d-%b-%Y %H:%M:%S %Z") tStop = datetime.datetime.strptime( self.metadata['Stop Time of Acquisition for Pass ' + sip1], "%d-%b-%Y %H:%M:%S %Z") dtMid = DTU.timeDeltaToSeconds(tStop - tStart) / 2. # print("dtMid = ", dtMid) tMid = tStart + datetime.timedelta(microseconds=int(dtMid * 1e6)) # print("tStart = ", tStart) # print("tMid = ", tMid) # print("tStop = ", tStop) frame = self.frame frame.setSensingStart(tStart) frame.setSensingStop(tStop) frame.setSensingMid(tMid) frame.setNumberOfLines( int(self.metadata['Single Look Complex Data Azimuth Lines'])) frame.setNumberOfSamples( int(self.metadata['Single Look Complex Data Range Samples'])) frame.setPolarization(self.metadata['Polarization']) frame.C0 = self.metadata['Single Look Complex Data at Near Range'] frame.S0 = self.metadata['Single Look Complex Data Starting Azimuth'] frame.nearLookAngle = self.metadata['Average Look Angle in Near Range'] frame.farLookAngle = self.metadata['Average Look Angle in Far Range'] # print("frame.nearLookAngle = ", math.degrees(frame.nearLookAngle)) # frame.setStartingAzimuth(frame.S0) self.extractDoppler() frame.setStartingRange(self.startingRange) frame.platformHeight = self.platformHeight # print("platformHeight, startingRange = ", self.platformHeight, frame.getStartingRange()) width = frame.getNumberOfSamples() deltaRange = frame.instrument.getRangePixelSize() nearRange = frame.getStartingRange() midRange = nearRange + (width / 2.) * deltaRange frame.setFarRange(nearRange + width * deltaRange) frame.peg = self.peg # print("frame.peg = ", frame.peg) frame.procVelocity = self.velocity # print("frame.procVelocity = ", frame.procVelocity) from isceobj.Location.Coordinate import Coordinate 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) frame.nearLookAngle = math.degrees( self.metadata['Average Look Angle in Near Range']) frame.farLookAngle = math.degrees( self.metadata['Average Look Angle in Far Range']) return def _populateFrameSolo(self): print("UAVSAR_RPI._populateFrameSolo") def _populateExtras(self): pass def _populateOrbit(self, **kwargs): """ Create the orbit as the reference orbit defined by the peg """ # print("UAVSAR_RPI._populateOrbit") numExtra = 10 deltaFactor = 200 dt = deltaFactor * 1.0 / self.frame.instrument.getPulseRepetitionFrequency( ) t0 = (self.frame.getSensingStart() - datetime.timedelta(microseconds=int(numExtra * dt * 1e6))) ds = deltaFactor * self.frame.instrument.getAzimuthPixelSize() s0 = self.platformStartingAzimuth - numExtra * ds # print("populateOrbit: t0, startingAzimuth, platformStartingAzimuth, s0, ds = ", # t0, self.frame.S0, self.platformStartingAzimuth, s0, ds) h = self.platformHeight v = [self.velocity, 0., 0.] # print("t0, dt = ", t0, dt) # print("s0, ds, h = ", s0, ds, h) # print("v = ", v[0]) platform = self.frame.getInstrument().getPlatform() elp = platform.getPlanet().get_elp() elp.setSCH(self.peg.latitude, self.peg.longitude, self.peg.heading) orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') # print("_populateOrbit: self.frame.numberOfLines, numExtra = ", self.frame.getNumberOfLines(), numExtra) for i in range(self.frame.getNumberOfLines() + numExtra): vec = OrbitStateVector() t = t0 + datetime.timedelta(microseconds=int(i * dt * 1e6)) vec.setTime(t) posSCH = [s0 + i * ds * (elp.pegRadCur + h) / elp.pegRadCur, 0., h] velSCH = v posXYZ, velXYZ = elp.schdot_to_xyzdot(posSCH, velSCH) vec.setPosition(posXYZ) vec.setVelocity(velXYZ) orbit.addStateVector(vec) # if i%1000 == 0 or i>self.frame.getNumberOfLines()+numExtra-3 or i < 3: # print("vec = ", vec) return def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() # self.extractDoppler() self._populateOrbit() def extractImage(self): from iscesys.Parsers import rdf self.metadata = rdf.parse(self.metadataFile) self.populateMetadata() slcImage = isceobj.createSlcImage() if self.name == 'reference' or self.name == 'scene1': self.slcname = self.metadata['Single Look Complex Data of Pass 1'] elif self.name == 'secondary' or self.name == 'scene2': self.slcname = self.metadata['Single Look Complex Data of Pass 2'] else: print("Unrecognized sensor.name = ", sensor.name) import sys sys.exit(0) 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): # print("UAVSAR_RPI._extractDoppler") #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 self.dopplerVals['Mid'] = self.dopplerVals['Mid'] self.dopplerVals['Far'] = self.dopplerVals['Far'] # print("UAVSAR_RPI: dopplerVals = ", self.dopplerVals) #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() deltaRange = instrument.getRangePixelSize() nearRangeBin = 0. midRangeBin = float(int((width - 1.0) / 2.0)) farRangeBin = width - 1.0 import numpy 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() # print("UAVSAR_RPI.extractDoppler: self.dopplerVals = ", self.dopplerVals) # print("UAVSAR_RPI.extractDoppler: prf = ", prf) # print("UAVSAR_RPI.extractDoppler: A, d = ", A, d) # print("UAVSAR_RPI.extractDoppler: coefs = ", coefs) coefs = {'a': coefs[0] / prf, 'b': coefs[1] / prf, 'c': coefs[2] / prf} # print("UAVSAR_RPI.extractDoppler: coefs normalized by prf = ", 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): return self.metadata['Global Average Terrain Height'] @property def platformHeight(self): return self.metadata['Global Average Altitude'] @property def platformStartingAzimuth(self): # r, a = self.getStartingRangeAzimuth() # return a h = self.platformHeight peg = self.peg platform = self.frame.getInstrument().getPlatform() elp = platform.getPlanet().get_elp() elp.setSCH(peg.latitude, peg.longitude, peg.heading) rc = elp.pegRadCur range = self.startingRange wavl = self.frame.getInstrument().getRadarWavelength() fd = self.dopplerVals['Near'] v = self.velocity tanbeta = (fd * wavl / v) * range * (rc + h) / (range**2 - (rc + h)**2 - rc**2) beta = math.atan(tanbeta) # th = self.metadata['Global Average Terrain Height'] # sinTheta = math.sqrt( 1 - ((h-th)/range)**2 ) # squint = math.radians(self.squintAngle) # c0 = self.startingRange*sinTheta*math.cos(squint) # print("platformStartingAzimuth: c0 = ", c0) # gamma = c0/rc # cosbeta = -(range**2-(rc+h)**2-rc**2)/(2.*rc*(rc+h)*math.cos(gamma)) # sinbeta = -fd*range*wavl/(2.*rc*v*math.cos(gamma)) # beta = math.atan2(sinbeta,cosbeta) t = beta * (rc + h) / v pDS = v * t azimuth = self.frame.S0 #- pDS + 473. return azimuth @property def startingRange(self): # r, a = self.getStartingRangeAzimuth() # return r return self.metadata['Single Look Complex Data at Near 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 # print("calculateSquint: h = ", h) # print("calculateSquint: startingRange = ", startingRange) # print("calculateSquint: sinTheta = ", sinTheta) # print("calculateSquint: self.dopplerVals['Near'] = ", self.dopplerVals['Near']) # print("calculateSquint: prf = ", prf) # print("calculateSquint: fd = ", fd) # print("calculateSquint: v = ", v) # print("calculateSquint: wavelength = ", wavelength) # print("calculateSquint: sinSquint = ", sinSquint) 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) # print("UAVSAR_RPI: self.frame.squintAngle = ", self.frame.squintAngle) return self.squint def getStartingRangeAzimuth(self): peg = self.peg platform = self.frame.getInstrument().getPlatform() elp = platform.getPlanet().get_elp() elp.setSCH(peg.latitude, peg.longitude, peg.heading) rc = elp.pegRadCur # assert(abs(rc-6370285.323386391) < 0.1) h = self.platformHeight # assert(abs(h-12494.4008) < 0.01) # c0 = self.frame.C0 # assert(abs(c0-13450.0141) < 0.01) fd = self.dopplerVals['Near'] # assert(abs(fd-84.21126622) < 0.01) wavl = self.frame.getInstrument().getRadarWavelength() # assert(abs((wavl-23.8403545e-2) /wavl) < 0.01) gamma = c0 / rc v = self.velocity # assert(abs(v-234.84106135055598) < 0.01) A = (fd * wavl / v)**2 * (1 + h / rc)**2 B = 1. + (1. + h / rc)**2 C = 2.0 * (1 + h / rc) * math.cos(gamma) # assert(abs(A-0.0073370197515515235) < 0.00001) # assert(abs(B-2.003926560005551) < 0.0001) # assert(abs(C-2.0039182464710574) < 0.0001) A2B = A / 2. - B D = (A / 2. - B)**2 - (B**2 - C**2) x2p = -(A / 2. - B) + math.sqrt(D) x2m = -(A / 2. - B) - math.sqrt(D) # assert(abs(x2m-8.328781731403723e-06) < 1.e-9) range = rc * math.sqrt(x2m) # assert(abs(range-18384.406963585432) < 0.1) sinbeta = -fd * range * wavl / (2. * rc * v * math.cos(gamma)) cosbeta = -(range**2 - (rc + h)**2 - rc**2) / (2. * rc * (rc + h) * math.cos(gamma)) # assert(abs(sinbeta**2+cosbeta**2 - 1.0) < 0.00001) beta = math.atan2(sinbeta, cosbeta) # assert(abs(beta+0.00012335892779153295) < 0.000001) t = beta * (rc + h) / v # assert(abs(t+3.3527904301617375) < 0.001) pDS = v * t # assert(abs(pDS+787.3728631051696) < 0.01) azimuth = self.frame.S0 #self.frame.getStartingAzimuth() #- pDS return range, azimuth @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) rc = elp.pegRadCur 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 peg(self): peg = [ math.degrees(self.metadata['Peg Latitude']), math.degrees(self.metadata['Peg Longitude']), math.degrees(self.metadata['Peg Heading']) ] platform = self.frame.getInstrument().getPlatform() elp = platform.getPlanet().get_elp() elp.setSCH(*peg) rc = elp.pegRadCur from isceobj.Location.Peg import Peg return Peg(latitude=peg[0], longitude=peg[1], heading=peg[2], radiusOfCurvature=rc)
class ALOS(Sensor): """Code to read CEOSFormat leader files for ALOS SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ family = 'alos' logging_name = 'isce.sensor.ALOS' parameter_list = (IMAGEFILE, LEADERFILE, RESAMPLE_FLAG) + Sensor.parameter_list # polarizationMap = ['H','V','H+V'] ## This is manifestly better than a method complete the lazy instantation ## of an instance attribute transmit = Distortion(complex(2.427029e-3, 1.293019e-2), complex(-1.147240e-2, -6.228230e-3), complex(9.572169e-1, 3.829563e-1)) receive = Distortion(complex(-6.263392e-3, 7.082863e-3), complex(-6.297074e-3, 8.026685e-3), complex(7.217117e-1, -2.367683e-2)) constants = Constants(iBias=15.5, qBias=15.5, pointingDirection=-1, antennaLength=8.9) HEADER_LINES = 720 RESAMPLE_FLAG = { '': 'do Nothing', 'single2dual': 'resample from single to dual pole', 'dual2single': 'resample from dual to single' } @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self._leaderFile = None self._imageFile = None self.frame = None return None #2013-06-03 Kosal: the functions below overwrite the transmit property #initiated above ''' @property def transmit(self): return self.__class__.transmit @transmit.setter def transmit(self, x): raise TypeError( "ALOS.transmit is a protected class attribute and cannot be set" ) @property def receive(self): return self.__class__.receive @receive.setter def receive(self, x): raise TypeError( "ALOS.receive is a protected class attribute and cannot be set" ) ''' #Kosal def getFrame(self): return self.frame def setLeaderFile(self, ldr): self._leaderFile = ldr return def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.imageFile = ImageFile(self) try: self.leaderFile.parse() self.imageFile.parse() except IOError: return self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() # Header orbits self._populateOrbit() self._populateAttitude() self._populateDistortions() productLevel = float( self.leaderFile.sceneHeaderRecord.metadata['Product level code']) if productLevel == 1.0: self.updateRawParameters() pass def _populatePlatform(self): platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setPointingDirection(self.constants.pointing_direction) platform.setAntennaLength(self.constants.antenna_length) platform.setPlanet(Planet(pname='Earth')) def _populateInstrument(self): instrument = self.frame.getInstrument() rangePixelSize = None rangeSamplingRate = None chirpSlope = None bandwidth = None prf = None try: rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ 'Range sampling rate'] * 1e6 pulseLength = self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length'] * 1e-6 rangePixelSize = SPEED_OF_LIGHT / (2.0 * rangeSamplingRate) prf = self.leaderFile.sceneHeaderRecord.metadata[ 'Pulse Repetition Frequency'] / 1000. print('LEADER PRF: ', prf) beamNumber = self.leaderFile.sceneHeaderRecord.metadata[ 'Antenna beam number'] # if self.imageFile.prf: # prf = self.imageFile.prf # else: # self.logger.info("Using nominal PRF") bandwidth = self.leaderFile.calibrationRecord.metadata[ 'Band width'] * 1e6 #if (not bandwidth): # bandwidth = self.leaderFile.sceneHeaderRecord.metadata[ # 'Bandwidth per look in range'] chirpSlope = -(bandwidth / pulseLength) except AttributeError: self.logger.info("Some of the instrument parameters were not set") self.logger.debug("PRF: %s" % prf) self.logger.debug("Bandwidth: %s" % bandwidth) self.logger.debug("Pulse Length: %s" % pulseLength) self.logger.debug("Chirp Slope: %s" % chirpSlope) self.logger.debug("Range Pixel Size: %s" % rangePixelSize) self.logger.debug("Range Sampling Rate: %s" % rangeSamplingRate) self.logger.debug("Beam Number: %s" % beamNumber) instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangePixelSize(rangePixelSize) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setPulseLength(pulseLength) instrument.setChirpSlope(chirpSlope) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) instrument.setBeamNumber(beamNumber) return None def _populateFrame(self, polarization='HH', farRange=None): frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: first_line_utc = self.imageFile.start_time last_line_utc = self.imageFile.stop_time centerTime = DTUtil.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 center_line_utc = first_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(center_line_utc) self.frame.setSensingStop(last_line_utc) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = (self.imageFile.startingRange + self.imageFile.width * rangePixelSize) except TypeError as strerr: self.logger.warn(strerr) self.frame.frameNumber = frame self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(self.imageFile.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(polarization) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) def _populateOrbit(self): orbit = self.frame.getOrbit() velocityScale = 1.0 if (self.leaderFile.sceneHeaderRecord. metadata['Processing facility identifier'] == 'ERSDAC'): # The ERSDAC header orbits are in mm/s velocityScale = 1000.0 orbit.setReferenceFrame(self.leaderFile.platformPositionRecord. metadata['Reference coordinate system']) orbit.setOrbitSource('Header') orbitQuality = self._decodeOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) orbit.setOrbitQuality(orbitQuality) 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) for i in range(self.leaderFile.platformPositionRecord. metadata['Number of data points']): vec = OrbitStateVector() t = t0 + datetime.timedelta( seconds=i * self.leaderFile.platformPositionRecord. metadata['Time interval between DATA points']) 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'] / velocityScale, dataPoints['Velocity vector Y'] / velocityScale, dataPoints['Velocity vector Z'] / velocityScale ]) orbit.addStateVector(vec) def _populateAttitude(self): if (self.leaderFile.leaderFDR. metadata['Number of attitude data records'] != 1): return attitude = self.frame.getAttitude() attitude.setAttitudeSource("Header") year = int( self.leaderFile.sceneHeaderRecord.metadata['Scene centre time'] [0:4]) t0 = datetime.datetime(year=year, month=1, day=1) for i in range(self.leaderFile.platformAttitudeRecord. metadata['Number of attitude data points']): vec = AttitudeStateVector() dataPoints = self.leaderFile.platformAttitudeRecord.metadata[ 'Attitude Data Points'][i] t = t0 + datetime.timedelta( days=(dataPoints['Day of the year'] - 1), milliseconds=dataPoints['Millisecond of day']) vec.setTime(t) vec.setPitch(dataPoints['Pitch']) vec.setRoll(dataPoints['Roll']) vec.setYaw(dataPoints['Yaw']) attitude.addStateVector(vec) def _populateDistortions(self): return None def readOrbitPulse(self, leader, raw, width): ''' No longer used. Can't rely on raw data headers. Should be done as part of extract Image. ''' from isceobj.Sensor import readOrbitPulse as ROP print('TTTT') rawImage = isceobj.createRawImage() leaImage = isceobj.createStreamImage() auxImage = isceobj.createImage() rawImage.initImage(raw, 'read', width) rawImage.renderVRT() rawImage.createImage() rawAccessor = rawImage.getImagePointer() leaImage.initImage(leader, 'read') leaImage.createImage() leaAccessor = leaImage.getImagePointer() widthAux = 2 auxName = raw + '.aux' self.frame.auxFile = auxName auxImage.initImage(auxName, 'write', widthAux, type='DOUBLE') auxImage.createImage() auxAccessor = auxImage.getImagePointer() length = rawImage.getLength() ROP.setNumberBitesPerLine_Py(width) ROP.setNumberLines_Py(length) ROP.readOrbitPulse_Py(leaAccessor, rawAccessor, auxAccessor) rawImage.finalizeImage() leaImage.finalizeImage() auxImage.finalizeImage() return None def makeFakeAux(self, outputNow): ''' Generate an aux file based on sensing start and prf. ''' import math, array prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = self.frame.numberOfLines # 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() ## Can this even be done/ ## should the pointer be an __Int__? def readOrbitPulseDevelopement(self, leader, raw, width): from isceobj.Sensor import readOrbitPulse as ROP with isceobj.contextRawImage( width=width, accessMode='read', ) as rawImage: with isceobj.contextStreamImage( width=width, accessMode='read', ) as leaImage: with isceobj.contextImage( width=width, accessMode='write', ) as auxImage: rawAccessor = rawImage.getImagePointer() leaAccessor = leaImage.getImagePointer() widthAux = 2 auxName = raw + '.aux' self.frame.auxFile = auxName auxImage.initImage(auxName, 'write', widthAux, type='DOUBLE') auxImage.createImage() auxAccessor = auxImage.getImagePointer() length = rawImage.getLength() ROP.setNumberBitesPerLine_Py(width) ROP.setNumberLines_Py(length) ROP.readOrbitPulse_Py(leaAccessor, rawAccessor, auxAccessor) pass #rawImage.finalizeImage() pass #leaImage.finalizeImage() pass #auxImage.finalizeImage() return None def extractImage(self): if (len(self._imageFileList) != len(self._leaderFileList)): self.logger.error( "Number of leader files different from number of image files.") raise RuntimeError 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.imageFile = ImageFile(self) try: self.leaderFile.parse() self.imageFile.parse(calculateRawDimensions=False) outputNow = self.output + appendStr if not (self._resampleFlag == ''): filein = self.output + '__tmp__' self.imageFile.extractImage(filein) self.populateMetadata() objResample = None if (self._resampleFlag == 'single2dual'): objResample = ALOS_fbs2fbdPy() else: objResample = ALOS_fbd2fbsPy() objResample.wireInputPort('frame', object=self.frame) objResample.setInputFilename(filein) objResample.setOutputFilename(outputNow) objResample.run() objResample.updateFrame(self.frame) os.remove(filein) else: self.imageFile.extractImage(outputNow) self.populateMetadata() width = self.frame.getImage().getWidth() # self.readOrbitPulse(self._leaderFile,outputNow,width) self.makeFakeAux(outputNow) self.frameList.append(self.frame) except IOError: return pass ## refactor this with __init__.tkfunc return tkfunc(self) def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber def _decodeOrbitQuality(self, quality): try: quality = int(quality) except ValueError: quality = None qualityString = '' if (quality == 0): qualityString = 'Preliminary' elif (quality == 1): qualityString = 'Decision' elif (quality == 2): qualityString = 'High Precision' else: qualityString = 'Unknown' return qualityString def updateRawParameters(self): ''' Parse the data in python. ''' with open(self._imageFile, 'rb') as fp: width = self.imageFile.width numberOfLines = self.imageFile.length prefix = self.imageFile.prefix suffix = self.imageFile.suffix dataSize = self.imageFile.dataSize fp.seek(720, os.SEEK_SET) # Skip the header tags = [] print('WIDTH: ', width) print('LENGTH: ', numberOfLines) print('PREFIX: ', prefix) print('SUFFIX: ', suffix) print('DATASIZE: ', dataSize) for i in range(numberOfLines): if not i % 1000: self.logger.info("Line %s" % i) imageRecord = CEOS.CEOSDB(xml=os.path.join( xmlPrefix, 'alos/image_record.xml'), dataFile=fp) imageRecord.parse() tags.append( float(imageRecord. metadata['Sensor acquisition milliseconds of day'])) data = fp.read(dataSize) pass ###Do parameter fit import numpy as np tarr = np.array(tags) - tags[0] ref = np.arange(tarr.size) / self.frame.PRF print('PRF: ', self.frame.PRF) ####Check every 20 microsecs off = np.arange(50) * 2.0e-5 res = np.zeros(off.size) ###Check which offset produces the same millisec truncation ###Assumes PRF is correct for xx in range(off.size): ttrunc = np.floor((ref + off[xx]) * 1000) res[xx] = np.sum(tarr - ttrunc) res = np.abs(res) # import matplotlib.pyplot as plt # plt.plot(res) # plt.show() delta = datetime.timedelta(seconds=np.argmin(res) * 2.0e-5) print('TIME OFFSET: ', delta) self.frame.sensingStart += delta self.frame.sensingMid += delta self.frame.sensingStop += delta return None
class Radarsat1(Component): """ Code to read CEOSFormat leader files for Radarsat-1 SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ auxLength = 50 def __init__(self): Component.__init__(self) self._leaderFile = None self._imageFile = None self._parFile = None self.output = None self.imageFile = None self.leaderFile = None #####Soecific doppler functions for RSAT1 self.doppler_ref_range = None self.doppler_ref_azi = None self.doppler_predict = None self.doppler_DAR = None self.doppler_coeff = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 15} self.descriptionOfVariables = {} self.dictionaryOfVariables = { 'LEADERFILE': ['self._leaderFile', 'str', 'mandatory'], 'IMAGEFILE': ['self._imageFile', 'str', 'mandatory'], 'PARFILE': ['self._parFile', 'str', 'optional'], 'OUTPUT': ['self.output', 'str', 'optional'] } def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate'] * 1e6) except ZeroDivisionError: rangePixelSize = 0 ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet('Earth')) ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) ##RSAT-1 does not have PRF for raw data in leader file. # self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency']) ins.setRangePixelSize(rangePixelSize) ins.setPulseLength( self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] * 1e-6) chirpPulseBandwidth = 15.50829e6 # Is this really not in the CEOSFormat Header? ins.setChirpSlope( chirpPulseBandwidth / (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] * 1e-6)) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) 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.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) self.frame.getOrbit().setOrbitSource('Header') self.frame.getOrbit().setOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates orb = Orbit() for i in range(self.leaderFile.platformPositionRecord. metadata['Number of data points']): vec = StateVector() t = t0 + datetime.timedelta( seconds=(i * self.leaderFile.platformPositionRecord. metadata['Time interval between DATA points'])) 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'] / 1000., dataPoints['Velocity vector Y'] / 1000., dataPoints['Velocity vector Z'] / 1000. ]) orb.addStateVector(vec) #####Convert orbits from ECI to ECEF frame. convOrb = ECI2ECEF(orb, eci='ECI_TOD') wgsorb = convOrb.convert() orb = self.frame.getOrbit() for sv in wgsorb: orb.addStateVector(sv) self.parseParFile() def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() ####RSAT1 is weird. Contains all useful info in RAW data and not leader. ins = self.frame.getInstrument() ins.setPulseRepetitionFrequency(self.imageFile.prf) ins.setPulseLength(self.imageFile.pulseLength) ins.setRangeSamplingRate(self.imageFile.rangeSamplingRate) ins.setRangePixelSize(Const.c / (2 * self.imageFile.rangeSamplingRate)) ins.setChirpSlope(self.imageFile.chirpSlope) ###### self.frame.setSensingStart(self.imageFile.sensingStart) sensingStop = self.imageFile.sensingStart + datetime.timedelta( seconds=((self.frame.getNumberOfLines() - 1) / self.imageFile.prf)) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingStop(sensingStop) self.frame.setSensingMid(sensingMid) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setStartingRange(self.imageFile.startingRange) farRange = self.imageFile.startingRange + ins.getRangePixelSize( ) * self.imageFile.width * 0.5 self.frame.setFarRange(farRange) rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) rawImage.renderHdr() self.frame.setImage(rawImage) def parseParFile(self): '''Parse the par file if any is available.''' if self._parFile not in (None, ''): par = ParFile(self._parFile) doppinfo = par['prep_block']['sensor']['beam'][ 'DopplerCentroidParameters'] #######Selectively update some values. #######Currently used only for doppler centroids. self.doppler_ref_range = float(doppinfo['reference_range']) self.doppler_ref_azi = datetime.datetime.strptime( doppinfo['reference_date'], '%Y%m%d%H%M%S%f') self.doppler_predict = float(doppinfo['Predict_doppler']) self.doppler_DAR = float(doppinfo['DAR_doppler']) coeff = doppinfo['doppler_centroid_coefficients'] rngOrder = int(coeff['number_of_coefficients_first_dimension']) azOrder = int(coeff['number_of_coefficients_second_dimension']) self.doppler_coeff = Polynomial(rangeOrder=rngOrder, azimuthOrder=azOrder) self.doppler_coeff.setMeanRange(self.doppler_ref_range) self.doppler_coeff.setMeanAzimuth( secondsSinceMidnight(self.doppler_ref_azi)) for ii in range(azOrder): for jj in range(rngOrder): key = 'a%d%d' % (ii, jj) val = float(coeff[key]) self.doppler_coeff.setCoeff(ii, jj, val) def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' rmin = self.frame.getStartingRange() rmax = self.frame.getFarRange() rmid = 0.5 * (rmin + rmax) azmid = secondsSinceMidnight(self.frame.getSensingMid()) print(rmid, self.doppler_coeff.getMeanRange()) print(azmid, self.doppler_coeff.getMeanAzimuth()) if self.doppler_coeff is None: raise Exception( 'ASF PARFILE was not provided. Cannot determine default doppler.' ) dopav = self.doppler_coeff(azmid, rmid) prf = self.frame.getInstrument().getPulseRepetitionFrequency() quadratic = {} quadratic['a'] = dopav / prf quadratic['b'] = 0. quadratic['c'] = 0. return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
class Risat1(Sensor): """ Code to read CEOSFormat leader files for Risat-1 SAR data. """ family = "risat1" logging_name = 'isce.sensor.Risat1' parameter_list = (IMAGEFILE, LEADERFILE, METAFILE) + Sensor.parameter_list @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.imageFile = None self.leaderFile = None #####Specific doppler functions for RISAT1 self.doppler_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 15} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate']) except ZeroDivisionError: rangePixelSize = 0 print( 'Average height: ', self.leaderFile.sceneHeaderRecord. metadata['Average terrain height in km']) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(1) platform.setPlanet(Planet(pname='Earth')) ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency( self.leaderFile.sceneHeaderRecord. metadata['Pulse Repetition Frequency']) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate( self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']) ins.setPulseLength( self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']) # chirpPulseBandwidth = self.leaderFile.processingRecord.metadata['Pulse bandwidth code']*1e4 # ins.setChirpSlope(chirpPulseBandwidth/self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']) ins.setChirpSlope(7.5e12) ins.setInPhaseValue(127.0) ins.setQuadratureValue(127.0) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along pixel direction'].strip() ######RISAT-1 sensor orientation convention is opposite to ours # lookSide = self.leaderFile.processingRecord.metadata['Sensor orientation'] # if lookSide == 'RIGHT': # platform.setPointingDirection(1) # elif lookSide == 'LEFT': # platform.setPointingDirection(-1) # else: # raise Exception('Unknown look side') self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) 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.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) ###### self.frame.getOrbit().setOrbitSource('Header') self.frame.getOrbit().setOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) t0 = datetime.datetime(year=2000 + 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( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates orb = Orbit() deltaT = self.leaderFile.platformPositionRecord.metadata[ 'Time interval between DATA points'] numPts = self.leaderFile.platformPositionRecord.metadata[ 'Number of data points'] for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i * deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata[ 'Positional Data Points'][i] pos = [ dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z'] ] vel = [ dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z'] ] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) #####Convert orbits from ECI to ECEF frame. t0 = orb._stateVectors[0]._time ang = self.leaderFile.platformPositionRecord.metadata[ 'Greenwich mean hour angle'] cOrb = ECI2ECR(orb, GAST=ang, epoch=t0) wgsorb = cOrb.convert() #####Extend the orbits by a few points planet = self.frame.instrument.platform.planet orbExt = OrbitExtender() orbExt.configure() orbExt._newPoints = 4 newOrb = orbExt.extendOrbit(wgsorb) orb = self.frame.getOrbit() for sv in newOrb: orb.addStateVector(sv) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() self.frame.setSensingStart(self.imageFile.sensingStart) self.frame.setSensingStop(self.imageFile.sensingStop) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingMid(sensingMid) dr = self.frame.instrument.rangePixelSize self.frame.setStartingRange(self.imageFile.nearRange) self.frame.setFarRange(self.imageFile.nearRange + (self.imageFile.width - 1) * dr) self.doppler_coeff = self.imageFile.dopplerCoeff self.frame.getInstrument().setPulseRepetitionFrequency( self.imageFile.prf) self.frame.instrument.setPulseLength(self.imageFile.chirpLength) print('Pulse length: ', self.imageFile.chirpLength) print('Roll angle: ', self.imageFile.roll) if self.imageFile.roll > 0.: self.frame.instrument.platform.setPointingDirection(1) else: self.frame.instrument.platform.setPointingDirection(-1) rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width * 2) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width * 2) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' print('Doppler: ', self.doppler_coeff) quadratic = {} quadratic['a'] = self.doppler_coeff[1] / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
class ERS(Sensor): family = 'ers' logging_name = 'isce.sensor.ers' 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._leaderFile = None self._imageFile = None self.frameList = [] 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(pname='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()) self.logger.info('Using ODR file: ' + orbitFile) 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 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 Sentinel1A(Component): """ A Class representing RadarSAT 2 data """ def __init__(self): Component.__init__(self) self.xml = None self.tiff = None self.output = None self.gdal_translate = 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'], 'OUTPUT': ['self.output', 'str', 'optional'], 'GDAL_TRANSLATE': ['self.gdal_translate', '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("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) self.extractOrbit() def extractOrbit(self): ''' Extract orbit information from xml node. ''' node = self._xml_root.find('generalAnnotation/orbitList') frameOrbit = self.frame.getOrbit() 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) def extractImage(self): """ Use gdal_translate to extract the slc """ import tempfile import subprocess if (not self.gdal_translate): raise TypeError( "The path to executable gdal_translate was not specified") if (not os.path.exists(self.gdal_translate)): raise OSError("Could not find gdal_translate in directory %s" % os.path.dirname(self.gdal_translate)) self.parse() # Use GDAL to convert the geoTIFF file to an raster image # There should be a way to do this using the GDAL python api curdir = os.getcwd() tempdir = tempfile.mkdtemp(dir=curdir) # os.rmdir(tempdir) # Wasteful, but if the directory exists, gdal_translate freaks out #instring = 'RADARSAT_2_CALIB:UNCALIB:%s' % self.xml #process = subprocess.Popen([self.gdal_translate,'-of','MFF2','-ot','CFloat32',instring,tempdir]) if (self.tiff is None) or (not os.path.exists(self.tiff)): raise Exception( 'Path to input tiff file: %s is wrong or file doesnt exist.' % (self.tiff)) process = subprocess.Popen([ self.gdal_translate, self.tiff.strip(), '-of', 'ENVI', '-ot', 'CFloat32', '-co', 'INTERLEAVE=BIP', os.path.join(tempdir, 'image_data') ]) process.wait() # Move the output of the gdal_translate call to a reasonable file name width = self.frame.getNumberOfSamples() lgth = self.frame.getNumberOfLines() os.rename(os.path.join(tempdir, 'image_data'), self.output) # os.unlink(os.path.join(tempdir,'attrib')) os.unlink(os.path.join(tempdir, 'image_data.hdr')) os.rmdir(tempdir) #### 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 ICEYE_SLC(Sensor): """ A class representing a Level1Product meta data. Level1Product(hdf5=h5filename) will parse the hdf5 file and produce an object with attributes for metadata. """ parameter_list = (HDF5, APPLY_SLANT_RANGE_PHASE) + Sensor.parameter_list logging_name = 'isce.Sensor.ICEYE_SLC' family = 'iceye_slc' def __init__(self, family='', name=''): super(ICEYE_SLC, self).__init__(family if family else self.__class__.family, name=name) self.frame = Frame() self.frame.configure() # Some extra processing parameters unique to CSK SLC (currently) self.dopplerRangeTime = [] self.dopplerAzimuthTime = [] self.azimuthRefTime = None self.rangeRefTime = None self.rangeFirstTime = None self.rangeLastTime = None self.lookMap = {'RIGHT': -1, 'LEFT': 1} return def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self, d): self.__dict__.update(d) self.logger = logging.getLogger('isce.Sensor.ICEYE_SLC') return def getFrame(self): return self.frame def parse(self): try: fp = h5py.File(self.hdf5, 'r') except Exception as strerr: self.logger.error("IOError: %s" % strerr) return None self.populateMetadata(fp) fp.close() def populateMetadata(self, file): """ Populate our Metadata objects """ self._populatePlatform(file) self._populateInstrument(file) self._populateFrame(file) self._populateOrbit(file) self._populateExtras(file) def _populatePlatform(self, file): platform = self.frame.getInstrument().getPlatform() platform.setMission(file['satellite_name'][()]) platform.setPointingDirection( self.lookMap[file['look_side'][()].upper()]) platform.setPlanet(Planet(pname="Earth")) ####This is an approximation for spotlight mode ####In spotlight mode, antenna length changes with azimuth position platform.setAntennaLength(2 * file['azimuth_ground_spacing'][()]) assert (file['range_looks'][()] == 1) assert (file['azimuth_looks'][()] == 1) def _populateInstrument(self, file): instrument = self.frame.getInstrument() rangePixelSize = file['slant_range_spacing'][()] instrument.setRadarWavelength(Const.c / file['carrier_frequency'][()]) instrument.setPulseRepetitionFrequency(file['processing_prf'][()]) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(file['chirp_duration'][()]) instrument.setChirpSlope(file['chirp_bandwidth'][()] / file['chirp_duration'][()]) instrument.setRangeSamplingRate(file['range_sampling_rate'][()]) incangle = file['local_incidence_angle'] instrument.setIncidenceAngle(incangle[incangle.size // 2]) def _populateFrame(self, file): rft = file['first_pixel_time'][()] slantRange = rft * Const.c / 2.0 self.frame.setStartingRange(slantRange) sensingStart = datetime.datetime.strptime( file['zerodoppler_start_utc'][()].decode('utf-8'), '%Y-%m-%dT%H:%M:%S.%f') sensingStop = datetime.datetime.strptime( file['zerodoppler_end_utc'][()].decode('utf-8'), '%Y-%m-%dT%H:%M:%S.%f') sensingMid = sensingStart + 0.5 * (sensingStop - sensingStart) self.frame.setPassDirection(file['orbit_direction'][()]) self.frame.setOrbitNumber(file['orbit_absolute_number'][()]) self.frame.setProcessingFacility('ICEYE') self.frame.setProcessingSoftwareVersion( str(file['processor_version'][()])) self.frame.setPolarization(file['polarization'][()]) self.frame.setNumberOfLines(file['number_of_azimuth_samples'][()]) self.frame.setNumberOfSamples(file['number_of_range_samples'][()]) self.frame.setSensingStart(sensingStart) self.frame.setSensingMid(sensingMid) self.frame.setSensingStop(sensingStop) rangePixelSize = self.frame.getInstrument().getRangePixelSize() farRange = slantRange + (self.frame.getNumberOfSamples() - 1) * rangePixelSize self.frame.setFarRange(farRange) def _populateOrbit(self, file): import numpy as np orbit = self.frame.getOrbit() orbit.setReferenceFrame('ECR') orbit.setOrbitSource('Header') t = file['state_vector_time_utc'][:] position = np.zeros((t.size, 3)) position[:, 0] = file['posX'][:] position[:, 1] = file['posY'][:] position[:, 2] = file['posZ'][:] velocity = np.zeros((t.size, 3)) velocity[:, 0] = file['velX'][:] velocity[:, 1] = file['velY'][:] velocity[:, 2] = file['velZ'][:] for ii in range(t.size): vec = StateVector() vec.setTime( datetime.datetime.strptime(t[ii][0].decode('utf-8'), '%Y-%m-%dT%H:%M:%S.%f')) vec.setPosition( [position[ii, 0], position[ii, 1], position[ii, 2]]) vec.setVelocity( [velocity[ii, 0], velocity[ii, 1], velocity[ii, 2]]) orbit.addStateVector(vec) def _populateExtras(self, file): """ Populate some of the extra fields unique to processing TSX data. In the future, other sensors may need this information as well, and a re-organization may be necessary. """ import numpy as np self.dcpoly = np.mean(file['dc_estimate_coeffs'][:], axis=0) def extractImage(self): import numpy as np import h5py self.parse() fid = h5py.File(self.hdf5, 'r') si = fid['s_i'] sq = fid['s_q'] nLines = si.shape[0] spectralShift = 2 * self.frame.getInstrument().getRangePixelSize( ) / self.frame.getInstrument().getRadarWavelength() spectralShift -= np.floor(spectralShift) phsShift = np.exp(-1j * 2 * np.pi * spectralShift * np.arange(si.shape[1])) with open(self.output, 'wb') as fout: for ii in range(nLines): line = (si[ii, :] + 1j * sq[ii, :]) if self.applySlantRangePhase: line *= phsShift line.astype(np.complex64).tofile(fout) fid.close() slcImage = isceobj.createSlcImage() slcImage.setFilename(self.output) slcImage.setXmin(0) slcImage.setXmax(self.frame.getNumberOfSamples()) slcImage.setWidth(self.frame.getNumberOfSamples()) slcImage.setAccessMode('r') self.frame.setImage(slcImage) def extractDoppler(self): """ Return the doppler centroid as defined in the HDF5 file. """ import numpy as np quadratic = {} rangePixelSize = self.frame.getInstrument().getRangePixelSize() rt0 = self.frame.getStartingRange() / (2 * Const.c) rt1 = rt0 + ((self.frame.getNumberOfSamples() - 1) * rangePixelSize) / (2 * Const.c) ####insarApp style quadratic['a'] = np.polyval(self.dcpoly, 0.5 * (rt0 + rt1)) / self.frame.PRF quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp more accurate ####Convert stuff to pixel wise coefficients x = np.linspace(rt0, rt1, num=len(self.dcpoly) + 1) pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(self.dcpoly) + 1) evals = np.polyval(self.dcpoly, x) fit = np.polyfit(pix, evals, len(self.dcpoly) - 1) self.frame._dopplerVsPixel = list(fit[::-1]) print('Doppler Fit: ', self.frame._dopplerVsPixel) return quadratic