sarkit-convert 0.1.0__py3-none-any.whl → 0.2.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 +32 -0
- sarkit_convert/_version.py +1 -1
- sarkit_convert/{csk.py → cosmo.py} +216 -59
- sarkit_convert/create_arp_poly.py +166 -0
- sarkit_convert/iceye.py +25 -14
- sarkit_convert/sentinel.py +224 -178
- sarkit_convert/sidd_metadata.py +201 -0
- sarkit_convert/{tsx.py → terrasar.py} +165 -62
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.2.0.dist-info}/METADATA +8 -18
- sarkit_convert-0.2.0.dist-info/RECORD +14 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.2.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.2.0.dist-info}/entry_points.txt +0 -0
- {sarkit_convert-0.1.0.dist-info → sarkit_convert-0.2.0.dist-info}/licenses/LICENSE +0 -0
sarkit_convert/sentinel.py
CHANGED
|
@@ -8,6 +8,7 @@ Convert a complex image(s) from the Sentinel SAFE to SICD(s).
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import argparse
|
|
11
|
+
import datetime
|
|
11
12
|
import pathlib
|
|
12
13
|
|
|
13
14
|
import dateutil.parser
|
|
@@ -138,6 +139,20 @@ def _collect_base_info(root_node):
|
|
|
138
139
|
# TOPSAR - closest SICD analog is Dynamic Stripmap
|
|
139
140
|
base_info["mode_type"] = "DYNAMIC STRIPMAP"
|
|
140
141
|
|
|
142
|
+
relative_orbit_num = int(
|
|
143
|
+
root_node.findtext(".//{*}relativeOrbitNumber[@type='start']")
|
|
144
|
+
)
|
|
145
|
+
base_info["parameters"] = {
|
|
146
|
+
"RELATIVE_ORBIT_NUM": relative_orbit_num,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
base_info["start_time_anx"] = float(
|
|
150
|
+
root_node.findtext(".//{*}acquisitionPeriod//{*}startTimeANX")
|
|
151
|
+
)
|
|
152
|
+
base_info["acq_start_str"] = root_node.findtext(
|
|
153
|
+
".//{*}acquisitionPeriod//{*}startTime"
|
|
154
|
+
)
|
|
155
|
+
|
|
141
156
|
# Image Creation
|
|
142
157
|
processing = root_node.find(
|
|
143
158
|
"./metadataSection/metadataObject[@ID='processing']/metadataWrap/xmlData/{*}processing",
|
|
@@ -148,9 +163,6 @@ def _collect_base_info(root_node):
|
|
|
148
163
|
f"{software.attrib['name']} {software.attrib['version']}"
|
|
149
164
|
)
|
|
150
165
|
base_info["creation_date_time"] = dateutil.parser.parse(processing.attrib["stop"])
|
|
151
|
-
base_info["creation_site"] = (
|
|
152
|
-
f"{facility.attrib['name']}, {facility.attrib['site']}, {facility.attrib['country']}"
|
|
153
|
-
)
|
|
154
166
|
|
|
155
167
|
# Radar Collection
|
|
156
168
|
polarizations = root_node.findall(
|
|
@@ -164,7 +176,7 @@ def _collect_base_info(root_node):
|
|
|
164
176
|
return base_info
|
|
165
177
|
|
|
166
178
|
|
|
167
|
-
def _collect_swath_info(product_root_node):
|
|
179
|
+
def _collect_swath_info(product_root_node, base_info):
|
|
168
180
|
swath_info = dict()
|
|
169
181
|
burst_list = product_root_node.findall("./swathTiming/burstList/burst")
|
|
170
182
|
|
|
@@ -173,12 +185,25 @@ def _collect_swath_info(product_root_node):
|
|
|
173
185
|
swath_info["mode_id"] = product_root_node.find("./adsHeader/mode").text
|
|
174
186
|
t_slice = _get_slice(product_root_node)
|
|
175
187
|
swath = _get_swath(product_root_node)
|
|
188
|
+
|
|
189
|
+
mission_data_take_id = product_root_node.find("./adsHeader/missionDataTakeId").text
|
|
176
190
|
swath_info["parameters"] = {
|
|
177
191
|
"SLICE": t_slice,
|
|
178
192
|
"SWATH": swath,
|
|
179
193
|
"ORBIT_SOURCE": "SLC_INTERNAL",
|
|
194
|
+
"MISSION_DATA_TAKE_ID": mission_data_take_id,
|
|
180
195
|
}
|
|
181
196
|
|
|
197
|
+
slice_list = product_root_node.findall(
|
|
198
|
+
"./imageAnnotation/imageInformation/sliceList/slice"
|
|
199
|
+
)
|
|
200
|
+
swath_info["sensing_start"] = dateutil.parser.parse(
|
|
201
|
+
slice_list[int(t_slice) - 1].find("./sensingStartTime").text
|
|
202
|
+
)
|
|
203
|
+
swath_info["sensing_stop"] = dateutil.parser.parse(
|
|
204
|
+
slice_list[int(t_slice) - 1].find("./sensingStopTime").text
|
|
205
|
+
)
|
|
206
|
+
|
|
182
207
|
# Radar Collection
|
|
183
208
|
center_frequency = float(
|
|
184
209
|
product_root_node.find(
|
|
@@ -226,8 +251,6 @@ def _collect_swath_info(product_root_node):
|
|
|
226
251
|
"./generalAnnotation/downlinkInformationList/downlinkInformation/prf"
|
|
227
252
|
).text
|
|
228
253
|
)
|
|
229
|
-
swath_info["t_start"] = 0
|
|
230
|
-
swath_info["ipp_start"] = 0
|
|
231
254
|
swath_info["ipp_poly"] = (0, swath_info["prf"])
|
|
232
255
|
|
|
233
256
|
# Image Formation
|
|
@@ -235,7 +258,6 @@ def _collect_swath_info(product_root_node):
|
|
|
235
258
|
f"{swath_info['tx_polarization']}:{swath_info['rcv_polarization']}"
|
|
236
259
|
)
|
|
237
260
|
swath_info["image_form_algo"] = "RMA"
|
|
238
|
-
swath_info["t_start_proc"] = 0
|
|
239
261
|
swath_info["tx_freq_proc"] = swath_info["tx_freq"]
|
|
240
262
|
swath_info["image_beam_comp"] = "SV"
|
|
241
263
|
swath_info["az_autofocus"] = "NO"
|
|
@@ -379,7 +401,7 @@ def _collect_swath_info(product_root_node):
|
|
|
379
401
|
return swath_info
|
|
380
402
|
|
|
381
403
|
|
|
382
|
-
def _collect_burst_info(product_root_node, swath_info):
|
|
404
|
+
def _collect_burst_info(product_root_node, base_info, swath_info):
|
|
383
405
|
burst_list = product_root_node.findall("./swathTiming/burstList/burst")
|
|
384
406
|
# parse the geolocation information - for SCP calculation
|
|
385
407
|
geo_grid_point_list = product_root_node.findall(
|
|
@@ -549,7 +571,7 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
549
571
|
)
|
|
550
572
|
|
|
551
573
|
# common use for the fitting efforts
|
|
552
|
-
poly_order =
|
|
574
|
+
poly_order = 4
|
|
553
575
|
grid_samples = poly_order + 4
|
|
554
576
|
num_rows = swath_info["num_rows"]
|
|
555
577
|
num_cols = swath_info["num_cols"]
|
|
@@ -584,12 +606,13 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
584
606
|
demod_phase = eta_arg * f_eta_c[:, np.newaxis]
|
|
585
607
|
total_phase = deramp_phase + demod_phase
|
|
586
608
|
|
|
587
|
-
phase = utils.
|
|
609
|
+
phase = utils.polyfit2d_tol(
|
|
588
610
|
coords_rg_2d.flatten(),
|
|
589
611
|
coords_az_2d.flatten(),
|
|
590
612
|
total_phase.flatten(),
|
|
591
613
|
poly_order,
|
|
592
|
-
poly_order,
|
|
614
|
+
poly_order + 1,
|
|
615
|
+
1e-2,
|
|
593
616
|
)
|
|
594
617
|
|
|
595
618
|
# DeltaKCOAPoly is derivative of phase in azimuth/Col direction
|
|
@@ -608,12 +631,13 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
608
631
|
)
|
|
609
632
|
time_coa_sampled = time_ca_sampled + dop_centroid_sampled / doppler_rate_sampled
|
|
610
633
|
|
|
611
|
-
burst_info["time_coa_poly_coefs"] = utils.
|
|
634
|
+
burst_info["time_coa_poly_coefs"] = utils.polyfit2d_tol(
|
|
612
635
|
coords_rg_2d.flatten(),
|
|
613
636
|
coords_az_2d.flatten(),
|
|
614
637
|
time_coa_sampled.flatten(),
|
|
615
638
|
poly_order,
|
|
616
639
|
poly_order,
|
|
640
|
+
1e-3,
|
|
617
641
|
)
|
|
618
642
|
|
|
619
643
|
full_img_verticies = np.array(
|
|
@@ -694,6 +718,28 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
694
718
|
|
|
695
719
|
return row_uvect_ecf, np.cross(uspz, row_uvect_ecf)
|
|
696
720
|
|
|
721
|
+
def _compute_burst_id(base_info, swath_info, burst_info):
|
|
722
|
+
"""Add `burst_id` to each burst info in `swaths_info` based on DI-MPC-IPFDPM, Issue 2.5, Clause 9.25"""
|
|
723
|
+
t_orb = 12 * 24 * 3600 / 175
|
|
724
|
+
t_pre = {"IW": 2.299849, "EW": 2.299970}[swath_info["mode_id"]]
|
|
725
|
+
t_beam = {"IW": 2.758273, "EW": 3.038376}[swath_info["mode_id"]]
|
|
726
|
+
|
|
727
|
+
acq_start_utc = datetime.datetime.fromisoformat(
|
|
728
|
+
base_info["acq_start_str"]
|
|
729
|
+
).replace(tzinfo=datetime.timezone.utc)
|
|
730
|
+
t_anx = acq_start_utc - datetime.timedelta(
|
|
731
|
+
milliseconds=base_info["start_time_anx"]
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
scp_tcoa = burst_info["time_coa_poly_coefs"][0, 0]
|
|
735
|
+
t_b = (
|
|
736
|
+
burst_info["collect_start"] + datetime.timedelta(seconds=scp_tcoa)
|
|
737
|
+
).replace(tzinfo=datetime.timezone.utc)
|
|
738
|
+
delta_t_b = (t_b - t_anx).total_seconds() + (
|
|
739
|
+
base_info["parameters"]["RELATIVE_ORBIT_NUM"] - 1
|
|
740
|
+
) * t_orb
|
|
741
|
+
return int(1 + (delta_t_b - t_pre) // t_beam)
|
|
742
|
+
|
|
697
743
|
def _finalize_stripmap():
|
|
698
744
|
burst_info = dict()
|
|
699
745
|
|
|
@@ -711,38 +757,34 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
711
757
|
(num_rows - 1, 0),
|
|
712
758
|
]
|
|
713
759
|
|
|
714
|
-
|
|
715
|
-
product_root_node.find(
|
|
716
|
-
"./generalAnnotation/downlinkInformationList/downlinkInformation/firstLineSensingTime"
|
|
717
|
-
).text
|
|
718
|
-
)
|
|
719
|
-
stop = dateutil.parser.parse(
|
|
720
|
-
product_root_node.find(
|
|
721
|
-
"./generalAnnotation/downlinkInformationList/downlinkInformation/lastLineSensingTime"
|
|
722
|
-
).text
|
|
723
|
-
)
|
|
724
|
-
slice = int(_get_slice(product_root_node))
|
|
760
|
+
t_slice = int(_get_slice(product_root_node))
|
|
725
761
|
swath = _get_swath(product_root_node)
|
|
726
762
|
burst_info["core_name"] = (
|
|
727
|
-
f"{
|
|
763
|
+
f"{swath_info['sensing_start'].strftime('%d%b%YT%H%M%S').upper()}_{product_root_node.find('./adsHeader/missionId').text}{product_root_node.find('./adsHeader/missionDataTakeId').text}_{t_slice:02d}_{swath}_01"
|
|
728
764
|
)
|
|
729
765
|
|
|
730
|
-
burst_info["parameters"] = {"BURST": f"{1:
|
|
766
|
+
burst_info["parameters"] = {"BURST": f"{1:02d}"}
|
|
767
|
+
|
|
731
768
|
prf = float(
|
|
732
769
|
product_root_node.find(
|
|
733
770
|
"./generalAnnotation/downlinkInformationList/downlinkInformation/prf"
|
|
734
771
|
).text
|
|
735
772
|
)
|
|
736
|
-
duration = (
|
|
773
|
+
duration = (
|
|
774
|
+
swath_info["sensing_stop"] - swath_info["sensing_start"]
|
|
775
|
+
).total_seconds()
|
|
737
776
|
|
|
738
|
-
burst_info["collect_start"] =
|
|
777
|
+
burst_info["collect_start"] = swath_info["sensing_start"]
|
|
739
778
|
burst_info["collect_duration"] = duration
|
|
779
|
+
burst_info["ipp_set_tstart"] = 0
|
|
740
780
|
burst_info["ipp_set_tend"] = duration
|
|
781
|
+
burst_info["ipp_set_ippstart"] = 0
|
|
741
782
|
burst_info["ipp_set_ippend"] = round(duration * prf) - 1
|
|
783
|
+
burst_info["tstart_proc"] = 0
|
|
742
784
|
burst_info["tend_proc"] = duration
|
|
743
785
|
|
|
744
786
|
burst_info["arp_poly_coefs"] = _compute_arp_poly_coefs(
|
|
745
|
-
product_root_node,
|
|
787
|
+
product_root_node, swath_info["sensing_start"]
|
|
746
788
|
).T
|
|
747
789
|
|
|
748
790
|
azimuth_time_first_line = dateutil.parser.parse(
|
|
@@ -750,9 +792,14 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
750
792
|
"./imageAnnotation/imageInformation/productFirstLineUtcTime"
|
|
751
793
|
).text
|
|
752
794
|
)
|
|
753
|
-
first_line_relative_start = (
|
|
795
|
+
first_line_relative_start = (
|
|
796
|
+
azimuth_time_first_line - swath_info["sensing_start"]
|
|
797
|
+
).total_seconds()
|
|
754
798
|
_, _ = _calc_rma_and_grid_info(
|
|
755
|
-
swath_info,
|
|
799
|
+
swath_info,
|
|
800
|
+
burst_info,
|
|
801
|
+
first_line_relative_start,
|
|
802
|
+
swath_info["sensing_start"],
|
|
756
803
|
)
|
|
757
804
|
burst_info["scp_ecf"], burst_info["scp_llh"] = _update_geo_data_info(
|
|
758
805
|
swath_info, burst_info
|
|
@@ -767,6 +814,7 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
767
814
|
burst_info_list = []
|
|
768
815
|
|
|
769
816
|
scps = _get_scps(swath_info, len(burst_list))
|
|
817
|
+
t_slice = int(_get_slice(product_root_node))
|
|
770
818
|
for j, burst in enumerate(burst_list):
|
|
771
819
|
# set preliminary geodata (required for projection)
|
|
772
820
|
burst_info = dict()
|
|
@@ -791,42 +839,53 @@ def _collect_burst_info(product_root_node, swath_info):
|
|
|
791
839
|
(last_row, first_col),
|
|
792
840
|
]
|
|
793
841
|
|
|
794
|
-
# This is the first and last zero doppler times of the columns in the burst.
|
|
795
|
-
# Not really CollectStart and CollectDuration in SICD (first last pulse time)
|
|
796
|
-
start = dateutil.parser.parse(burst.find("./azimuthTime").text)
|
|
797
|
-
t_slice = int(_get_slice(product_root_node))
|
|
798
842
|
swath = _get_swath(product_root_node)
|
|
843
|
+
# Use burst index for burst_id to maintain SARPy compatibility
|
|
799
844
|
burst_info["core_name"] = (
|
|
800
|
-
f"{
|
|
845
|
+
f"{swath_info['sensing_start'].strftime('%d%b%YT%H%M%S').upper()}_{product_root_node.find('./adsHeader/missionId').text}{product_root_node.find('./adsHeader/missionDataTakeId').text}_{t_slice:02d}_{swath}_{j + 1:02d}"
|
|
846
|
+
)
|
|
847
|
+
arp_poly_coefs = _compute_arp_poly_coefs(
|
|
848
|
+
product_root_node, swath_info["sensing_start"]
|
|
801
849
|
)
|
|
802
|
-
|
|
803
|
-
burst_info["parameters"] = {"BURST": f"{j + 1:d}"}
|
|
804
|
-
arp_poly_coefs = _compute_arp_poly_coefs(product_root_node, start)
|
|
805
850
|
burst_info["arp_poly_coefs"] = arp_poly_coefs.T
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
851
|
+
|
|
852
|
+
az_time = dateutil.parser.parse(burst.find("./azimuthTime").text)
|
|
853
|
+
first_line_relative_start = (
|
|
854
|
+
az_time - swath_info["sensing_start"]
|
|
855
|
+
).total_seconds()
|
|
856
|
+
early, late = _calc_rma_and_grid_info(
|
|
857
|
+
swath_info,
|
|
858
|
+
burst_info,
|
|
859
|
+
first_line_relative_start,
|
|
860
|
+
swath_info["sensing_start"],
|
|
861
|
+
)
|
|
809
862
|
prf = float(
|
|
810
863
|
product_root_node.find(
|
|
811
864
|
"./generalAnnotation/downlinkInformationList/downlinkInformation/prf"
|
|
812
865
|
).text
|
|
813
866
|
)
|
|
814
|
-
burst_info["collect_start"] =
|
|
815
|
-
burst_info["collect_duration"] =
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
burst_info["
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
burst_info["
|
|
822
|
-
burst_info["
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
867
|
+
burst_info["collect_start"] = swath_info["sensing_start"]
|
|
868
|
+
burst_info["collect_duration"] = (
|
|
869
|
+
swath_info["sensing_stop"] - swath_info["sensing_start"]
|
|
870
|
+
).total_seconds()
|
|
871
|
+
burst_info["ipp_set_tstart"] = early
|
|
872
|
+
burst_info["ipp_set_tend"] = late
|
|
873
|
+
burst_info["ipp_set_ippstart"] = round(early * prf)
|
|
874
|
+
burst_info["ipp_set_ippend"] = round(late * prf) - 1
|
|
875
|
+
burst_info["tstart_proc"] = early
|
|
876
|
+
burst_info["tend_proc"] = late
|
|
877
|
+
|
|
878
|
+
if burst.find("./burstId") is not None:
|
|
879
|
+
burst_id = burst.findtext("./burstId")
|
|
880
|
+
else:
|
|
881
|
+
burst_id = _compute_burst_id(base_info, swath_info, burst_info)
|
|
882
|
+
|
|
883
|
+
# Keep BURST as the index to maintain SARPy compatibility
|
|
884
|
+
burst_info["parameters"] = {
|
|
885
|
+
"BURST": f"{j + 1:02d}",
|
|
886
|
+
"BURST_ID": burst_id,
|
|
887
|
+
}
|
|
888
|
+
|
|
830
889
|
burst_info["arp_poly_coefs"] = arp_poly_coefs.T
|
|
831
890
|
|
|
832
891
|
burst_info["scp_ecf"], burst_info["scp_llh"] = _update_geo_data_info(
|
|
@@ -884,14 +943,15 @@ def _calc_radiometric_info(cal_file_name, swath_info, burst_info_list):
|
|
|
884
943
|
gamma = 1.0 / (gamma * gamma)
|
|
885
944
|
|
|
886
945
|
for idx, burst_info in enumerate(burst_info_list):
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
)
|
|
946
|
+
burst_first_line = idx * lines_per_burst
|
|
947
|
+
burst_last_line = burst_first_line + lines_per_burst
|
|
948
|
+
valid_lines = (line >= burst_first_line) & (line < burst_last_line)
|
|
890
949
|
valid_count = np.sum(valid_lines)
|
|
891
950
|
if valid_count == 0:
|
|
892
951
|
# this burst contained no useful calibration data
|
|
893
952
|
return
|
|
894
953
|
|
|
954
|
+
max_poly_order = 4
|
|
895
955
|
first_row = swath_info["first_row"]
|
|
896
956
|
first_col = swath_info["first_col"]
|
|
897
957
|
scp_row = swath_info["scp_pixel"][0]
|
|
@@ -899,32 +959,45 @@ def _calc_radiometric_info(cal_file_name, swath_info, burst_info_list):
|
|
|
899
959
|
row_ss = swath_info["row_ss"]
|
|
900
960
|
col_ss = swath_info["col_ss"]
|
|
901
961
|
coords_rg = (pixel[valid_lines] + first_row - scp_row) * row_ss
|
|
902
|
-
coords_az = (
|
|
962
|
+
coords_az = (
|
|
963
|
+
line[valid_lines] + first_col - scp_col - burst_first_line
|
|
964
|
+
) * col_ss
|
|
903
965
|
# NB: coords_rg = (valid_count, M) and coords_az = (valid_count, )
|
|
904
966
|
coords_az = np.repeat(coords_az, pixel.shape[1])
|
|
905
967
|
if valid_count > 1:
|
|
906
968
|
coords_az = coords_az.reshape((valid_count, -1))
|
|
969
|
+
max_poly_order_rg = min(max_poly_order, len(coords_rg) - 1)
|
|
970
|
+
max_poly_order_az = min(max_poly_order, len(coords_az) - 1)
|
|
907
971
|
|
|
908
|
-
|
|
972
|
+
sigma_vals = sigma[valid_lines, :].flatten()
|
|
973
|
+
sigma_tol = np.maximum(np.std(sigma_vals) * 1e-1, np.mean(sigma_vals) * 1e-2)
|
|
974
|
+
burst_info["radiometric"]["sigma_zero_poly_coefs"] = utils.polyfit2d_tol(
|
|
909
975
|
coords_rg.flatten(),
|
|
910
976
|
coords_az.flatten(),
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
977
|
+
sigma_vals,
|
|
978
|
+
max_poly_order_rg,
|
|
979
|
+
max_poly_order_az,
|
|
980
|
+
sigma_tol,
|
|
914
981
|
)
|
|
915
|
-
|
|
982
|
+
beta_vals = beta[valid_lines, :].flatten()
|
|
983
|
+
beta_tol = np.maximum(np.std(beta_vals) * 1e-1, np.mean(beta_vals) * 1e-2)
|
|
984
|
+
burst_info["radiometric"]["beta_zero_poly_coefs"] = utils.polyfit2d_tol(
|
|
916
985
|
coords_rg.flatten(),
|
|
917
986
|
coords_az.flatten(),
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
987
|
+
beta_vals,
|
|
988
|
+
max_poly_order_rg,
|
|
989
|
+
max_poly_order_az,
|
|
990
|
+
beta_tol,
|
|
921
991
|
)
|
|
922
|
-
|
|
992
|
+
gamma_vals = gamma[valid_lines, :].flatten()
|
|
993
|
+
gamma_tol = np.maximum(np.std(gamma_vals) * 1e-1, np.mean(gamma_vals) * 1e-2)
|
|
994
|
+
burst_info["radiometric"]["gamma_zero_poly_coefs"] = utils.polyfit2d_tol(
|
|
923
995
|
coords_rg.flatten(),
|
|
924
996
|
coords_az.flatten(),
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
997
|
+
gamma_vals,
|
|
998
|
+
max_poly_order_rg,
|
|
999
|
+
max_poly_order_az,
|
|
1000
|
+
gamma_tol,
|
|
928
1001
|
)
|
|
929
1002
|
|
|
930
1003
|
range_weight_f = azimuth_weight_f = 1.0
|
|
@@ -1017,7 +1090,7 @@ def _calc_noise_level_info(noise_file_name, swath_info, burst_info_list):
|
|
|
1017
1090
|
else:
|
|
1018
1091
|
azimuth_line, azimuth_noise = None, None
|
|
1019
1092
|
|
|
1020
|
-
rg_poly_order = min(
|
|
1093
|
+
rg_poly_order = min(4, range_pixel[0].size - 1)
|
|
1021
1094
|
first_row = swath_info["first_row"]
|
|
1022
1095
|
first_col = swath_info["first_col"]
|
|
1023
1096
|
scp_row = swath_info["scp_pixel"][0]
|
|
@@ -1033,12 +1106,13 @@ def _calc_noise_level_info(noise_file_name, swath_info, burst_info_list):
|
|
|
1033
1106
|
|
|
1034
1107
|
coords_az_2d, coords_rg_2d = np.meshgrid(coords_az, coords_rg)
|
|
1035
1108
|
|
|
1036
|
-
noise_poly = utils.
|
|
1109
|
+
noise_poly = utils.polyfit2d_tol(
|
|
1037
1110
|
coords_rg_2d.flatten(),
|
|
1038
1111
|
coords_az_2d.flatten(),
|
|
1039
1112
|
np.array(range_noise).flatten(),
|
|
1040
1113
|
rg_poly_order,
|
|
1041
1114
|
az_poly_order,
|
|
1115
|
+
1e-2,
|
|
1042
1116
|
)
|
|
1043
1117
|
else:
|
|
1044
1118
|
# TOPSAR has single LUT per burst
|
|
@@ -1083,9 +1157,8 @@ def _calc_noise_level_info(noise_file_name, swath_info, burst_info_list):
|
|
|
1083
1157
|
|
|
1084
1158
|
|
|
1085
1159
|
def _complete_filename(swath_info, burst_info, filename_template):
|
|
1086
|
-
core_name = burst_info["core_name"]
|
|
1087
|
-
burst = core_name[-2:]
|
|
1088
1160
|
swath = swath_info["parameters"]["SWATH"]
|
|
1161
|
+
burst = burst_info["parameters"]["BURST"]
|
|
1089
1162
|
polarization = swath_info["tx_rcv_polarization_proc"].replace(":", "")
|
|
1090
1163
|
formatted_name = filename_template.name.format(
|
|
1091
1164
|
swath=swath, burst=burst, pol=polarization
|
|
@@ -1098,8 +1171,11 @@ def _complete_filename(swath_info, burst_info, filename_template):
|
|
|
1098
1171
|
def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
1099
1172
|
em = lxml.builder.ElementMaker(namespace=NSMAP["sicd"], nsmap={None: NSMAP["sicd"]})
|
|
1100
1173
|
|
|
1174
|
+
sicd_xml_obj = em.SICD()
|
|
1175
|
+
sicd_ew = sksicd.ElementWrapper(sicd_xml_obj)
|
|
1176
|
+
|
|
1101
1177
|
# Collection Info
|
|
1102
|
-
|
|
1178
|
+
sicd_ew["CollectionInfo"] = em.CollectionInfo(
|
|
1103
1179
|
em.CollectorName(swath_info["collector_name"]),
|
|
1104
1180
|
em.CoreName(burst_info["core_name"]),
|
|
1105
1181
|
em.CollectType(base_info["collect_type"]),
|
|
@@ -1114,18 +1190,33 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1114
1190
|
em.Parameter(
|
|
1115
1191
|
{"name": "ORBIT_SOURCE"}, swath_info["parameters"]["ORBIT_SOURCE"]
|
|
1116
1192
|
),
|
|
1193
|
+
*(
|
|
1194
|
+
[
|
|
1195
|
+
em.Parameter(
|
|
1196
|
+
{"name": "BURST_ID"}, str(burst_info["parameters"]["BURST_ID"])
|
|
1197
|
+
)
|
|
1198
|
+
]
|
|
1199
|
+
if burst_info["parameters"].get("BURST_ID") is not None
|
|
1200
|
+
else []
|
|
1201
|
+
),
|
|
1202
|
+
em.Parameter(
|
|
1203
|
+
{"name": "MISSION_DATA_TAKE_ID"},
|
|
1204
|
+
swath_info["parameters"]["MISSION_DATA_TAKE_ID"],
|
|
1205
|
+
),
|
|
1206
|
+
em.Parameter(
|
|
1207
|
+
{"name": "RELATIVE_ORBIT_NUM"},
|
|
1208
|
+
str(base_info["parameters"]["RELATIVE_ORBIT_NUM"]),
|
|
1209
|
+
),
|
|
1117
1210
|
)
|
|
1118
1211
|
|
|
1119
1212
|
# Image Creation
|
|
1120
|
-
|
|
1213
|
+
sicd_ew["ImageCreation"] = em.ImageCreation(
|
|
1121
1214
|
em.Application(base_info["creation_application"]),
|
|
1122
1215
|
em.DateTime(base_info["creation_date_time"].strftime("%Y-%m-%dT%H:%M:%SZ")),
|
|
1123
|
-
em.Site(base_info["creation_site"]),
|
|
1124
|
-
em.Profile(f"sarkit-convert {__version__}"),
|
|
1125
1216
|
)
|
|
1126
1217
|
|
|
1127
1218
|
# Image Data
|
|
1128
|
-
|
|
1219
|
+
sicd_ew["ImageData"] = em.ImageData(
|
|
1129
1220
|
em.PixelType(swath_info["pixel_type"]),
|
|
1130
1221
|
em.NumRows(str(swath_info["num_rows"])),
|
|
1131
1222
|
em.NumCols(str(swath_info["num_cols"])),
|
|
@@ -1171,7 +1262,7 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1171
1262
|
return [em.Lat(str(arr[0])), em.Lon(str(arr[1])), em.HAE(str(arr[2]))]
|
|
1172
1263
|
|
|
1173
1264
|
# Geo Data
|
|
1174
|
-
|
|
1265
|
+
sicd_ew["GeoData"] = em.GeoData(
|
|
1175
1266
|
em.EarthModel("WGS_84"),
|
|
1176
1267
|
em.SCP(
|
|
1177
1268
|
em.ECF(*_make_xyz(burst_info["scp_ecf"])),
|
|
@@ -1182,7 +1273,7 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1182
1273
|
)
|
|
1183
1274
|
|
|
1184
1275
|
# Grid
|
|
1185
|
-
|
|
1276
|
+
sicd_ew["Grid"] = em.Grid(
|
|
1186
1277
|
em.ImagePlane(swath_info["image_plane"]),
|
|
1187
1278
|
em.Type(swath_info["grid_type"]),
|
|
1188
1279
|
em.TimeCOAPoly(),
|
|
@@ -1239,50 +1330,35 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1239
1330
|
),
|
|
1240
1331
|
),
|
|
1241
1332
|
)
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
)
|
|
1248
|
-
sksicd.Poly2dType().set_elem(
|
|
1249
|
-
grid_node.find("./{*}Col/{*}DeltaKCOAPoly"), burst_info["col_deltak_coa_poly"]
|
|
1250
|
-
)
|
|
1251
|
-
wgtfunc = em.WgtFunct()
|
|
1252
|
-
sksicd.TRANSCODERS["Grid/Row/WgtFunct"].set_elem(wgtfunc, swath_info["row_wgts"])
|
|
1253
|
-
grid_node.find("./{*}Row").append(wgtfunc)
|
|
1254
|
-
wgtfunc = em.WgtFunct()
|
|
1255
|
-
sksicd.TRANSCODERS["Grid/Col/WgtFunct"].set_elem(wgtfunc, swath_info["col_wgts"])
|
|
1256
|
-
grid_node.find("./{*}Col").append(wgtfunc)
|
|
1333
|
+
sicd_ew["Grid"]["TimeCOAPoly"] = burst_info["time_coa_poly_coefs"]
|
|
1334
|
+
sicd_ew["Grid"]["Row"]["DeltaKCOAPoly"] = swath_info["row_deltak_coa_poly"]
|
|
1335
|
+
sicd_ew["Grid"]["Col"]["DeltaKCOAPoly"] = burst_info["col_deltak_coa_poly"]
|
|
1336
|
+
sicd_ew["Grid"]["Row"]["WgtFunct"] = swath_info["row_wgts"]
|
|
1337
|
+
sicd_ew["Grid"]["Col"]["WgtFunct"] = swath_info["col_wgts"]
|
|
1257
1338
|
|
|
1258
1339
|
# Timeline
|
|
1259
|
-
|
|
1340
|
+
sicd_ew["Timeline"] = em.Timeline(
|
|
1260
1341
|
em.CollectStart(burst_info["collect_start"].strftime("%Y-%m-%dT%H:%M:%S.%fZ")),
|
|
1261
1342
|
em.CollectDuration(str(burst_info["collect_duration"])),
|
|
1262
1343
|
em.IPP(
|
|
1263
1344
|
{"size": "1"},
|
|
1264
1345
|
em.Set(
|
|
1265
1346
|
{"index": "1"},
|
|
1266
|
-
em.TStart(str(
|
|
1347
|
+
em.TStart(str(burst_info["ipp_set_tstart"])),
|
|
1267
1348
|
em.TEnd(str(burst_info["ipp_set_tend"])),
|
|
1268
|
-
em.IPPStart(str(
|
|
1349
|
+
em.IPPStart(str(burst_info["ipp_set_ippstart"])),
|
|
1269
1350
|
em.IPPEnd(str(burst_info["ipp_set_ippend"])),
|
|
1270
1351
|
em.IPPPoly(),
|
|
1271
1352
|
),
|
|
1272
1353
|
),
|
|
1273
1354
|
)
|
|
1274
|
-
|
|
1275
|
-
timeline_node.find("./{*}IPP/{*}Set/{*}IPPPoly"), swath_info["ipp_poly"]
|
|
1276
|
-
)
|
|
1355
|
+
sicd_ew["Timeline"]["IPP"]["Set"][0]["IPPPoly"] = swath_info["ipp_poly"]
|
|
1277
1356
|
|
|
1278
1357
|
# Position
|
|
1279
|
-
|
|
1280
|
-
sksicd.XyzPolyType().set_elem(
|
|
1281
|
-
position_node.find("./{*}ARPPoly"), burst_info["arp_poly_coefs"]
|
|
1282
|
-
)
|
|
1358
|
+
sicd_ew["Position"]["ARPPoly"] = burst_info["arp_poly_coefs"]
|
|
1283
1359
|
|
|
1284
1360
|
# Radar Collection
|
|
1285
|
-
|
|
1361
|
+
sicd_ew["RadarCollection"] = em.RadarCollection(
|
|
1286
1362
|
em.TxFrequency(
|
|
1287
1363
|
em.Min(str(swath_info["tx_freq"][0])),
|
|
1288
1364
|
em.Max(str(swath_info["tx_freq"][1])),
|
|
@@ -1321,14 +1397,19 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1321
1397
|
chan_indices = str(i)
|
|
1322
1398
|
|
|
1323
1399
|
# Image Formation
|
|
1324
|
-
|
|
1400
|
+
now = (
|
|
1401
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
1402
|
+
.isoformat(timespec="microseconds")
|
|
1403
|
+
.replace("+00:00", "Z")
|
|
1404
|
+
)
|
|
1405
|
+
sicd_ew["ImageFormation"] = em.ImageFormation(
|
|
1325
1406
|
em.RcvChanProc(
|
|
1326
1407
|
em.NumChanProc("1"),
|
|
1327
1408
|
em.PRFScaleFactor("1"),
|
|
1328
1409
|
em.ChanIndex(chan_indices),
|
|
1329
1410
|
),
|
|
1330
1411
|
em.TxRcvPolarizationProc(swath_info["tx_rcv_polarization_proc"]),
|
|
1331
|
-
em.TStartProc(str(
|
|
1412
|
+
em.TStartProc(str(burst_info["tstart_proc"])),
|
|
1332
1413
|
em.TEndProc(str(burst_info["tend_proc"])),
|
|
1333
1414
|
em.TxFrequencyProc(
|
|
1334
1415
|
em.MinProc(str(swath_info["tx_freq_proc"][0])),
|
|
@@ -1339,10 +1420,14 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1339
1420
|
em.ImageBeamComp(swath_info["image_beam_comp"]),
|
|
1340
1421
|
em.AzAutofocus(swath_info["az_autofocus"]),
|
|
1341
1422
|
em.RgAutofocus(swath_info["rg_autofocus"]),
|
|
1423
|
+
em.Processing(
|
|
1424
|
+
em.Type(f"sarkit-convert {__version__} @ {now}"),
|
|
1425
|
+
em.Applied("true"),
|
|
1426
|
+
),
|
|
1342
1427
|
)
|
|
1343
1428
|
|
|
1344
1429
|
# RMA
|
|
1345
|
-
|
|
1430
|
+
sicd_ew["RMA"] = em.RMA(
|
|
1346
1431
|
em.RMAlgoType(swath_info["rm_algo_type"]),
|
|
1347
1432
|
em.ImageType(swath_info["image_type"]),
|
|
1348
1433
|
em.INCA(
|
|
@@ -1354,65 +1439,33 @@ def _create_sicd_xml(base_info, swath_info, burst_info, classification):
|
|
|
1354
1439
|
em.DopCentroidCOA(swath_info["dop_centroid_coa"]),
|
|
1355
1440
|
),
|
|
1356
1441
|
)
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
)
|
|
1363
|
-
sksicd.Poly2dType().set_elem(
|
|
1364
|
-
rma_node.find("./{*}INCA/{*}DopCentroidPoly"),
|
|
1365
|
-
burst_info["doppler_centroid_poly_coefs"],
|
|
1366
|
-
)
|
|
1442
|
+
sicd_ew["RMA"]["INCA"]["TimeCAPoly"] = burst_info["time_ca_poly_coefs"]
|
|
1443
|
+
sicd_ew["RMA"]["INCA"]["DRateSFPoly"] = burst_info["drsf_poly_coefs"]
|
|
1444
|
+
sicd_ew["RMA"]["INCA"]["DopCentroidPoly"] = burst_info[
|
|
1445
|
+
"doppler_centroid_poly_coefs"
|
|
1446
|
+
]
|
|
1367
1447
|
|
|
1368
|
-
sicd_xml_obj = em.SICD(
|
|
1369
|
-
collection_info_node,
|
|
1370
|
-
image_creation_node,
|
|
1371
|
-
image_data_node,
|
|
1372
|
-
geo_data_node,
|
|
1373
|
-
grid_node,
|
|
1374
|
-
timeline_node,
|
|
1375
|
-
position_node,
|
|
1376
|
-
radar_collection_node,
|
|
1377
|
-
image_formation_node,
|
|
1378
|
-
rma_node,
|
|
1379
|
-
)
|
|
1380
|
-
breakpoint()
|
|
1381
1448
|
# Add Radiometric after Sentinel baseline processing calibration update on 25 Nov 2015.
|
|
1382
1449
|
if "radiometric" in burst_info:
|
|
1383
1450
|
# Radiometric
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
sksicd.Poly2dType().set_elem(
|
|
1403
|
-
radiometric_node.find("./{*}SigmaZeroSFPoly"),
|
|
1404
|
-
burst_info["radiometric"]["sigma_zero_poly_coefs"],
|
|
1405
|
-
)
|
|
1406
|
-
sksicd.Poly2dType().set_elem(
|
|
1407
|
-
radiometric_node.find("./{*}BetaZeroSFPoly"),
|
|
1408
|
-
burst_info["radiometric"]["beta_zero_poly_coefs"],
|
|
1409
|
-
)
|
|
1410
|
-
sksicd.Poly2dType().set_elem(
|
|
1411
|
-
radiometric_node.find("./{*}GammaZeroSFPoly"),
|
|
1412
|
-
burst_info["radiometric"]["gamma_zero_poly_coefs"],
|
|
1413
|
-
)
|
|
1414
|
-
|
|
1415
|
-
sicd_xml_obj.find("{*}RMA").addprevious(radiometric_node)
|
|
1451
|
+
sicd_ew["Radiometric"]["NoiseLevel"]["NoiseLevelType"] = burst_info[
|
|
1452
|
+
"radiometric"
|
|
1453
|
+
]["noise_level_type"]
|
|
1454
|
+
sicd_ew["Radiometric"]["NoiseLevel"]["NoisePoly"] = burst_info["radiometric"][
|
|
1455
|
+
"noise_poly_coefs"
|
|
1456
|
+
]
|
|
1457
|
+
sicd_ew["Radiometric"]["RCSSFPoly"] = burst_info["radiometric"][
|
|
1458
|
+
"rcs_sf_poly_coefs"
|
|
1459
|
+
]
|
|
1460
|
+
sicd_ew["Radiometric"]["SigmaZeroSFPoly"] = burst_info["radiometric"][
|
|
1461
|
+
"sigma_zero_poly_coefs"
|
|
1462
|
+
]
|
|
1463
|
+
sicd_ew["Radiometric"]["BetaZeroSFPoly"] = burst_info["radiometric"][
|
|
1464
|
+
"beta_zero_poly_coefs"
|
|
1465
|
+
]
|
|
1466
|
+
sicd_ew["Radiometric"]["GammaZeroSFPoly"] = burst_info["radiometric"][
|
|
1467
|
+
"gamma_zero_poly_coefs"
|
|
1468
|
+
]
|
|
1416
1469
|
|
|
1417
1470
|
return sicd_xml_obj
|
|
1418
1471
|
|
|
@@ -1481,12 +1534,6 @@ def main(args=None):
|
|
|
1481
1534
|
type=pathlib.Path,
|
|
1482
1535
|
help="path of the output SICD file. The strings '{swath}', '{burst}', '{pol}' will be replaced as appropriate for multiple images",
|
|
1483
1536
|
)
|
|
1484
|
-
parser.add_argument(
|
|
1485
|
-
"--ostaid",
|
|
1486
|
-
type=str,
|
|
1487
|
-
help="content of the originating station ID (OSTAID) field of the NITF header",
|
|
1488
|
-
default="Unknown",
|
|
1489
|
-
)
|
|
1490
1537
|
config = parser.parse_args(args)
|
|
1491
1538
|
|
|
1492
1539
|
manifest_filename = config.safe_product_folder / "manifest.safe"
|
|
@@ -1498,9 +1545,8 @@ def main(args=None):
|
|
|
1498
1545
|
used_filenames = set()
|
|
1499
1546
|
for entry in files:
|
|
1500
1547
|
product_root_node = et.parse(entry["product"]).getroot()
|
|
1501
|
-
swath_info = _collect_swath_info(product_root_node)
|
|
1502
|
-
burst_info_list = _collect_burst_info(product_root_node, swath_info)
|
|
1503
|
-
breakpoint()
|
|
1548
|
+
swath_info = _collect_swath_info(product_root_node, base_info)
|
|
1549
|
+
burst_info_list = _collect_burst_info(product_root_node, base_info, swath_info)
|
|
1504
1550
|
if base_info["creation_date_time"].date() >= np.datetime64("2015-11-25"):
|
|
1505
1551
|
[burst_info.update({"radiometric": {}}) for burst_info in burst_info_list]
|
|
1506
1552
|
_calc_radiometric_info(entry["calibration"], swath_info, burst_info_list)
|
|
@@ -1544,7 +1590,7 @@ def main(args=None):
|
|
|
1544
1590
|
metadata = sksicd.NitfMetadata(
|
|
1545
1591
|
xmltree=sicd.getroottree(),
|
|
1546
1592
|
file_header_part={
|
|
1547
|
-
"ostaid":
|
|
1593
|
+
"ostaid": "ESA",
|
|
1548
1594
|
"ftitle": xml_helper.load("{*}CollectionInfo/{*}CoreName"),
|
|
1549
1595
|
"security": {
|
|
1550
1596
|
"clas": config.classification[0].upper(),
|