def get_sicd_collection(self): """ Gets the list of sicd objects, one per polarimetric entry. Returns ------- Tuple[SICDType] """ nitf, collection_info = self._get_collection_info() image_creation = self._get_image_creation() image_data, geo_data = self._get_image_and_geo_data() position = self._get_position() grid = self._get_grid() radar_collection = self._get_radar_collection() timeline = self._get_timeline() image_formation = self._get_image_formation(timeline, radar_collection) scpcoa = self._get_scpcoa() rma = self._get_rma_adjust_grid(scpcoa, grid, image_data, position, collection_info) radiometric = self._get_radiometric(image_data, grid) base_sicd = SICDType(CollectionInfo=collection_info, ImageCreation=image_creation, GeoData=geo_data, ImageData=image_data, Position=position, Grid=grid, RadarCollection=radar_collection, Timeline=timeline, ImageFormation=image_formation, SCPCOA=scpcoa, RMA=rma, Radiometric=radiometric) if len(nitf) > 0: base_sicd._NITF = nitf self._update_geo_data(base_sicd) base_sicd.derive() # derive all the fields # now, make one copy per polarimetric entry, as appropriate tx_pols, tx_rcv_pols = self._get_polarizations() sicd_list = [] for i, entry in enumerate(tx_rcv_pols): this_sicd = base_sicd.copy() this_sicd.ImageFormation.RcvChanProc.ChanIndices = [ i + 1, ] this_sicd.ImageFormation.TxRcvPolarizationProc = \ this_sicd.RadarCollection.RcvChannels[i].TxRcvPolarization this_sicd.populate_rniirs(override=False) sicd_list.append(this_sicd) return tuple(sicd_list)
def get_sicd(self): """ Get the SICD metadata for the image. Returns ------- SICDType """ def convert_string_dict(dict_in): # type: (dict) -> dict dict_out = OrderedDict() for key, val in dict_in.items(): if isinstance(val, string_types): dict_out[key] = val elif isinstance(val, int): dict_out[key] = str(val) elif isinstance(val, float): dict_out[key] = '{0:0.16G}'.format(val) else: raise TypeError('Got unhandled type {}'.format(type(val))) return dict_out def extract_state_vector(): # type: () -> (numpy.ndarray, numpy.ndarray, numpy.ndarray) vecs = collect['state']['state_vectors'] times = numpy.zeros((len(vecs), ), dtype=numpy.float64) positions = numpy.zeros((len(vecs), 3), dtype=numpy.float64) velocities = numpy.zeros((len(vecs), 3), dtype=numpy.float64) for i, entry in enumerate(vecs): times[i] = get_seconds(parse_timestring(entry['time'], precision='ns'), start_time, precision='ns') positions[i, :] = entry['position'] velocities[i, :] = entry['velocity'] return times, positions, velocities def get_collection_info(): # type: () -> CollectionInfoType coll_name = collect['platform'] start_dt = start_time.astype('datetime64[us]').astype(datetime) mode = collect['mode'].strip().lower() if mode == 'stripmap': radar_mode = RadarModeType(ModeType='STRIPMAP') elif mode == 'sliding_spotlight': radar_mode = RadarModeType(ModeType='DYNAMIC STRIPMAP') else: raise ValueError('Got unhandled radar mode {}'.format(mode)) return CollectionInfoType(CollectorName=coll_name, CoreName='{}{}{}'.format( start_dt.strftime('%d%b%y').upper(), coll_name, start_dt.strftime('%H%M%S')), RadarMode=radar_mode, Classification='UNCLASSIFIED', CollectType='MONOSTATIC') def get_image_creation(): # type: () -> ImageCreationType from sarpy.__about__ import __version__ return ImageCreationType( Application=self._tiff_details.tags['Software'], DateTime=parse_timestring( self._img_desc_tags['processing_time'], precision='us'), Profile='sarpy {}'.format(__version__), Site='Unknown') def get_image_data(): # type: () -> ImageDataType img = collect['image'] rows = int( img['columns']) # capella uses flipped row/column definition? cols = int(img['rows']) if img['data_type'] == 'CInt16': pixel_type = 'RE16I_IM16I' else: raise ValueError('Got unhandled data_type {}'.format( img['data_type'])) scp_pixel = (int(0.5 * rows), int(0.5 * cols)) if collect['radar']['pointing'] == 'left': scp_pixel = (rows - scp_pixel[0] - 1, cols - scp_pixel[1] - 1) return ImageDataType(NumRows=rows, NumCols=cols, FirstRow=0, FirstCol=0, PixelType=pixel_type, FullImage=(rows, cols), SCPPixel=scp_pixel) def get_geo_data(): # type: () -> GeoDataType return GeoDataType(SCP=SCPType( ECF=collect['image']['center_pixel']['target_position'])) def get_position(): # type: () -> PositionType px, py, pz = fit_position_xvalidation(state_time, state_position, state_velocity, max_degree=6) return PositionType(ARPPoly=XYZPolyType(X=px, Y=py, Z=pz)) def get_grid(): # type: () -> GridType img = collect['image'] image_plane = 'OTHER' grid_type = 'PLANE' if self._img_desc_tags['product_type'] == 'SLC' and img[ 'algorithm'] != 'backprojection': image_plane = 'SLANT' grid_type = 'RGZERO' coa_time = parse_timestring(img['center_pixel']['center_time'], precision='ns') row_imp_rsp_bw = 2 * bw / speed_of_light row = DirParamType(SS=img['pixel_spacing_column'], ImpRespBW=row_imp_rsp_bw, ImpRespWid=img['range_resolution'], KCtr=2 * fc / speed_of_light, DeltaK1=-0.5 * row_imp_rsp_bw, DeltaK2=0.5 * row_imp_rsp_bw, DeltaKCOAPoly=[ [ 0.0, ], ], WgtType=WgtTypeType( WindowName=img['range_window']['name'], Parameters=convert_string_dict( img['range_window']['parameters']))) # get timecoa value timecoa_value = get_seconds(coa_time, start_time) # TODO: constant? # find an approximation for zero doppler spacing - necessarily rough for backprojected images # find velocity at coatime arp_velocity = position.ARPPoly.derivative_eval(timecoa_value, der_order=1) arp_speed = numpy.linalg.norm(arp_velocity) col_ss = img['pixel_spacing_row'] dop_bw = img['processed_azimuth_bandwidth'] # ss_zd_s = col_ss/arp_speed col = DirParamType(SS=col_ss, ImpRespWid=img['azimuth_resolution'], ImpRespBW=dop_bw / arp_speed, KCtr=0, WgtType=WgtTypeType( WindowName=img['azimuth_window']['name'], Parameters=convert_string_dict( img['azimuth_window']['parameters']))) # TODO: from Wade - account for numeric WgtFunct return GridType(ImagePlane=image_plane, Type=grid_type, TimeCOAPoly=[ [ timecoa_value, ], ], Row=row, Col=col) def get_radar_colection(): # type: () -> RadarCollectionType radar = collect['radar'] freq_min = fc - 0.5 * bw return RadarCollectionType( TxPolarization=radar['transmit_polarization'], TxFrequency=TxFrequencyType(Min=freq_min, Max=freq_min + bw), Waveform=[ WaveformParametersType( TxRFBandwidth=bw, TxPulseLength=radar['pulse_duration'], RcvDemodType='CHIRP', ADCSampleRate=radar['sampling_frequency'], TxFreqStart=freq_min) ], RcvChannels=[ ChanParametersType(TxRcvPolarization='{}:{}'.format( radar['transmit_polarization'], radar['receive_polarization'])) ]) def get_timeline(): # type: () -> TimelineType prf = collect['radar']['prf'][0]['prf'] return TimelineType(CollectStart=start_time, CollectDuration=duration, IPP=[ IPPSetType(TStart=0, TEnd=duration, IPPStart=0, IPPEnd=duration * prf, IPPPoly=(0, prf)), ]) def get_image_formation(): # type: () -> ImageFormationType radar = collect['radar'] algo = collect['image']['algorithm'].upper() processings = None if algo == 'BACKPROJECTION': processings = [ ProcessingType(Type='Backprojected to DEM', Applied=True), ] if algo not in ('PFA', 'RMA', 'RGAZCOMP'): logging.warning( 'Image formation algorithm {} not one of the recognized SICD options, ' 'being set to "OTHER".'.format(algo)) algo = 'OTHER' return ImageFormationType( RcvChanProc=RcvChanProcType(NumChanProc=1, PRFScaleFactor=1), ImageFormAlgo=algo, TStartProc=0, TEndProc=duration, TxRcvPolarizationProc='{}:{}'.format( radar['transmit_polarization'], radar['receive_polarization']), TxFrequencyProc=TxFrequencyProcType( MinProc=radar_collection.TxFrequency.Min, MaxProc=radar_collection.TxFrequency.Max), STBeamComp='NO', ImageBeamComp='NO', AzAutofocus='NO', RgAutofocus='NO', Processings=processings) # TODO: From Wade - Radiometric is not suitable? # extract general use information collect = self._img_desc_tags['collect'] start_time = parse_timestring(collect['start_timestamp'], precision='ns') end_time = parse_timestring(collect['stop_timestamp'], precision='ns') duration = get_seconds(end_time, start_time, precision='ns') state_time, state_position, state_velocity = extract_state_vector() bw = collect['radar']['pulse_bandwidth'] fc = collect['radar']['center_frequency'] # define the sicd elements collection_info = get_collection_info() image_creation = get_image_creation() image_data = get_image_data() geo_data = get_geo_data() position = get_position() grid = get_grid() radar_collection = get_radar_colection() timeline = get_timeline() image_formation = get_image_formation() sicd = SICDType(CollectionInfo=collection_info, ImageCreation=image_creation, ImageData=image_data, GeoData=geo_data, Position=position, Grid=grid, RadarCollection=radar_collection, Timeline=timeline, ImageFormation=image_formation) sicd.derive() # this would be a rough estimate - waiting for radiometric data # sicd.populate_rniirs(override=False) return sicd
def get_sicd(self): """ Gets the SICD structure. Returns ------- Tuple[SICDType, tuple, tuple] The sicd structure, the data size argument, and the symmetry argument. """ def get_collection_info(): # type: () -> CollectionInfoType return CollectionInfoType( CollectorName=_stringify(hf['satellite_name'][()]), CoreName=_stringify(hf['product_name'][()]), CollectType='MONOSTATIC', Classification='UNCLASSIFIED', RadarMode=RadarModeType( ModeType=_stringify(hf['acquisition_mode'][()]).upper(), ModeID=_stringify(hf['product_type'][()]))) def get_image_creation(): # type: () -> ImageCreationType from sarpy.__about__ import __version__ return ImageCreationType( Application='ICEYE_P_{}'.format(hf['processor_version'][()]), DateTime=_parse_time(hf['processing_time'][()]), Site='Unknown', Profile='sarpy {}'.format(__version__)) def get_image_data(): # type: () -> ImageDataType samp_prec = _stringify(hf['sample_precision'][()]) if samp_prec.upper() == 'INT16': pixel_type = 'RE16I_IM16I' elif samp_prec.upper() == 'FLOAT32': pixel_type = 'RE32F_IM32F' else: raise ValueError( 'Got unhandled sample precision {}'.format(samp_prec)) num_rows = int_func(number_of_range_samples) num_cols = int_func(number_of_azimuth_samples) scp_row = int_func(coord_center[0]) - 1 scp_col = int_func(coord_center[1]) - 1 if 0 < scp_col < num_rows - 1: if look_side == 'left': scp_col = num_cols - scp_col - 1 else: # early ICEYE processing bug led to nonsensical SCP scp_col = int_func(num_cols / 2.0) return ImageDataType(PixelType=pixel_type, NumRows=num_rows, NumCols=num_cols, FirstRow=0, FirstCol=0, FullImage=(num_rows, num_cols), SCPPixel=(scp_row, scp_col)) def get_geo_data(): # type: () -> GeoDataType # NB: the remainder will be derived. return GeoDataType(SCP=SCPType( LLH=[coord_center[2], coord_center[3], avg_scene_height])) def get_timeline(): # type: () -> TimelineType acq_prf = hf['acquisition_prf'][()] return TimelineType(CollectStart=start_time, CollectDuration=duration, IPP=[ IPPSetType(index=0, TStart=0, TEnd=duration, IPPStart=0, IPPEnd=int_func( round(acq_prf * duration)), IPPPoly=[0, acq_prf]), ]) def get_position(): # type: () -> PositionType # fetch the state information times_str = hf['state_vector_time_utc'][:, 0] times = numpy.zeros((times_str.shape[0], ), dtype='float64') positions = numpy.zeros((times.size, 3), dtype='float64') velocities = numpy.zeros((times.size, 3), dtype='float64') for i, entry in enumerate(times_str): times[i] = get_seconds(_parse_time(entry), start_time, precision='us') positions[:, 0], positions[:, 1], positions[:, 2] = hf[ 'posX'][:], hf['posY'][:], hf['posZ'][:] velocities[:, 0], velocities[:, 1], velocities[:, 2] = hf[ 'velX'][:], hf['velY'][:], hf['velZ'][:] # fir the the position polynomial using cross validation P_x, P_y, P_z = fit_position_xvalidation(times, positions, velocities, max_degree=8) return PositionType(ARPPoly=XYZPolyType(X=P_x, Y=P_y, Z=P_z)) def get_radar_collection(): # type : () -> RadarCollection return RadarCollectionType( TxPolarization=tx_pol, TxFrequency=TxFrequencyType(Min=min_freq, Max=max_freq), Waveform=[ WaveformParametersType( TxFreqStart=min_freq, TxRFBandwidth=tx_bandwidth, TxPulseLength=hf['chirp_duration'][()], ADCSampleRate=hf['range_sampling_rate'][()], RcvDemodType='CHIRP', RcvFMRate=0, index=1) ], RcvChannels=[ ChanParametersType(TxRcvPolarization=polarization, index=1) ]) def get_image_formation(): # type: () -> ImageFormationType return ImageFormationType( TxRcvPolarizationProc=polarization, ImageFormAlgo='RMA', TStartProc=0, TEndProc=duration, TxFrequencyProc=TxFrequencyProcType(MinProc=min_freq, MaxProc=max_freq), STBeamComp='NO', ImageBeamComp='SV', AzAutofocus='NO', RgAutofocus='NO', RcvChanProc=RcvChanProcType(NumChanProc=1, PRFScaleFactor=1, ChanIndices=[ 1, ]), ) def get_radiometric(): # type: () -> RadiometricType return RadiometricType(BetaZeroSFPoly=[ [ float(hf['calibration_factor'][()]), ], ]) def calculate_drate_sf_poly(): r_ca_coeffs = numpy.array([r_ca_scp, 1], dtype='float64') dop_rate_coeffs = hf['doppler_rate_coeffs'][:] # Prior to ICEYE 1.14 processor, absolute value of Doppler rate was # provided, not true Doppler rate. Doppler rate should always be negative if dop_rate_coeffs[0] > 0: dop_rate_coeffs *= -1 dop_rate_poly = Poly1DType(Coefs=dop_rate_coeffs) # now adjust to create t_drate_ca_poly = dop_rate_poly.shift(t_0=zd_ref_time - rg_time_scp, alpha=2 / speed_of_light, return_poly=False) return t_drate_ca_poly, -polynomial.polymul( t_drate_ca_poly, r_ca_coeffs) * speed_of_light / ( 2 * center_freq * vm_ca_sq) def calculate_doppler_polys(): # extract doppler centroid coefficients dc_estimate_coeffs = hf['dc_estimate_coeffs'][:] dc_time_str = hf['dc_estimate_time_utc'][:, 0] dc_zd_times = numpy.zeros((dc_time_str.shape[0], ), dtype='float64') for i, entry in enumerate(dc_time_str): dc_zd_times[i] = get_seconds(_parse_time(entry), start_time, precision='us') # create a sampled doppler centroid samples = 49 # copied from corresponding matlab, we just need enough for appropriate refitting # create doppler time samples diff_time_rg = first_pixel_time - zd_ref_time + \ numpy.linspace(0, number_of_range_samples/range_sampling_rate, samples) # doppler centroid samples definition dc_sample_array = numpy.zeros((samples, dc_zd_times.size), dtype='float64') for i, coeffs in enumerate(dc_estimate_coeffs): dc_sample_array[:, i] = polynomial.polyval(diff_time_rg, coeffs) # create arrays for range/azimuth from scp in meters azimuth_scp_m, range_scp_m = numpy.meshgrid( col_ss * (dc_zd_times - zd_time_scp) / ss_zd_s, (diff_time_rg + zd_ref_time - rg_time_scp) * speed_of_light / 2) # fit the doppler centroid sample array x_order = min(3, range_scp_m.shape[0] - 1) y_order = min(3, range_scp_m.shape[1] - 1) t_dop_centroid_poly, residuals, rank, sing_values = two_dim_poly_fit( range_scp_m, azimuth_scp_m, dc_sample_array, x_order=x_order, y_order=y_order, x_scale=1e-3, y_scale=1e-3, rcond=1e-40) logging.info( 'The dop_centroid_poly fit details:\nroot mean square ' 'residuals = {}\nrank = {}\nsingular values = {}'.format( residuals, rank, sing_values)) # define and fit the time coa array doppler_rate_sampled = polynomial.polyval(azimuth_scp_m, drate_ca_poly) time_coa = dc_zd_times + dc_sample_array / doppler_rate_sampled t_time_coa_poly, residuals, rank, sing_values = two_dim_poly_fit( range_scp_m, azimuth_scp_m, time_coa, x_order=x_order, y_order=y_order, x_scale=1e-3, y_scale=1e-3, rcond=1e-40) logging.info( 'The time_coa_poly fit details:\nroot mean square ' 'residuals = {}\nrank = {}\nsingular values = {}'.format( residuals, rank, sing_values)) return t_dop_centroid_poly, t_time_coa_poly def get_rma(): # type: () -> RMAType dop_centroid_poly = Poly2DType(Coefs=dop_centroid_poly_coeffs) dop_centroid_coa = True if collect_info.RadarMode.ModeType == 'SPOTLIGHT': dop_centroid_poly = None dop_centroid_coa = None # NB: DRateSFPoly is defined as a function of only range - reshape appropriately inca = INCAType( R_CA_SCP=r_ca_scp, FreqZero=center_freq, DRateSFPoly=Poly2DType( Coefs=numpy.reshape(drate_sf_poly_coefs, (-1, 1))), DopCentroidPoly=dop_centroid_poly, DopCentroidCOA=dop_centroid_coa, TimeCAPoly=Poly1DType(Coefs=time_ca_poly_coeffs)) return RMAType(RMAlgoType='OMEGA_K', INCA=inca) def get_grid(): # type: () -> GridType time_coa_poly = Poly2DType(Coefs=time_coa_poly_coeffs) if collect_info.RadarMode.ModeType == 'SPOTLIGHT': time_coa_poly = Poly2DType(Coefs=[ [ float(time_coa_poly_coeffs[0, 0]), ], ]) row_win = _stringify(hf['window_function_range'][()]) if row_win == 'NONE': row_win = 'UNIFORM' row = DirParamType(SS=row_ss, Sgn=-1, KCtr=2 * center_freq / speed_of_light, ImpRespBW=2 * tx_bandwidth / speed_of_light, DeltaKCOAPoly=Poly2DType(Coefs=[[ 0, ]]), WgtType=WgtTypeType(WindowName=row_win)) col_win = _stringify(hf['window_function_azimuth'][()]) if col_win == 'NONE': col_win = 'UNIFORM' col = DirParamType( SS=col_ss, Sgn=-1, KCtr=0, ImpRespBW=col_imp_res_bw, WgtType=WgtTypeType(WindowName=col_win), DeltaKCOAPoly=Poly2DType(Coefs=dop_centroid_poly_coeffs * ss_zd_s / col_ss)) return GridType(Type='RGZERO', ImagePlane='SLANT', TimeCOAPoly=time_coa_poly, Row=row, Col=col) def correct_scp(): scp_pixel = sicd.ImageData.SCPPixel.get_array() scp_ecf = sicd.project_image_to_ground(scp_pixel, projection_type='HAE') sicd.update_scp(scp_ecf, coord_system='ECF') with h5py.File(self._file_name, 'r') as hf: # some common use variables look_side = _stringify(hf['look_side'][()]) coord_center = hf['coord_center'][:] avg_scene_height = float(hf['avg_scene_height'][()]) start_time = _parse_time(hf['acquisition_start_utc'][()]) end_time = _parse_time(hf['acquisition_end_utc'][()]) duration = get_seconds(end_time, start_time, precision='us') center_freq = float(hf['carrier_frequency'][()]) tx_bandwidth = float(hf['chirp_bandwidth'][()]) min_freq = center_freq - 0.5 * tx_bandwidth max_freq = center_freq + 0.5 * tx_bandwidth pol_temp = _stringify(hf['polarization'][()]) tx_pol = pol_temp[0] rcv_pol = pol_temp[1] polarization = tx_pol + ':' + rcv_pol first_pixel_time = float(hf['first_pixel_time'][()]) near_range = first_pixel_time * speed_of_light / 2 number_of_range_samples = float(hf['number_of_range_samples'][()]) number_of_azimuth_samples = float( hf['number_of_azimuth_samples'][()]) range_sampling_rate = float(hf['range_sampling_rate'][()]) row_ss = speed_of_light / (2 * range_sampling_rate) # define the sicd elements collect_info = get_collection_info() image_creation = get_image_creation() image_data = get_image_data() geo_data = get_geo_data() timeline = get_timeline() position = get_position() radar_collection = get_radar_collection() image_formation = get_image_formation() radiometric = get_radiometric() # calculate some zero doppler parameters ss_zd_s = float(hf['azimuth_time_interval'][()]) if look_side == 'left': ss_zd_s *= -1 zero_doppler_left = _parse_time(hf['zerodoppler_end_utc'][()]) else: zero_doppler_left = _parse_time( hf['zerodoppler_start_utc'][()]) dop_bw = hf['total_processed_bandwidth_azimuth'][()] zd_time_scp = get_seconds(zero_doppler_left, start_time, precision='us') + \ image_data.SCPPixel.Col*ss_zd_s zd_ref_time = first_pixel_time + number_of_range_samples / ( 2 * range_sampling_rate) vel_scp = position.ARPPoly.derivative_eval(zd_time_scp, der_order=1) vm_ca_sq = numpy.sum(vel_scp * vel_scp) rg_time_scp = first_pixel_time + image_data.SCPPixel.Row / range_sampling_rate r_ca_scp = rg_time_scp * speed_of_light / 2 # calculate the doppler rate sf polynomial drate_ca_poly, drate_sf_poly_coefs = calculate_drate_sf_poly() # calculate some doppler dependent grid parameters col_ss = float( numpy.sqrt(vm_ca_sq) * abs(ss_zd_s) * drate_sf_poly_coefs[0]) col_imp_res_bw = dop_bw * abs(ss_zd_s) / col_ss time_ca_poly_coeffs = [zd_time_scp, ss_zd_s / col_ss] # calculate the doppler polynomials dop_centroid_poly_coeffs, time_coa_poly_coeffs = calculate_doppler_polys( ) # finish definition of sicd elements rma = get_rma() grid = get_grid() sicd = SICDType(CollectionInfo=collect_info, ImageCreation=image_creation, ImageData=image_data, GeoData=geo_data, Timeline=timeline, Position=position, RadarCollection=radar_collection, ImageFormation=image_formation, Radiometric=radiometric, RMA=rma, Grid=grid) # adjust the scp location correct_scp() # derive sicd fields sicd.derive() # TODO: RNIIRS? data_size = (image_data.NumCols, image_data.NumRows) symmetry = (True, False, True) if look_side == 'left' else (False, False, True) return sicd, data_size, symmetry
def get_sicd(self): """ Get the SICD metadata for the image. Returns ------- SICDType """ def convert_string_dict(dict_in): # type: (dict) -> dict dict_out = OrderedDict() for key, val in dict_in.items(): if isinstance(val, str): dict_out[key] = val elif isinstance(val, int): dict_out[key] = str(val) elif isinstance(val, float): dict_out[key] = '{0:0.17G}'.format(val) else: raise TypeError('Got unhandled type {}'.format(type(val))) return dict_out def extract_state_vector(): # type: () -> (numpy.ndarray, numpy.ndarray, numpy.ndarray) vecs = collect['state']['state_vectors'] times = numpy.zeros((len(vecs), ), dtype=numpy.float64) positions = numpy.zeros((len(vecs), 3), dtype=numpy.float64) velocities = numpy.zeros((len(vecs), 3), dtype=numpy.float64) for i, entry in enumerate(vecs): times[i] = get_seconds(parse_timestring(entry['time'], precision='ns'), start_time, precision='ns') positions[i, :] = entry['position'] velocities[i, :] = entry['velocity'] return times, positions, velocities def get_radar_parameter(name): if name in radar: return radar[name] if len(radar_time_varying) > 0: element = radar_time_varying[0] if name in element: return element[name] raise ValueError( 'Unable to determine radar parameter `{}`'.format(name)) def get_collection_info(): # type: () -> CollectionInfoType coll_name = collect['platform'] mode = collect['mode'].strip().lower() if mode == 'stripmap': radar_mode = RadarModeType(ModeType='STRIPMAP', ModeID=mode) elif mode == 'spotlight': radar_mode = RadarModeType(ModeType='SPOTLIGHT', ModeID=mode) elif mode == 'sliding_spotlight': radar_mode = RadarModeType(ModeType='DYNAMIC STRIPMAP', ModeID=mode) else: raise ValueError('Got unhandled radar mode {}'.format(mode)) return CollectionInfoType(CollectorName=coll_name, CoreName=collect['collect_id'], RadarMode=radar_mode, Classification='UNCLASSIFIED', CollectType='MONOSTATIC') def get_image_creation(): # type: () -> ImageCreationType from sarpy.__about__ import __version__ return ImageCreationType( Application=self._tiff_details.tags['Software'], DateTime=parse_timestring( self._img_desc_tags['processing_time'], precision='us'), Profile='sarpy {}'.format(__version__), Site='Unknown') def get_image_data(): # type: () -> ImageDataType rows = int( img['columns']) # capella uses flipped row/column definition? cols = int(img['rows']) if img['data_type'] == 'CInt16': pixel_type = 'RE16I_IM16I' else: raise ValueError('Got unhandled data_type {}'.format( img['data_type'])) scp_pixel = (int(0.5 * rows), int(0.5 * cols)) if radar['pointing'] == 'left': scp_pixel = (rows - scp_pixel[0] - 1, cols - scp_pixel[1] - 1) return ImageDataType(NumRows=rows, NumCols=cols, FirstRow=0, FirstCol=0, PixelType=pixel_type, FullImage=(rows, cols), SCPPixel=scp_pixel) def get_geo_data(): # type: () -> GeoDataType return GeoDataType(SCP=SCPType( ECF=img['center_pixel']['target_position'])) def get_position(): # type: () -> PositionType px, py, pz = fit_position_xvalidation(state_time, state_position, state_velocity, max_degree=8) return PositionType(ARPPoly=XYZPolyType(X=px, Y=py, Z=pz)) def get_grid(): # type: () -> GridType def get_weight(window_dict): window_name = window_dict['name'] if window_name.lower() == 'rectangular': return WgtTypeType(WindowName='UNIFORM'), None elif window_name.lower() == 'avci-nacaroglu': return WgtTypeType( WindowName=window_name.upper(), Parameters=convert_string_dict(window_dict['parameters'])), \ avci_nacaroglu_window(64, alpha=window_dict['parameters']['alpha']) else: return WgtTypeType(WindowName=window_name, Parameters=convert_string_dict( window_dict['parameters'])), None image_plane = 'SLANT' grid_type = 'RGZERO' coa_time = parse_timestring(img['center_pixel']['center_time'], precision='ns') row_bw = img.get('processed_range_bandwidth', bw) row_imp_rsp_bw = 2 * row_bw / speed_of_light row_wgt, row_wgt_funct = get_weight(img['range_window']) row = DirParamType(SS=img['image_geometry']['delta_range_sample'], Sgn=-1, ImpRespBW=row_imp_rsp_bw, ImpRespWid=img['range_resolution'], KCtr=2 * fc / speed_of_light, DeltaK1=-0.5 * row_imp_rsp_bw, DeltaK2=0.5 * row_imp_rsp_bw, DeltaKCOAPoly=[ [ 0.0, ], ], WgtFunct=row_wgt_funct, WgtType=row_wgt) # get timecoa value timecoa_value = get_seconds(coa_time, start_time) # find an approximation for zero doppler spacing - necessarily rough for backprojected images col_ss = img['pixel_spacing_row'] dop_bw = img['processed_azimuth_bandwidth'] col_wgt, col_wgt_funct = get_weight(img['azimuth_window']) col = DirParamType(SS=col_ss, Sgn=-1, ImpRespWid=img['azimuth_resolution'], ImpRespBW=dop_bw * abs(ss_zd_s) / col_ss, KCtr=0, WgtFunct=col_wgt_funct, WgtType=col_wgt) # TODO: # column deltakcoa poly - it's in there at ["image"]["frequency_doppler_centroid_polynomial"] return GridType(ImagePlane=image_plane, Type=grid_type, TimeCOAPoly=[ [ timecoa_value, ], ], Row=row, Col=col) def get_radar_collection(): # type: () -> RadarCollectionType freq_min = fc - 0.5 * bw return RadarCollectionType( TxPolarization=radar['transmit_polarization'], TxFrequency=(freq_min, freq_min + bw), Waveform=[ WaveformParametersType( TxRFBandwidth=bw, TxPulseLength=get_radar_parameter('pulse_duration'), RcvDemodType='CHIRP', ADCSampleRate=radar['sampling_frequency'], TxFreqStart=freq_min) ], RcvChannels=[ ChanParametersType(TxRcvPolarization='{}:{}'.format( radar['transmit_polarization'], radar['receive_polarization'])) ]) def get_timeline(): # type: () -> TimelineType prf = radar['prf'][0]['prf'] return TimelineType(CollectStart=start_time, CollectDuration=duration, IPP=[ IPPSetType(TStart=0, TEnd=duration, IPPStart=0, IPPEnd=duration * prf, IPPPoly=(0, prf)), ]) def get_image_formation(): # type: () -> ImageFormationType algo = img['algorithm'].upper() processings = None if algo == 'BACKPROJECTION': processings = [ ProcessingType(Type='Backprojected to DEM', Applied=True), ] else: logger.warning('Got unexpected algorithm, the results for the ' 'sicd struture might be unexpected') if algo not in ('PFA', 'RMA', 'RGAZCOMP'): logger.warning( 'Image formation algorithm {} not one of the recognized SICD options, ' 'being set to "OTHER".'.format(algo)) algo = 'OTHER' return ImageFormationType( RcvChanProc=RcvChanProcType(NumChanProc=1, PRFScaleFactor=1), ImageFormAlgo=algo, TStartProc=0, TEndProc=duration, TxRcvPolarizationProc='{}:{}'.format( radar['transmit_polarization'], radar['receive_polarization']), TxFrequencyProc=(radar_collection.TxFrequency.Min, radar_collection.TxFrequency.Max), STBeamComp='NO', ImageBeamComp='NO', AzAutofocus='NO', RgAutofocus='NO', Processings=processings) def get_rma(): # type: () -> RMAType img_geometry = img['image_geometry'] near_range = img_geometry['range_to_first_sample'] center_time = parse_timestring(img['center_pixel']['center_time'], precision='us') first_time = parse_timestring(img_geometry['first_line_time'], precision='us') zd_time_scp = get_seconds(center_time, first_time, 'us') r_ca_scp = near_range + image_data.SCPPixel.Row * grid.Row.SS time_ca_poly = numpy.array( [zd_time_scp, -look * ss_zd_s / grid.Col.SS], dtype='float64') timecoa_value = get_seconds(center_time, start_time) arp_velocity = position.ARPPoly.derivative_eval(timecoa_value, der_order=1) vm_ca = numpy.linalg.norm(arp_velocity) inca = INCAType(R_CA_SCP=r_ca_scp, FreqZero=fc, TimeCAPoly=time_ca_poly, DRateSFPoly=[ [1 / (vm_ca * ss_zd_s / grid.Col.SS)], ]) return RMAType(RMAlgoType='RG_DOP', INCA=inca) def get_radiometric(): # type: () -> Union[None, RadiometricType] if img['radiometry'].lower() != 'beta_nought': logger.warning('Got unrecognized Capella radiometry {},\n\t' 'skipping the radiometric metadata'.format( img['radiometry'])) return None return RadiometricType(BetaZeroSFPoly=[ [ img['scale_factor']**2, ], ]) def add_noise(): if sicd.Radiometric is None: return nesz_raw = numpy.array(img['nesz_polynomial']['coefficients'], dtype='float64') test_value = polynomial.polyval(rma.INCA.R_CA_SCP, nesz_raw) if abs(test_value - img['nesz_peak']) > 100: # this polynomial reversed in early versions, so reverse if evaluated results are nonsense nesz_raw = nesz_raw[::-1] nesz_poly_raw = Poly2DType(Coefs=numpy.reshape(nesz_raw, (-1, 1))) noise_coeffs = nesz_poly_raw.shift(-rma.INCA.R_CA_SCP, 1, 0, 1, return_poly=False) # this is in nesz units, so shift to absolute units noise_coeffs[0] -= 10 * numpy.log10( sicd.Radiometric.SigmaZeroSFPoly[0, 0]) sicd.Radiometric.NoiseLevel = NoiseLevelType_( NoiseLevelType='ABSOLUTE', NoisePoly=noise_coeffs) # extract general use information collect = self._img_desc_tags['collect'] img = collect['image'] radar = collect['radar'] radar_time_varying = radar.get('time_varying_parameters', []) start_time = parse_timestring(collect['start_timestamp'], precision='ns') end_time = parse_timestring(collect['stop_timestamp'], precision='ns') duration = get_seconds(end_time, start_time, precision='ns') state_time, state_position, state_velocity = extract_state_vector() bw = get_radar_parameter('pulse_bandwidth') fc = get_radar_parameter('center_frequency') ss_zd_s = img['image_geometry']['delta_line_time'] look = -1 if radar['pointing'] == 'right' else 1 # define the sicd elements collection_info = get_collection_info() image_creation = get_image_creation() image_data = get_image_data() geo_data = get_geo_data() position = get_position() grid = get_grid() radar_collection = get_radar_collection() timeline = get_timeline() image_formation = get_image_formation() rma = get_rma() radiometric = get_radiometric() sicd = SICDType(CollectionInfo=collection_info, ImageCreation=image_creation, ImageData=image_data, GeoData=geo_data, Position=position, Grid=grid, RadarCollection=radar_collection, Timeline=timeline, ImageFormation=image_formation, RMA=rma, Radiometric=radiometric) sicd.derive() add_noise() sicd.populate_rniirs(override=False) return sicd