sarkit-convert 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sarkit_convert/_utils.py +47 -18
- sarkit_convert/_version.py +1 -1
- sarkit_convert/{csk.py → cosmo.py} +369 -218
- sarkit_convert/create_arp_poly.py +166 -0
- sarkit_convert/iceye.py +217 -301
- sarkit_convert/sentinel.py +457 -453
- sarkit_convert/sidd_metadata.py +201 -0
- sarkit_convert/{tsx.py → terrasar.py} +318 -215
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/METADATA +26 -26
- sarkit_convert-0.3.0.dist-info/RECORD +14 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/WHEEL +1 -1
- sarkit_convert-0.1.0.dist-info/RECORD +0 -12
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/entry_points.txt +0 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,10 +15,11 @@ metadata that would predict the complex data characteristics
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
|
+
import datetime
|
|
18
19
|
import pathlib
|
|
19
20
|
|
|
20
21
|
import dateutil.parser
|
|
21
|
-
import lxml.
|
|
22
|
+
import lxml.etree
|
|
22
23
|
import numpy as np
|
|
23
24
|
import numpy.linalg as npl
|
|
24
25
|
import numpy.polynomial.polynomial as npp
|
|
@@ -26,8 +27,8 @@ import sarkit.sicd as sksicd
|
|
|
26
27
|
import sarkit.verification
|
|
27
28
|
import sarkit.wgs84
|
|
28
29
|
import scipy.constants
|
|
29
|
-
from lxml import etree
|
|
30
30
|
|
|
31
|
+
from sarkit_convert import __version__
|
|
31
32
|
from sarkit_convert import _utils as utils
|
|
32
33
|
|
|
33
34
|
NSMAP = {
|
|
@@ -57,10 +58,6 @@ def _parse_to_naive(timestamp_str):
|
|
|
57
58
|
return dateutil.parser.parse(timestamp_str).replace(tzinfo=None)
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
def _naive_to_sicd_str(timestamp):
|
|
61
|
-
return timestamp.replace(tzinfo=None).isoformat() + "Z"
|
|
62
|
-
|
|
63
|
-
|
|
64
61
|
def _boolstr_to_bool(text):
|
|
65
62
|
return text in ("1", "true")
|
|
66
63
|
|
|
@@ -154,7 +151,6 @@ def cosar_to_sicd(
|
|
|
154
151
|
cosar_file,
|
|
155
152
|
sicd_file,
|
|
156
153
|
classification,
|
|
157
|
-
ostaid,
|
|
158
154
|
chan_index,
|
|
159
155
|
tx_polarizations,
|
|
160
156
|
tx_rcv_pols,
|
|
@@ -196,7 +192,7 @@ def cosar_to_sicd(
|
|
|
196
192
|
application = generation_system.text
|
|
197
193
|
version = generation_system.attrib["version"]
|
|
198
194
|
creation_application = f"{application} version {version}"
|
|
199
|
-
|
|
195
|
+
originator_facility = tsx_xml.findtext(
|
|
200
196
|
"./productInfo/generationInfo/level1ProcessingFacility"
|
|
201
197
|
)
|
|
202
198
|
|
|
@@ -491,43 +487,156 @@ def cosar_to_sicd(
|
|
|
491
487
|
uspz = spz / npl.norm(spz)
|
|
492
488
|
u_col = np.cross(uspz, u_row)
|
|
493
489
|
|
|
494
|
-
#
|
|
495
|
-
|
|
496
|
-
|
|
490
|
+
# Antenna
|
|
491
|
+
attitude_elem = tsx_xml.find("./platform/attitude")
|
|
492
|
+
attitude_utcs = []
|
|
493
|
+
attitude_quaternions = []
|
|
494
|
+
for attitude_data in attitude_elem.findall("./attitudeData"):
|
|
495
|
+
attitude_utcs.append(_parse_to_naive(attitude_data.findtext("./timeUTC")))
|
|
496
|
+
quat = [
|
|
497
|
+
float(attitude_data.findtext("./q0")),
|
|
498
|
+
float(attitude_data.findtext("./q1")),
|
|
499
|
+
float(attitude_data.findtext("./q2")),
|
|
500
|
+
float(attitude_data.findtext("./q3")),
|
|
501
|
+
]
|
|
502
|
+
attitude_quaternions.append(quat)
|
|
503
|
+
attitude_quaternions = np.array(attitude_quaternions)
|
|
504
|
+
|
|
505
|
+
def get_mech_frame_from_quat(att_quat):
|
|
506
|
+
scipy_quat = np.roll(att_quat, -1)
|
|
507
|
+
return scipy.spatial.transform.Rotation.from_quat(scipy_quat).inv().as_matrix()
|
|
508
|
+
|
|
509
|
+
rel_att_times = np.array(
|
|
510
|
+
[(att_utc - collection_start_time).total_seconds() for att_utc in attitude_utcs]
|
|
511
|
+
)
|
|
512
|
+
good_indices = np.where(
|
|
513
|
+
np.logical_and(
|
|
514
|
+
np.less(-60, rel_att_times),
|
|
515
|
+
np.less(rel_att_times, 60 + collection_duration),
|
|
516
|
+
)
|
|
497
517
|
)
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
sicd.RadarMode(sicd.ModeType(radar_mode_type), sicd.ModeID(radar_mode_id)),
|
|
503
|
-
sicd.Classification(classification),
|
|
518
|
+
good_times = rel_att_times[good_indices]
|
|
519
|
+
good_att_quat = attitude_quaternions[good_indices]
|
|
520
|
+
mech_frame = np.array(
|
|
521
|
+
[get_mech_frame_from_quat(att_quat) for att_quat in good_att_quat]
|
|
504
522
|
)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
523
|
+
|
|
524
|
+
ux_rot = mech_frame[:, 0, :]
|
|
525
|
+
uy_rot = mech_frame[:, 1, :]
|
|
526
|
+
|
|
527
|
+
ant_x_dir_poly = utils.fit_state_vectors(
|
|
528
|
+
(0, (collection_stop_time - collection_start_time).total_seconds()),
|
|
529
|
+
good_times,
|
|
530
|
+
ux_rot,
|
|
531
|
+
None,
|
|
532
|
+
None,
|
|
533
|
+
order=4,
|
|
534
|
+
)
|
|
535
|
+
ant_y_dir_poly = utils.fit_state_vectors(
|
|
536
|
+
(0, (collection_stop_time - collection_start_time).total_seconds()),
|
|
537
|
+
good_times,
|
|
538
|
+
uy_rot,
|
|
539
|
+
None,
|
|
540
|
+
None,
|
|
541
|
+
order=4,
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
freq_zero = center_frequency
|
|
545
|
+
antenna_pattern_elem = tsx_xml.xpath(
|
|
546
|
+
f'./calibration/calibrationData/antennaPattern[polLayer[text()="{pol_layer}"]]'
|
|
547
|
+
)[0]
|
|
548
|
+
antenna_beam_elevation = np.arctan2(
|
|
549
|
+
float(antenna_pattern_elem.findtext("./beamPointingVector/y")),
|
|
550
|
+
float(antenna_pattern_elem.findtext("./beamPointingVector/z")),
|
|
551
|
+
)
|
|
552
|
+
spotlight_elem = tsx_xml.find(
|
|
553
|
+
"./productInfo/acquisitionInfo/imagingModeSpecificInfo/spotLight"
|
|
554
|
+
)
|
|
555
|
+
if spotlight_elem is not None:
|
|
556
|
+
azimuth_steering = np.array(
|
|
557
|
+
[
|
|
558
|
+
float(spotlight_elem.findtext("./azimuthSteeringAngleFirst")),
|
|
559
|
+
float(spotlight_elem.findtext("./azimuthSteeringAngleLast")),
|
|
560
|
+
]
|
|
561
|
+
)
|
|
562
|
+
eb_dcx_poly = npp.polyfit(
|
|
563
|
+
[0, collection_duration], np.sin(np.deg2rad(azimuth_steering)), 1
|
|
564
|
+
)
|
|
565
|
+
else:
|
|
566
|
+
eb_dcx_poly = [0.0]
|
|
567
|
+
eb_dcy_poly = [-look * np.sin(antenna_beam_elevation)]
|
|
568
|
+
|
|
569
|
+
def get_angles_gains(pattern_elem):
|
|
570
|
+
antenna_angles = []
|
|
571
|
+
antenna_gains = []
|
|
572
|
+
for gain_ext in pattern_elem.findall("./gainExt"):
|
|
573
|
+
antenna_angles.append(float(gain_ext.attrib["angle"]))
|
|
574
|
+
antenna_gains.append(float(gain_ext.text))
|
|
575
|
+
return np.array(antenna_angles), np.array(antenna_gains)
|
|
576
|
+
|
|
577
|
+
antenna_rg_angles, antenna_rg_gains = get_angles_gains(
|
|
578
|
+
antenna_pattern_elem.find("./elevationPattern")
|
|
509
579
|
)
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
sicd.NumRows(str(num_rows)),
|
|
513
|
-
sicd.NumCols(str(num_cols)),
|
|
514
|
-
sicd.FirstRow(str(first_row)),
|
|
515
|
-
sicd.FirstCol(str(first_col)),
|
|
516
|
-
sicd.FullImage(sicd.NumRows(str(num_rows)), sicd.NumCols(str(num_cols))),
|
|
517
|
-
sicd.SCPPixel(sicd.Row(str(scp_pixel[0])), sicd.Col(str(scp_pixel[1]))),
|
|
580
|
+
antenna_az_angles, antenna_az_gains = get_angles_gains(
|
|
581
|
+
antenna_pattern_elem.find("./azimuthPattern")
|
|
518
582
|
)
|
|
519
583
|
|
|
520
|
-
|
|
521
|
-
return [sicd.X(str(arr[0])), sicd.Y(str(arr[1])), sicd.Z(str(arr[2]))]
|
|
584
|
+
fit_order = 4
|
|
522
585
|
|
|
523
|
-
def
|
|
524
|
-
|
|
586
|
+
def fit_gains(angles, gains):
|
|
587
|
+
fit_limit = -9
|
|
588
|
+
array_mask = gains > fit_limit
|
|
589
|
+
dcs = np.sin(np.deg2rad(angles))
|
|
590
|
+
return npp.polyfit(dcs[array_mask], gains[array_mask], fit_order)
|
|
525
591
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
592
|
+
antenna_array_gain = np.zeros((fit_order + 1, fit_order + 1), dtype=float)
|
|
593
|
+
antenna_array_gain[0, :] = fit_gains(
|
|
594
|
+
antenna_rg_angles + look * np.rad2deg(antenna_beam_elevation),
|
|
595
|
+
antenna_rg_gains,
|
|
530
596
|
)
|
|
597
|
+
antenna_array_gain[:, 0] = fit_gains(antenna_az_angles, antenna_az_gains)
|
|
598
|
+
antenna_array_gain[0, 0] = 0.0
|
|
599
|
+
|
|
600
|
+
# Build XML
|
|
601
|
+
sicd_xml_obj = lxml.etree.Element(
|
|
602
|
+
f"{{{NSMAP['sicd']}}}SICD", nsmap={None: NSMAP["sicd"]}
|
|
603
|
+
)
|
|
604
|
+
sicd_ew = sksicd.ElementWrapper(sicd_xml_obj)
|
|
605
|
+
|
|
606
|
+
sicd_ew["CollectionInfo"] = {
|
|
607
|
+
"CollectorName": collector_name,
|
|
608
|
+
"CoreName": core_name,
|
|
609
|
+
"CollectType": "MONOSTATIC",
|
|
610
|
+
"RadarMode": {
|
|
611
|
+
"ModeType": radar_mode_type,
|
|
612
|
+
"ModeID": radar_mode_id,
|
|
613
|
+
},
|
|
614
|
+
"Classification": classification,
|
|
615
|
+
}
|
|
616
|
+
sicd_ew["ImageCreation"] = {
|
|
617
|
+
"Application": creation_application,
|
|
618
|
+
"DateTime": creation_time,
|
|
619
|
+
}
|
|
620
|
+
sicd_ew["ImageData"] = {
|
|
621
|
+
"PixelType": COSAR_PIXEL_TYPE,
|
|
622
|
+
"NumRows": num_rows,
|
|
623
|
+
"NumCols": num_cols,
|
|
624
|
+
"FirstRow": first_row,
|
|
625
|
+
"FirstCol": first_col,
|
|
626
|
+
"FullImage": {
|
|
627
|
+
"NumRows": num_rows,
|
|
628
|
+
"NumCols": num_cols,
|
|
629
|
+
},
|
|
630
|
+
"SCPPixel": scp_pixel,
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
sicd_ew["GeoData"] = {
|
|
634
|
+
"EarthModel": "WGS_84",
|
|
635
|
+
"SCP": {
|
|
636
|
+
"ECF": scp_ecf,
|
|
637
|
+
"LLH": scp_llh,
|
|
638
|
+
},
|
|
639
|
+
}
|
|
531
640
|
|
|
532
641
|
dc_sgn = np.sign(-doppler_rate_poly[0, 0])
|
|
533
642
|
col_deltakcoa_poly = (
|
|
@@ -552,168 +661,180 @@ def cosar_to_sicd(
|
|
|
552
661
|
col_window_name = proc_param.findtext("./azimuthWindowID")
|
|
553
662
|
col_window_coeff = float(proc_param.findtext("./azimuthWindowCoefficient"))
|
|
554
663
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
sksicd.Poly2dType().set_elem(grid.find("./{*}TimeCOAPoly"), time_coa_poly)
|
|
591
|
-
sksicd.Poly2dType().set_elem(grid.find("./{*}Row/{*}DeltaKCOAPoly"), [[0]])
|
|
592
|
-
sksicd.Poly2dType().set_elem(
|
|
593
|
-
grid.find("./{*}Col/{*}DeltaKCOAPoly"), col_deltakcoa_poly
|
|
594
|
-
)
|
|
664
|
+
sicd_ew["Grid"] = {
|
|
665
|
+
"ImagePlane": "SLANT",
|
|
666
|
+
"Type": "RGZERO",
|
|
667
|
+
"TimeCOAPoly": time_coa_poly,
|
|
668
|
+
"Row": {
|
|
669
|
+
"UVectECF": u_row,
|
|
670
|
+
"SS": spacings[0],
|
|
671
|
+
"ImpRespWid": row_wid,
|
|
672
|
+
"Sgn": -1,
|
|
673
|
+
"ImpRespBW": row_bw,
|
|
674
|
+
"KCtr": center_frequency / (scipy.constants.speed_of_light / 2),
|
|
675
|
+
"DeltaK1": -row_bw / 2,
|
|
676
|
+
"DeltaK2": row_bw / 2,
|
|
677
|
+
"DeltaKCOAPoly": [[0.0]],
|
|
678
|
+
"WgtType": {
|
|
679
|
+
"WindowName": row_window_name,
|
|
680
|
+
"Parameter": [("COEFFICIENT", str(row_window_coeff))],
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
"Col": {
|
|
684
|
+
"UVectECF": u_col,
|
|
685
|
+
"SS": spacings[1],
|
|
686
|
+
"ImpRespWid": col_wid,
|
|
687
|
+
"Sgn": -1,
|
|
688
|
+
"ImpRespBW": col_bw,
|
|
689
|
+
"KCtr": 0.0,
|
|
690
|
+
"DeltaK1": dk1,
|
|
691
|
+
"DeltaK2": dk2,
|
|
692
|
+
"DeltaKCOAPoly": col_deltakcoa_poly,
|
|
693
|
+
"WgtType": {
|
|
694
|
+
"WindowName": col_window_name,
|
|
695
|
+
"Parameter": [("COEFFICIENT", str(col_window_coeff))],
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
}
|
|
595
699
|
rcs_row_sf = None
|
|
596
700
|
rcs_col_sf = None
|
|
597
701
|
if row_window_name == "Hamming":
|
|
598
702
|
wgts = scipy.signal.windows.general_hamming(512, row_window_coeff, sym=True)
|
|
599
|
-
|
|
600
|
-
sksicd.TRANSCODERS["Grid/Row/WgtFunct"].set_elem(wgtfunc, wgts)
|
|
601
|
-
grid.find("./{*}Row").append(wgtfunc)
|
|
703
|
+
sicd_ew["Grid"]["Row"]["WgtFunct"] = wgts
|
|
602
704
|
row_broadening_factor = utils.broadening_from_amp(wgts)
|
|
603
705
|
row_wid = row_broadening_factor / row_bw
|
|
604
|
-
|
|
706
|
+
sicd_ew["Grid"]["Row"]["ImpRespWid"] = row_wid
|
|
605
707
|
rcs_row_sf = 1 + np.var(wgts) / np.mean(wgts) ** 2
|
|
606
708
|
if col_window_name == "Hamming":
|
|
607
709
|
wgts = scipy.signal.windows.general_hamming(512, col_window_coeff, sym=True)
|
|
608
|
-
|
|
609
|
-
sksicd.TRANSCODERS["Grid/Col/WgtFunct"].set_elem(wgtfunc, wgts)
|
|
610
|
-
grid.find("./{*}Col").append(wgtfunc)
|
|
710
|
+
sicd_ew["Grid"]["Col"]["WgtFunct"] = wgts
|
|
611
711
|
col_broadening_factor = utils.broadening_from_amp(wgts)
|
|
612
712
|
col_wid = col_broadening_factor / col_bw
|
|
613
|
-
|
|
713
|
+
sicd_ew["Grid"]["Col"]["ImpRespWid"] = col_wid
|
|
614
714
|
rcs_col_sf = 1 + np.var(wgts) / np.mean(wgts) ** 2
|
|
615
715
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
{
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
716
|
+
sicd_ew["Timeline"] = {
|
|
717
|
+
"CollectStart": collection_start_time,
|
|
718
|
+
"CollectDuration": collection_duration,
|
|
719
|
+
"IPP": {
|
|
720
|
+
"@size": 1,
|
|
721
|
+
"Set": [
|
|
722
|
+
{
|
|
723
|
+
"@index": 1,
|
|
724
|
+
"TStart": 0,
|
|
725
|
+
"TEnd": num_pulses / prf,
|
|
726
|
+
"IPPStart": 0,
|
|
727
|
+
"IPPEnd": num_pulses - 1,
|
|
728
|
+
"IPPPoly": [0, prf],
|
|
729
|
+
}
|
|
730
|
+
],
|
|
731
|
+
},
|
|
732
|
+
}
|
|
632
733
|
|
|
633
|
-
|
|
634
|
-
sksicd.XyzPolyType().set_elem(position.find("./{*}ARPPoly"), apc_poly)
|
|
734
|
+
sicd_ew["Position"]["ARPPoly"] = apc_poly
|
|
635
735
|
|
|
636
|
-
|
|
637
|
-
{"size": str(len(tx_rcv_pols))},
|
|
638
|
-
)
|
|
736
|
+
chan_parameters = []
|
|
639
737
|
for ndx, tx_rcv_pol in enumerate(tx_rcv_pols):
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
738
|
+
chan_parameters.append(
|
|
739
|
+
{
|
|
740
|
+
"@index": ndx + 1,
|
|
741
|
+
"TxRcvPolarization": tx_rcv_pol,
|
|
742
|
+
}
|
|
644
743
|
)
|
|
645
744
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
745
|
+
sicd_ew["RadarCollection"] = {
|
|
746
|
+
"TxFrequency": {
|
|
747
|
+
"Min": tx_freq_min,
|
|
748
|
+
"Max": tx_freq_max,
|
|
749
|
+
},
|
|
750
|
+
"Waveform": {
|
|
751
|
+
"@size": 1,
|
|
752
|
+
"WFParameters": [
|
|
753
|
+
{
|
|
754
|
+
"@index": 1,
|
|
755
|
+
"TxPulseLength": tx_pulse_length,
|
|
756
|
+
"TxRFBandwidth": tx_rf_bw,
|
|
757
|
+
"TxFreqStart": tx_freq_start,
|
|
758
|
+
"TxFMRate": tx_fm_rate,
|
|
759
|
+
"RcvWindowLength": rcv_window_length,
|
|
760
|
+
"ADCSampleRate": adc_sample_rate,
|
|
761
|
+
}
|
|
762
|
+
],
|
|
763
|
+
},
|
|
764
|
+
"TxPolarization": tx_polarization,
|
|
765
|
+
"RcvChannels": {
|
|
766
|
+
"@size": len(tx_rcv_pols),
|
|
767
|
+
"ChanParameters": chan_parameters,
|
|
768
|
+
},
|
|
769
|
+
}
|
|
663
770
|
if len(tx_polarizations) > 1:
|
|
664
|
-
|
|
665
|
-
|
|
771
|
+
sicd_ew["RadarCollection"]["TxPolarization"] = "SEQUENCE"
|
|
772
|
+
tx_steps = []
|
|
666
773
|
for ndx, tx_pol in enumerate(tx_polarizations):
|
|
667
|
-
|
|
668
|
-
|
|
774
|
+
tx_steps.append(
|
|
775
|
+
{
|
|
776
|
+
"@index": ndx + 1,
|
|
777
|
+
"TxPolarization": tx_pol,
|
|
778
|
+
}
|
|
669
779
|
)
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
780
|
+
sicd_ew["RadarCollection"]["TxSequence"] = {
|
|
781
|
+
"@size": len(tx_polarizations),
|
|
782
|
+
"TxStep": tx_steps,
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
now = (
|
|
786
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
787
|
+
.isoformat(timespec="microseconds")
|
|
788
|
+
.replace("+00:00", "Z")
|
|
789
|
+
)
|
|
790
|
+
sicd_ew["ImageFormation"] = {
|
|
791
|
+
"RcvChanProc": {
|
|
792
|
+
"NumChanProc": 1,
|
|
793
|
+
"ChanIndex": [chan_index],
|
|
794
|
+
},
|
|
795
|
+
"TxRcvPolarizationProc": tx_rcv_polarization,
|
|
796
|
+
"TStartProc": 0,
|
|
797
|
+
"TEndProc": collection_duration,
|
|
798
|
+
"TxFrequencyProc": {
|
|
799
|
+
"MinProc": tx_freq_min,
|
|
800
|
+
"MaxProc": tx_freq_max,
|
|
801
|
+
},
|
|
802
|
+
"ImageFormAlgo": "RMA",
|
|
803
|
+
"STBeamComp": st_beam_comp,
|
|
804
|
+
"ImageBeamComp": "SV",
|
|
805
|
+
"AzAutofocus": "NO",
|
|
806
|
+
"RgAutofocus": "NO",
|
|
807
|
+
"Processing": [
|
|
808
|
+
{
|
|
809
|
+
"Type": f"sarkit-convert {__version__} @ {now}",
|
|
810
|
+
"Applied": True,
|
|
811
|
+
},
|
|
812
|
+
],
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
sicd_ew["Antenna"]["TwoWay"]["XAxisPoly"] = ant_x_dir_poly
|
|
816
|
+
sicd_ew["Antenna"]["TwoWay"]["YAxisPoly"] = ant_y_dir_poly
|
|
817
|
+
sicd_ew["Antenna"]["TwoWay"]["FreqZero"] = freq_zero
|
|
818
|
+
sicd_ew["Antenna"]["TwoWay"]["EB"]["DCXPoly"] = eb_dcx_poly
|
|
819
|
+
sicd_ew["Antenna"]["TwoWay"]["EB"]["DCYPoly"] = eb_dcy_poly
|
|
820
|
+
sicd_ew["Antenna"]["TwoWay"]["Array"]["GainPoly"] = antenna_array_gain
|
|
821
|
+
sicd_ew["Antenna"]["TwoWay"]["Array"]["PhasePoly"] = np.zeros(
|
|
822
|
+
dtype=float, shape=(1, 1)
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
sicd_ew["RMA"] = {
|
|
826
|
+
"RMAlgoType": "OMEGA_K",
|
|
827
|
+
"ImageType": "INCA",
|
|
828
|
+
"INCA": {
|
|
829
|
+
"TimeCAPoly": time_ca_poly,
|
|
830
|
+
"R_CA_SCP": scp_rca,
|
|
831
|
+
"FreqZero": center_frequency,
|
|
832
|
+
"DRateSFPoly": drsf_poly,
|
|
833
|
+
"DopCentroidPoly": doppler_centroid_poly,
|
|
834
|
+
},
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
sicd_ew["SCPCOA"] = sksicd.compute_scp_coa(sicd_xml_obj.getroottree())
|
|
717
838
|
|
|
718
839
|
# Add Radiometric
|
|
719
840
|
cal_constant = float(cal_const_elem.findtext("./calFactor"))
|
|
@@ -738,28 +859,19 @@ def cosar_to_sicd(
|
|
|
738
859
|
1e-2,
|
|
739
860
|
)
|
|
740
861
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
radiometric.find("./{*}SigmaZeroSFPoly"), sigmazero_poly
|
|
752
|
-
)
|
|
753
|
-
sksicd.Poly2dType().set_elem(radiometric.find("./{*}BetaZeroSFPoly"), betazero_poly)
|
|
754
|
-
sksicd.Poly2dType().set_elem(
|
|
755
|
-
radiometric.find("./{*}GammaZeroSFPoly"), gammazero_poly
|
|
756
|
-
)
|
|
862
|
+
sicd_ew["Radiometric"] = {
|
|
863
|
+
"NoiseLevel": {
|
|
864
|
+
"NoiseLevelType": "ABSOLUTE",
|
|
865
|
+
"NoisePoly": noise_poly,
|
|
866
|
+
},
|
|
867
|
+
"SigmaZeroSFPoly": sigmazero_poly,
|
|
868
|
+
"BetaZeroSFPoly": betazero_poly,
|
|
869
|
+
"GammaZeroSFPoly": gammazero_poly,
|
|
870
|
+
}
|
|
871
|
+
|
|
757
872
|
if rcs_row_sf and rcs_col_sf:
|
|
758
873
|
rcssf_poly = betazero_poly * (rcs_row_sf * rcs_col_sf / (row_bw * col_bw))
|
|
759
|
-
|
|
760
|
-
sksicd.Poly2dType().set_elem(radiometric.find("./{*}RCSSFPoly"), rcssf_poly)
|
|
761
|
-
|
|
762
|
-
sicd_xml_obj.find("./{*}RMA").addprevious(radiometric)
|
|
874
|
+
sicd_ew["Radiometric"]["RCSSFPoly"] = rcssf_poly
|
|
763
875
|
|
|
764
876
|
# Add Geodata Corners
|
|
765
877
|
sicd_xmltree = sicd_xml_obj.getroottree()
|
|
@@ -776,18 +888,15 @@ def cosar_to_sicd(
|
|
|
776
888
|
sarkit.wgs84.up(sarkit.wgs84.cartesian_to_geodetic(scp_ecf)),
|
|
777
889
|
)
|
|
778
890
|
icp_llh = sarkit.wgs84.cartesian_to_geodetic(icp_ecef)
|
|
779
|
-
|
|
780
|
-
sksicd.ImageCornersType().set_elem(image_corners, icp_llh[:, :2])
|
|
781
|
-
geo_data.append(image_corners)
|
|
891
|
+
sicd_ew["GeoData"]["ImageCorners"] = icp_llh[:, :2]
|
|
782
892
|
|
|
783
893
|
# Add RNIIRS
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
sicd.Parameter({"name": "INFORMATION_DENSITY"}, f"{inf_density:.2g}")
|
|
894
|
+
inf_density, pred_rniirs = utils.get_rniirs_estimate(sicd_ew)
|
|
895
|
+
sicd_ew["CollectionInfo"].add(
|
|
896
|
+
"Parameter", ("INFORMATION_DENSITY", f"{inf_density:.2g}")
|
|
788
897
|
)
|
|
789
|
-
|
|
790
|
-
|
|
898
|
+
sicd_ew["CollectionInfo"].add(
|
|
899
|
+
"Parameter", ("PREDICTED_RNIIRS", f"{pred_rniirs:.1f}")
|
|
791
900
|
)
|
|
792
901
|
|
|
793
902
|
# Validate XML
|
|
@@ -803,7 +912,7 @@ def cosar_to_sicd(
|
|
|
803
912
|
metadata = sksicd.NitfMetadata(
|
|
804
913
|
xmltree=sicd_xmltree,
|
|
805
914
|
file_header_part={
|
|
806
|
-
"ostaid":
|
|
915
|
+
"ostaid": originator_facility,
|
|
807
916
|
"ftitle": core_name,
|
|
808
917
|
"security": {
|
|
809
918
|
"clas": classification[0].upper(),
|
|
@@ -847,17 +956,12 @@ def main(args=None):
|
|
|
847
956
|
type=pathlib.Path,
|
|
848
957
|
help='path of the output SICD file. The string "{pol}" will be replaced with polarization for multiple images',
|
|
849
958
|
)
|
|
850
|
-
parser.add_argument(
|
|
851
|
-
"--ostaid",
|
|
852
|
-
help="content of the originating station ID (OSTAID) field of the NITF header",
|
|
853
|
-
default="Unknown",
|
|
854
|
-
)
|
|
855
959
|
config = parser.parse_args(args)
|
|
856
960
|
|
|
857
961
|
if not config.input_xml_file.is_file():
|
|
858
962
|
raise ValueError(f"Input XML file {str(config.input_xml_file)} is not a file")
|
|
859
963
|
|
|
860
|
-
tsx_xml = etree.parse(config.input_xml_file).getroot()
|
|
964
|
+
tsx_xml = lxml.etree.parse(config.input_xml_file).getroot()
|
|
861
965
|
|
|
862
966
|
images = dict()
|
|
863
967
|
img_ndx = 1
|
|
@@ -895,7 +999,6 @@ def main(args=None):
|
|
|
895
999
|
cosar_file=img_info["cosar_filename"],
|
|
896
1000
|
sicd_file=img_info["sicd_filename"],
|
|
897
1001
|
classification=config.classification,
|
|
898
|
-
ostaid=config.ostaid,
|
|
899
1002
|
chan_index=img_info["chan_index"],
|
|
900
1003
|
tx_polarizations=tx_polarizations,
|
|
901
1004
|
tx_rcv_pols=tx_rcv_pols,
|