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 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 Radarsat2(Sensor): """ A Class representing RADARSAT 2 data """ family = 'radarsat2' parameter_list = (XML, TIFF) + Sensor.parameter_list def __init__(self, family='', name=''): super().__init__(family if family else self.__class__.family, name=name) self.product = _Product() self.frame = Frame() self.frame.configure() 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 orig_prf = self.product.sourceAttributes.radarParameters.prf # original PRF not necessarily effective 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 # some RS2 scenes have oversampled SLC images because processed azimuth bandwidth larger than PRF EJF 2015/08/15 azimuthPixelSize = self.product.imageAttributes.rasterAttributes.sampledLineSpacing # ground spacing in meters totalProcessedAzimuthBandwidth = self.product.imageGenerationParameters.sarProcessingInformation.totalProcessedAzimuthBandwidth prf = orig_prf * np.ceil( totalProcessedAzimuthBandwidth / orig_prf ) # effective PRF can be double original, suggested by Piyush print("effective PRF %f, original PRF %f" % (prf, orig_prf)) 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(pname="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) # save the Doppler centroid coefficients, converting units from product.xml 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 # added EJF 2015/08/17 dc = self.product.imageGenerationParameters.dopplerCentroid poly = dc.dopplerCentroidCoefficients # 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) # Guessing that ISCE expects Hz, Hz/(range sample), Hz((range sample)^2 # note that RS2 Doppler values are estimated at time dc.dopplerRateReferenceTime, # so the values might need to be adjusted for ISCE usage # added EJF 2015/08/17 dr = self.product.imageGenerationParameters.dopplerRateValues fmpoly = dr.dopplerRateValuesCoefficients # need to convert units fmpoly[1] = fmpoly[1] / rangeSamplingRate fmpoly[2] = fmpoly[2] / rangeSamplingRate**2 self.azfmrate_coeff = fmpoly # now calculate effective PRF from the azimuth line spacing after we have the orbit info EJF 2015/08/15 # this does not work because azimuth spacing is on ground. Instead use bandwidth ratio calculated above EJF # SCHvelocity = self.frame.getSchVelocity() # SCHvelocity = 7550.75 # hard code orbit velocity for now m/s # prf = SCHvelocity/azimuthPixelSize # instrument.setPulseRepetitionFrequency(prf) 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 ####For insarApp quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate from isceobj.Util import Poly1D coeffs = poly dr = self.frame.getInstrument().getRangePixelSize() rref = 0.5 * Const.c * t0 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 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 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 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 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 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 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 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