10
10
11
11
12
12
# Other functionalities
13
- def compute_az_carrier (burst , orbit , offset , position ):
14
- '''
15
- Estimate azimuth carrier and store in numpy arrary
16
-
17
- Parameters
18
- ----------
19
- burst: Sentinel1BurstSlc
20
- Sentinel1 burst object
21
- orbit: isce3.core.Orbit
22
- Sentinel1 orbit ephemerides
23
- offset: float
24
- Offset between reference and secondary burst
25
- position: tuple
26
- Tuple of locations along y and x directions
27
-
28
- Returns
29
- -------
30
- carr: np.ndarray
31
- Azimuth carrier
32
- '''
33
-
34
- # Get burst sensing mid relative to orbit reference epoch
35
- fmt = "%Y-%m-%dT%H:%M:%S.%f"
36
- orbit_ref_epoch = datetime .datetime .strptime (orbit .reference_epoch .__str__ ()[:- 3 ], fmt )
37
-
38
- t_mid = burst .sensing_mid - orbit_ref_epoch
39
- _ , v = orbit .interpolate (t_mid .total_seconds ())
40
- vs = np .linalg .norm (v )
41
- ks = 2 * vs * burst .azimuth_steer_rate / burst .wavelength
42
-
43
- y , x = position
44
-
45
- n_lines , _ = burst .shape
46
- eta = (y - (n_lines // 2 ) + offset ) * burst .azimuth_time_interval
47
- rng = burst .starting_range + x * burst .range_pixel_spacing
48
-
49
- f_etac = np .array (
50
- burst .doppler .poly1d .eval (rng .flatten ().tolist ())).reshape (rng .shape )
51
- ka = np .array (
52
- burst .azimuth_fm_rate .eval (rng .flatten ().tolist ())).reshape (rng .shape )
53
-
54
- eta_ref = (burst .doppler .poly1d .eval (
55
- burst .starting_range ) / burst .azimuth_fm_rate .eval (
56
- burst .starting_range )) - (f_etac / ka )
57
- kt = ks / (1.0 - ks / ka )
58
-
59
- carr = np .pi * kt * ((eta - eta_ref ) ** 2 )
60
-
61
- return carr
62
-
63
-
64
13
def polyfit (xin , yin , zin , azimuth_order , range_order ,
65
14
sig = None , snr = None , cond = 1.0e-12 ,
66
15
max_order = True ):
@@ -155,6 +104,19 @@ class represents a polynomial function of range
155
104
poly = isce3 .core .Poly2d (coeffs , xmin , ymin , xnorm , ynorm )
156
105
return poly
157
106
107
+ @dataclass
108
+ class AzimuthCarrierComponents :
109
+ kt : np .ndarray
110
+ eta : float
111
+ eta_ref : float
112
+
113
+ @property
114
+ def antenna_steering_doppler (self ):
115
+ return self .kt * (self .eta - self .eta_ref )
116
+
117
+ @property
118
+ def carrier (self ):
119
+ return np .pi * self .kt * ((self .eta - self .eta_ref ) ** 2 )
158
120
159
121
@dataclass (frozen = True )
160
122
class Doppler :
@@ -198,6 +160,7 @@ class Sentinel1BurstSlc:
198
160
range_window_coefficient : float
199
161
rank : int # The number of PRI between transmitted pulse and return echo.
200
162
prf_raw_data : float # Pulse repetition frequency (PRF) of the raw data [Hz]
163
+ range_chirp_rate : float # Range chirp rate [Hz]
201
164
202
165
def as_isce3_radargrid (self ):
203
166
'''Init and return isce3.product.RadarGridParameters.
@@ -339,14 +302,14 @@ class represents a polynomial function of range
339
302
x_mesh , y_mesh = np .meshgrid (x , y )
340
303
341
304
# Estimate azimuth carrier
342
- az_carrier = compute_az_carrier ( self , self . orbit ,
305
+ az_carr_comp = self . az_carrier_components (
343
306
offset = offset ,
344
307
position = (y_mesh , x_mesh ))
345
308
346
309
# Fit azimuth carrier polynomial with x/y or range/azimuth
347
310
if index_as_coord :
348
311
az_carrier_poly = polyfit (x_mesh .flatten ()+ 1 , y_mesh .flatten ()+ 1 ,
349
- az_carrier .flatten (), az_order ,
312
+ az_carr_comp . carrier .flatten (), az_order ,
350
313
rg_order )
351
314
else :
352
315
# Convert x/y to range/azimuth
@@ -356,7 +319,7 @@ class represents a polynomial function of range
356
319
357
320
# Estimate azimuth carrier polynomials
358
321
az_carrier_poly = polyfit (rg_mesh .flatten (), az_mesh .flatten (),
359
- az_carrier .flatten (), az_order ,
322
+ az_carr_comp . carrier .flatten (), az_order ,
360
323
rg_order )
361
324
362
325
return az_carrier_poly
@@ -478,6 +441,126 @@ def bistatic_delay(self, xstep=1, ystep=1):
478
441
479
442
return isce3 .core .LUT2d (x , y , bistatic_correction )
480
443
444
+ def geometrical_and_steering_doppler (self , xstep = 500 , ystep = 50 ):
445
+ """
446
+ Compute total Doppler which is the sum of two components:
447
+ (1) the geometrical Doppler induced by the relative movement
448
+ of the sensor and target
449
+ (2) the TOPS specicifc Doppler caused by the electric steering
450
+ of the beam along the azimuth direction resulting in Doppler varying
451
+ with azimuth time.
452
+ Parameters
453
+ ----------
454
+ xstep: int
455
+ Spacing along x direction [pixels]
456
+ ystep: int
457
+ Spacing along y direction [pixels]
458
+
459
+ Returns
460
+ -------
461
+ x : int
462
+ The index of samples in range direction as an 1D array
463
+ y : int
464
+ The index of samples in azimuth direction as an 1D array
465
+ total_doppler : float
466
+ Total Doppler which is the sum of the geometrical Doppler and
467
+ beam steering induced Doppler [Hz] as a 2D array
468
+ """
469
+
470
+ x = np .arange (0 , self .width , xstep , dtype = int )
471
+ y = np .arange (0 , self .length , ystep , dtype = int )
472
+ x_mesh , y_mesh = np .meshgrid (x , y )
473
+ az_carr_comp = self .az_carrier_components (
474
+ offset = 0.0 ,
475
+ position = (y_mesh , x_mesh ))
476
+
477
+ slant_range = self .starting_range + x * self .range_pixel_spacing
478
+ geometrical_doppler = self .doppler .poly1d .eval (slant_range )
479
+
480
+ total_doppler = az_carr_comp .antenna_steering_doppler + geometrical_doppler
481
+
482
+ return x , y , total_doppler
483
+
484
+ def doppler_induced_range_shift (self , xstep = 500 , ystep = 50 ):
485
+ """
486
+ Computes the range delay caused by the Doppler shift as described
487
+ by Gisinger et al 2021
488
+
489
+ Parameters
490
+ ----------
491
+ xstep: int
492
+ Spacing along x direction [pixels]
493
+ ystep: int
494
+ Spacing along y direction [pixels]
495
+
496
+ Returns
497
+ -------
498
+ isce3.core.LUT2d:
499
+ LUT2D object of range delay correction [seconds] as a function
500
+ of the x and y indices.
501
+
502
+ """
503
+
504
+ x , y , doppler_shift = self .geometrical_and_steering_doppler (
505
+ xstep = xstep , ystep = ystep )
506
+ tau_corr = doppler_shift / self .range_chirp_rate
507
+
508
+ return isce3 .core .LUT2d (x , y , tau_corr )
509
+
510
+ def az_carrier_components (self , offset , position ):
511
+ '''
512
+ Estimate azimuth carrier and store in numpy arrary. Also return
513
+ contributing components.
514
+
515
+ Parameters
516
+ ----------
517
+ offset: float
518
+ Offset between reference and secondary burst
519
+ position: tuple
520
+ Tuple of locations along y and x directions
521
+
522
+ Returns
523
+ -------
524
+ eta: float
525
+ zero-Doppler azimuth time centered in the middle of the burst
526
+ eta_ref: float
527
+ refernce time
528
+ kt: np.ndarray
529
+ Doppler centroid rate in the focused TOPS SLC data [Hz/s]
530
+ carr: np.ndarray
531
+ Azimuth carrier
532
+
533
+ Reference
534
+ ---------
535
+ https://sentinels.copernicus.eu/documents/247904/0/Sentinel-1-TOPS-SLC_Deramping/b041f20f-e820-46b7-a3ed-af36b8eb7fa0
536
+ '''
537
+ # Get self.sensing mid relative to orbit reference epoch
538
+ fmt = "%Y-%m-%dT%H:%M:%S.%f"
539
+ orbit_ref_epoch = datetime .datetime .strptime (self .orbit .reference_epoch .__str__ ()[:- 3 ], fmt )
540
+
541
+ t_mid = self .sensing_mid - orbit_ref_epoch
542
+ _ , v = self .orbit .interpolate (t_mid .total_seconds ())
543
+ vs = np .linalg .norm (v )
544
+ ks = 2 * vs * self .azimuth_steer_rate / self .wavelength
545
+
546
+ y , x = position
547
+
548
+ n_lines , _ = self .shape
549
+ eta = (y - (n_lines // 2 ) + offset ) * self .azimuth_time_interval
550
+ rng = self .starting_range + x * self .range_pixel_spacing
551
+
552
+ f_etac = np .array (
553
+ self .doppler .poly1d .eval (rng .flatten ().tolist ())).reshape (rng .shape )
554
+ ka = np .array (
555
+ self .azimuth_fm_rate .eval (rng .flatten ().tolist ())).reshape (rng .shape )
556
+
557
+ eta_ref = (self .doppler .poly1d .eval (
558
+ self .starting_range ) / self .azimuth_fm_rate .eval (
559
+ self .starting_range )) - (f_etac / ka )
560
+ kt = ks / (1.0 - ks / ka )
561
+
562
+
563
+ return AzimuthCarrierComponents (kt , eta , eta_ref )
481
564
482
565
@property
483
566
def sensing_mid (self ):
0 commit comments