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 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