248 lines
8.5 KiB
Python
248 lines
8.5 KiB
Python
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
#
|
|
# Author: Piyush Agram
|
|
# Copyright 2010, by the California Institute of Technology. ALL RIGHTS
|
|
# RESERVED. United States Government Sponsorship acknowledged. Any commercial
|
|
# use must be negotiated with the Office of Technology Transfer at the
|
|
# California Institute of Technology.
|
|
#
|
|
# This software may be subject to U.S. export control laws. By accepting this
|
|
# software, the user agrees to comply with all applicable U.S. export laws and
|
|
# regulations. User has the responsibility to obtain export licenses, or other
|
|
# export authority as may be required before exporting such information to
|
|
# foreign countries or providing access to foreign persons.
|
|
#
|
|
# NASA Jet Propulsion Laboratory
|
|
# California Institute of Technology
|
|
# (C) 2010 All Rights Reserved
|
|
#
|
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
import datetime
|
|
import isceobj
|
|
from isceobj.Orbit.Orbit import StateVector
|
|
from isceobj.Planet.AstronomicalHandbook import Const
|
|
from isceobj.Planet.Planet import Planet
|
|
from isceobj.Scene.Frame import Frame
|
|
from iscesys.DateTimeUtil.DateTimeUtil import DateTimeUtil as DTUtil
|
|
from iscesys.Component.Component import Component
|
|
from isceobj.Sensor.Sensor import Sensor
|
|
|
|
|
|
SICD = Component.Parameter(
|
|
'sicd',
|
|
public_name='SICD',
|
|
default=None,
|
|
type=str,
|
|
mandatory=True,
|
|
intent='input',
|
|
doc='SICD input file')
|
|
|
|
class SICD_RGZERO(Sensor):
|
|
"""
|
|
A class to parse SICD RGZERO metadata
|
|
"""
|
|
|
|
parameter_list = (SICD,) + Sensor.parameter_list
|
|
logging_name = "isce.sensor.SICD_RGZERO"
|
|
family_name = "sicd_rgzero"
|
|
|
|
def __init__(self):
|
|
super(SICD_RGZERO,self).__init__()
|
|
self._sicdmeta = None
|
|
|
|
return None
|
|
|
|
def getFrame(self):
|
|
return self.frame
|
|
|
|
|
|
def parse(self):
|
|
try:
|
|
import sarpy.io.complex as cf
|
|
except ImportError:
|
|
raise Exception('You need to install sarpy from NGA - https://github.com/ngageoint/sarpy to work with SICD data')
|
|
self._sicdmeta = cf.open(self.sicd).sicdmeta
|
|
self.populateMetadata()
|
|
|
|
|
|
def _populatePlatform(self):
|
|
mdict = self._sicdmeta
|
|
platform = self.frame.getInstrument().getPlatform()
|
|
|
|
platform.setMission(mdict.CollectionInfo.CollectorName)
|
|
platform.setPlanet(Planet(pname="Earth"))
|
|
side = mdict.SCPCOA.SideOfTrack
|
|
if side.startswith('R'):
|
|
side = -1
|
|
else:
|
|
side = 1
|
|
platform.setPointingDirection(side)
|
|
|
|
if mdict.CollectionInfo.RadarMode.ModeType.upper() != 'STRIPMAP':
|
|
raise Exception('SICD ModeType should be STRIPMAP')
|
|
|
|
if mdict.CollectionInfo.CollectType.upper() != 'MONOSTATIC':
|
|
raise Exception('SICD ModeType should be MONOSTATIC')
|
|
|
|
|
|
def _populateInstrument(self, mdict=None):
|
|
if mdict is None:
|
|
mdict = self._sicdmeta
|
|
|
|
instrument = self.frame.getInstrument()
|
|
|
|
###Ensure that data is actually SICD RGZERO
|
|
if (mdict.Grid.Type != 'RGZERO'):
|
|
raise Exception('Input data must be SICD RGZERO')
|
|
|
|
if (mdict.Grid.ImagePlane != 'SLANT'):
|
|
raise Exception('Input data must be SICD RGZERO in Slant Range plane')
|
|
|
|
rangePixelSize = mdict.Grid.Row.SS
|
|
azimuthPixelSize = mdict.Grid.Col.SS
|
|
fs = Const.c/(2*rangePixelSize)
|
|
|
|
fc = mdict.RMA.INCA.FreqZero
|
|
prf = mdict.Timeline.IPP.Set.IPPPoly[1] * mdict.ImageFormation.RcvChanProc.PRFScaleFactor
|
|
|
|
instrument.setRadarWavelength(Const.c/fc)
|
|
instrument.setPulseRepetitionFrequency(prf)
|
|
instrument.setRangePixelSize(rangePixelSize)
|
|
instrument.setPulseLength(mdict.RadarCollection.Waveform.WFParameters[0].TxPulseLength)
|
|
instrument.setChirpSlope(mdict.RadarCollection.Waveform.WFParameters[0].TxRFBandwidth / mdict.RadarCollection.Waveform.WFParameters[0].TxPulseLength )
|
|
instrument.setRangeSamplingRate(fs)
|
|
instrument.setInPhaseValue(0.)
|
|
instrument.setQuadratureValue(0.)
|
|
instrument.platform.setAntennaLength(2.2 * azimuthPixelSize)
|
|
|
|
def _populateFrame(self, mdict=None):
|
|
if mdict is None:
|
|
mdict = self._sicdmeta
|
|
|
|
startRange = mdict.RMA.INCA.R_CA_SCP - (mdict.ImageData.SCPPixel.Row * mdict.Grid.Row.SS)
|
|
|
|
####Compute the UTC times
|
|
zd_t_scp = mdict.RMA.INCA.TimeCAPoly[0]
|
|
ss_zd_s = 1 /self.frame.PRF
|
|
sensingStart = mdict.Timeline.CollectStart + datetime.timedelta(seconds = (zd_t_scp - mdict.ImageData.SCPPixel.Col * ss_zd_s))
|
|
sensingStop = sensingStart + datetime.timedelta(seconds = (mdict.ImageData.NumCols-1) / self.frame.PRF)
|
|
sensingMid = sensingStart + 0.5 * (sensingStop - sensingStart)
|
|
|
|
self.frame.setStartingRange(startRange)
|
|
if mdict.SCPCOA.ARPVel.Z > 0:
|
|
self.frame.setPassDirection('ASCENDING')
|
|
else:
|
|
self.frame.setPassDirection('DESCENDING')
|
|
|
|
self.frame.setOrbitNumber(9999)
|
|
self.frame.setProcessingFacility(mdict.ImageCreation.Site)
|
|
self.frame.setProcessingSoftwareVersion(mdict.ImageCreation.Application)
|
|
|
|
pol = mdict.ImageFormation.TxRcvPolarizationProc
|
|
self.frame.setPolarization(pol[0] + pol[2])
|
|
self.frame.setNumberOfLines(mdict.ImageData.NumCols)
|
|
self.frame.setNumberOfSamples(mdict.ImageData.NumRows)
|
|
|
|
|
|
self.frame.setSensingStart(sensingStart)
|
|
self.frame.setSensingMid(sensingMid)
|
|
self.frame.setSensingStop(sensingStop)
|
|
|
|
rangePixelSize = self.frame.getInstrument().getRangePixelSize()
|
|
farRange = startRange + self.frame.getNumberOfSamples()*rangePixelSize
|
|
self.frame.setFarRange(farRange)
|
|
|
|
|
|
def _populateOrbit(self, mdict=None):
|
|
import numpy.polynomial.polynomial as poly
|
|
if mdict is None:
|
|
mdict = self._sicdmeta
|
|
|
|
raw_start_time = mdict.Timeline.CollectStart
|
|
|
|
tmin = self.frame.sensingStart - datetime.timedelta(seconds=5)
|
|
tmax = self.frame.sensingStop + datetime.timedelta(seconds=5)
|
|
|
|
|
|
orbit = self.frame.getOrbit()
|
|
orbit.setReferenceFrame('ECEF')
|
|
orbit.setOrbitSource('Header')
|
|
|
|
posX = mdict.Position.ARPPoly.X
|
|
posY = mdict.Position.ARPPoly.Y
|
|
posZ = mdict.Position.ARPPoly.Z
|
|
velX = poly.polyder(posX)
|
|
velY = poly.polyder(posY)
|
|
velZ = poly.polyder(posZ)
|
|
|
|
tinp = tmin
|
|
while tinp <= tmax:
|
|
|
|
deltaT = (tinp - raw_start_time).total_seconds()
|
|
vec = StateVector()
|
|
vec.setTime(tinp)
|
|
vec.setPosition([poly.polyval(deltaT, posX),
|
|
poly.polyval(deltaT, posY),
|
|
poly.polyval(deltaT, posZ)])
|
|
vec.setVelocity([poly.polyval(deltaT, velX),
|
|
poly.polyval(deltaT, velY),
|
|
poly.polyval(deltaT, velZ)])
|
|
|
|
orbit.addStateVector(vec)
|
|
tinp = tinp + datetime.timedelta(seconds=1)
|
|
|
|
|
|
def populateImage(self):
|
|
import sarpy.io.complex as cf
|
|
|
|
img = cf.open(self.sicd)
|
|
data = img.read_chip()
|
|
data.T.tofile(self.output)
|
|
|
|
rawImage = isceobj.createSlcImage()
|
|
rawImage.setByteOrder('l')
|
|
rawImage.setFilename(self.output)
|
|
rawImage.setAccessMode('read')
|
|
rawImage.setWidth(self.frame.getNumberOfSamples())
|
|
rawImage.setXmax(self.frame.getNumberOfSamples())
|
|
rawImage.setXmin(0)
|
|
self.getFrame().setImage(rawImage)
|
|
#rawImage.renderHdr()
|
|
|
|
def _populateExtras(self):
|
|
"""
|
|
Populate some extra fields.
|
|
"""
|
|
from sarpy.geometry.point_projection import coa_projection_set
|
|
import numpy as np
|
|
mdict = self._sicdmeta
|
|
|
|
###Imagesize
|
|
rows = np.linspace(0., mdict.ImageData.NumRows*1.0, num=3)
|
|
rdot = []
|
|
|
|
for grow in rows:
|
|
pt = coa_projection_set(mdict,[grow,0])
|
|
rdot.append( pt[1][0])
|
|
|
|
self.frame._dopplerVsPixel = list(np.polyfit(rows, rdot, 2)[::-1])
|
|
|
|
|
|
def extractImage(self):
|
|
"""Extract the raw image data"""
|
|
self.parse()
|
|
self._populateExtras()
|
|
self.populateImage()
|
|
|
|
def extractDoppler(self):
|
|
"""
|
|
Return the doppler centroid as defined in the HDF5 file.
|
|
"""
|
|
dopp = self.frame._dopplerVsPixel
|
|
quadratic = {}
|
|
quadratic['a'] = dopp[0]
|
|
quadratic['b'] = dopp[1]
|
|
quadratic['c'] = dopp[2]
|
|
return quadratic
|
|
|