class Risat1_SLC(Sensor): """ Code to read CEOSFormat leader files for Risat-1 SAR data. """ family = "risat1" logging_name = 'isce.sensor.Risat1' parameter_list = (IMAGEFILE, LEADERFILE, METAFILE, DATATYPE) + Sensor.parameter_list @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.imageFile = None self.leaderFile = None #####Specific doppler functions for RISAT1 self.doppler_coeff = None self.azfmrate_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = { 'antennaLength': 6, } self.TxPolMap = { 1: 'V', 2: 'H', 3: 'L', 4: 'R', } self.RxPolMap = { 1: 'V', 2: 'H', } def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) try: rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate']) except ZeroDivisionError: rangePixelSize = 0 print( 'Average terrain height: ', 1000 * self.leaderFile. sceneHeaderRecord.metadata['Average terrain height in km']) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPlanet(Planet(pname='Earth')) ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency( self.leaderFile.sceneHeaderRecord. metadata['Pulse Repetition Frequency']) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate( self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']) ins.setPulseLength( self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']) chirpPulseBandwidth = self.leaderFile.processingRecord.metadata[ 'Pulse bandwidth code'] * 1e4 ins.setChirpSlope( chirpPulseBandwidth / self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']) ins.setInPhaseValue(0.0) ins.setQuadratureValue(0.0) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along pixel direction'].strip() ######RISAT-1 sensor orientation convention is opposite to ours lookSide = self.leaderFile.processingRecord.metadata[ 'Sensor orientation'] if lookSide == 'RIGHT': platform.setPointingDirection(1) elif lookSide == 'LEFT': platform.setPointingDirection(-1) else: raise Exception('Unknown look side') print('Leader file look side: ', lookSide) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setProcessingFacility( self.leaderFile.sceneHeaderRecord. metadata['Processing facility identifier']) self.frame.setProcessingSystem( self.leaderFile.sceneHeaderRecord. metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion( self.leaderFile.sceneHeaderRecord. metadata['Processing version identifier']) self.frame.setNumberOfLines( self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) ###### self.frame.getOrbit().setOrbitSource('Header') self.frame.getOrbit().setOrbitQuality( self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']) t0 = datetime.datetime(year=2000 + self.leaderFile.platformPositionRecord. metadata['Year of data point'], month=self.leaderFile.platformPositionRecord. metadata['Month of data point'], day=self.leaderFile.platformPositionRecord. metadata['Day of data point']) t0 = t0 + datetime.timedelta( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates orb = Orbit() deltaT = self.leaderFile.platformPositionRecord.metadata[ 'Time interval between DATA points'] numPts = self.leaderFile.platformPositionRecord.metadata[ 'Number of data points'] for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i * deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata[ 'Positional Data Points'][i] pos = [ dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z'] ] vel = [ dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z'] ] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) #####Convert orbits from ECI to ECR frame t0 = orb._stateVectors[0]._time ang = self.leaderFile.platformPositionRecord.metadata[ 'Greenwich mean hour angle'] cOrb = ECI2ECR(orb, GAST=ang, epoch=t0) iOrb = cOrb.convert() #####Extend the orbits by a few points #####Expect large azimuth shifts - absolutely needed #####Since CEOS contains state vectors that barely covers scene extent planet = self.frame.instrument.platform.planet orbExt = OrbitExtender() orbExt.configure() orbExt._newPoints = 4 newOrb = orbExt.extendOrbit(iOrb) orb = self.frame.getOrbit() for sv in newOrb: orb.addStateVector(sv) self.doppler_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid quadratic term'] ] self.azfmrate_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate quadratic term'] ] def 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, dtype=self._dataType) out.close() self.frame.setSensingStart(self.imageFile.sensingStart) self.frame.setSensingStop(self.imageFile.sensingStop) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingMid(sensingMid) self.frame.setStartingRange(self.imageFile.nearRange) self.frame.setFarRange(self.imageFile.farRange) # self.doppler_coeff = self.imageFile.dopplerCoeff self.frame.getInstrument().setPulseRepetitionFrequency( self.imageFile.prf) pol = self.TxPolMap[int( self.imageFile.polarization[0])] + self.TxPolMap[int( self.imageFile.polarization[1])] self.frame.setPolarization(pol) rawImage = isceobj.createSlcImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' ####For insarApp quadratic = {} quadratic['a'] = self.doppler_coeff[0] / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ###For roiApp ###More accurate self.frame._dopplerVsPixel = self.doppler_coeff return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
class Track(object): """A class to represent a collection of temporally continuous radar frame objects""" logging_name = "isce.Scene.Track" @logged def __init__(self): # These are attributes representing the starting time and stopping # time of the track # As well as the early and late times (range times) of the track self._startTime = datetime.datetime(year=datetime.MAXYEAR, month=1, day=1) self._stopTime = datetime.datetime(year=datetime.MINYEAR, month=1, day=1) # Hopefully this number is large # enough, Python doesn't appear to have a MAX_FLT variable self._nearRange = float_info.max self._farRange = 0.0 self._frames = [] self._frame = Frame() self._lastFile = '' return None def combineFrames(self, output, frames): attitudeOk = True for frame in frames: self.addFrame(frame) if hasattr(frame, '_attitude'): att = frame.getAttitude() if not att: attitudeOk = False self.createInstrument() self.createTrack(output) self.createOrbit() if attitudeOk: self.createAttitude() return self._frame def createAuxFile(self, fileList, output): import struct from operator import itemgetter import os import array import copy dateIndx = [] cnt = 0 #first sort the files from earlier to latest. use the first element for name in fileList: with open(name, 'rb') as fp: date = fp.read(16) day, musec = struct.unpack('<dd', date) dateIndx.append([day, musec, name]) cnt += 1 sortedDate = sorted(dateIndx, key=itemgetter(0, 1)) #we need to make sure that there are not duplicate points in the orbit since some frames overlap allL = array.array('d') allL1 = array.array('d') name = sortedDate[0][2] size = os.path.getsize(name) // 8 with open(name, 'rb') as fp1: allL.fromfile(fp1, size) lastDay = allL[-2] lastMusec = allL[-1] for j in range(1, len(sortedDate)): name = sortedDate[j][2] size = os.path.getsize(name) // 8 with open(name, 'rb') as fp1: allL1.fromfile(fp1, size) indxFound = None avgPRI = 0 cnt = 0 for i in range(len(allL1) // 2): if i > 0: avgPRI += allL1[2 * i + 1] - allL1[2 * i - 1] cnt += 1 if allL1[2 * i] >= lastDay and allL1[2 * i + 1] > lastMusec: avgPRI //= (cnt - 1) if ( allL1[2 * i + 1] - lastMusec ) > avgPRI / 2: # make sure that the distance in pulse is atleast 1/2 PRI indxFound = 2 * i else: #if not take the next indxFound = 2 * (i + 1) pass break if not indxFound is None: allL.extend(allL1[indxFound:]) lastDay = allL[-2] lastMusec = allL[-1] pass pass with open(output, 'wb') as fp: allL.tofile(fp) return # Add an additional Frame object to the track @type_check(Frame) def addFrame(self, frame): self.logger.info("Adding Frame to Track") self._updateTrackTimes(frame) self._frames.append(frame) return None def createOrbit(self): orbitAll = Orbit() for i in range(len(self._frames)): orbit = self._frames[i].getOrbit() #remember that everything is by reference, so the changes applied to orbitAll will be made to the Orbit #object in self.frame for sv in orbit._stateVectors: orbitAll.addStateVector(sv) # sort the orbit state vecotrs according to time orbitAll._stateVectors.sort(key=lambda sv: sv.time) self.removeDuplicateVectors(orbitAll._stateVectors) self._frame.setOrbit(orbitAll) def removeDuplicateVectors(self, stateVectors): i1 = 0 #remove duplicate state vectors while True: if i1 >= len(stateVectors) - 1: break if stateVectors[i1].time == stateVectors[i1 + 1].time: stateVectors.pop(i1 + 1) #since is sorted by time if is not equal we can pass to the next else: i1 += 1 def createAttitude(self): attitudeAll = Attitude() for i in range(len(self._frames)): attitude = self._frames[i].getAttitude() #remember that everything is by reference, so the changes applied to attitudeAll will be made to the Attitude object in self.frame for sv in attitude._stateVectors: attitudeAll.addStateVector(sv) # sort the attitude state vecotrs according to time attitudeAll._stateVectors.sort(key=lambda sv: sv.time) self.removeDuplicateVectors(attitudeAll._stateVectors) self._frame.setAttitude(attitudeAll) def createInstrument(self): # the platform is already part of the instrument ins = self._frames[0].getInstrument() self._frame.setInstrument(ins) # sometime the startLine computed below from the sensingStart is not #precise and the image are missaligned. #for each pair do an exact mach by comparing the lines around lineStart #file1,2 input files, startLine1 is the estimated start line in the first file #line1 = last line used in the first file #width = width of the files #frameNum1,2 number of the frames in the sequence of frames to stitch #returns a more accurate line1 def findOverlapLine(self, file1, file2, line1, width, frameNum1, frameNum2): import numpy as np import array fin2 = open(file2, 'rb') arr2 = array.array('b') #read full line at the beginning of second file arr2.fromfile(fin2, width) buf2 = np.array(arr2, dtype=np.int8) numTries = 30 # start around line1 and try numTries around line1 # see searchlist to see which lines it searches searchNumLines = 2 #make a sliding window that search for the searchSize samples inside buf2 searchSize = 500 max = 0 indx = None fin1 = open(file1, 'rb') for i in range(numTries): # example line1 = 0,searchNumLine = 2 and i = 0 search = [-2,-1,0,1], i = 1, serach = [-4,-3,2,3] search = list( range(line1 - (i + 1) * searchNumLines, line1 - i * searchNumLines)) search.extend( list( range(line1 + i * searchNumLines, line1 + (i + 1) * searchNumLines))) for k in search: arr1 = array.array('b') #seek to the line k and read +- searchSize/2 samples from the middle of the line fin1.seek(k * width + (width - searchSize) // 2, 0) arr1.fromfile(fin1, searchSize) buf1 = np.array(arr1, dtype=np.int8) found = False for i in np.arange(width - searchSize): lenSame = len( np.nonzero(buf1 == buf2[i:i + searchSize])[0]) if lenSame > max: max = lenSame indx = k if (lenSame == searchSize): found = True break if (found): break if (found): break if not found: self.logger.warning( "Cannot find perfect overlap between frame %d and frame %d. Using acquisition time to find overlap position." % (frameNum1, frameNum2)) fin1.close() fin2.close() print('Match found: ', indx) return indx def reAdjustStartLine(self, sortedList, width): """ Computed the adjusted starting lines based on matching in overlapping regions """ from operator import itemgetter import os #first one always starts from zero startLine = [sortedList[0][0]] outputs = [sortedList[0][1]] for i in range(1, len(sortedList)): # endLine of the first file. we use all the lines of the first file up to endLine endLine = sortedList[i][0] - sortedList[i - 1][0] indx = self.findOverlapLine(sortedList[i - 1][1], sortedList[i][1], endLine, width, i - 1, i) #if indx is not None than indx is the new start line #otherwise we use startLine computed from acquisition time if (indx is not None) and (indx + sortedList[i - 1][0] != sortedList[i][0]): startLine.append(indx + sortedList[i - 1][0]) outputs.append(sortedList[i][1]) self.logger.info( "Changing starting line for frame %d from %d to %d" % (i, endLine, indx)) else: startLine.append(sortedList[i][0]) outputs.append(sortedList[i][1]) return startLine, outputs # Create the actual Track data by concatenating data from # all of the Frames objects together def createTrack(self, output): import os from operator import itemgetter from isceobj import Constants as CN from ctypes import cdll, c_char_p, c_int, c_ubyte, byref lib = cdll.LoadLibrary(os.path.dirname(__file__) + '/concatenate.so') # Perhaps we should check to see if Xmin is 0, if it is not, strip off the header self.logger.info( "Adjusting Sampling Window Start Times for all Frames") # Iterate over each frame object, and calculate the number of samples with which to pad it on the left and right outputs = [] totalWidth = 0 auxList = [] for frame in self._frames: # Calculate the amount of padding thisNearRange = frame.getStartingRange() thisFarRange = frame.getFarRange() left_pad = int( round((thisNearRange - self._nearRange) * frame.getInstrument().getRangeSamplingRate() / (CN.SPEED_OF_LIGHT / 2.0))) * 2 right_pad = int( round((self._farRange - thisFarRange) * frame.getInstrument().getRangeSamplingRate() / (CN.SPEED_OF_LIGHT / 2.0))) * 2 width = frame.getImage().getXmax() if width - int(width) != 0: raise ValueError("frame Xmax is not an integer") else: width = int(width) input = frame.getImage().getFilename() # tempOutput = os.path.basename(os.tmpnam()) # Some temporary filename with tempfile.NamedTemporaryFile(dir='.') as f: tempOutput = f.name pad_value = int(frame.getInstrument().getInPhaseValue()) if totalWidth < left_pad + width + right_pad: totalWidth = left_pad + width + right_pad # Resample this frame with swst_resample input_c = c_char_p(bytes(input, 'utf-8')) output_c = c_char_p(bytes(tempOutput, 'utf-8')) width_c = c_int(width) left_pad_c = c_int(left_pad) right_pad_c = c_int(right_pad) pad_value_c = c_ubyte(pad_value) lib.swst_resample(input_c, output_c, byref(width_c), byref(left_pad_c), byref(right_pad_c), byref(pad_value_c)) outputs.append(tempOutput) auxList.append(frame.auxFile) #this step construct the aux file withe the pulsetime info for the all set of frames self.createAuxFile(auxList, output + '.aux') # This assumes that all of the frames to be concatenated are sampled at the same PRI prf = self._frames[0].getInstrument().getPulseRepetitionFrequency() # Calculate the starting output line of each scene i = 0 lineSort = [] # the listSort has 2 elements: a line start number which is the position of that specific frame # computed from acquisition time and the corresponding file name for frame in self._frames: startLine = int( round( DTU.timeDeltaToSeconds(frame.getSensingStart() - self._startTime) * prf)) lineSort.append([startLine, outputs[i]]) i += 1 sortedList = sorted( lineSort, key=itemgetter(0)) # sort by line number i.e. acquisition time startLines, outputs = self.reAdjustStartLine(sortedList, totalWidth) self.logger.info("Concatenating Frames along Track") # this is a hack since the length of the file could be actually different from the one computed using start and stop time. it only matters the last frame added import os fileSize = os.path.getsize(outputs[-1]) numLines = fileSize // totalWidth + startLines[-1] totalLines_c = c_int(numLines) # Next, call frame_concatenate width_c = c_int( totalWidth ) # Width of each frame (with the padding added in swst_resample) numberOfFrames_c = c_int(len(self._frames)) inputs_c = (c_char_p * len(outputs))( ) # These are the inputs to frame_concatenate, but the outputs from swst_resample for kk in range(len(outputs)): inputs_c[kk] = bytes(outputs[kk], 'utf-8') output_c = c_char_p(bytes(output, 'utf-8')) startLines_c = (c_int * len(startLines))() startLines_c[:] = startLines lib.frame_concatenate(output_c, byref(width_c), byref(totalLines_c), byref(numberOfFrames_c), inputs_c, startLines_c) # Clean up the temporary output files from swst_resample for file in outputs: os.unlink(file) orbitNum = self._frames[0].getOrbitNumber() first_line_utc = self._startTime last_line_utc = self._stopTime centerTime = DTU.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 center_line_utc = first_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) procFac = self._frames[0].getProcessingFacility() procSys = self._frames[0].getProcessingSystem() procSoft = self._frames[0].getProcessingSoftwareVersion() pol = self._frames[0].getPolarization() xmin = self._frames[0].getImage().getXmin() self._frame.setOrbitNumber(orbitNum) self._frame.setSensingStart(first_line_utc) self._frame.setSensingMid(center_line_utc) self._frame.setSensingStop(last_line_utc) self._frame.setStartingRange(self._nearRange) self._frame.setFarRange(self._farRange) self._frame.setProcessingFacility(procFac) self._frame.setProcessingSystem(procSys) self._frame.setProcessingSoftwareVersion(procSoft) self._frame.setPolarization(pol) self._frame.setNumberOfLines(numLines) self._frame.setNumberOfSamples(width) # add image to frame rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setFilename(output) rawImage.setAccessMode('r') rawImage.setWidth(totalWidth) rawImage.setXmax(totalWidth) rawImage.setXmin(xmin) self._frame.setImage(rawImage) # Extract the early, late, start and stop times from a Frame object # And use this information to update def _updateTrackTimes(self, frame): if (frame.getSensingStart() < self._startTime): self._startTime = frame.getSensingStart() if (frame.getSensingStop() > self._stopTime): self._stopTime = frame.getSensingStop() if (frame.getStartingRange() < self._nearRange): self._nearRange = frame.getStartingRange() if (frame.getFarRange() > self._farRange): self._farRange = frame.getFarRange() pass pass pass
class EnviSAT_SLC(Sensor): parameter_list = (ORBIT_DIRECTORY, ORBITFILE, INSTRUMENTFILE, INSTRUMENT_DIRECTORY, IMAGEFILE) + Sensor.parameter_list """ A Class for parsing EnviSAT instrument and imagery files """ family = 'envisat' def __init__(self, family='', name=''): super(EnviSAT_SLC, self).__init__(family if family else self.__class__.family, name=name) self._imageFile = None self._instrumentFileData = None self._imageryFileData = None self.dopplerRangeTime = None self.rangeRefTime = None self.logger = logging.getLogger("isce.sensor.EnviSAT_SLC") self.frame = None self.frameList = [] self.constants = {'antennaLength': 10.0, 'iBias': 128, 'qBias': 128} def getFrame(self): return self.frame def parse(self): """ Parse both imagery and instrument files and create objects representing the platform, instrument and scene """ self.frame = Frame() self.frame.configure() self._imageFile = ImageryFile(fileName=self._imageFileName) self._imageryFileData = self._imageFile.parse() if self.instrumentFile in [None, '']: self.findInstrumentFile() instrumentFileParser = InstrumentFile(fileName=self.instrumentFile) self._instrumentFileData = instrumentFileParser.parse() self.populateMetadata() def populateMetadata(self): self._populatePlatform() self._populateInstrument() self._populateFrame() self._populateOrbit() self.dopplerRangeTime = self._imageryFileData['doppler'] self.rangeRefTime = self._imageryFileData['dopplerOrigin'][0] * 1.0e-9 # print('Doppler confidence: ', 100.0 * self._imageryFileData['dopplerConfidence'][0]) def _populatePlatform(self): """Populate the platform object with metadata""" platform = self.frame.getInstrument().getPlatform() # Populate the Platform and Scene objects platform.setMission("Envisat") platform.setPointingDirection(-1) platform.setAntennaLength(self.constants['antennaLength']) platform.setPlanet(Planet(pname="Earth")) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() rangeSampleSpacing = Const.c / ( 2 * self._imageryFileData['rangeSamplingRate']) pri = self._imageryFileData['pri'] ####These shouldnt matter for SLC data since data is already focused. txPulseLength = 512 / 19207680.000000 chirpPulseBandwidth = 16.0e6 chirpSlope = chirpPulseBandwidth / txPulseLength instrument.setRangePixelSize(rangeSampleSpacing) instrument.setPulseLength(txPulseLength) #instrument.setSwath(imageryFileData['SWATH']) instrument.setRadarFrequency(self._instrumentFileData['frequency']) instrument.setChirpSlope(chirpSlope) instrument.setRangeSamplingRate( self._imageryFileData['rangeSamplingRate']) instrument.setPulseRepetitionFrequency(1.0 / pri) #instrument.setRangeBias(rangeBias) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" numberOfLines = self._imageryFileData['numLines'] numberOfSamples = self._imageryFileData['numSamples'] pri = self._imageryFileData['pri'] startingRange = Const.c * float( self._imageryFileData['timeToFirstSample']) * 1.0e-9 / 2.0 rangeSampleSpacing = Const.c / ( 2 * self._imageryFileData['rangeSamplingRate']) farRange = startingRange + numberOfSamples * rangeSampleSpacing first_line_utc = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') center_line_utc = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') last_line_utc = datetime.datetime.strptime( self._imageryFileData['LAST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') centerTime = DTUtil.timeDeltaToSeconds(last_line_utc - first_line_utc) / 2.0 center_line_utc = center_line_utc + datetime.timedelta( microseconds=int(centerTime * 1e6)) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self._imageryFileData['PROC_CENTER']) self.frame.setProcessingSystem(self._imageryFileData['SOFTWARE_VER']) self.frame.setTrackNumber(int(self._imageryFileData['REL_ORBIT'])) self.frame.setOrbitNumber(int(self._imageryFileData['ABS_ORBIT'])) self.frame.setPolarization(self._imageryFileData['MDS1_TX_RX_POLAR']) self.frame.setNumberOfSamples(numberOfSamples) self.frame.setNumberOfLines(numberOfLines) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(center_line_utc) self.frame.setSensingStop(last_line_utc) def _populateOrbit(self): if self.orbitFile in [None, '']: self.findOrbitFile() dorParser = DOR(fileName=self.orbitFile) dorParser.parse() startTime = self.frame.getSensingStart() - datetime.timedelta( minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.frame.setOrbit(dorParser.orbit.trimOrbit(startTime, stopTime)) def _populateImage(self, outname, width, length): #farRange = self.frame.getStartingRange() + width*self.frame.getInstrument().getRangeSamplingRate() # Update the NumberOfSamples and NumberOfLines in the Frame object self.frame.setNumberOfSamples(width) self.frame.setNumberOfLines(length) #self.frame.setFarRange(farRange) # Create a RawImage object rawImage = createSlcImage() rawImage.setFilename(outname) rawImage.setAccessMode('read') rawImage.setByteOrder('l') rawImage.setXmin(0) rawImage.setXmax(width) rawImage.setWidth(width) self.frame.setImage(rawImage) def extractImage(self): from datetime import datetime as dt import tempfile as tf self.parse() width = self._imageryFileData['numSamples'] length = self._imageryFileData['numLines'] self._imageFile.extractImage(self.output, width, length) self._populateImage(self.output, width, length) pass def findOrbitFile(self): datefmt = '%Y%m%d%H%M%S' # sensingStart = self.frame.getSensingStart() sensingStart = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') outFile = None if self.orbitDir in [None, '']: raise Exception( 'No Envisat Orbit File or Orbit Directory specified') try: for fname in os.listdir(self.orbitDir): if not os.path.isfile(os.path.join(self.orbitDir, fname)): continue if not fname.startswith('DOR'): continue fields = fname.split('_') procdate = datetime.datetime.strptime( fields[-6][-8:] + fields[-5], datefmt) startdate = datetime.datetime.strptime(fields[-4] + fields[-3], datefmt) enddate = datetime.datetime.strptime(fields[-2] + fields[-1], datefmt) if (sensingStart > startdate) and (sensingStart < enddate): outFile = os.path.join(self.orbitDir, fname) break except: raise Exception( 'Error occured when trying to find orbit file in %s' % (self.orbitDir)) if not outFile: raise Exception('Envisat orbit file could not be found in %s' % (self.orbitDir)) self.orbitFile = outFile return def findInstrumentFile(self): datefmt = '%Y%m%d%H%M%S' sensingStart = datetime.datetime.strptime( self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f') print('sens: ', sensingStart) outFile = None if self.instrumentDir in [None, '']: raise Exception( 'No Envisat Instrument File or Instrument Directory specified') try: for fname in os.listdir(self.instrumentDir): if not os.path.isfile(os.path.join(self.instrumentDir, fname)): continue if not fname.startswith('ASA_INS'): continue fields = fname.split('_') procdate = datetime.datetime.strptime( fields[-6][-8:] + fields[-5], datefmt) startdate = datetime.datetime.strptime(fields[-4] + fields[-3], datefmt) enddate = datetime.datetime.strptime(fields[-2] + fields[-1], datefmt) if (sensingStart > startdate) and (sensingStart < enddate): outFile = os.path.join(self.instrumentDir, fname) break except: raise Exception( 'Error occured when trying to find instrument file in %s' % (self.instrumentDir)) if not outFile: raise Exception( 'Envisat instrument file could not be found in %s' % (self.instrumentDir)) self.instrumentFile = outFile return def extractDoppler(self): """ Return the doppler centroid as defined in the ASAR file. """ quadratic = {} r0 = self.frame.getStartingRange() dr = self.frame.instrument.getRangePixelSize() width = self.frame.getNumberOfSamples() midr = r0 + (width / 2.0) * dr midtime = 2 * midr / Const.c - self.rangeRefTime fd_mid = 0.0 tpow = midtime for kk in self.dopplerRangeTime: fd_mid += kk * tpow tpow *= midtime ####For insarApp quadratic['a'] = fd_mid / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate from isceobj.Util import Poly1D coeffs = self.dopplerRangeTime dr = self.frame.getInstrument().getRangePixelSize() rref = 0.5 * Const.c * self.rangeRefTime r0 = self.frame.getStartingRange() norm = 0.5 * Const.c / dr dcoeffs = [] for ind, val in enumerate(coeffs): dcoeffs.append(val / (norm**ind)) poly = Poly1D.Poly1D() poly.initPoly(order=len(coeffs) - 1) poly.setMean((rref - r0) / dr - 1.0) poly.setCoeffs(dcoeffs) pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(coeffs) + 1) evals = poly(pix) fit = np.polyfit(pix, evals, len(coeffs) - 1) self.frame._dopplerVsPixel = list(fit[::-1]) print('Doppler Fit: ', fit[::-1]) return quadratic
class ERS(Component): #Parsers.CEOS.CEOSFormat.ceosTypes['text'] = # {'typeCode': 63, 'subtypeCode': [18,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['leaderFile'] = # {'typeCode': 192, 'subtypeCode': [63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['dataSetSummary'] = # {'typeCode': 10, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['platformPositionData'] = # {'typeCode': 30, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['facilityData'] = # {'typeCode': 200, 'subtypeCode': [10,31,50]} #Parsers.CEOS.CEOSFormat.ceosTypes['datafileDescriptor'] = # {'typeCode': 192, 'subtypeCode':[63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['signalData'] = # {'typeCode': 10, 'subtypeCode': [50,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['nullFileDescriptor'] = # {'typeCode': 192, 'subtypeCode': [192,63,18]} logging_name = 'isce.sensor.ers' def __init__(self): Component.__init__(self) self._leaderFile = None self._imageFileList = '' self._leaderFileList = '' self._imageFile = None self._orbitDir = None # Use this for Delft Orbit files self._orbitFile = None # Use this for PDS Orbit files for now self._orbitType = None self.frameList = [] self.output = None self.descriptionOfVariables = {} self.dictionaryOfVariables = { 'ORBIT_TYPE': ['self._orbitType','str','mandatory'], 'ORBIT_DIRECTORY': ['self._orbitDir','str','optional'], 'ORBIT_FILE': ['self._orbitFile','str','optional'], 'LEADERFILE': ['self._leaderFileList','str','mandatory'], 'IMAGEFILE': ['self._imageFileList','str','mandatory'], 'OUTPUT': ['self.output','str','optional']} self.frame = Frame() self.frame.configure() # Constants are from # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = {'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime':6.622e-6, 'iBias': 15.5, 'qBias': 15.5} return None def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() elif (self._orbitType == 'PDS'): self._populatePDSOrbits() else: self._populateHeaderOrbit() def _populatePlatform(self): """ Populate the platform object with metadata """ platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet('Earth')) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() pri = self.imageFile.firstPri rangeSamplingRate = self.constants['rangeSamplingRate'] #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ # 'Range sampling rate']*1e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 4.0/rangeSamplingRate*(pri+2.0) prf = 1.0/pulseInterval instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord.metadata[ 'Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length']*1e-6) instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/ (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']* 1e-6)) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" rangeSamplingRate = self.constants['rangeSamplingRate'] #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[ # 'Range sampling rate']*1e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency() frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord.metadata[ 'Scene reference number']) startingRange = (9*pulseInterval + self.imageFile.minSwst*4/rangeSamplingRate-self.constants['delayTime'])*Const.c/2.0 farRange = startingRange + self.imageFile.width*rangePixelSize # Use the Scene center time to get the date, then use the ICU on board time from the image for the rest centerLineTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Scene centre time'],"%Y%m%d%H%M%S%f") first_line_utc = datetime.datetime(year=centerLineTime.year, month=centerLineTime.month, day=centerLineTime.day) if(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'] in ('CRDC_SARDPF','GTS - ERS')): first_line_utc = first_line_utc + datetime.timedelta(milliseconds=self.imageFile.startTime) else: deltaSeconds = (self.imageFile.startTime - self.leaderFile.sceneHeaderRecord.metadata['Satellite encoded binary time code'])* 1/256.0 # Sometimes, the ICU on board clock is corrupt, if the time suggested by the on board clock is more than # 5 days from the satellite clock time, assume its bogus and use the low-precision scene centre time if (math.fabs(deltaSeconds) > 5*86400): self.logger.warn("ICU on board time appears to be corrupt, resorting to low precision clock") first_line_utc = centerLineTime - datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6) else: satelliteClockTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Satellite clock time'],"%Y%m%d%H%M%S%f") first_line_utc = satelliteClockTime + datetime.timedelta(microseconds=int(deltaSeconds*1e6)) mid_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6) last_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*self.imageFile.length*1e6) self.logger.debug("Frame UTC start, mid, end times: %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(mid_line_utc) self.frame.setSensingStop(last_line_utc) def _populateHeaderOrbit(self): """Populate an orbit object with the header orbits""" self.logger.info("Using Header Orbits") orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') orbit.setOrbitQuality('Unknown') t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'] t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]) vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]) orbit.addStateVector(vec) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) odr = ODR(file=os.path.join(self._orbitDir,orbitFile)) #jng it seem that for this tipe of orbit points are separated by 60 sec. In ODR at least 9 state vectors are needed to compute the velocities. add # extra time before and after to allow interpolation, but do not do it for all data points. too slow startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60) odr.parseHeader(startTimePreInterp,stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) orbit = odr.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir,orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePDSOrbits(self): """ Populate an orbit object using the ERS-2 PDS format """ from isceobj.Orbit.PDS import PDS self.logger.info("Using PDS Orbits") pds = PDS(file=self._orbitFile) pds.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = pds.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def extractImage(self): import array import math # just in case there was only one image and it was passed as a str instead of a list with only one element if(isinstance(self._imageFileList,str)): self._imageFileList = [self._imageFileList] self._leaderFileList = [self._leaderFileList] if(len(self._imageFileList) != len(self._leaderFileList)): self.logger.error("Number of leader files different from number of image files.") raise Exception self.frameList = [] for i in range(len(self._imageFileList)): appendStr = "_" + str(i) #if only one file don't change the name if(len(self._imageFileList) == 1): appendStr = '' self.frame = Frame() self.frame.configure() self._leaderFile = self._leaderFileList[i] self._imageFile = self._imageFileList[i] self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) try: outputNow = self.output + appendStr out = open(outputNow,'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) return self.imageFile.extractImage(output=out) out.close() rawImage = isceobj.createRawImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(outputNow) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) self.frame.setImage(rawImage) self.populateMetadata() self.frameList.append(self.frame) #jng Howard Z at this point adjusts the sampling starting time for imagery generated from CRDC_SARDPF facility. # for now create the orbit aux file based in starting time and prf prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf)) # the aux files has two entries per line. day of the year and microseconds in the day musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond maxMusec = (24*3600)*10**6#use it to check if we went across a day. very rare day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1 outputArray = array.array('d',[0]*2*numPulses) self.frame.auxFile = outputNow + '.aux' fp = open(self.frame.auxFile,'wb') j = -1 for i1 in range(numPulses): j += 1 musec = round((j/prf)*10**6) + musec0 if musec >= maxMusec: day0 += 1 musec0 = musec%maxMusec musec = musec0 j = 0 outputArray[2*i1] = day0 outputArray[2*i1+1] = musec outputArray.tofile(fp) fp.close() tk = Track() if(len(self._imageFileList) > 1): self.frame = tk.combineFrames(self.output,self.frameList) for i in range(len(self._imageFileList)): try: os.remove(self.output + "_" + str(i)) except OSError: print("Error. Cannot remove temporary file",self.output + "_" + str(i)) raise OSError def _decodeSceneReferenceNumber(self,referenceNumber): frameNumber = referenceNumber.split('=') if (len(frameNumber) > 2): frameNumber = frameNumber[2].strip() else: frameNumber = frameNumber[0] return frameNumber
class 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 ALOS2(Sensor): """ Code to read CEOSFormat leader files for ALOS2 SLC data. """ family = 'alos2' parameter_list = (WAVELENGTH, LEADERFILE, IMAGEFILE) + Sensor.parameter_list fsampConst = { 104: 1.047915957140240E+08, 52: 5.239579785701190E+07, 34: 3.493053190467460E+07, 17: 1.746526595233730E+07 } #Orbital Elements (Quality) Designator #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description #PALSAR-2_xx_Format_CEOS_E_r.pdf orbitElementsDesignator = { '0': 'preliminary', '1': 'decision', '2': 'high precision' } def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.leaderFile = None self.imageFile = None #####Soecific doppler functions for ALOS2 self.doppler_coeff = None self.azfmrate_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 10} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord. metadata['Scene reference number']) fsamplookup = int(self.leaderFile.sceneHeaderRecord. metadata['Range sampling rate in MHz']) rangePixelSize = Const.c / (2 * self.fsampConst[fsamplookup]) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord. metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(1) platform.setPlanet(Planet(pname='Earth')) if self.wavelength: ins.setRadarWavelength(float(self.wavelength)) # print('ins.radarWavelength = ', ins.getRadarWavelength(), # type(ins.getRadarWavelength())) else: ins.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord. metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency( self.leaderFile.sceneHeaderRecord. metadata['Pulse Repetition Frequency in mHz'] * 1.0e-3) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate(self.fsampConst[fsamplookup]) ins.setPulseLength(self.leaderFile.sceneHeaderRecord. metadata['Range pulse length in microsec'] * 1.0e-6) chirpSlope = self.leaderFile.sceneHeaderRecord.metadata[ 'Nominal range pulse (chirp) amplitude coefficient linear term'] chirpPulseBandwidth = abs( chirpSlope * self.leaderFile.sceneHeaderRecord. metadata['Range pulse length in microsec'] * 1.0e-6) ins.setChirpSlope(chirpSlope) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[ 'Time direction indicator along pixel direction'].strip() ######ALOS2 includes this information in clock angle clockAngle = self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor clock angle'] if clockAngle == 90.0: platform.setPointingDirection(-1) elif clockAngle == -90.0: platform.setPointingDirection(1) else: raise Exception( 'Unknown look side. Clock Angle = {0}'.format(clockAngle)) # print(self.leaderFile.sceneHeaderRecord.metadata["Sensor ID and mode of operation for this channel"]) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber( self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setProcessingFacility( self.leaderFile.sceneHeaderRecord. metadata['Processing facility identifier']) self.frame.setProcessingSystem( self.leaderFile.sceneHeaderRecord. metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion( self.leaderFile.sceneHeaderRecord. metadata['Processing version identifier']) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfLines( self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples( self.imageFile.imageFDR. metadata['Number of pixels per line per SAR channel']) ###### orb = self.frame.getOrbit() orb.setOrbitSource('Header') orb.setOrbitQuality(self.orbitElementsDesignator[ self.leaderFile.platformPositionRecord. metadata['Orbital elements designator']]) t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord. metadata['Year of data point'], month=self.leaderFile.platformPositionRecord. metadata['Month of data point'], day=self.leaderFile.platformPositionRecord. metadata['Day of data point']) t0 = t0 + datetime.timedelta( seconds=self.leaderFile.platformPositionRecord. metadata['Seconds of day']) #####Read in orbit in inertial coordinates deltaT = self.leaderFile.platformPositionRecord.metadata[ 'Time interval between data points'] numPts = self.leaderFile.platformPositionRecord.metadata[ 'Number of data points'] orb = self.frame.getOrbit() for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i * deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata[ 'Positional Data Points'][i] pos = [ dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z'] ] vel = [ dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z'] ] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) self.doppler_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency centroid quadratic term'] ] self.azfmrate_coeff = [ self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate constant term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate linear term'], self.leaderFile.sceneHeaderRecord. metadata['Cross track Doppler frequency rate quadratic term'] ] # print('Terrain height: ', self.leaderFile.sceneHeaderRecord.metadata['Average terrain ellipsoid height']) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() # rangeGate = self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6 # delt = datetime.timedelta(seconds=rangeGate) delt = datetime.timedelta(seconds=0.0) self.frame.setSensingStart(self.imageFile.sensingStart + delt) self.frame.setSensingStop(self.imageFile.sensingStop + delt) sensingMid = self.imageFile.sensingStart + datetime.timedelta( seconds=0.5 * (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) + delt self.frame.setSensingMid(sensingMid) self.frame.setStartingRange(self.imageFile.nearRange) self.frame.getInstrument().setPulseRepetitionFrequency( self.imageFile.prf) pixelSize = self.frame.getInstrument().getRangePixelSize() farRange = self.imageFile.nearRange + (pixelSize - 1) * self.imageFile.width self.frame.setFarRange(farRange) rawImage = isceobj.createSlcImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' midwidth = self.frame.getNumberOfSamples() / 2.0 dop = 0.0 prod = 1.0 for ind, kk in enumerate(self.doppler_coeff): dop += kk * prod prod *= midwidth print('Average Doppler: {0}'.format(dop)) ####For insarApp quadratic = {} quadratic['a'] = dop / self.frame.getInstrument( ).getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate ####CEOS already provides function vs pixel self.frame._dopplerVsPixel = self.doppler_coeff return quadratic def _decodeSceneReferenceNumber(self, referenceNumber): return referenceNumber
class 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 JERS(Component): """ Code to read CEOSFormat leader files for ERS-1/2 SAR data. The tables used to create this parser are based on document number ER-IS-EPO-GS-5902.1 from the European Space Agency. """ #Parsers.CEOS.CEOSFormat.ceosTypes['text'] = {'typeCode': 63, 'subtypeCode': [18,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['leaderFile'] = {'typeCode': 192, 'subtypeCode': [63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['dataSetSummary'] = {'typeCode': 10, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['platformPositionData'] = {'typeCode': 30, 'subtypeCode': [10,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['facilityData'] = {'typeCode': 200, 'subtypeCode': [10,31,50]} #Parsers.CEOS.CEOSFormat.ceosTypes['datafileDescriptor'] = {'typeCode': 192, 'subtypeCode':[63,18,18]} #Parsers.CEOS.CEOSFormat.ceosTypes['signalData'] = {'typeCode': 10, 'subtypeCode': [50,31,20]} #Parsers.CEOS.CEOSFormat.ceosTypes['nullFileDescriptor'] = {'typeCode': 192, 'subtypeCode': [192,63,18]} def __init__(self): Component.__init__(self) self._leaderFile = None self._imageFile = None self.output = None self.frame = Frame() self.frame.configure() self.constants = {'polarization': 'HH', 'antennaLength': 12} self.descriptionOfVariables = {} self.dictionaryOfVariables = {'LEADERFILE': ['self._leaderFile','str','mandatory'], 'IMAGEFILE': ['self._imageFile','str','mandatory'], 'OUTPUT': ['self.output','str','optional']} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(file=self._imageFile) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self.leaderFile.sceneHeaderRecord.metadata['Scene reference number'].strip() frame = self._decodeSceneReferenceNumber(frame) rangePixelSize = Constants.SPEED_OF_LIGHT/(2*self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1e6) self.frame.getInstrument().getPlatform().setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier']) self.frame.getInstrument().getPlatform().setPlanet(Planet(pname='Earth')) self.frame.getInstrument().setWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) self.frame.getInstrument().setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency']) self.frame.getInstrument().setRangePixelSize(rangePixelSize) self.frame.getInstrument().setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6) chirpPulseBandwidth = 15.50829e6 # Is this really not in the CEOSFormat Header? self.frame.getInstrument().setChirpSlope(chirpPulseBandwidth/(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) #self.frame.setStartingRange(self.leaderFile.facilityRecord.metadata['Slant range reference']) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setPolarization('HH') self.frame.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel']) self.frame.getOrbit().setOrbitSource('Header') t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() t = t0 + datetime.timedelta(seconds=(i*self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'])) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]) vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]) self.frame.getOrbit().addStateVector(vec) def extractImage(self): raise NotImplementedError() def _decodeSceneReferenceNumber(self,referenceNumber): return referenceNumber
class 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 ALOS_SLC(Sensor): """ Code to read CEOSFormat leader files for ALOS SLC data. """ parameter_list = (WAVELENGTH, LEADERFILE, IMAGEFILE) + Sensor.parameter_list family = 'alos_slc' logging_name = 'isce.sensor.ALOS_SLC' #Orbital Elements (Quality) Designator #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description #PALSAR-2_xx_Format_CEOS_E_r.pdf orbitElementsDesignator = {'0': 'preliminary', '1': 'decision', '2': 'high precision'} def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.imageFile = None self.leaderFile = None # Specific doppler functions for ALOS self.doppler_coeff = None self.azfmrate_coeff = None self.lineDirection = None self.pixelDirection = None self.frame = Frame() self.frame.configure() self.constants = {'antennaLength': 15} def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(self, file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self, file=self._imageFile) self.imageFile.parse() self.populateMetadata() self._populateExtras() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ frame = self._decodeSceneReferenceNumber(self.leaderFile.sceneHeaderRecord.metadata['Scene reference number']) fsamplookup = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate in MHz']*1.0e6 rangePixelSize = Const.c/(2*fsamplookup) ins = self.frame.getInstrument() platform = ins.getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(1) platform.setPlanet(Planet(pname='Earth')) if self.wavelength: ins.setRadarWavelength(float(self.wavelength)) else: ins.setRadarWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre']) self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency in mHz']*1.0e-3) ins.setRangePixelSize(rangePixelSize) ins.setRangeSamplingRate(fsamplookup) ins.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6) chirpSlope = self.leaderFile.sceneHeaderRecord.metadata['Nominal range pulse (chirp) amplitude coefficient linear term'] chirpPulseBandwidth = abs(chirpSlope * self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6) ins.setChirpSlope(chirpSlope) ins.setInPhaseValue(7.5) ins.setQuadratureValue(7.5) self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along line direction'].strip() self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along pixel direction'].strip() ######ALOS includes this information in clock angle clockAngle = self.leaderFile.sceneHeaderRecord.metadata['Sensor clock angle'] if clockAngle == 90.0: platform.setPointingDirection(-1) elif clockAngle == -90.0: platform.setPointingDirection(1) else: raise Exception('Unknown look side. Clock Angle = {0}'.format(clockAngle)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set']) self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel']) self.frame.instrument.setAzimuthPixelSize(self.leaderFile.dataQualitySummaryRecord.metadata['Azimuth resolution']) ###### orb = self.frame.getOrbit() orb.setOrbitSource('Header') orb.setOrbitQuality( self.orbitElementsDesignator[ self.leaderFile.platformPositionRecord.metadata['Orbital elements designator'] ] ) t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']) #####Read in orbit in inertial coordinates deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between data points'] numPts = self.leaderFile.platformPositionRecord.metadata['Number of data points'] orb = self.frame.getOrbit() for i in range(numPts): vec = StateVector() t = t0 + datetime.timedelta(seconds=i*deltaT) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] pos = [dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']] vel = [dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']] vec.setPosition(pos) vec.setVelocity(vel) orb.addStateVector(vec) self.doppler_coeff = [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term']] self.azfmrate_coeff = [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate constant term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate linear term'], self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate quadratic term']] def _populateExtras(self): dataset = self.leaderFile.radiometricRecord.metadata print("Record Number: %d" % (dataset["Record Number"])) print("First Record Subtype: %d" % (dataset["First Record Subtype"])) print("Record Type Code: %d" % (dataset["Record Type Code"])) print("Second Record Subtype: %d" % (dataset["Second Record Subtype"])) print("Third Record Subtype: %d" % (dataset["Third Record Subtype"])) print("Record Length: %d" % (dataset["Record Length"])) print("SAR channel indicator: %d" % (dataset["SAR channel indicator"])) print("Number of data sets: %d" % (dataset["Number of data sets"])) numPts = dataset['Number of data sets'] for i in range(numPts): if i > 1: break print('Radiometric record field: %d' % (i+1)) dataset = self.leaderFile.radiometricRecord.metadata[ 'Radiometric data sets'][i] DT11 = complex(dataset['Real part of DT 1,1'], dataset['Imaginary part of DT 1,1']) DT12 = complex(dataset['Real part of DT 1,2'], dataset['Imaginary part of DT 1,2']) DT21 = complex(dataset['Real part of DT 2,1'], dataset['Imaginary part of DT 2,1']) DT22 = complex(dataset['Real part of DT 2,2'], dataset['Imaginary part of DT 2,2']) DR11 = complex(dataset['Real part of DR 1,1'], dataset['Imaginary part of DR 1,1']) DR12 = complex(dataset['Real part of DR 1,2'], dataset['Imaginary part of DR 1,2']) DR21 = complex(dataset['Real part of DR 2,1'], dataset['Imaginary part of DR 2,1']) DR22 = complex(dataset['Real part of DR 2,2'], dataset['Imaginary part of DR 2,2']) print("Calibration factor [dB]: %f" % (dataset["Calibration factor"])) print('Distortion matrix Trasmission [DT11, DT12, DT21, DT22]: ' '[%s, %s, %s, %s]' % (str(DT11), str(DT12), str(DT21), str(DT22))) print('Distortion matrix Reception [DR11, DR12, DR21, DR22]: ' '[%s, %s, %s, %s]' % (str(DR11), str(DR12), str(DR21), str(DR22))) self.transmit = Distortion(DT12, DT21, DT22) self.receive = Distortion(DR12, DR21, DR22) self.calibrationFactor = float( dataset['Calibration factor']) def extractImage(self): import isceobj if (self.imageFile is None) or (self.leaderFile is None): self.parse() try: out = open(self.output, 'wb') except IOError as strerr: self.logger.error("IOError: %s" % strerr) self.imageFile.extractImage(output=out) out.close() self.frame.setSensingStart(self.imageFile.sensingStart) self.frame.setSensingStop(self.imageFile.sensingStop) sensingMid = self.imageFile.sensingStart + datetime.timedelta(seconds = 0.5* (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds()) self.frame.setSensingMid(sensingMid) try: rngGate= Const.c*0.5*self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6 except: rngGate = None if (rngGate is None) or (rngGate == 0.0): rngGate = self.imageFile.nearRange self.frame.setStartingRange(rngGate) self.frame.getInstrument().setPulseRepetitionFrequency(self.imageFile.prf) pixelSize = self.frame.getInstrument().getRangePixelSize() farRange = self.imageFile.nearRange + (pixelSize-1) * self.imageFile.width self.frame.setFarRange(farRange) self.frame.setPolarization(self.imageFile.current_polarization) rawImage = isceobj.createSlcImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) rawImage.renderHdr() self.frame.setImage(rawImage) return def extractDoppler(self): ''' Evaluate the doppler polynomial and return the average value for now. ''' midwidth = self.frame.getNumberOfSamples() / 2.0 dop = 0.0 prod = 1.0 for ind, kk in enumerate(self.doppler_coeff): dop += kk * prod prod *= midwidth print ('Average Doppler: {0}'.format(dop)) ####For insarApp quadratic = {} quadratic['a'] = dop / self.frame.getInstrument().getPulseRepetitionFrequency() quadratic['b'] = 0. quadratic['c'] = 0. ####For roiApp ####More accurate ####CEOS already provides function vs pixel self.frame._dopplerVsPixel = self.doppler_coeff return quadratic def _decodeSceneReferenceNumber(self,referenceNumber): return referenceNumber
class ERS_SLC(Sensor): family = 'ers_slc' logging_name = 'isce.sensor.ers_slc' parameter_list = (IMAGEFILE, LEADERFILE, ORBIT_TYPE, ORBIT_DIRECTORY, ORBIT_FILE) + Sensor.parameter_list @logged def __init__(self, name=''): super().__init__(family=self.__class__.family, name=name) self.frame = Frame() self.frame.configure() self.dopplerRangeTime = None # Constants are from # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001. self.constants = {'polarization': 'VV', 'antennaLength': 10, 'lookDirection': 'RIGHT', 'chirpPulseBandwidth': 15.50829e6, 'rangeSamplingRate': 18.962468e6, 'delayTime':6.622e-6, 'iBias': 15.5, 'qBias': 15.5} return None def getFrame(self): return self.frame def parse(self): self.leaderFile = LeaderFile(file=self._leaderFile) self.leaderFile.parse() self.imageFile = ImageFile(self) self.imageFile.parse() self.populateMetadata() def populateMetadata(self): """ Create the appropriate metadata objects from our CEOSFormat metadata """ self._populatePlatform() self._populateInstrument() self._populateFrame() if (self._orbitType == 'ODR'): self._populateDelftOrbits() elif (self._orbitType == 'PRC'): self._populatePRCOrbits() elif (self._orbitType == 'PDS'): self._populatePDSOrbits() else: self._populateHeaderOrbit() self._populateDoppler() def _populatePlatform(self): """ Populate the platform object with metadata """ platform = self.frame.getInstrument().getPlatform() platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[ 'Sensor platform mission identifier']) platform.setAntennaLength(self.constants['antennaLength']) platform.setPointingDirection(-1) platform.setPlanet(Planet(pname='Earth')) def _populateInstrument(self): """Populate the instrument object with metadata""" instrument = self.frame.getInstrument() prf = self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency'] rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1.0e6 rangePixelSize = Const.c/(2.0*rangeSamplingRate) instrument.setRadarWavelength( self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength']) instrument.setIncidenceAngle( self.leaderFile.sceneHeaderRecord.metadata[ 'Incidence angle at scene centre']) instrument.setPulseRepetitionFrequency(prf) instrument.setRangeSamplingRate(rangeSamplingRate) instrument.setRangePixelSize(rangePixelSize) instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[ 'Range pulse length']*1e-6) instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/ (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']* 1e-6)) instrument.setInPhaseValue(self.constants['iBias']) instrument.setQuadratureValue(self.constants['qBias']) def _populateFrame(self): """Populate the scene object with metadata""" rangeSamplingRate = self.constants['rangeSamplingRate'] rangePixelSize = Const.c/(2.0*rangeSamplingRate) pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency() frame = self._decodeSceneReferenceNumber( self.leaderFile.sceneHeaderRecord.metadata[ 'Scene reference number']) prf = self.frame.instrument.getPulseRepetitionFrequency() tau0 = self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler range time of first range pixel']*1.0e-3 startingRange = tau0*Const.c/2.0 farRange = startingRange + self.imageFile.width*rangePixelSize first_line_utc = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler azimuth time of first azimuth pixel'], "%d-%b-%Y %H:%M:%S.%f") mid_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1) * 0.5 / prf) last_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1)/prf) self.logger.debug("Frame UTC start, mid, end times: %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc)) self.frame.setFrameNumber(frame) self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number']) self.frame.setStartingRange(startingRange) self.frame.setFarRange(farRange) self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier']) self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier']) self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier']) self.frame.setPolarization(self.constants['polarization']) self.frame.setNumberOfLines(self.imageFile.length) self.frame.setNumberOfSamples(self.imageFile.width) self.frame.setSensingStart(first_line_utc) self.frame.setSensingMid(mid_line_utc) self.frame.setSensingStop(last_line_utc) def _populateHeaderOrbit(self): """Populate an orbit object with the header orbits""" self.logger.info("Using Header Orbits") orbit = self.frame.getOrbit() orbit.setOrbitSource('Header') orbit.setOrbitQuality('Unknown') t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'], month=self.leaderFile.platformPositionRecord.metadata['Month of data point'], day=self.leaderFile.platformPositionRecord.metadata['Day of data point']) t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6) for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']): vec = StateVector() deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points'] t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6) vec.setTime(t) dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i] vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]) vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]) orbit.addStateVector(vec) def _populateDelftOrbits(self): """Populate an orbit object with the Delft orbits""" from isceobj.Orbit.ODR import ODR, Arclist self.logger.info("Using Delft Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) odr = ODR(file=os.path.join(self._orbitDir,orbitFile)) startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60) stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60) odr.parseHeader(startTimePreInterp,stopTimePreInterp) startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) orbit = odr.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePRCOrbits(self): """Populate an orbit object the D-PAF PRC orbits""" from isceobj.Orbit.PRC import PRC, Arclist self.logger.info("Using PRC Orbits") arclist = Arclist(os.path.join(self._orbitDir,'arclist')) arclist.parse() orbitFile = arclist.getOrbitFile(self.frame.getSensingStart()) self.logger.debug("Using file %s" % (orbitFile)) prc = PRC(file=os.path.join(self._orbitDir,orbitFile)) prc.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = prc.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populatePDSOrbits(self): """ Populate an orbit object using the ERS-2 PDS format """ from isceobj.Orbit.PDS import PDS self.logger.info("Using PDS Orbits") pds = PDS(file=self._orbitFile) pds.parse() startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5) stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5) self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime)) fullOrbit = pds.getOrbit() orbit = fullOrbit.trimOrbit(startTime,stopTime) self.frame.setOrbit(orbit) def _populateDoppler(self): ''' Extract doppler from the CEOS file. ''' prf = self.frame.instrument.getPulseRepetitionFrequency() #####ERS provides doppler as a function of slant range time in seconds d0 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term'] d1 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term'] d2 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term'] self.dopplerRangeTime = [d0, d1, d2] return def extractDoppler(self): width = self.frame.getNumberOfSamples() prf = self.frame.instrument.getPulseRepetitionFrequency() midtime = 0.5*width/self.frame.instrument.getRangeSamplingRate() fd_mid = 0.0 x = 1.0 for ind, coeff in enumerate(self.dopplerRangeTime): fd_mid += coeff * x x *= midtime ####For insarApp quadratic = {} quadratic['a'] = fd_mid / prf quadratic['b'] = 0.0 quadratic['c'] = 0.0 ###For roiApp more accurate ####Convert stuff to pixel wise coefficients dr = self.frame.getInstrument().getRangePixelSize() norm = 0.5*Const.c/dr dcoeffs = [] for ind, val in enumerate(self.dopplerRangeTime): dcoeffs.append( val / (norm**ind)) self.frame._dopplerVsPixel = dcoeffs print('Doppler Fit: ', fit[::-1]) return quadratic def extractImage(self): import array import math self.parse() try: out = open(self.output, 'wb') except: raise Exception('Cannot open output file: %s'%(self.output)) self.imageFile.extractImage(output=out) out.close() rawImage = isceobj.createSlcImage() rawImage.setByteOrder('l') rawImage.setAccessMode('read') rawImage.setFilename(self.output) rawImage.setWidth(self.imageFile.width) rawImage.setXmin(0) rawImage.setXmax(self.imageFile.width) self.frame.setImage(rawImage) prf = self.frame.getInstrument().getPulseRepetitionFrequency() senStart = self.frame.getSensingStart() numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf)) musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond maxMusec = (24*3600)*10**6#use it to check if we went across a day. very rare day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1 outputArray = array.array('d',[0]*2*numPulses) self.frame.auxFile = self.output + '.aux' fp = open(self.frame.auxFile,'wb') j = -1 for i1 in range(numPulses): j += 1 musec = round((j/prf)*10**6) + musec0 if musec >= maxMusec: day0 += 1 musec0 = musec%maxMusec musec = musec0 j = 0 outputArray[2*i1] = day0 outputArray[2*i1+1] = musec outputArray.tofile(fp) fp.close() def _decodeSceneReferenceNumber(self,referenceNumber): frameNumber = referenceNumber.split('=') if (len(frameNumber) > 2): frameNumber = frameNumber[2].strip() else: frameNumber = frameNumber[0] return frameNumber