def computeBaseline(trackReference, trackSecondary, azimuthTime, rangeDistance): import numpy as np from isceobj.Planet.Planet import Planet #modify Piyush's code for computing baslines refElp = Planet(pname='Earth').ellipsoid #for x in points: referenceSV = trackReference.orbit.interpolate(azimuthTime, method='hermite') target = trackReference.orbit.rdr2geo(azimuthTime, rangeDistance) slvTime, slvrng = trackSecondary.orbit.geo2rdr(target) secondarySV = trackSecondary.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array( refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(referenceSV.getPosition()) mvel = np.array(referenceSV.getVelocity()) sxyz = np.array(secondarySV.getPosition()) #to fix abrupt change near zero in baseline grid. JUN-05-2020 mvelunit = mvel / np.linalg.norm(mvel) sxyz = sxyz - np.dot(sxyz - mxyz, mvelunit) * mvelunit aa = np.linalg.norm(sxyz - mxyz) costheta = (rangeDistance * rangeDistance + aa * aa - slvrng * slvrng) / (2. * rangeDistance * aa) Bpar = aa * costheta perp = aa * np.sqrt(1 - costheta * costheta) direction = np.sign(np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel)) Bperp = direction * perp return (Bpar, Bperp)
def runPreprocessor(self): '''Extract images. ''' catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) #find files #actually no need to use absolute path any longer, since we are able to find file from vrt now. 27-JAN-2020, CRL. #denseoffset may still need absolute path when making links self.masterDir = os.path.abspath(self.masterDir) self.slaveDir = os.path.abspath(self.slaveDir) ledFilesMaster = sorted(glob.glob(os.path.join(self.masterDir, 'LED-ALOS2*-*-*'))) imgFilesMaster = sorted(glob.glob(os.path.join(self.masterDir, 'IMG-{}-ALOS2*-*-*'.format(self.masterPolarization.upper())))) ledFilesSlave = sorted(glob.glob(os.path.join(self.slaveDir, 'LED-ALOS2*-*-*'))) imgFilesSlave = sorted(glob.glob(os.path.join(self.slaveDir, 'IMG-{}-ALOS2*-*-*'.format(self.slavePolarization.upper())))) firstFrameMaster = ledFilesMaster[0].split('-')[-3][-4:] firstFrameSlave = ledFilesSlave[0].split('-')[-3][-4:] firstFrameImagesMaster = sorted(glob.glob(os.path.join(self.masterDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.masterPolarization.upper(), firstFrameMaster)))) firstFrameImagesSlave = sorted(glob.glob(os.path.join(self.slaveDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.slavePolarization.upper(), firstFrameSlave)))) #determin operation mode masterMode = os.path.basename(ledFilesMaster[0]).split('-')[-1][0:3] slaveMode = os.path.basename(ledFilesSlave[0]).split('-')[-1][0:3] spotlightModes = ['SBS'] stripmapModes = ['UBS', 'UBD', 'HBS', 'HBD', 'HBQ', 'FBS', 'FBD', 'FBQ'] scansarNominalModes = ['WBS', 'WBD', 'WWS', 'WWD'] scansarWideModes = ['VBS', 'VBD'] scansarModes = ['WBS', 'WBD', 'WWS', 'WWD', 'VBS', 'VBD'] #usable combinations if (masterMode in spotlightModes) and (slaveMode in spotlightModes): self._insar.modeCombination = 0 elif (masterMode in stripmapModes) and (slaveMode in stripmapModes): self._insar.modeCombination = 1 elif (masterMode in scansarNominalModes) and (slaveMode in scansarNominalModes): self._insar.modeCombination = 21 elif (masterMode in scansarWideModes) and (slaveMode in scansarWideModes): self._insar.modeCombination = 22 elif (masterMode in scansarNominalModes) and (slaveMode in stripmapModes): self._insar.modeCombination = 31 elif (masterMode in scansarWideModes) and (slaveMode in stripmapModes): self._insar.modeCombination = 32 else: print('\n\nthis mode combination is not possible') print('note that for ScanSAR-stripmap, ScanSAR must be master\n\n') raise Exception('mode combination not supported') if self._insar.modeCombination != 21: print('\n\nburst processing only support {}\n\n'.format(scansarNominalModes)) raise Exception('mode combination not supported') #determine default number of looks: self._insar.numberRangeLooks1 = self.numberRangeLooks1 self._insar.numberAzimuthLooks1 = self.numberAzimuthLooks1 self._insar.numberRangeLooks2 = self.numberRangeLooks2 self._insar.numberAzimuthLooks2 = self.numberAzimuthLooks2 #the following two will be automatically determined by runRdrDemOffset.py self._insar.numberRangeLooksSim = self.numberRangeLooksSim self._insar.numberAzimuthLooksSim = self.numberAzimuthLooksSim self._insar.numberRangeLooksIon = self.numberRangeLooksIon self._insar.numberAzimuthLooksIon = self.numberAzimuthLooksIon self._insar.numberRangeLooksSd = self.numberRangeLooksSd self._insar.numberAzimuthLooksSd = self.numberAzimuthLooksSd #force number of looks 1 to 1 self.numberRangeLooks1 = 1 self.numberAzimuthLooks1 = 1 self._insar.numberRangeLooks1 = 1 self._insar.numberAzimuthLooks1 = 1 if self._insar.numberRangeLooks2 == None: self._insar.numberRangeLooks2 = 7 if self._insar.numberAzimuthLooks2 == None: self._insar.numberAzimuthLooks2 = 2 if self._insar.numberRangeLooksIon == None: self._insar.numberRangeLooksIon = 42 if self._insar.numberAzimuthLooksIon == None: self._insar.numberAzimuthLooksIon = 12 if self._insar.numberRangeLooksSd == None: self._insar.numberRangeLooksSd = 14 if self._insar.numberAzimuthLooksSd == None: self._insar.numberAzimuthLooksSd = 4 #define processing file names self._insar.masterDate = os.path.basename(ledFilesMaster[0]).split('-')[2] self._insar.slaveDate = os.path.basename(ledFilesSlave[0]).split('-')[2] self._insar.setFilename(masterDate=self._insar.masterDate, slaveDate=self._insar.slaveDate, nrlks1=self._insar.numberRangeLooks1, nalks1=self._insar.numberAzimuthLooks1, nrlks2=self._insar.numberRangeLooks2, nalks2=self._insar.numberAzimuthLooks2) self._insar.setFilenameSd(masterDate=self._insar.masterDate, slaveDate=self._insar.slaveDate, nrlks1=self._insar.numberRangeLooks1, nalks1=self._insar.numberAzimuthLooks1, nrlks_sd=self._insar.numberRangeLooksSd, nalks_sd=self._insar.numberAzimuthLooksSd, nsd=3) #find frame numbers if (self._insar.modeCombination == 31) or (self._insar.modeCombination == 32): if (self.masterFrames == None) or (self.slaveFrames == None): raise Exception('for ScanSAR-stripmap inteferometry, you must set master and slave frame numbers') #if not set, find frames automatically if self.masterFrames == None: self.masterFrames = [] for led in ledFilesMaster: frameNumber = os.path.basename(led).split('-')[1][-4:] if frameNumber not in self.masterFrames: self.masterFrames.append(frameNumber) if self.slaveFrames == None: self.slaveFrames = [] for led in ledFilesSlave: frameNumber = os.path.basename(led).split('-')[1][-4:] if frameNumber not in self.slaveFrames: self.slaveFrames.append(frameNumber) #sort frames self.masterFrames = sorted(self.masterFrames) self.slaveFrames = sorted(self.slaveFrames) #check number of frames if len(self.masterFrames) != len(self.slaveFrames): raise Exception('number of frames in master dir is not equal to number of frames \ in slave dir. please set frame number manually') #find swath numbers (if not ScanSAR-ScanSAR, compute valid swaths) if (self._insar.modeCombination == 0) or (self._insar.modeCombination == 1): self.startingSwath = 1 self.endingSwath = 1 if self._insar.modeCombination == 21: if self.startingSwath == None: self.startingSwath = 1 if self.endingSwath == None: self.endingSwath = 5 if self._insar.modeCombination == 22: if self.startingSwath == None: self.startingSwath = 1 if self.endingSwath == None: self.endingSwath = 7 #determine starting and ending swaths for ScanSAR-stripmap, user's settings are overwritten #use first frame to check overlap if (self._insar.modeCombination == 31) or (self._insar.modeCombination == 32): if self._insar.modeCombination == 31: numberOfSwaths = 5 else: numberOfSwaths = 7 overlapSubswaths = [] for i in range(numberOfSwaths): overlapRatio = check_overlap(ledFilesMaster[0], firstFrameImagesMaster[i], ledFilesSlave[0], firstFrameImagesSlave[0]) if overlapRatio > 1.0 / 4.0: overlapSubswaths.append(i+1) if overlapSubswaths == []: raise Exception('There is no overlap area between the ScanSAR-stripmap pair') self.startingSwath = int(overlapSubswaths[0]) self.endingSwath = int(overlapSubswaths[-1]) #save the valid frames and swaths for future processing self._insar.masterFrames = self.masterFrames self._insar.slaveFrames = self.slaveFrames self._insar.startingSwath = self.startingSwath self._insar.endingSwath = self.endingSwath ################################################## #1. create directories and read data ################################################## self.master.configure() self.slave.configure() self.master.track.configure() self.slave.track.configure() for i, (masterFrame, slaveFrame) in enumerate(zip(self._insar.masterFrames, self._insar.slaveFrames)): #frame number starts with 1 frameDir = 'f{}_{}'.format(i+1, masterFrame) if not os.path.exists(frameDir): os.makedirs(frameDir) os.chdir(frameDir) #attach a frame to master and slave frameObjMaster = MultiMode.createFrame() frameObjSlave = MultiMode.createFrame() frameObjMaster.configure() frameObjSlave.configure() self.master.track.frames.append(frameObjMaster) self.slave.track.frames.append(frameObjSlave) #swath number starts with 1 for j in range(self._insar.startingSwath, self._insar.endingSwath+1): print('processing frame {} swath {}'.format(masterFrame, j)) swathDir = 's{}'.format(j) if not os.path.exists(swathDir): os.makedirs(swathDir) os.chdir(swathDir) #attach a swath to master and slave swathObjMaster = MultiMode.createSwath() swathObjSlave = MultiMode.createSwath() swathObjMaster.configure() swathObjSlave.configure() self.master.track.frames[-1].swaths.append(swathObjMaster) self.slave.track.frames[-1].swaths.append(swathObjSlave) #setup master self.master.leaderFile = sorted(glob.glob(os.path.join(self.masterDir, 'LED-ALOS2*{}-*-*'.format(masterFrame))))[0] if masterMode in scansarModes: self.master.imageFile = sorted(glob.glob(os.path.join(self.masterDir, 'IMG-{}-ALOS2*{}-*-*-F{}'.format(self.masterPolarization.upper(), masterFrame, j))))[0] else: self.master.imageFile = sorted(glob.glob(os.path.join(self.masterDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.masterPolarization.upper(), masterFrame))))[0] self.master.outputFile = self._insar.masterSlc self.master.useVirtualFile = self.useVirtualFile #read master (imageFDR, imageData)=self.master.readImage() (leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord)=self.master.readLeader() self.master.setSwath(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.master.setFrame(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.master.setTrack(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) #setup slave self.slave.leaderFile = sorted(glob.glob(os.path.join(self.slaveDir, 'LED-ALOS2*{}-*-*'.format(slaveFrame))))[0] if slaveMode in scansarModes: self.slave.imageFile = sorted(glob.glob(os.path.join(self.slaveDir, 'IMG-{}-ALOS2*{}-*-*-F{}'.format(self.slavePolarization.upper(), slaveFrame, j))))[0] else: self.slave.imageFile = sorted(glob.glob(os.path.join(self.slaveDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.slavePolarization.upper(), slaveFrame))))[0] self.slave.outputFile = self._insar.slaveSlc self.slave.useVirtualFile = self.useVirtualFile #read slave (imageFDR, imageData)=self.slave.readImage() (leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord)=self.slave.readLeader() self.slave.setSwath(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.slave.setFrame(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.slave.setTrack(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) os.chdir('../') self._insar.saveProduct(self.master.track.frames[-1], self._insar.masterFrameParameter) self._insar.saveProduct(self.slave.track.frames[-1], self._insar.slaveFrameParameter) os.chdir('../') self._insar.saveProduct(self.master.track, self._insar.masterTrackParameter) self._insar.saveProduct(self.slave.track, self._insar.slaveTrackParameter) ################################################## #2. compute burst synchronization ################################################## #burst synchronization may slowly change along a track as a result of the changing relative speed of the two flights #in one frame, real unsynchronized time is the same for all swaths unsynTime = 0 #real synchronized time/percentage depends on the swath burst length (synTime = burstlength - abs(unsynTime)) #synTime = 0 synPercentage = 0 numberOfFrames = len(self._insar.masterFrames) numberOfSwaths = self._insar.endingSwath - self._insar.startingSwath + 1 for i, frameNumber in enumerate(self._insar.masterFrames): for j, swathNumber in enumerate(range(self._insar.startingSwath, self._insar.endingSwath + 1)): masterSwath = self.master.track.frames[i].swaths[j] slaveSwath = self.slave.track.frames[i].swaths[j] #using Piyush's code for computing range and azimuth offsets midRange = masterSwath.startingRange + masterSwath.rangePixelSize * masterSwath.numberOfSamples * 0.5 midSensingStart = masterSwath.sensingStart + datetime.timedelta(seconds = masterSwath.numberOfLines * 0.5 / masterSwath.prf) llh = self.master.track.orbit.rdr2geo(midSensingStart, midRange) slvaz, slvrng = self.slave.track.orbit.geo2rdr(llh) ###Translate to offsets #note that slave range pixel size and prf might be different from master, here we assume there is a virtual slave with same #range pixel size and prf rgoff = ((slvrng - slaveSwath.startingRange) / masterSwath.rangePixelSize) - masterSwath.numberOfSamples * 0.5 azoff = ((slvaz - slaveSwath.sensingStart).total_seconds() * masterSwath.prf) - masterSwath.numberOfLines * 0.5 #compute burst synchronization #burst parameters for ScanSAR wide mode not estimed yet if self._insar.modeCombination == 21: scburstStartLine = (masterSwath.burstStartTime - masterSwath.sensingStart).total_seconds() * masterSwath.prf + azoff #slave burst start times corresponding to master burst start times (100% synchronization) scburstStartLines = np.arange(scburstStartLine - 100000*masterSwath.burstCycleLength, \ scburstStartLine + 100000*masterSwath.burstCycleLength, \ masterSwath.burstCycleLength) dscburstStartLines = -((slaveSwath.burstStartTime - slaveSwath.sensingStart).total_seconds() * slaveSwath.prf - scburstStartLines) #find the difference with minimum absolute value unsynLines = dscburstStartLines[np.argmin(np.absolute(dscburstStartLines))] if np.absolute(unsynLines) >= slaveSwath.burstLength: synLines = 0 if unsynLines > 0: unsynLines = slaveSwath.burstLength else: unsynLines = -slaveSwath.burstLength else: synLines = slaveSwath.burstLength - np.absolute(unsynLines) unsynTime += unsynLines / masterSwath.prf synPercentage += synLines / masterSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(synLines / masterSwath.burstLength * 100.0), 'runPreprocessor') ############################################################################################ #illustration of the sign of the number of unsynchronized lines (unsynLines) #The convention is the same as ampcor offset, that is, # slaveLineNumber = masterLineNumber + unsynLines # # |-----------------------| ------------ # | | ^ # | | | # | | | unsynLines < 0 # | | | # | | \ / # | | |-----------------------| # | | | | # | | | | # |-----------------------| | | # Master Burst | | # | | # | | # | | # | | # |-----------------------| # Slave Burst # # ############################################################################################ ##burst parameters for ScanSAR wide mode not estimed yet elif self._insar.modeCombination == 31: #scansar is master scburstStartLine = (masterSwath.burstStartTime - masterSwath.sensingStart).total_seconds() * masterSwath.prf + azoff #slave burst start times corresponding to master burst start times (100% synchronization) for k in range(-100000, 100000): saz_burstx = scburstStartLine + masterSwath.burstCycleLength * k st_burstx = slaveSwath.sensingStart + datetime.timedelta(seconds=saz_burstx / masterSwath.prf) if saz_burstx >= 0.0 and saz_burstx <= slaveSwath.numberOfLines -1: slaveSwath.burstStartTime = st_burstx slaveSwath.burstLength = masterSwath.burstLength slaveSwath.burstCycleLength = masterSwath.burstCycleLength slaveSwath.swathNumber = masterSwath.swathNumber break #unsynLines = 0 #synLines = masterSwath.burstLength #unsynTime += unsynLines / masterSwath.prf #synPercentage += synLines / masterSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(100.0), 'runPreprocessor') else: pass #overwrite original frame parameter file if self._insar.modeCombination == 31: frameDir = 'f{}_{}'.format(i+1, frameNumber) self._insar.saveProduct(self.slave.track.frames[i], os.path.join(frameDir, self._insar.slaveFrameParameter)) #getting average if self._insar.modeCombination == 21: unsynTime /= numberOfFrames*numberOfSwaths synPercentage /= numberOfFrames*numberOfSwaths elif self._insar.modeCombination == 31: unsynTime = 0. synPercentage = 100. else: pass #record results if (self._insar.modeCombination == 21) or (self._insar.modeCombination == 31): self._insar.burstUnsynchronizedTime = unsynTime self._insar.burstSynchronization = synPercentage catalog.addItem('burst synchronization averaged', '%.1f%%'%(synPercentage), 'runPreprocessor') ################################################## #3. compute baseline ################################################## #only compute baseline at four corners and center of the master track bboxRdr = getBboxRdr(self.master.track) rangeMin = bboxRdr[0] rangeMax = bboxRdr[1] azimuthTimeMin = bboxRdr[2] azimuthTimeMax = bboxRdr[3] azimuthTimeMid = azimuthTimeMin+datetime.timedelta(seconds=(azimuthTimeMax-azimuthTimeMin).total_seconds()/2.0) rangeMid = (rangeMin + rangeMax) / 2.0 points = [[azimuthTimeMin, rangeMin], [azimuthTimeMin, rangeMax], [azimuthTimeMax, rangeMin], [azimuthTimeMax, rangeMax], [azimuthTimeMid, rangeMid]] Bpar = [] Bperp = [] #modify Piyush's code for computing baslines refElp = Planet(pname='Earth').ellipsoid for x in points: masterSV = self.master.track.orbit.interpolate(x[0], method='hermite') target = self.master.track.orbit.rdr2geo(x[0], x[1]) slvTime, slvrng = self.slave.track.orbit.geo2rdr(target) slaveSV = self.slave.track.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array(refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(masterSV.getPosition()) mvel = np.array(masterSV.getVelocity()) sxyz = np.array(slaveSV.getPosition()) aa = np.linalg.norm(sxyz-mxyz) costheta = (x[1]*x[1] + aa*aa - slvrng*slvrng)/(2.*x[1]*aa) Bpar.append(aa*costheta) perp = aa * np.sqrt(1 - costheta*costheta) direction = np.sign(np.dot( np.cross(targxyz-mxyz, sxyz-mxyz), mvel)) Bperp.append(direction*perp) catalog.addItem('parallel baseline at upperleft of master track', Bpar[0], 'runPreprocessor') catalog.addItem('parallel baseline at upperright of master track', Bpar[1], 'runPreprocessor') catalog.addItem('parallel baseline at lowerleft of master track', Bpar[2], 'runPreprocessor') catalog.addItem('parallel baseline at lowerright of master track', Bpar[3], 'runPreprocessor') catalog.addItem('parallel baseline at center of master track', Bpar[4], 'runPreprocessor') catalog.addItem('perpendicular baseline at upperleft of master track', Bperp[0], 'runPreprocessor') catalog.addItem('perpendicular baseline at upperright of master track', Bperp[1], 'runPreprocessor') catalog.addItem('perpendicular baseline at lowerleft of master track', Bperp[2], 'runPreprocessor') catalog.addItem('perpendicular baseline at lowerright of master track', Bperp[3], 'runPreprocessor') catalog.addItem('perpendicular baseline at center of master track', Bperp[4], 'runPreprocessor') ################################################## #4. compute bounding box ################################################## masterBbox = getBboxGeo(self.master.track) slaveBbox = getBboxGeo(self.slave.track) catalog.addItem('master bounding box', masterBbox, 'runPreprocessor') catalog.addItem('slave bounding box', slaveBbox, 'runPreprocessor') catalog.printToLog(logger, "runPreprocessor") self._insar.procDoc.addAllFromCatalog(catalog)
def main(iargs=None): '''Compute baseline. ''' inps = cmdLineParse(iargs) from isceobj.Planet.Planet import Planet import numpy as np referenceSwathList = ut.getSwathList(inps.reference) secondarySwathList = ut.getSwathList(inps.secondary) swathList = list(sorted(set(referenceSwathList + secondarySwathList))) #catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) baselineDir = os.path.dirname(inps.baselineFile) if baselineDir != '': os.makedirs(baselineDir, exist_ok=True) referenceswaths = [] secondaryswaths = [] for swath in swathList: referencexml = os.path.join(inps.reference, 'IW{0}.xml'.format(swath)) secondaryxml = os.path.join(inps.secondary, 'IW{0}.xml'.format(swath)) if os.path.exists(referencexml) and os.path.exists(secondaryxml): reference = ut.loadProduct( os.path.join(inps.reference, 'IW{0}.xml'.format(swath))) secondary = ut.loadProduct( os.path.join(inps.secondary, 'IW{0}.xml'.format(swath))) referenceswaths.append(reference) secondaryswaths.append(secondary) refElp = Planet(pname='Earth').ellipsoid mStartingRange = min([x.startingRange for x in referenceswaths]) mFarRange = max([x.farRange for x in referenceswaths]) mSensingStart = min([x.sensingStart for x in referenceswaths]) mSensingStop = max([x.sensingStop for x in referenceswaths]) mOrb = getMergedOrbit(referenceswaths) dr = referenceswaths[0].bursts[0].rangePixelSize dt = referenceswaths[0].bursts[0].azimuthTimeInterval nPixels = int(np.round((mFarRange - mStartingRange) / dr)) + 1 nLines = int(np.round( (mSensingStop - mSensingStart).total_seconds() / dt)) + 1 sOrb = getMergedOrbit(secondaryswaths) rangeLimits = mFarRange - mStartingRange nRange = int(np.ceil(rangeLimits / 7000.)) slantRange = mStartingRange + np.arange(nRange) * rangeLimits / (nRange - 1.0) azimuthLimits = (mSensingStop - mSensingStart).total_seconds() nAzimuth = int(np.ceil(azimuthLimits)) azimuthTime = [ mSensingStart + datetime.timedelta(seconds=x * azimuthLimits / (nAzimuth - 1.0)) for x in range(nAzimuth) ] Bpar = np.zeros(nRange, dtype=np.float32) Bperp = np.zeros(nRange, dtype=np.float32) fid = open(inps.baselineFile, 'wb') print('Baseline file {0} dims: {1}L x {2}P'.format(inps.baselineFile, nAzimuth, nRange)) if inps.reference == inps.secondary: Bperp = np.zeros((nAzimuth, nRange), dtype=np.float32) Bperp.tofile(fid) else: for ii, taz in enumerate(azimuthTime): referenceSV = mOrb.interpolate(taz, method='hermite') mxyz = np.array(referenceSV.getPosition()) mvel = np.array(referenceSV.getVelocity()) for jj, rng in enumerate(slantRange): target = mOrb.rdr2geo(taz, rng) targxyz = np.array( refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) slvTime, slvrng = sOrb.geo2rdr(target) secondarySV = sOrb.interpolateOrbit(slvTime, method='hermite') sxyz = np.array(secondarySV.getPosition()) aa = np.linalg.norm(sxyz - mxyz) costheta = (rng * rng + aa * aa - slvrng * slvrng) / (2. * rng * aa) Bpar[jj] = aa * costheta perp = aa * np.sqrt(1 - costheta * costheta) direction = np.sign( np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel)) Bperp[jj] = direction * perp Bperp.tofile(fid) fid.close() ####Write XML img = isceobj.createImage() img.setFilename(inps.baselineFile) img.bands = 1 img.scheme = 'BIP' img.dataType = 'FLOAT' img.setWidth(nRange) img.setAccessMode('READ') img.setLength(nAzimuth) img.renderHdr() img.renderVRT() ###Create oversampled VRT file cmd = 'gdal_translate -of VRT -ot Float32 -r bilinear -outsize {xsize} {ysize} {infile}.vrt {infile}.full.vrt'.format( xsize=nPixels, ysize=nLines, infile=inps.baselineFile) status = os.system(cmd) if status: raise Exception('cmd: {0} Failed'.format(cmd))
def main(iargs=None): '''Compute baseline. ''' inps = cmdLineParse(iargs) from isceobj.Planet.Planet import Planet import numpy as np import shelve baselineDir = os.path.dirname(inps.baselineFile) if baselineDir != '': os.makedirs(baselineDir, exist_ok=True) with shelve.open(os.path.join(inps.reference, 'data'), flag='r') as mdb: reference = mdb['frame'] with shelve.open(os.path.join(inps.secondary, 'data'), flag='r') as mdb: secondary = mdb['frame'] # check if the reference and secondary shelf are the same, i.e. it is baseline grid for the reference reference_SensingStart = reference.getSensingStart() secondary_SensingStart = secondary.getSensingStart() if reference_SensingStart == secondary_SensingStart: referenceBaseline = True else: referenceBaseline = False refElp = Planet(pname='Earth').ellipsoid dr = reference.instrument.rangePixelSize dt = 1. / reference.PRF #reference.azimuthTimeInterval mStartingRange = reference.startingRange #min([x.startingRange for x in referenceswaths]) mFarRange = reference.startingRange + dr * ( reference.numberOfSamples - 1 ) #max([x.farRange for x in referenceswaths]) mSensingStart = reference.sensingStart # min([x.sensingStart for x in referenceswaths]) mSensingStop = reference.sensingStop #max([x.sensingStop for x in referenceswaths]) mOrb = getMergedOrbit(reference) nPixels = int(np.round((mFarRange - mStartingRange) / dr)) + 1 nLines = int(np.round( (mSensingStop - mSensingStart).total_seconds() / dt)) + 1 sOrb = getMergedOrbit(secondary) rangeLimits = mFarRange - mStartingRange # To make sure that we have at least 30 points nRange = int(np.max([30, int(np.ceil(rangeLimits / 7000.))])) slantRange = mStartingRange + np.arange(nRange) * rangeLimits / (nRange - 1.0) azimuthLimits = (mSensingStop - mSensingStart).total_seconds() nAzimuth = int(np.max([30, int(np.ceil(azimuthLimits))])) azimuthTime = [ mSensingStart + datetime.timedelta(seconds=x * azimuthLimits / (nAzimuth - 1.0)) for x in range(nAzimuth) ] Bperp = np.zeros((nAzimuth, nRange), dtype=np.float32) Bpar = np.zeros((nAzimuth, nRange), dtype=np.float32) fid = open(inps.baselineFile, 'wb') print('Baseline file {0} dims: {1}L x {2}P'.format(inps.baselineFile, nAzimuth, nRange)) if referenceBaseline: Bperp = np.zeros((nAzimuth, nRange), dtype=np.float32) Bperp.tofile(fid) else: for ii, taz in enumerate(azimuthTime): referenceSV = mOrb.interpolate(taz, method='hermite') mxyz = np.array(referenceSV.getPosition()) mvel = np.array(referenceSV.getVelocity()) for jj, rng in enumerate(slantRange): target = mOrb.rdr2geo(taz, rng) targxyz = np.array( refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) slvTime, slvrng = sOrb.geo2rdr(target) secondarySV = sOrb.interpolateOrbit(slvTime, method='hermite') sxyz = np.array(secondarySV.getPosition()) aa = np.linalg.norm(sxyz - mxyz) costheta = (rng * rng + aa * aa - slvrng * slvrng) / (2. * rng * aa) Bpar[ii, jj] = aa * costheta perp = aa * np.sqrt(1 - costheta * costheta) direction = np.sign( np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel)) Bperp[ii, jj] = direction * perp Bperp.tofile(fid) fid.close() ####Write XML img = isceobj.createImage() img.setFilename(inps.baselineFile) img.bands = 1 img.scheme = 'BIP' img.dataType = 'FLOAT' img.setWidth(nRange) img.setAccessMode('READ') img.setLength(nAzimuth) img.renderHdr() img.renderVRT() ###Create oversampled VRT file cmd = 'gdal_translate -of VRT -ot Float32 -r bilinear -outsize {xsize} {ysize} {infile}.vrt {infile}.full.vrt'.format( xsize=nPixels, ysize=nLines, infile=inps.baselineFile) status = os.system(cmd) if status: raise Exception('cmd: {0} Failed'.format(cmd))
def runBaseline(self): '''compute baseline ''' catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) self.updateParamemetersFromUser() referenceTrack = self._insar.loadTrack(reference=True) secondaryTrack = self._insar.loadTrack(reference=False) ################################################## #2. compute burst synchronization ################################################## #burst synchronization may slowly change along a track as a result of the changing relative speed of the two flights #in one frame, real unsynchronized time is the same for all swaths unsynTime = 0 #real synchronized time/percentage depends on the swath burst length (synTime = burstlength - abs(unsynTime)) #synTime = 0 synPercentage = 0 numberOfFrames = len(self._insar.referenceFrames) numberOfSwaths = self._insar.endingSwath - self._insar.startingSwath + 1 for i, frameNumber in enumerate(self._insar.referenceFrames): for j, swathNumber in enumerate(range(self._insar.startingSwath, self._insar.endingSwath + 1)): referenceSwath = referenceTrack.frames[i].swaths[j] secondarySwath = secondaryTrack.frames[i].swaths[j] #using Piyush's code for computing range and azimuth offsets midRange = referenceSwath.startingRange + referenceSwath.rangePixelSize * referenceSwath.numberOfSamples * 0.5 midSensingStart = referenceSwath.sensingStart + datetime.timedelta(seconds = referenceSwath.numberOfLines * 0.5 / referenceSwath.prf) llh = referenceTrack.orbit.rdr2geo(midSensingStart, midRange) slvaz, slvrng = secondaryTrack.orbit.geo2rdr(llh) ###Translate to offsets #note that secondary range pixel size and prf might be different from reference, here we assume there is a virtual secondary with same #range pixel size and prf rgoff = ((slvrng - secondarySwath.startingRange) / referenceSwath.rangePixelSize) - referenceSwath.numberOfSamples * 0.5 azoff = ((slvaz - secondarySwath.sensingStart).total_seconds() * referenceSwath.prf) - referenceSwath.numberOfLines * 0.5 #compute burst synchronization #burst parameters for ScanSAR wide mode not estimed yet if self._insar.modeCombination == 21: scburstStartLine = (referenceSwath.burstStartTime - referenceSwath.sensingStart).total_seconds() * referenceSwath.prf + azoff #secondary burst start times corresponding to reference burst start times (100% synchronization) scburstStartLines = np.arange(scburstStartLine - 100000*referenceSwath.burstCycleLength, \ scburstStartLine + 100000*referenceSwath.burstCycleLength, \ referenceSwath.burstCycleLength) dscburstStartLines = -((secondarySwath.burstStartTime - secondarySwath.sensingStart).total_seconds() * secondarySwath.prf - scburstStartLines) #find the difference with minimum absolute value unsynLines = dscburstStartLines[np.argmin(np.absolute(dscburstStartLines))] if np.absolute(unsynLines) >= secondarySwath.burstLength: synLines = 0 if unsynLines > 0: unsynLines = secondarySwath.burstLength else: unsynLines = -secondarySwath.burstLength else: synLines = secondarySwath.burstLength - np.absolute(unsynLines) unsynTime += unsynLines / referenceSwath.prf synPercentage += synLines / referenceSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(synLines / referenceSwath.burstLength * 100.0), 'runBaseline') ############################################################################################ #illustration of the sign of the number of unsynchronized lines (unsynLines) #The convention is the same as ampcor offset, that is, # secondaryLineNumber = referenceLineNumber + unsynLines # # |-----------------------| ------------ # | | ^ # | | | # | | | unsynLines < 0 # | | | # | | \ / # | | |-----------------------| # | | | | # | | | | # |-----------------------| | | # Reference Burst | | # | | # | | # | | # | | # |-----------------------| # Secondary Burst # # ############################################################################################ ##burst parameters for ScanSAR wide mode not estimed yet elif self._insar.modeCombination == 31: #scansar is reference scburstStartLine = (referenceSwath.burstStartTime - referenceSwath.sensingStart).total_seconds() * referenceSwath.prf + azoff #secondary burst start times corresponding to reference burst start times (100% synchronization) for k in range(-100000, 100000): saz_burstx = scburstStartLine + referenceSwath.burstCycleLength * k st_burstx = secondarySwath.sensingStart + datetime.timedelta(seconds=saz_burstx / referenceSwath.prf) if saz_burstx >= 0.0 and saz_burstx <= secondarySwath.numberOfLines -1: secondarySwath.burstStartTime = st_burstx secondarySwath.burstLength = referenceSwath.burstLength secondarySwath.burstCycleLength = referenceSwath.burstCycleLength secondarySwath.swathNumber = referenceSwath.swathNumber break #unsynLines = 0 #synLines = referenceSwath.burstLength #unsynTime += unsynLines / referenceSwath.prf #synPercentage += synLines / referenceSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(100.0), 'runBaseline') else: pass #overwrite original frame parameter file if self._insar.modeCombination == 31: frameDir = 'f{}_{}'.format(i+1, frameNumber) self._insar.saveProduct(secondaryTrack.frames[i], os.path.join(frameDir, self._insar.secondaryFrameParameter)) #getting average if self._insar.modeCombination == 21: unsynTime /= numberOfFrames*numberOfSwaths synPercentage /= numberOfFrames*numberOfSwaths elif self._insar.modeCombination == 31: unsynTime = 0. synPercentage = 100. else: pass #record results if (self._insar.modeCombination == 21) or (self._insar.modeCombination == 31): self._insar.burstUnsynchronizedTime = unsynTime self._insar.burstSynchronization = synPercentage catalog.addItem('burst synchronization averaged', '%.1f%%'%(synPercentage), 'runBaseline') ################################################## #3. compute baseline ################################################## #only compute baseline at four corners and center of the reference track bboxRdr = getBboxRdr(referenceTrack) rangeMin = bboxRdr[0] rangeMax = bboxRdr[1] azimuthTimeMin = bboxRdr[2] azimuthTimeMax = bboxRdr[3] azimuthTimeMid = azimuthTimeMin+datetime.timedelta(seconds=(azimuthTimeMax-azimuthTimeMin).total_seconds()/2.0) rangeMid = (rangeMin + rangeMax) / 2.0 points = [[azimuthTimeMin, rangeMin], [azimuthTimeMin, rangeMax], [azimuthTimeMax, rangeMin], [azimuthTimeMax, rangeMax], [azimuthTimeMid, rangeMid]] Bpar = [] Bperp = [] #modify Piyush's code for computing baslines refElp = Planet(pname='Earth').ellipsoid for x in points: referenceSV = referenceTrack.orbit.interpolate(x[0], method='hermite') target = referenceTrack.orbit.rdr2geo(x[0], x[1]) slvTime, slvrng = secondaryTrack.orbit.geo2rdr(target) secondarySV = secondaryTrack.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array(refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(referenceSV.getPosition()) mvel = np.array(referenceSV.getVelocity()) sxyz = np.array(secondarySV.getPosition()) #to fix abrupt change near zero in baseline grid. JUN-05-2020 mvelunit = mvel / np.linalg.norm(mvel) sxyz = sxyz - np.dot ( sxyz-mxyz, mvelunit) * mvelunit aa = np.linalg.norm(sxyz-mxyz) costheta = (x[1]*x[1] + aa*aa - slvrng*slvrng)/(2.*x[1]*aa) Bpar.append(aa*costheta) perp = aa * np.sqrt(1 - costheta*costheta) direction = np.sign(np.dot( np.cross(targxyz-mxyz, sxyz-mxyz), mvel)) Bperp.append(direction*perp) catalog.addItem('parallel baseline at upperleft of reference track', Bpar[0], 'runBaseline') catalog.addItem('parallel baseline at upperright of reference track', Bpar[1], 'runBaseline') catalog.addItem('parallel baseline at lowerleft of reference track', Bpar[2], 'runBaseline') catalog.addItem('parallel baseline at lowerright of reference track', Bpar[3], 'runBaseline') catalog.addItem('parallel baseline at center of reference track', Bpar[4], 'runBaseline') catalog.addItem('perpendicular baseline at upperleft of reference track', Bperp[0], 'runBaseline') catalog.addItem('perpendicular baseline at upperright of reference track', Bperp[1], 'runBaseline') catalog.addItem('perpendicular baseline at lowerleft of reference track', Bperp[2], 'runBaseline') catalog.addItem('perpendicular baseline at lowerright of reference track', Bperp[3], 'runBaseline') catalog.addItem('perpendicular baseline at center of reference track', Bperp[4], 'runBaseline') ################################################## #4. compute bounding box ################################################## referenceBbox = getBboxGeo(referenceTrack) secondaryBbox = getBboxGeo(secondaryTrack) catalog.addItem('reference bounding box', referenceBbox, 'runBaseline') catalog.addItem('secondary bounding box', secondaryBbox, 'runBaseline') catalog.printToLog(logger, "runBaseline") self._insar.procDoc.addAllFromCatalog(catalog)
def runPreprocessor(self): '''Extract images. ''' catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) #find files #actually no need to use absolute path any longer, since we are able to find file from vrt now. 27-JAN-2020, CRL. #denseoffset may still need absolute path when making links self.referenceDir = os.path.abspath(self.referenceDir) self.secondaryDir = os.path.abspath(self.secondaryDir) ledFilesReference = sorted(glob.glob(os.path.join(self.referenceDir, 'LED-ALOS2*-*-*'))) imgFilesReference = sorted(glob.glob(os.path.join(self.referenceDir, 'IMG-{}-ALOS2*-*-*'.format(self.referencePolarization.upper())))) ledFilesSecondary = sorted(glob.glob(os.path.join(self.secondaryDir, 'LED-ALOS2*-*-*'))) imgFilesSecondary = sorted(glob.glob(os.path.join(self.secondaryDir, 'IMG-{}-ALOS2*-*-*'.format(self.secondaryPolarization.upper())))) firstFrameReference = ledFilesReference[0].split('-')[-3][-4:] firstFrameSecondary = ledFilesSecondary[0].split('-')[-3][-4:] firstFrameImagesReference = sorted(glob.glob(os.path.join(self.referenceDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.referencePolarization.upper(), firstFrameReference)))) firstFrameImagesSecondary = sorted(glob.glob(os.path.join(self.secondaryDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.secondaryPolarization.upper(), firstFrameSecondary)))) #determin operation mode referenceMode = os.path.basename(ledFilesReference[0]).split('-')[-1][0:3] secondaryMode = os.path.basename(ledFilesSecondary[0]).split('-')[-1][0:3] spotlightModes = ['SBS'] stripmapModes = ['UBS', 'UBD', 'HBS', 'HBD', 'HBQ', 'FBS', 'FBD', 'FBQ'] scansarNominalModes = ['WBS', 'WBD', 'WWS', 'WWD'] scansarWideModes = ['VBS', 'VBD'] scansarModes = ['WBS', 'WBD', 'WWS', 'WWD', 'VBS', 'VBD'] #usable combinations if (referenceMode in spotlightModes) and (secondaryMode in spotlightModes): self._insar.modeCombination = 0 elif (referenceMode in stripmapModes) and (secondaryMode in stripmapModes): self._insar.modeCombination = 1 elif (referenceMode in scansarNominalModes) and (secondaryMode in scansarNominalModes): self._insar.modeCombination = 21 elif (referenceMode in scansarWideModes) and (secondaryMode in scansarWideModes): self._insar.modeCombination = 22 elif (referenceMode in scansarNominalModes) and (secondaryMode in stripmapModes): self._insar.modeCombination = 31 elif (referenceMode in scansarWideModes) and (secondaryMode in stripmapModes): self._insar.modeCombination = 32 else: print('\n\nthis mode combination is not possible') print('note that for ScanSAR-stripmap, ScanSAR must be reference\n\n') raise Exception('mode combination not supported') # pixel size from real data processing. azimuth pixel size may change a bit as # the antenna points to a different swath and therefore uses a different PRF. # MODE RANGE PIXEL SIZE (LOOKS) AZIMUTH PIXEL SIZE (LOOKS) # ------------------------------------------------------------------- # SPT [SBS] # 1.4304222392897463 (2) 0.9351804642158579 (4) # SM1 [UBS,UBD] # 1.4304222392897463 (2) 1.8291988125114438 (2) # SM2 [HBS,HBD,HBQ] # 2.8608444785794984 (2) 3.0672373839847196 (2) # SM3 [FBS,FBD,FBQ] # 4.291266717869248 (2) 3.2462615913656667 (4) # WD1 [WBS,WBD] [WWS,WWD] # 8.582533435738496 (1) 2.6053935830031887 (14) # 8.582533435738496 (1) 2.092362043327227 (14) # 8.582533435738496 (1) 2.8817632034495717 (14) # 8.582533435738496 (1) 3.054362492601842 (14) # 8.582533435738496 (1) 2.4582084463356977 (14) # WD2 [VBS,VBD] # 8.582533435738496 (1) 2.9215796012950728 (14) # 8.582533435738496 (1) 3.088859074497863 (14) # 8.582533435738496 (1) 2.8792293071133073 (14) # 8.582533435738496 (1) 3.0592146044234854 (14) # 8.582533435738496 (1) 2.8818767752199137 (14) # 8.582533435738496 (1) 3.047038521027477 (14) # 8.582533435738496 (1) 2.898816222039108 (14) #determine default number of looks: self._insar.numberRangeLooks1 = self.numberRangeLooks1 self._insar.numberAzimuthLooks1 = self.numberAzimuthLooks1 self._insar.numberRangeLooks2 = self.numberRangeLooks2 self._insar.numberAzimuthLooks2 = self.numberAzimuthLooks2 #the following two will be automatically determined by runRdrDemOffset.py self._insar.numberRangeLooksSim = self.numberRangeLooksSim self._insar.numberAzimuthLooksSim = self.numberAzimuthLooksSim self._insar.numberRangeLooksIon = self.numberRangeLooksIon self._insar.numberAzimuthLooksIon = self.numberAzimuthLooksIon if self._insar.numberRangeLooks1 == None: if referenceMode in ['SBS']: self._insar.numberRangeLooks1 = 2 elif referenceMode in ['UBS', 'UBD']: self._insar.numberRangeLooks1 = 2 elif referenceMode in ['HBS', 'HBD', 'HBQ']: self._insar.numberRangeLooks1 = 2 elif referenceMode in ['FBS', 'FBD', 'FBQ']: self._insar.numberRangeLooks1 = 2 elif referenceMode in ['WBS', 'WBD']: self._insar.numberRangeLooks1 = 1 elif referenceMode in ['WWS', 'WWD']: self._insar.numberRangeLooks1 = 2 elif referenceMode in ['VBS', 'VBD']: self._insar.numberRangeLooks1 = 1 else: raise Exception('unknow acquisition mode') if self._insar.numberAzimuthLooks1 == None: if referenceMode in ['SBS']: self._insar.numberAzimuthLooks1 = 4 elif referenceMode in ['UBS', 'UBD']: self._insar.numberAzimuthLooks1 = 2 elif referenceMode in ['HBS', 'HBD', 'HBQ']: self._insar.numberAzimuthLooks1 = 2 elif referenceMode in ['FBS', 'FBD', 'FBQ']: self._insar.numberAzimuthLooks1 = 4 elif referenceMode in ['WBS', 'WBD']: self._insar.numberAzimuthLooks1 = 14 elif referenceMode in ['WWS', 'WWD']: self._insar.numberAzimuthLooks1 = 14 elif referenceMode in ['VBS', 'VBD']: self._insar.numberAzimuthLooks1 = 14 else: raise Exception('unknow acquisition mode') if self._insar.numberRangeLooks2 == None: if referenceMode in spotlightModes: self._insar.numberRangeLooks2 = 4 elif referenceMode in stripmapModes: self._insar.numberRangeLooks2 = 4 elif referenceMode in scansarModes: self._insar.numberRangeLooks2 = 5 else: raise Exception('unknow acquisition mode') if self._insar.numberAzimuthLooks2 == None: if referenceMode in spotlightModes: self._insar.numberAzimuthLooks2 = 4 elif referenceMode in stripmapModes: self._insar.numberAzimuthLooks2 = 4 elif referenceMode in scansarModes: self._insar.numberAzimuthLooks2 = 2 else: raise Exception('unknow acquisition mode') if self._insar.numberRangeLooksIon == None: if referenceMode in spotlightModes: self._insar.numberRangeLooksIon = 16 elif referenceMode in stripmapModes: self._insar.numberRangeLooksIon = 16 elif referenceMode in scansarModes: self._insar.numberRangeLooksIon = 40 else: raise Exception('unknow acquisition mode') if self._insar.numberAzimuthLooksIon == None: if referenceMode in spotlightModes: self._insar.numberAzimuthLooksIon = 16 elif referenceMode in stripmapModes: self._insar.numberAzimuthLooksIon = 16 elif referenceMode in scansarModes: self._insar.numberAzimuthLooksIon = 16 else: raise Exception('unknow acquisition mode') #define processing file names self._insar.referenceDate = os.path.basename(ledFilesReference[0]).split('-')[2] self._insar.secondaryDate = os.path.basename(ledFilesSecondary[0]).split('-')[2] self._insar.setFilename(referenceDate=self._insar.referenceDate, secondaryDate=self._insar.secondaryDate, nrlks1=self._insar.numberRangeLooks1, nalks1=self._insar.numberAzimuthLooks1, nrlks2=self._insar.numberRangeLooks2, nalks2=self._insar.numberAzimuthLooks2) #find frame numbers if (self._insar.modeCombination == 31) or (self._insar.modeCombination == 32): if (self.referenceFrames == None) or (self.secondaryFrames == None): raise Exception('for ScanSAR-stripmap inteferometry, you must set reference and secondary frame numbers') #if not set, find frames automatically if self.referenceFrames == None: self.referenceFrames = [] for led in ledFilesReference: frameNumber = os.path.basename(led).split('-')[1][-4:] if frameNumber not in self.referenceFrames: self.referenceFrames.append(frameNumber) if self.secondaryFrames == None: self.secondaryFrames = [] for led in ledFilesSecondary: frameNumber = os.path.basename(led).split('-')[1][-4:] if frameNumber not in self.secondaryFrames: self.secondaryFrames.append(frameNumber) #sort frames self.referenceFrames = sorted(self.referenceFrames) self.secondaryFrames = sorted(self.secondaryFrames) #check number of frames if len(self.referenceFrames) != len(self.secondaryFrames): raise Exception('number of frames in reference dir is not equal to number of frames \ in secondary dir. please set frame number manually') #find swath numbers (if not ScanSAR-ScanSAR, compute valid swaths) if (self._insar.modeCombination == 0) or (self._insar.modeCombination == 1): self.startingSwath = 1 self.endingSwath = 1 if self._insar.modeCombination == 21: if self.startingSwath == None: self.startingSwath = 1 if self.endingSwath == None: self.endingSwath = 5 if self._insar.modeCombination == 22: if self.startingSwath == None: self.startingSwath = 1 if self.endingSwath == None: self.endingSwath = 7 #determine starting and ending swaths for ScanSAR-stripmap, user's settings are overwritten #use first frame to check overlap if (self._insar.modeCombination == 31) or (self._insar.modeCombination == 32): if self._insar.modeCombination == 31: numberOfSwaths = 5 else: numberOfSwaths = 7 overlapSubswaths = [] for i in range(numberOfSwaths): overlapRatio = check_overlap(ledFilesReference[0], firstFrameImagesReference[i], ledFilesSecondary[0], firstFrameImagesSecondary[0]) if overlapRatio > 1.0 / 4.0: overlapSubswaths.append(i+1) if overlapSubswaths == []: raise Exception('There is no overlap area between the ScanSAR-stripmap pair') self.startingSwath = int(overlapSubswaths[0]) self.endingSwath = int(overlapSubswaths[-1]) #save the valid frames and swaths for future processing self._insar.referenceFrames = self.referenceFrames self._insar.secondaryFrames = self.secondaryFrames self._insar.startingSwath = self.startingSwath self._insar.endingSwath = self.endingSwath ################################################## #1. create directories and read data ################################################## self.reference.configure() self.secondary.configure() self.reference.track.configure() self.secondary.track.configure() for i, (referenceFrame, secondaryFrame) in enumerate(zip(self._insar.referenceFrames, self._insar.secondaryFrames)): #frame number starts with 1 frameDir = 'f{}_{}'.format(i+1, referenceFrame) os.makedirs(frameDir, exist_ok=True) os.chdir(frameDir) #attach a frame to reference and secondary frameObjReference = MultiMode.createFrame() frameObjSecondary = MultiMode.createFrame() frameObjReference.configure() frameObjSecondary.configure() self.reference.track.frames.append(frameObjReference) self.secondary.track.frames.append(frameObjSecondary) #swath number starts with 1 for j in range(self._insar.startingSwath, self._insar.endingSwath+1): print('processing frame {} swath {}'.format(referenceFrame, j)) swathDir = 's{}'.format(j) os.makedirs(swathDir, exist_ok=True) os.chdir(swathDir) #attach a swath to reference and secondary swathObjReference = MultiMode.createSwath() swathObjSecondary = MultiMode.createSwath() swathObjReference.configure() swathObjSecondary.configure() self.reference.track.frames[-1].swaths.append(swathObjReference) self.secondary.track.frames[-1].swaths.append(swathObjSecondary) #setup reference self.reference.leaderFile = sorted(glob.glob(os.path.join(self.referenceDir, 'LED-ALOS2*{}-*-*'.format(referenceFrame))))[0] if referenceMode in scansarModes: self.reference.imageFile = sorted(glob.glob(os.path.join(self.referenceDir, 'IMG-{}-ALOS2*{}-*-*-F{}'.format(self.referencePolarization.upper(), referenceFrame, j))))[0] else: self.reference.imageFile = sorted(glob.glob(os.path.join(self.referenceDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.referencePolarization.upper(), referenceFrame))))[0] self.reference.outputFile = self._insar.referenceSlc self.reference.useVirtualFile = self.useVirtualFile #read reference (imageFDR, imageData)=self.reference.readImage() (leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord)=self.reference.readLeader() self.reference.setSwath(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.reference.setFrame(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.reference.setTrack(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) #setup secondary self.secondary.leaderFile = sorted(glob.glob(os.path.join(self.secondaryDir, 'LED-ALOS2*{}-*-*'.format(secondaryFrame))))[0] if secondaryMode in scansarModes: self.secondary.imageFile = sorted(glob.glob(os.path.join(self.secondaryDir, 'IMG-{}-ALOS2*{}-*-*-F{}'.format(self.secondaryPolarization.upper(), secondaryFrame, j))))[0] else: self.secondary.imageFile = sorted(glob.glob(os.path.join(self.secondaryDir, 'IMG-{}-ALOS2*{}-*-*'.format(self.secondaryPolarization.upper(), secondaryFrame))))[0] self.secondary.outputFile = self._insar.secondarySlc self.secondary.useVirtualFile = self.useVirtualFile #read secondary (imageFDR, imageData)=self.secondary.readImage() (leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord)=self.secondary.readLeader() self.secondary.setSwath(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.secondary.setFrame(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) self.secondary.setTrack(leaderFDR, sceneHeaderRecord, platformPositionRecord, facilityRecord, imageFDR, imageData) os.chdir('../') self._insar.saveProduct(self.reference.track.frames[-1], self._insar.referenceFrameParameter) self._insar.saveProduct(self.secondary.track.frames[-1], self._insar.secondaryFrameParameter) os.chdir('../') self._insar.saveProduct(self.reference.track, self._insar.referenceTrackParameter) self._insar.saveProduct(self.secondary.track, self._insar.secondaryTrackParameter) ################################################## #2. compute burst synchronization ################################################## #burst synchronization may slowly change along a track as a result of the changing relative speed of the two flights #in one frame, real unsynchronized time is the same for all swaths unsynTime = 0 #real synchronized time/percentage depends on the swath burst length (synTime = burstlength - abs(unsynTime)) #synTime = 0 synPercentage = 0 numberOfFrames = len(self._insar.referenceFrames) numberOfSwaths = self._insar.endingSwath - self._insar.startingSwath + 1 for i, frameNumber in enumerate(self._insar.referenceFrames): for j, swathNumber in enumerate(range(self._insar.startingSwath, self._insar.endingSwath + 1)): referenceSwath = self.reference.track.frames[i].swaths[j] secondarySwath = self.secondary.track.frames[i].swaths[j] #using Piyush's code for computing range and azimuth offsets midRange = referenceSwath.startingRange + referenceSwath.rangePixelSize * referenceSwath.numberOfSamples * 0.5 midSensingStart = referenceSwath.sensingStart + datetime.timedelta(seconds = referenceSwath.numberOfLines * 0.5 / referenceSwath.prf) llh = self.reference.track.orbit.rdr2geo(midSensingStart, midRange) slvaz, slvrng = self.secondary.track.orbit.geo2rdr(llh) ###Translate to offsets #note that secondary range pixel size and prf might be different from reference, here we assume there is a virtual secondary with same #range pixel size and prf rgoff = ((slvrng - secondarySwath.startingRange) / referenceSwath.rangePixelSize) - referenceSwath.numberOfSamples * 0.5 azoff = ((slvaz - secondarySwath.sensingStart).total_seconds() * referenceSwath.prf) - referenceSwath.numberOfLines * 0.5 #compute burst synchronization #burst parameters for ScanSAR wide mode not estimed yet if self._insar.modeCombination == 21: scburstStartLine = (referenceSwath.burstStartTime - referenceSwath.sensingStart).total_seconds() * referenceSwath.prf + azoff #secondary burst start times corresponding to reference burst start times (100% synchronization) scburstStartLines = np.arange(scburstStartLine - 100000*referenceSwath.burstCycleLength, \ scburstStartLine + 100000*referenceSwath.burstCycleLength, \ referenceSwath.burstCycleLength) dscburstStartLines = -((secondarySwath.burstStartTime - secondarySwath.sensingStart).total_seconds() * secondarySwath.prf - scburstStartLines) #find the difference with minimum absolute value unsynLines = dscburstStartLines[np.argmin(np.absolute(dscburstStartLines))] if np.absolute(unsynLines) >= secondarySwath.burstLength: synLines = 0 if unsynLines > 0: unsynLines = secondarySwath.burstLength else: unsynLines = -secondarySwath.burstLength else: synLines = secondarySwath.burstLength - np.absolute(unsynLines) unsynTime += unsynLines / referenceSwath.prf synPercentage += synLines / referenceSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(synLines / referenceSwath.burstLength * 100.0), 'runPreprocessor') ############################################################################################ #illustration of the sign of the number of unsynchronized lines (unsynLines) #The convention is the same as ampcor offset, that is, # secondaryLineNumber = referenceLineNumber + unsynLines # # |-----------------------| ------------ # | | ^ # | | | # | | | unsynLines < 0 # | | | # | | \ / # | | |-----------------------| # | | | | # | | | | # |-----------------------| | | # Reference Burst | | # | | # | | # | | # | | # |-----------------------| # Secondary Burst # # ############################################################################################ ##burst parameters for ScanSAR wide mode not estimed yet elif self._insar.modeCombination == 31: #scansar is reference scburstStartLine = (referenceSwath.burstStartTime - referenceSwath.sensingStart).total_seconds() * referenceSwath.prf + azoff #secondary burst start times corresponding to reference burst start times (100% synchronization) for k in range(-100000, 100000): saz_burstx = scburstStartLine + referenceSwath.burstCycleLength * k st_burstx = secondarySwath.sensingStart + datetime.timedelta(seconds=saz_burstx / referenceSwath.prf) if saz_burstx >= 0.0 and saz_burstx <= secondarySwath.numberOfLines -1: secondarySwath.burstStartTime = st_burstx secondarySwath.burstLength = referenceSwath.burstLength secondarySwath.burstCycleLength = referenceSwath.burstCycleLength secondarySwath.swathNumber = referenceSwath.swathNumber break #unsynLines = 0 #synLines = referenceSwath.burstLength #unsynTime += unsynLines / referenceSwath.prf #synPercentage += synLines / referenceSwath.burstLength * 100.0 catalog.addItem('burst synchronization of frame {} swath {}'.format(frameNumber, swathNumber), '%.1f%%'%(100.0), 'runPreprocessor') else: pass #overwrite original frame parameter file if self._insar.modeCombination == 31: frameDir = 'f{}_{}'.format(i+1, frameNumber) self._insar.saveProduct(self.secondary.track.frames[i], os.path.join(frameDir, self._insar.secondaryFrameParameter)) #getting average if self._insar.modeCombination == 21: unsynTime /= numberOfFrames*numberOfSwaths synPercentage /= numberOfFrames*numberOfSwaths elif self._insar.modeCombination == 31: unsynTime = 0. synPercentage = 100. else: pass #record results if (self._insar.modeCombination == 21) or (self._insar.modeCombination == 31): self._insar.burstUnsynchronizedTime = unsynTime self._insar.burstSynchronization = synPercentage catalog.addItem('burst synchronization averaged', '%.1f%%'%(synPercentage), 'runPreprocessor') ################################################## #3. compute baseline ################################################## #only compute baseline at four corners and center of the reference track bboxRdr = getBboxRdr(self.reference.track) rangeMin = bboxRdr[0] rangeMax = bboxRdr[1] azimuthTimeMin = bboxRdr[2] azimuthTimeMax = bboxRdr[3] azimuthTimeMid = azimuthTimeMin+datetime.timedelta(seconds=(azimuthTimeMax-azimuthTimeMin).total_seconds()/2.0) rangeMid = (rangeMin + rangeMax) / 2.0 points = [[azimuthTimeMin, rangeMin], [azimuthTimeMin, rangeMax], [azimuthTimeMax, rangeMin], [azimuthTimeMax, rangeMax], [azimuthTimeMid, rangeMid]] Bpar = [] Bperp = [] #modify Piyush's code for computing baslines refElp = Planet(pname='Earth').ellipsoid for x in points: referenceSV = self.reference.track.orbit.interpolate(x[0], method='hermite') target = self.reference.track.orbit.rdr2geo(x[0], x[1]) slvTime, slvrng = self.secondary.track.orbit.geo2rdr(target) secondarySV = self.secondary.track.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array(refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(referenceSV.getPosition()) mvel = np.array(referenceSV.getVelocity()) sxyz = np.array(secondarySV.getPosition()) #to fix abrupt change near zero in baseline grid. JUN-05-2020 mvelunit = mvel / np.linalg.norm(mvel) sxyz = sxyz - np.dot ( sxyz-mxyz, mvelunit) * mvelunit aa = np.linalg.norm(sxyz-mxyz) costheta = (x[1]*x[1] + aa*aa - slvrng*slvrng)/(2.*x[1]*aa) Bpar.append(aa*costheta) perp = aa * np.sqrt(1 - costheta*costheta) direction = np.sign(np.dot( np.cross(targxyz-mxyz, sxyz-mxyz), mvel)) Bperp.append(direction*perp) catalog.addItem('parallel baseline at upperleft of reference track', Bpar[0], 'runPreprocessor') catalog.addItem('parallel baseline at upperright of reference track', Bpar[1], 'runPreprocessor') catalog.addItem('parallel baseline at lowerleft of reference track', Bpar[2], 'runPreprocessor') catalog.addItem('parallel baseline at lowerright of reference track', Bpar[3], 'runPreprocessor') catalog.addItem('parallel baseline at center of reference track', Bpar[4], 'runPreprocessor') catalog.addItem('perpendicular baseline at upperleft of reference track', Bperp[0], 'runPreprocessor') catalog.addItem('perpendicular baseline at upperright of reference track', Bperp[1], 'runPreprocessor') catalog.addItem('perpendicular baseline at lowerleft of reference track', Bperp[2], 'runPreprocessor') catalog.addItem('perpendicular baseline at lowerright of reference track', Bperp[3], 'runPreprocessor') catalog.addItem('perpendicular baseline at center of reference track', Bperp[4], 'runPreprocessor') ################################################## #4. compute bounding box ################################################## referenceBbox = getBboxGeo(self.reference.track) secondaryBbox = getBboxGeo(self.secondary.track) catalog.addItem('reference bounding box', referenceBbox, 'runPreprocessor') catalog.addItem('secondary bounding box', secondaryBbox, 'runPreprocessor') catalog.printToLog(logger, "runPreprocessor") self._insar.procDoc.addAllFromCatalog(catalog)
def runComputeBaseline(self): from isceobj.Planet.Planet import Planet import numpy as np swathList = self._insar.getInputSwathList(self.swaths) commonBurstStartMasterIndex = [-1] * self._insar.numberOfSwaths commonBurstStartSlaveIndex = [-1] * self._insar.numberOfSwaths numberOfCommonBursts = [0] * self._insar.numberOfSwaths catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) for swath in swathList: masterxml = os.path.join(self._insar.masterSlcProduct, 'IW{0}.xml'.format(swath)) slavexml = os.path.join(self._insar.slaveSlcProduct, 'IW{0}.xml'.format(swath)) if os.path.exists(masterxml) and os.path.exists(slavexml): master = self._insar.loadProduct(masterxml) slave = self._insar.loadProduct(slavexml) burstOffset, minBurst, maxBurst = master.getCommonBurstLimits( slave) commonSlaveIndex = minBurst + burstOffset numberCommon = maxBurst - minBurst if numberCommon == 0: print('No common bursts found for swath {0}'.format(swath)) else: ###Bookkeeping commonBurstStartMasterIndex[swath - 1] = minBurst commonBurstStartSlaveIndex[swath - 1] = commonSlaveIndex numberOfCommonBursts[swath - 1] = numberCommon catalog.addItem( 'IW-{0} Number of bursts in master'.format(swath), master.numberOfBursts, 'baseline') catalog.addItem( 'IW-{0} First common burst in master'.format(swath), minBurst, 'baseline') catalog.addItem( 'IW-{0} Last common burst in master'.format(swath), maxBurst, 'baseline') catalog.addItem( 'IW-{0} Number of bursts in slave'.format(swath), slave.numberOfBursts, 'baseline') catalog.addItem( 'IW-{0} First common burst in slave'.format(swath), minBurst + burstOffset, 'baseline') catalog.addItem( 'IW-{0} Last common burst in slave'.format(swath), maxBurst + burstOffset, 'baseline') catalog.addItem('IW-{0} Number of common bursts'.format(swath), numberCommon, 'baseline') refElp = Planet(pname='Earth').ellipsoid Bpar = [] Bperp = [] for boff in [0, numberCommon - 1]: ###Baselines at top of common bursts mBurst = master.bursts[minBurst + boff] sBurst = slave.bursts[commonSlaveIndex + boff] ###Target at mid range tmid = mBurst.sensingMid rng = mBurst.midRange masterSV = mBurst.orbit.interpolate(tmid, method='hermite') target = mBurst.orbit.rdr2geo(tmid, rng) slvTime, slvrng = sBurst.orbit.geo2rdr(target) slaveSV = sBurst.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array( refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(masterSV.getPosition()) mvel = np.array(masterSV.getVelocity()) sxyz = np.array(slaveSV.getPosition()) mvelunit = mvel / np.linalg.norm(mvel) sxyz = sxyz - np.dot(sxyz - mxyz, mvelunit) * mvelunit aa = np.linalg.norm(sxyz - mxyz) costheta = (rng * rng + aa * aa - slvrng * slvrng) / (2. * rng * aa) Bpar.append(aa * costheta) perp = aa * np.sqrt(1 - costheta * costheta) direction = np.sign( np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel)) Bperp.append(direction * perp) catalog.addItem( 'IW-{0} Bpar at midrange for first common burst'.format( swath), Bpar[0], 'baseline') catalog.addItem( 'IW-{0} Bperp at midrange for first common burst'.format( swath), Bperp[0], 'baseline') catalog.addItem( 'IW-{0} Bpar at midrange for last common burst'.format( swath), Bpar[1], 'baseline') catalog.addItem( 'IW-{0} Bperp at midrange for last common burst'.format( swath), Bperp[1], 'baseline') else: print('Skipping processing for swath number IW-{0}'.format(swath)) self._insar.commonBurstStartMasterIndex = commonBurstStartMasterIndex self._insar.commonBurstStartSlaveIndex = commonBurstStartSlaveIndex self._insar.numberOfCommonBursts = numberOfCommonBursts if not any([x >= 2 for x in self._insar.numberOfCommonBursts]): print( 'No swaths contain any burst overlaps ... cannot continue for interferometry applications' ) catalog.printToLog(logger, "runComputeBaseline") self._insar.procDoc.addAllFromCatalog(catalog)
def main(iargs=None): '''Compute baseline. ''' inps = cmdLineParse(iargs) from isceobj.Planet.Planet import Planet import numpy as np #swathList = self._insar.getInputSwathList(self.swaths) #commonBurstStartMasterIndex = [-1] * self._insar.numberOfSwaths #commonBurstStartSlaveIndex = [-1] * self._insar.numberOfSwaths #numberOfCommonBursts = [0] * self._insar.numberOfSwaths masterSwathList = ut.getSwathList(inps.master) slaveSwathList = ut.getSwathList(inps.slave) swathList = list(sorted(set(masterSwathList + slaveSwathList))) #catalog = isceobj.Catalog.createCatalog(self._insar.procDoc.name) baselineDir = os.path.dirname(inps.baselineFile) if not os.path.exists(baselineDir): os.makedirs(baselineDir) f = open(inps.baselineFile, 'w') for swath in swathList: masterxml = os.path.join(inps.master, 'IW{0}.xml'.format(swath)) slavexml = os.path.join(inps.slave, 'IW{0}.xml'.format(swath)) if os.path.exists(masterxml) and os.path.exists(slavexml): master = ut.loadProduct( os.path.join(inps.master, 'IW{0}.xml'.format(swath))) slave = ut.loadProduct( os.path.join(inps.slave, 'IW{0}.xml'.format(swath))) minMaster = master.bursts[0].burstNumber maxMaster = master.bursts[-1].burstNumber minSlave = slave.bursts[0].burstNumber maxSlave = slave.bursts[-1].burstNumber minBurst = max(minSlave, minMaster) maxBurst = min(maxSlave, maxMaster) print('minSlave,maxSlave', minSlave, maxSlave) print('minMaster,maxMaster', minMaster, maxMaster) print('minBurst, maxBurst: ', minBurst, maxBurst) refElp = Planet(pname='Earth').ellipsoid Bpar = [] Bperp = [] for ii in range(minBurst, maxBurst + 1): ###Bookkeeping #commonBurstStartMasterIndex[swath-1] = minBurst #commonBurstStartSlaveIndex[swath-1] = commonSlaveIndex #numberOfCommonBursts[swath-1] = numberCommon #catalog.addItem('IW-{0} Number of bursts in master'.format(swath), master.numberOfBursts, 'baseline') #catalog.addItem('IW-{0} First common burst in master'.format(swath), minBurst, 'baseline') #catalog.addItem('IW-{0} Last common burst in master'.format(swath), maxBurst, 'baseline') #catalog.addItem('IW-{0} Number of bursts in slave'.format(swath), slave.numberOfBursts, 'baseline') #catalog.addItem('IW-{0} First common burst in slave'.format(swath), minBurst + burstOffset, 'baseline') #catalog.addItem('IW-{0} Last common burst in slave'.format(swath), maxBurst + burstOffset, 'baseline') #catalog.addItem('IW-{0} Number of common bursts'.format(swath), numberCommon, 'baseline') #refElp = Planet(pname='Earth').ellipsoid #Bpar = [] #Bperp = [] #for boff in [0, numberCommon-1]: ###Baselines at top of common bursts mBurst = master.bursts[ii - minMaster] sBurst = slave.bursts[ii - minSlave] ###Target at mid range tmid = mBurst.sensingMid rng = mBurst.midRange masterSV = mBurst.orbit.interpolate(tmid, method='hermite') target = mBurst.orbit.rdr2geo(tmid, rng) slvTime, slvrng = sBurst.orbit.geo2rdr(target) slaveSV = sBurst.orbit.interpolateOrbit(slvTime, method='hermite') targxyz = np.array( refElp.LLH(target[0], target[1], target[2]).ecef().tolist()) mxyz = np.array(masterSV.getPosition()) mvel = np.array(masterSV.getVelocity()) sxyz = np.array(slaveSV.getPosition()) aa = np.linalg.norm(sxyz - mxyz) costheta = (rng * rng + aa * aa - slvrng * slvrng) / (2. * rng * aa) Bpar.append(aa * costheta) perp = aa * np.sqrt(1 - costheta * costheta) direction = np.sign( np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel)) Bperp.append(direction * perp) #catalog.addItem('IW-{0} Bpar at midrange for first common burst'.format(swath), Bpar[0], 'baseline') #catalog.addItem('IW-{0} Bperp at midrange for first common burst'.format(swath), Bperp[0], 'baseline') #catalog.addItem('IW-{0} Bpar at midrange for last common burst'.format(swath), Bpar[1], 'baseline') #catalog.addItem('IW-{0} Bperp at midrange for last common burst'.format(swath), Bperp[1], 'baseline') print('Bprep: ', Bperp) print('Bpar: ', Bpar) f.write('swath: IW{0}'.format(swath) + '\n') f.write('Bperp (average): ' + str(np.mean(Bperp)) + '\n') f.write('Bpar (average): ' + str(np.mean(Bpar)) + '\n') f.close()