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
|
@@ -17,11 +17,15 @@ metadata that would predict the complex data characteristics
|
|
|
17
17
|
|
|
18
18
|
import argparse
|
|
19
19
|
import contextlib
|
|
20
|
+
import datetime
|
|
20
21
|
import pathlib
|
|
21
22
|
|
|
23
|
+
import astropy.coordinates as apcoord
|
|
24
|
+
import astropy.units as apu
|
|
25
|
+
import astropy.utils
|
|
22
26
|
import dateutil.parser
|
|
23
27
|
import h5py
|
|
24
|
-
import lxml.
|
|
28
|
+
import lxml.etree
|
|
25
29
|
import numpy as np
|
|
26
30
|
import numpy.linalg as npl
|
|
27
31
|
import numpy.polynomial.polynomial as npp
|
|
@@ -30,9 +34,13 @@ import sarkit.verification
|
|
|
30
34
|
import sarkit.wgs84
|
|
31
35
|
import scipy.constants
|
|
32
36
|
import scipy.optimize
|
|
37
|
+
import scipy.spatial.transform
|
|
33
38
|
|
|
39
|
+
from sarkit_convert import __version__
|
|
34
40
|
from sarkit_convert import _utils as utils
|
|
35
41
|
|
|
42
|
+
astropy.utils.iers.conf.autodownload = False
|
|
43
|
+
|
|
36
44
|
NSMAP = {
|
|
37
45
|
"sicd": "urn:SICD:1.4.0",
|
|
38
46
|
}
|
|
@@ -130,7 +138,6 @@ def hdf5_to_sicd(
|
|
|
130
138
|
h5_filename,
|
|
131
139
|
sicd_filename,
|
|
132
140
|
classification,
|
|
133
|
-
ostaid,
|
|
134
141
|
img_str,
|
|
135
142
|
chan_index,
|
|
136
143
|
tx_polarizations,
|
|
@@ -141,8 +148,10 @@ def hdf5_to_sicd(
|
|
|
141
148
|
mission_id = h5_attrs["Mission ID"]
|
|
142
149
|
if mission_id == "CSG":
|
|
143
150
|
dataset_str = "IMG"
|
|
151
|
+
burst_str = "B0001"
|
|
144
152
|
else:
|
|
145
153
|
dataset_str = "SBI"
|
|
154
|
+
burst_str = "B001"
|
|
146
155
|
sample_data_h5_path = f"{img_str}/{dataset_str}"
|
|
147
156
|
sample_data_shape = h5file[sample_data_h5_path].shape
|
|
148
157
|
sample_data_dtype = h5file[sample_data_h5_path].dtype
|
|
@@ -171,7 +180,6 @@ def hdf5_to_sicd(
|
|
|
171
180
|
|
|
172
181
|
# Creation Info
|
|
173
182
|
creation_time = dateutil.parser.parse(h5_attrs["Product Generation UTC"])
|
|
174
|
-
creation_site = h5_attrs["Processing Centre"]
|
|
175
183
|
l0_ver = h5_attrs.get("L0 Software Version", "NONE")
|
|
176
184
|
l1_ver = h5_attrs.get("L1A Software Version", "NONE")
|
|
177
185
|
creation_application = f"L0: {l0_ver}, L1: {l1_ver}"
|
|
@@ -311,31 +319,34 @@ def hdf5_to_sicd(
|
|
|
311
319
|
range_rate_per_hz = -scipy.constants.speed_of_light / (2 * center_frequency)
|
|
312
320
|
range_rate = doppler_centroid * range_rate_per_hz
|
|
313
321
|
range_rate_rate = doppler_rate * range_rate_per_hz
|
|
314
|
-
doppler_centroid_poly = utils.
|
|
322
|
+
doppler_centroid_poly = utils.polyfit2d_tol(
|
|
315
323
|
grid_coords[..., 0].flatten(),
|
|
316
324
|
grid_coords[..., 1].flatten(),
|
|
317
325
|
doppler_centroid.flatten(),
|
|
318
326
|
4,
|
|
319
327
|
4,
|
|
328
|
+
1e-2,
|
|
320
329
|
)
|
|
321
|
-
doppler_rate_poly = utils.
|
|
330
|
+
doppler_rate_poly = utils.polyfit2d_tol(
|
|
322
331
|
grid_coords[..., 0].flatten(),
|
|
323
332
|
grid_coords[..., 1].flatten(),
|
|
324
333
|
doppler_rate.flatten(),
|
|
325
334
|
4,
|
|
326
335
|
4,
|
|
336
|
+
1e-3,
|
|
327
337
|
)
|
|
328
338
|
time_ca_samps = time_coords[..., 1] - start_minus_ref
|
|
329
339
|
time_ca_poly = npp.polyfit(
|
|
330
340
|
grid_coords[..., 1].flatten(), time_ca_samps.flatten(), 1
|
|
331
341
|
)
|
|
332
342
|
time_coa_samps = time_ca_samps + range_rate / range_rate_rate
|
|
333
|
-
time_coa_poly = utils.
|
|
343
|
+
time_coa_poly = utils.polyfit2d_tol(
|
|
334
344
|
grid_coords[..., 0].flatten(),
|
|
335
345
|
grid_coords[..., 1].flatten(),
|
|
336
346
|
time_coa_samps.flatten(),
|
|
337
347
|
4,
|
|
338
348
|
4,
|
|
349
|
+
1e-3,
|
|
339
350
|
)
|
|
340
351
|
|
|
341
352
|
range_ca = time_coords[..., 0] * scipy.constants.speed_of_light / 2
|
|
@@ -344,12 +355,13 @@ def hdf5_to_sicd(
|
|
|
344
355
|
axis=0,
|
|
345
356
|
)
|
|
346
357
|
drsf = range_rate_rate * range_ca / speed_ca**2
|
|
347
|
-
drsf_poly = utils.
|
|
358
|
+
drsf_poly = utils.polyfit2d_tol(
|
|
348
359
|
grid_coords[..., 0].flatten(),
|
|
349
360
|
grid_coords[..., 1].flatten(),
|
|
350
361
|
drsf.flatten(),
|
|
351
362
|
4,
|
|
352
363
|
4,
|
|
364
|
+
1e-6,
|
|
353
365
|
)
|
|
354
366
|
|
|
355
367
|
llh_ddm = h5_attrs["Scene Centre Geodetic Coordinates"]
|
|
@@ -398,53 +410,198 @@ def hdf5_to_sicd(
|
|
|
398
410
|
uspz = spz / npl.norm(spz)
|
|
399
411
|
u_col = np.cross(uspz, u_row)
|
|
400
412
|
|
|
401
|
-
#
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
413
|
+
# Antenna
|
|
414
|
+
attitude_quaternion = np.roll(h5_attrs["Attitude Quaternions"], -1, axis=1)
|
|
415
|
+
attitude_times = h5_attrs["Attitude Times"]
|
|
416
|
+
attitude_utcs = [
|
|
417
|
+
ref_time + datetime.timedelta(seconds=attitude_time)
|
|
418
|
+
for attitude_time in attitude_times
|
|
419
|
+
]
|
|
420
|
+
|
|
421
|
+
inertial_position = h5_attrs["Inertial Satellite Position"]
|
|
422
|
+
inertial_velocity = h5_attrs["Inertial Satellite Velocity"]
|
|
423
|
+
inertial_acceleration = h5_attrs["Inertial Satellite Acceleration"]
|
|
424
|
+
eci_apc_poly = utils.fit_state_vectors(
|
|
425
|
+
(0, (collection_stop_time - collection_start_time).total_seconds()),
|
|
426
|
+
h5_attrs["State Vectors Times"]
|
|
427
|
+
- (collection_start_time - ref_time).total_seconds(),
|
|
428
|
+
inertial_position,
|
|
429
|
+
inertial_velocity,
|
|
430
|
+
inertial_acceleration,
|
|
431
|
+
order=5,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
def get_nadir_plane_at_time(time):
|
|
435
|
+
obstime = collection_start_time + datetime.timedelta(seconds=time)
|
|
436
|
+
eci_pos = npp.polyval(time, eci_apc_poly)
|
|
437
|
+
eci_vel = npp.polyval(time, npp.polyder(eci_apc_poly))
|
|
438
|
+
|
|
439
|
+
# Derived from https://adsabs.harvard.edu/full/2006ESASP.606E..35C, Section 3
|
|
440
|
+
z_sc = -eci_pos / np.linalg.norm(eci_pos)
|
|
441
|
+
y_sc_dir = np.cross(z_sc, eci_vel)
|
|
442
|
+
y_sc = y_sc_dir / np.linalg.norm(y_sc_dir)
|
|
443
|
+
x_sc = np.cross(y_sc, z_sc)
|
|
444
|
+
eci_2_ecf = np.array(
|
|
445
|
+
[
|
|
446
|
+
apcoord.GCRS(
|
|
447
|
+
apcoord.CartesianRepresentation(1, 0, 0, unit=apu.m),
|
|
448
|
+
obstime=obstime,
|
|
449
|
+
)
|
|
450
|
+
.transform_to(apcoord.ITRS(obstime=obstime))
|
|
451
|
+
.data.xyz.value,
|
|
452
|
+
apcoord.GCRS(
|
|
453
|
+
apcoord.CartesianRepresentation(0, 1, 0, unit=apu.m),
|
|
454
|
+
obstime=obstime,
|
|
455
|
+
)
|
|
456
|
+
.transform_to(apcoord.ITRS(obstime=obstime))
|
|
457
|
+
.data.xyz.value,
|
|
458
|
+
apcoord.GCRS(
|
|
459
|
+
apcoord.CartesianRepresentation(0, 0, 1, unit=apu.m),
|
|
460
|
+
obstime=obstime,
|
|
461
|
+
)
|
|
462
|
+
.transform_to(apcoord.ITRS(obstime=obstime))
|
|
463
|
+
.data.xyz.value,
|
|
464
|
+
]
|
|
465
|
+
)
|
|
466
|
+
x_sc = x_sc @ eci_2_ecf
|
|
467
|
+
y_sc = y_sc @ eci_2_ecf
|
|
468
|
+
z_sc = z_sc @ eci_2_ecf
|
|
469
|
+
return np.array([x_sc, y_sc, z_sc])
|
|
470
|
+
|
|
471
|
+
rel_att_times = np.array(
|
|
472
|
+
[(att_utc - collection_start_time).total_seconds() for att_utc in attitude_utcs]
|
|
473
|
+
)
|
|
474
|
+
good_indices = np.where(
|
|
475
|
+
np.logical_and(
|
|
476
|
+
np.less(-60, rel_att_times),
|
|
477
|
+
np.less(rel_att_times, 60 + collection_duration),
|
|
478
|
+
)
|
|
479
|
+
)
|
|
480
|
+
good_times = rel_att_times[good_indices]
|
|
481
|
+
good_att_quat = attitude_quaternion[good_indices]
|
|
482
|
+
nadir_planes = [get_nadir_plane_at_time(time) for time in good_times]
|
|
483
|
+
body_frame = np.array(
|
|
484
|
+
[
|
|
485
|
+
scipy.spatial.transform.Rotation.from_quat(att_quat)
|
|
486
|
+
.inv()
|
|
487
|
+
.apply(nadir_plane.T)
|
|
488
|
+
.T
|
|
489
|
+
for att_quat, nadir_plane in zip(good_att_quat, nadir_planes)
|
|
490
|
+
]
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
ux_rot = body_frame[:, 0, :]
|
|
494
|
+
uy_rot = body_frame[:, 1, :]
|
|
495
|
+
|
|
496
|
+
ant_x_dir_poly = utils.fit_state_vectors(
|
|
497
|
+
(0, (collection_stop_time - collection_start_time).total_seconds()),
|
|
498
|
+
good_times,
|
|
499
|
+
ux_rot,
|
|
500
|
+
None,
|
|
501
|
+
None,
|
|
502
|
+
order=4,
|
|
503
|
+
)
|
|
504
|
+
ant_y_dir_poly = utils.fit_state_vectors(
|
|
505
|
+
(0, (collection_stop_time - collection_start_time).total_seconds()),
|
|
506
|
+
good_times,
|
|
507
|
+
uy_rot,
|
|
508
|
+
None,
|
|
509
|
+
None,
|
|
510
|
+
order=4,
|
|
446
511
|
)
|
|
447
512
|
|
|
513
|
+
freq_zero = h5_attrs["Radar Frequency"]
|
|
514
|
+
antenna_beam_elevation = h5_attrs[img_str]["Antenna Beam Elevation"]
|
|
515
|
+
fit_order = 4
|
|
516
|
+
|
|
517
|
+
def fit_steering(code_change_lines, dcs):
|
|
518
|
+
if len(code_change_lines) > 1:
|
|
519
|
+
times = code_change_lines / prf
|
|
520
|
+
return npp.polyfit(times, dcs, fit_order)
|
|
521
|
+
else:
|
|
522
|
+
return np.array(dcs).reshape((1,))
|
|
523
|
+
|
|
524
|
+
if radar_mode_type != "STRIPMAP":
|
|
525
|
+
azimuth_ramp_code_change_lines = h5_attrs[img_str][burst_str][
|
|
526
|
+
"Azimuth Ramp Code Change Lines"
|
|
527
|
+
]
|
|
528
|
+
azimuth_steering = h5_attrs[img_str][burst_str]["Azimuth Steering"]
|
|
529
|
+
elevation_ramp_code_change_lines = h5_attrs[img_str][burst_str][
|
|
530
|
+
"Elevation Ramp Code Change Lines"
|
|
531
|
+
]
|
|
532
|
+
elevation_steering = h5_attrs[img_str][burst_str]["Elevation Steering"]
|
|
533
|
+
eb_dcx = np.sin(np.deg2rad(azimuth_steering))
|
|
534
|
+
eb_dcx_poly = fit_steering(azimuth_ramp_code_change_lines, eb_dcx)
|
|
535
|
+
eb_dcy = -np.sin(np.deg2rad(antenna_beam_elevation + elevation_steering))
|
|
536
|
+
eb_dcy_poly = fit_steering(elevation_ramp_code_change_lines, eb_dcy)
|
|
537
|
+
else:
|
|
538
|
+
eb_dcx_poly = [0.0]
|
|
539
|
+
eb_dcy_poly = [-np.sin(np.deg2rad(antenna_beam_elevation))]
|
|
540
|
+
|
|
541
|
+
antenna_az_gains = h5_attrs[img_str]["Azimuth Antenna Pattern Gains"]
|
|
542
|
+
antenna_az_origin = h5_attrs[img_str]["Azimuth Antenna Pattern Origin"]
|
|
543
|
+
antenna_az_spacing = h5_attrs[img_str]["Azimuth Antenna Pattern Resolution"]
|
|
544
|
+
|
|
545
|
+
antenna_rg_gains = h5_attrs[img_str]["Range Antenna Pattern Gains"]
|
|
546
|
+
antenna_rg_origin = h5_attrs[img_str]["Range Antenna Pattern Origin"]
|
|
547
|
+
antenna_rg_spacing = h5_attrs[img_str]["Range Antenna Pattern Resolution"]
|
|
548
|
+
|
|
549
|
+
def fit_gains(origin, spacing, gains):
|
|
550
|
+
fit_limit = -9
|
|
551
|
+
array_mask = gains > fit_limit
|
|
552
|
+
dcs = np.sin(np.deg2rad(origin + spacing * np.arange(len(gains))))
|
|
553
|
+
return npp.polyfit(dcs[array_mask], gains[array_mask], fit_order)
|
|
554
|
+
|
|
555
|
+
antenna_array_gain = np.zeros((fit_order + 1, fit_order + 1), dtype=float)
|
|
556
|
+
antenna_array_gain[0, :] = fit_gains(
|
|
557
|
+
antenna_rg_origin, antenna_rg_spacing, antenna_rg_gains
|
|
558
|
+
)
|
|
559
|
+
antenna_array_gain[:, 0] = fit_gains(
|
|
560
|
+
antenna_az_origin, antenna_az_spacing, antenna_az_gains
|
|
561
|
+
)
|
|
562
|
+
antenna_array_gain[0, 0] = 0.0
|
|
563
|
+
|
|
564
|
+
# Build XML
|
|
565
|
+
sicd_xml_obj = lxml.etree.Element(
|
|
566
|
+
f"{{{NSMAP['sicd']}}}SICD", nsmap={None: NSMAP["sicd"]}
|
|
567
|
+
)
|
|
568
|
+
sicd_ew = sksicd.ElementWrapper(sicd_xml_obj)
|
|
569
|
+
|
|
570
|
+
sicd_ew["CollectionInfo"] = {
|
|
571
|
+
"CollectorName": collector_name,
|
|
572
|
+
"CoreName": core_name,
|
|
573
|
+
"CollectType": "MONOSTATIC",
|
|
574
|
+
"RadarMode": {
|
|
575
|
+
"ModeType": radar_mode_type,
|
|
576
|
+
"ModeID": radar_mode_id,
|
|
577
|
+
},
|
|
578
|
+
"Classification": classification,
|
|
579
|
+
}
|
|
580
|
+
sicd_ew["ImageCreation"] = {
|
|
581
|
+
"Application": creation_application,
|
|
582
|
+
"DateTime": creation_time,
|
|
583
|
+
}
|
|
584
|
+
sicd_ew["ImageData"] = {
|
|
585
|
+
"PixelType": pixel_type,
|
|
586
|
+
"NumRows": num_rows,
|
|
587
|
+
"NumCols": num_cols,
|
|
588
|
+
"FirstRow": first_row,
|
|
589
|
+
"FirstCol": first_col,
|
|
590
|
+
"FullImage": {
|
|
591
|
+
"NumRows": num_rows,
|
|
592
|
+
"NumCols": num_cols,
|
|
593
|
+
},
|
|
594
|
+
"SCPPixel": scp_pixel,
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
sicd_ew["GeoData"] = {
|
|
598
|
+
"EarthModel": "WGS_84",
|
|
599
|
+
"SCP": {
|
|
600
|
+
"ECF": scp_ecf,
|
|
601
|
+
"LLH": scp_llh,
|
|
602
|
+
},
|
|
603
|
+
}
|
|
604
|
+
|
|
448
605
|
dc_sgn = np.sign(-doppler_rate_poly[0, 0])
|
|
449
606
|
col_deltakcoa_poly = (
|
|
450
607
|
-look * dc_sgn * doppler_centroid_poly * intervals[1] / spacings[1]
|
|
@@ -468,168 +625,180 @@ def hdf5_to_sicd(
|
|
|
468
625
|
col_window_name = h5_attrs["Azimuth Focusing Weighting Function"]
|
|
469
626
|
col_window_coeff = h5_attrs["Azimuth Focusing Weighting Coefficient"]
|
|
470
627
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
sksicd.Poly2dType().set_elem(grid.find("./{*}TimeCOAPoly"), time_coa_poly)
|
|
507
|
-
sksicd.Poly2dType().set_elem(grid.find("./{*}Row/{*}DeltaKCOAPoly"), [[0]])
|
|
508
|
-
sksicd.Poly2dType().set_elem(
|
|
509
|
-
grid.find("./{*}Col/{*}DeltaKCOAPoly"), col_deltakcoa_poly
|
|
510
|
-
)
|
|
628
|
+
sicd_ew["Grid"] = {
|
|
629
|
+
"ImagePlane": "SLANT",
|
|
630
|
+
"Type": "RGZERO",
|
|
631
|
+
"TimeCOAPoly": time_coa_poly,
|
|
632
|
+
"Row": {
|
|
633
|
+
"UVectECF": u_row,
|
|
634
|
+
"SS": spacings[0],
|
|
635
|
+
"ImpRespWid": row_wid,
|
|
636
|
+
"Sgn": -1,
|
|
637
|
+
"ImpRespBW": row_bw,
|
|
638
|
+
"KCtr": center_frequency / (scipy.constants.speed_of_light / 2),
|
|
639
|
+
"DeltaK1": -row_bw / 2,
|
|
640
|
+
"DeltaK2": row_bw / 2,
|
|
641
|
+
"DeltaKCOAPoly": [[0.0]],
|
|
642
|
+
"WgtType": {
|
|
643
|
+
"WindowName": row_window_name,
|
|
644
|
+
"Parameter": [("COEFFICIENT", str(row_window_coeff))],
|
|
645
|
+
},
|
|
646
|
+
},
|
|
647
|
+
"Col": {
|
|
648
|
+
"UVectECF": u_col,
|
|
649
|
+
"SS": spacings[1],
|
|
650
|
+
"ImpRespWid": col_wid,
|
|
651
|
+
"Sgn": -1,
|
|
652
|
+
"ImpRespBW": col_bw,
|
|
653
|
+
"KCtr": 0.0,
|
|
654
|
+
"DeltaK1": dk1,
|
|
655
|
+
"DeltaK2": dk2,
|
|
656
|
+
"DeltaKCOAPoly": col_deltakcoa_poly,
|
|
657
|
+
"WgtType": {
|
|
658
|
+
"WindowName": col_window_name,
|
|
659
|
+
"Parameter": [("COEFFICIENT", str(col_window_coeff))],
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
}
|
|
511
663
|
rcs_row_sf = None
|
|
512
664
|
rcs_col_sf = None
|
|
513
665
|
if row_window_name == "HAMMING":
|
|
514
666
|
wgts = scipy.signal.windows.general_hamming(512, row_window_coeff, sym=True)
|
|
515
|
-
|
|
516
|
-
sksicd.TRANSCODERS["Grid/Row/WgtFunct"].set_elem(wgtfunc, wgts)
|
|
517
|
-
grid.find("./{*}Row").append(wgtfunc)
|
|
667
|
+
sicd_ew["Grid"]["Row"]["WgtFunct"] = wgts
|
|
518
668
|
row_broadening_factor = utils.broadening_from_amp(wgts)
|
|
519
669
|
row_wid = row_broadening_factor / row_bw
|
|
520
|
-
|
|
670
|
+
sicd_ew["Grid"]["Row"]["ImpRespWid"] = row_wid
|
|
521
671
|
rcs_row_sf = 1 + np.var(wgts) / np.mean(wgts) ** 2
|
|
522
672
|
if col_window_name == "HAMMING":
|
|
523
673
|
wgts = scipy.signal.windows.general_hamming(512, col_window_coeff, sym=True)
|
|
524
|
-
|
|
525
|
-
sksicd.TRANSCODERS["Grid/Col/WgtFunct"].set_elem(wgtfunc, wgts)
|
|
526
|
-
grid.find("./{*}Col").append(wgtfunc)
|
|
674
|
+
sicd_ew["Grid"]["Col"]["WgtFunct"] = wgts
|
|
527
675
|
col_broadening_factor = utils.broadening_from_amp(wgts)
|
|
528
676
|
col_wid = col_broadening_factor / col_bw
|
|
529
|
-
|
|
677
|
+
sicd_ew["Grid"]["Col"]["ImpRespWid"] = col_wid
|
|
530
678
|
rcs_col_sf = 1 + np.var(wgts) / np.mean(wgts) ** 2
|
|
531
679
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
{
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
680
|
+
sicd_ew["Timeline"] = {
|
|
681
|
+
"CollectStart": collection_start_time,
|
|
682
|
+
"CollectDuration": collection_duration,
|
|
683
|
+
"IPP": {
|
|
684
|
+
"@size": 1,
|
|
685
|
+
"Set": [
|
|
686
|
+
{
|
|
687
|
+
"@index": 1,
|
|
688
|
+
"TStart": 0,
|
|
689
|
+
"TEnd": num_pulses / prf,
|
|
690
|
+
"IPPStart": 0,
|
|
691
|
+
"IPPEnd": num_pulses - 1,
|
|
692
|
+
"IPPPoly": [0, prf],
|
|
693
|
+
}
|
|
694
|
+
],
|
|
695
|
+
},
|
|
696
|
+
}
|
|
548
697
|
|
|
549
|
-
|
|
550
|
-
sksicd.XyzPolyType().set_elem(position.find("./{*}ARPPoly"), apc_poly)
|
|
698
|
+
sicd_ew["Position"]["ARPPoly"] = apc_poly
|
|
551
699
|
|
|
552
|
-
|
|
553
|
-
{"size": str(len(tx_rcv_pols))},
|
|
554
|
-
)
|
|
700
|
+
chan_parameters = []
|
|
555
701
|
for ndx, tx_rcv_pol in enumerate(tx_rcv_pols):
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
702
|
+
chan_parameters.append(
|
|
703
|
+
{
|
|
704
|
+
"@index": ndx + 1,
|
|
705
|
+
"TxRcvPolarization": tx_rcv_pol,
|
|
706
|
+
}
|
|
560
707
|
)
|
|
561
708
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
709
|
+
sicd_ew["RadarCollection"] = {
|
|
710
|
+
"TxFrequency": {
|
|
711
|
+
"Min": tx_freq_min,
|
|
712
|
+
"Max": tx_freq_max,
|
|
713
|
+
},
|
|
714
|
+
"Waveform": {
|
|
715
|
+
"@size": 1,
|
|
716
|
+
"WFParameters": [
|
|
717
|
+
{
|
|
718
|
+
"@index": 1,
|
|
719
|
+
"TxPulseLength": tx_pulse_length,
|
|
720
|
+
"TxRFBandwidth": tx_rf_bw,
|
|
721
|
+
"TxFreqStart": tx_freq_start,
|
|
722
|
+
"TxFMRate": tx_fm_rate,
|
|
723
|
+
"RcvWindowLength": rcv_window_length,
|
|
724
|
+
"ADCSampleRate": adc_sample_rate,
|
|
725
|
+
}
|
|
726
|
+
],
|
|
727
|
+
},
|
|
728
|
+
"TxPolarization": tx_polarization,
|
|
729
|
+
"RcvChannels": {
|
|
730
|
+
"@size": len(tx_rcv_pols),
|
|
731
|
+
"ChanParameters": chan_parameters,
|
|
732
|
+
},
|
|
733
|
+
}
|
|
579
734
|
if len(tx_polarizations) > 1:
|
|
580
|
-
|
|
581
|
-
|
|
735
|
+
sicd_ew["RadarCollection"]["TxPolarization"] = "SEQUENCE"
|
|
736
|
+
tx_steps = []
|
|
582
737
|
for ndx, tx_pol in enumerate(tx_polarizations):
|
|
583
|
-
|
|
584
|
-
|
|
738
|
+
tx_steps.append(
|
|
739
|
+
{
|
|
740
|
+
"@index": ndx + 1,
|
|
741
|
+
"TxPolarization": tx_pol,
|
|
742
|
+
}
|
|
585
743
|
)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
744
|
+
sicd_ew["RadarCollection"]["TxSequence"] = {
|
|
745
|
+
"@size": len(tx_polarizations),
|
|
746
|
+
"TxStep": tx_steps,
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
now = (
|
|
750
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
751
|
+
.isoformat(timespec="microseconds")
|
|
752
|
+
.replace("+00:00", "Z")
|
|
753
|
+
)
|
|
754
|
+
sicd_ew["ImageFormation"] = {
|
|
755
|
+
"RcvChanProc": {
|
|
756
|
+
"NumChanProc": 1,
|
|
757
|
+
"ChanIndex": [chan_index],
|
|
758
|
+
},
|
|
759
|
+
"TxRcvPolarizationProc": tx_rcv_polarization,
|
|
760
|
+
"TStartProc": 0,
|
|
761
|
+
"TEndProc": collection_duration,
|
|
762
|
+
"TxFrequencyProc": {
|
|
763
|
+
"MinProc": tx_freq_min,
|
|
764
|
+
"MaxProc": tx_freq_max,
|
|
765
|
+
},
|
|
766
|
+
"ImageFormAlgo": "RMA",
|
|
767
|
+
"STBeamComp": "NO",
|
|
768
|
+
"ImageBeamComp": "SV",
|
|
769
|
+
"AzAutofocus": "NO",
|
|
770
|
+
"RgAutofocus": "NO",
|
|
771
|
+
"Processing": [
|
|
772
|
+
{
|
|
773
|
+
"Type": f"sarkit-convert {__version__} @ {now}",
|
|
774
|
+
"Applied": True,
|
|
775
|
+
},
|
|
776
|
+
],
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
sicd_ew["Antenna"]["TwoWay"]["XAxisPoly"] = ant_x_dir_poly
|
|
780
|
+
sicd_ew["Antenna"]["TwoWay"]["YAxisPoly"] = ant_y_dir_poly
|
|
781
|
+
sicd_ew["Antenna"]["TwoWay"]["FreqZero"] = freq_zero
|
|
782
|
+
sicd_ew["Antenna"]["TwoWay"]["EB"]["DCXPoly"] = eb_dcx_poly
|
|
783
|
+
sicd_ew["Antenna"]["TwoWay"]["EB"]["DCYPoly"] = eb_dcy_poly
|
|
784
|
+
sicd_ew["Antenna"]["TwoWay"]["Array"]["GainPoly"] = antenna_array_gain
|
|
785
|
+
sicd_ew["Antenna"]["TwoWay"]["Array"]["PhasePoly"] = np.zeros(
|
|
786
|
+
dtype=float, shape=(1, 1)
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
sicd_ew["RMA"] = {
|
|
790
|
+
"RMAlgoType": "OMEGA_K",
|
|
791
|
+
"ImageType": "INCA",
|
|
792
|
+
"INCA": {
|
|
793
|
+
"TimeCAPoly": time_ca_poly,
|
|
794
|
+
"R_CA_SCP": scp_rca,
|
|
795
|
+
"FreqZero": center_frequency,
|
|
796
|
+
"DRateSFPoly": drsf_poly,
|
|
797
|
+
"DopCentroidPoly": doppler_centroid_poly,
|
|
798
|
+
},
|
|
799
|
+
}
|
|
631
800
|
|
|
632
|
-
|
|
801
|
+
sicd_ew["SCPCOA"] = sksicd.compute_scp_coa(sicd_xml_obj.getroottree())
|
|
633
802
|
|
|
634
803
|
# Add Radiometric
|
|
635
804
|
if mission_id == "CSK":
|
|
@@ -648,27 +817,16 @@ def hdf5_to_sicd(
|
|
|
648
817
|
sigmazero_poly = betazero_poly * np.cos(graze) * np.cos(twist)
|
|
649
818
|
gammazero_poly = betazero_poly / np.tan(graze) * np.cos(twist)
|
|
650
819
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
)
|
|
657
|
-
sksicd.Poly2dType().set_elem(
|
|
658
|
-
radiometric.find("./{*}BetaZeroSFPoly"), betazero_poly
|
|
659
|
-
)
|
|
660
|
-
sksicd.Poly2dType().set_elem(
|
|
661
|
-
radiometric.find("./{*}GammaZeroSFPoly"), gammazero_poly
|
|
662
|
-
)
|
|
820
|
+
sicd_ew["Radiometric"] = {
|
|
821
|
+
"SigmaZeroSFPoly": sigmazero_poly,
|
|
822
|
+
"BetaZeroSFPoly": betazero_poly,
|
|
823
|
+
"GammaZeroSFPoly": gammazero_poly,
|
|
824
|
+
}
|
|
663
825
|
if rcs_row_sf and rcs_col_sf:
|
|
664
826
|
rcssf_poly = betazero_poly * (
|
|
665
827
|
rcs_row_sf * rcs_col_sf / (row_bw * col_bw)
|
|
666
828
|
)
|
|
667
|
-
|
|
668
|
-
sksicd.Poly2dType().set_elem(
|
|
669
|
-
radiometric.find("./{*}RCSSFPoly"), rcssf_poly
|
|
670
|
-
)
|
|
671
|
-
sicd_xml_obj.find("./{*}RMA").addprevious(radiometric)
|
|
829
|
+
sicd_ew["Radiometric"]["RCSSFPoly"] = rcssf_poly
|
|
672
830
|
|
|
673
831
|
# Add Geodata Corners
|
|
674
832
|
sicd_xmltree = sicd_xml_obj.getroottree()
|
|
@@ -685,8 +843,7 @@ def hdf5_to_sicd(
|
|
|
685
843
|
sarkit.wgs84.up(sarkit.wgs84.cartesian_to_geodetic(scp_ecf)),
|
|
686
844
|
)
|
|
687
845
|
icp_llh = sarkit.wgs84.cartesian_to_geodetic(icp_ecef)
|
|
688
|
-
|
|
689
|
-
xml_helper.set("./{*}GeoData/{*}ImageCorners", icp_llh[:, :2])
|
|
846
|
+
sicd_ew["GeoData"]["ImageCorners"] = icp_llh[:, :2]
|
|
690
847
|
|
|
691
848
|
# Validate XML
|
|
692
849
|
sicd_con = sarkit.verification.SicdConsistency(sicd_xmltree)
|
|
@@ -708,7 +865,7 @@ def hdf5_to_sicd(
|
|
|
708
865
|
metadata = sksicd.NitfMetadata(
|
|
709
866
|
xmltree=sicd_xmltree,
|
|
710
867
|
file_header_part={
|
|
711
|
-
"ostaid":
|
|
868
|
+
"ostaid": h5_attrs["Processing Centre"],
|
|
712
869
|
"ftitle": core_name,
|
|
713
870
|
"security": {
|
|
714
871
|
"clas": classification[0].upper(),
|
|
@@ -756,11 +913,6 @@ def main(args=None):
|
|
|
756
913
|
type=pathlib.Path,
|
|
757
914
|
help='path of the output SICD file. The string "{pol}" will be replaced with polarization for multiple images',
|
|
758
915
|
)
|
|
759
|
-
parser.add_argument(
|
|
760
|
-
"--ostaid",
|
|
761
|
-
help="content of the originating station ID (OSTAID) field of the NITF header",
|
|
762
|
-
default="Unknown",
|
|
763
|
-
)
|
|
764
916
|
config = parser.parse_args(args)
|
|
765
917
|
|
|
766
918
|
tx_polarizations = []
|
|
@@ -810,7 +962,6 @@ def main(args=None):
|
|
|
810
962
|
h5_filename=config.input_h5_file,
|
|
811
963
|
sicd_filename=img_info["filename"],
|
|
812
964
|
classification=config.classification,
|
|
813
|
-
ostaid=config.ostaid,
|
|
814
965
|
img_str=img_str,
|
|
815
966
|
chan_index=img_info["chan_index"],
|
|
816
967
|
tx_polarizations=tx_polarizations,
|