#!/usr/bin/env python3 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Copyright 2010 California Institute of Technology. ALL RIGHTS RESERVED. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # United States Government Sponsorship acknowledged. This software is subject to # U.S. export control laws and regulations and has been classified as 'EAR99 NLR' # (No [Export] License Required except when exporting to an embargoed country, # end user, or in support of a prohibited end use). By downloading this software, # the user agrees to comply with all applicable U.S. export laws and regulations. # The user has the responsibility to obtain export licenses, or other export # authority as may be required before exporting this software to any 'EAR99' # embargoed foreign country or citizen of those countries. # # Author: Walter Szeliga #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import isce from isce import logging from iscesys.Compatibility import Compatibility from iscesys.Component.Component import Component, Port from isceobj.Planet.Ellipsoid import Ellipsoid from isceobj.Doppler.Doppler import Doppler from isceobj.Orbit.Orbit import Orbit #from iscesys.DateTimeUtil.DateTimeUtil import DateTimeUtil as DTU from iscesys import DateTimeUtil as DTU from iscesys.Component.Application import Application from isce.applications.insarApp import SENSOR_NAME, DOPPLER_METHOD from isceobj.Scene.Frame import FrameMixin from isceobj.Util.decorators import port SENSOR = Application.Facility('sensor', public_name='sensor', module='isceobj.Sensor', factory='createSensor', args=(SENSOR_NAME, ), mandatory=True, doc="Reference raw data component" ) DOPPLER = Application.Facility('doppler', public_name='doppler', module='isceobj.Doppler', factory='createDoppler', args=(DOPPLER_METHOD, ), mandatory=False, doc="Reference Doppler calculation method" ) class makeRawApp(Application): parameter_list = (SENSOR_NAME, DOPPLER_METHOD) facility_list = (SENSOR, DOPPLER) def main(self): self.make_raw.wireInputPort(name='doppler', object=self.doppler) self.make_raw.wireInputPort(name='sensor', object=self.sensor) self.make_raw.make_raw() self.printInfo() def printInfo(self): print(self.make_raw.frame) print(self.make_raw) def __init__(self): Application.__init__(self, "makeraw") self.sensor = None self.doppler = None self.make_raw = make_raw() def initFromArglist(self, arglist): self.initFactory(arglist) self.sensor = self.getComponent('Sensor') self.doppler = self.getComponent('Doppler') class make_raw(Component, FrameMixin): def __init__(self): self.sensor = None self.doppler = None self.dopplerValues = None self.frame = None # Derived Values self.spacecraftHeight = 0.0 self.heightDt = 0.0 self.velocity = 0.0 self.squint = 0.0 self.iqImage = None Component.__init__(self) sensorPort = Port(name='sensor', method=self.addSensor) dopplerPort = Port(name='doppler', method=self.addDoppler) self._inputPorts.add(sensorPort) self._inputPorts.add(dopplerPort) self.logger = logging.getLogger("isce.make_raw") return None def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self, d): self.__dict__.update(d) self.logger = logging.getLogger("isce.make_raw") return None @port('extractImage') def addSensor(self): return None @port('calculateDoppler') def addDoppler(self): return None def getFrame(self): return self.frame def getIQImage(self): return self.iqImage def getDopplerValues(self): return self.dopplerValues def getSpacecraftHeight(self): return self.spacecraftHeight def getHeightDT(self): return self.heightDt def getVelocity(self): return self.velocity def getSquint(self): return self.squint def calculateHeightDt(self): orbit = self.orbit ellipsoid = self.ellipsoid startTime = self.sensingStart midTime = self.sensingMid sv0 = orbit.interpolate(startTime) sv1 = orbit.interpolate(midTime) startHeight = sv0.calculateHeight(ellipsoid) midHeight = sv1.calculateHeight(ellipsoid) if ('uav' in self.sensor.family.lower()) and (hasattr(self.sensor, 'platformHeight')): self.spacecraftHeight = self.sensor.platformHeight else: self.spacecraftHeight = startHeight self.heightDt = ( (midHeight - startHeight)/ DTU.timeDeltaToSeconds(midTime - startTime) ) def calculateVelocity(self): import math orbit = self.orbit midTime = self.sensingMid sv = orbit.interpolateOrbit(midTime) vx1, vy1, vz1 = sv.velocity self.velocity = math.sqrt(vx1**2 + vy1**2 + vz1**2) def calculateSquint(self): """Calculate the squint angle R0 is the starting range h is the height at mid-swath v is the velocity at mid-swath """ import math startingRange = self.startingRange prf = self.PRF wavelength = self.radarWavelength h = self.spacecraftHeight try: z = self.sensor.terrainHeight except: z = 0.0 v = self.velocity if h - z > startingRange: raise ValueError( ("Spacecraft Height - Terrain Height (%s) " + "larger than starting Range (%s)") % (h-z, startingRange)) sinTheta = math.sqrt( 1 - ((h-z)/startingRange)**2 ) if 'a' in self.doppler.quadratic: fd = self.doppler.quadratic['a']*prf elif isinstance(self.doppler.quadratic, (list, tuple)): ####For UAVSAR fd = self.doppler.quadratic[0] else: self.logger.error( "make_raw doesn't handle doppler coefficient object type, ", type(self.doppler.quadratic) ) sinSquint = fd/(2.0*v*sinTheta)*wavelength if sinSquint**2 > 1: raise ValueError( "Error in One or More of the Squint Calculation Values\n"+ "Doppler Centroid: %s\nVelocity: %s\nWavelength: %s\n" % (fd, v, wavelength) ) self.squint = math.degrees( math.atan2(sinSquint, math.sqrt(1-sinSquint**2)) ) #squint is used later on from the frame; add it here self.frame.squintAngle = math.radians(self.squint) def make_raw(self): from isceobj.Image import createRawImage, createSlcImage self.activateInputPorts() # Parse the image metadata and extract the image self.logger.info('Extracting image') try: self.sensor.extractImage() except NotImplementedError as strerr: self.logger.error("%s" % (strerr)) self.logger.error( "make_raw not implemented for %s" % self.sensor.__class__ ) raise NotImplementedError #reset the global variable to empty so can go back to use default api self.sensor.frame.image.renderVRT() self.frame = self.sensor.frame #jng NOTE if we pass just the sensor also in the case of raw image we ## can avoid the if if isinstance(self.frame.image, createRawImage().__class__): # Calculate the doppler fit self.logger.info("Calculating Doppler Centroid") try: self.doppler.wireInputPort(name='frame', object=self.frame) except: computeFlag = False else: computeFlag = True if computeFlag: self.doppler.wireInputPort(name='instrument', object=self.frame.instrument) self.doppler.wireInputPort(name='image', object=self.frame.image) self.doppler.calculateDoppler() else: self.doppler.wireInputPort(name='sensor', object=self.sensor) self.doppler.calculateDoppler() #new jng compute slc image size here rangeSamplingRate = self.instrument.rangeSamplingRate rangePulseDuration = self.instrument.pulseLength goodBytes = self.frame.image.xmax - self.frame.image.xmin try: #check if the instrument implements it, if not set it to zero chirpExtension = self.instrument.chirpExtension # Should probably be a percentage rather than a set number except AttributeError: chirpExtension = 0 chirpSize = int(rangeSamplingRate * rangePulseDuration) self.frame.numberRangeBins = (int(goodBytes/2) - chirpSize + chirpExtension) elif isinstance(self.frame.image, createSlcImage().__class__): # jng changed in view of the new tsx preproc from Howard self.doppler.wireInputPort(name='sensor', object=self.sensor) self.doppler.calculateDoppler() #new jng compute slc image size here self.frame.numberRangeBins = self.frame.image.width else: message = ( "Unrecognized image type %s" % str(self.frame.image.__class__) ) self.logger.error(message) raise TypeError(message) # Fit a polynomial to the doppler values. in the tsx case or every # zero doppler case this function simple sets the a = fd b = 0, c = 0 self.doppler.fitDoppler() # Create a doppler object prf = self.frame.instrument.PRF #coef = self.doppler.coeff_list #for ii in range(len(coef), 4): # coef.append(0.0) if 'a' in self.doppler.quadratic: coef = [self.doppler.quadratic['a']*prf,0.0,0.0,0.0] elif isinstance(self.doppler.quadratic, (list, tuple)): ####For UAVSAR coef = self.doppler.quadratic else: self.logger.error( "make_raw doesn't handle doppler coefficient object type, ", type(self.doppler.quadratic) ) self.dopplerValues = Doppler(prf=prf) self.dopplerValues.setDopplerCoefficients(coef, inHz=True) if self.frame._dopplerVsPixel is None: self.frame._dopplerVsPixel = [x*prf for x in coef] # Calculate the height, height_dt, and velocity self.logger.info("Calculating Spacecraft Velocity") self.calculateHeightDt() self.calculateVelocity() # Calculate squint angle self.logger.info("Calculating Squint Angle") self.calculateSquint() self.frame.image.numberGoodBytes = self.frame.image.xmax - self.frame.image.xmin self.frame.image.coord1.coordStart = self.frame.image.xmin self.createIQImage() self.frame.image.renderHdr() #just in case the Sensor does not compute the pulse timing try: self.adjustSensingStart() except: pass return None def createIQImage(self): from isceobj.Image import createRawIQImage #create an RawIQImage with appropriate values from the RawImage self.iqImage = createRawIQImage() self.iqImage.width = self.frame.image.width/2 self.iqImage.xmax = self.iqImage.width self.iqImage.length = self.frame.image.length self.iqImage.coord1.coordStart = int(self.frame.image.coord1.coordStart/2) self.iqImage.numberGoodSamples = int(self.frame.image.numberGoodBytes/2) self.iqImage.filename = self.frame.image.filename #the file is the same as for the raw self.iqImage.inPhase = self.frame.instrument.getInPhaseValue() self.iqImage.quadrature = self.frame.instrument.getQuadratureValue() #change the name that will be used for the xml file filename = self.frame.image.filename.replace('.raw','.iq.xml') #just in case the extension was not .raw if not filename.count('.iq'): filename += '.iq.xml' self.iqImage.renderHdr(filename) #change the name that will be used for the vrt file filename = filename.replace('.xml','.vrt') self.iqImage.renderVRT(filename) def adjustSensingStart(self, pulseTimingFilename=None, ext='.aux'): pulseTimingFilename = ( pulseTimingFilename or self.frame.image.filename + ext ) import datetime as dt import math import struct with open(pulseTimingFilename) as fp: allF = fp.read() pass #use only a limited number of point from the first frame lines = min(len(allF)/16, 10000) allT = [0]*lines d0 = struct.unpack('" % sys.argv[0]) sys.exit(1) main()