@@ -109,15 +109,111 @@ def __init__(self,
109
109
self .rg_bandwidth = rg_bandwidth
110
110
self .center_frequency = center_frequency
111
111
self .slant_range = slant_range
112
+
113
+ def bandpass_shift_spectrum (self ,
114
+ slc_raster ,
115
+ low_frequency ,
116
+ high_frequency ,
117
+ new_center_frequency ,
118
+ window ,
119
+ window_shape = 0.25 ,
120
+ fft_size = None ,
121
+ resampling = True
122
+ ):
123
+
124
+ """Bandpass SLC for given center frequency and bandwidth
125
+
126
+ Parameters
127
+ ----------
128
+ slc_raster : numpy.ndarray
129
+ numpy array of slc raster,
130
+ low_frequency : float
131
+ low frequency of band to be passed [Hz]
132
+ high_frequency : float
133
+ high frequency band to be passed [Hz]
134
+ new_center_frequency : float
135
+ new center frequency for bandpass [Hz]
136
+ window_shape : float
137
+ parameter for the raised cosine filter (e.g. 0 ~ 1)
138
+ fft_size : int
139
+ fft size.
140
+ resampling : bool
141
+ if True, then resample SLC and meta data with new range spacing
142
+ If False, return SLC and meta with original range spacing
143
+
144
+ Returns
145
+ -------
146
+ resampled_slc or slc_demodulate: numpy.ndarray
147
+ numpy array of bandpassed slc
148
+ if resampling is True, return resampled_slc
149
+ if resampling is False, return slc_demodulate
150
+ meta : dict
151
+ dict containing meta data of bandpassed slc
152
+ center_frequency, rg_bandwidth, range_spacing, slant_range
153
+ """
154
+ error_channel = journal .error ('splitspectrum.bandpass_shift_spectrum' )
155
+
156
+ rg_sample_freq = self .rg_sample_freq
157
+ rg_bandwidth = self .rg_bandwidth
158
+ diff_frequency = self .center_frequency - new_center_frequency
159
+ height , width = slc_raster .shape
160
+ slc_raster = np .asanyarray (slc_raster , dtype = 'complex' )
161
+
162
+ slc_bp = self .bandpass_spectrum (
163
+ slc_raster = slc_raster ,
164
+ low_frequency = low_frequency ,
165
+ high_frequency = high_frequency ,
166
+ window = window ,
167
+ window_shape = window_shape ,
168
+ fft_size = fft_size ,
169
+ )
170
+
171
+ # demodulate the SLC to be baseband to new center frequency
172
+ # if fft_size > width, then crop the spectrum from 0 to width
173
+ slc_demodulate = self .demodulate_slc (slc_bp [:, :width ],
174
+ diff_frequency ,
175
+ rg_sample_freq )
176
+
177
+ # update metadata with new parameters
178
+ meta = dict ()
179
+ new_bandwidth = high_frequency - low_frequency
180
+ meta ['center_frequency' ] = new_center_frequency
181
+ meta ['rg_bandwidth' ] = new_bandwidth
182
+
183
+ # Resampling changes the spacing and slant range
184
+ if resampling :
185
+ resampling_scale_factor = rg_bandwidth / new_bandwidth
186
+ sub_width = int (width / resampling_scale_factor )
187
+
188
+ x_cand = np .arange (1 , width + 1 )
189
+ # find the maximum of the multiple of resampling_scale_factor
190
+ resample_width_end = np .max (x_cand [x_cand % resampling_scale_factor == 0 ])
191
+
192
+ # resample SLC
193
+ resampled_slc = resample (slc_demodulate [:, :resample_width_end ], sub_width , axis = 1 )
194
+
195
+ meta ['range_spacing' ] = self .rg_pxl_spacing * resampling_scale_factor
196
+ meta ['slant_range' ] = np .linspace (self .slant_range (0 ), self .slant_range (width ),\
197
+ sub_width , endpoint = False )
198
+
199
+ return resampled_slc , meta
200
+
201
+ else :
202
+ filtered_slc = slc_demodulate
203
+
204
+ meta ['range_spacing' ] = self .rg_pxl_spacing
205
+ meta ['slant_range' ] = np .linspace (self .slant_range (0 ), self .slant_range (width ),\
206
+ width , endpoint = False )
207
+
208
+ return slc_demodulate , meta
112
209
113
210
def bandpass_spectrum (self ,
114
211
slc_raster ,
115
212
low_frequency ,
116
213
high_frequency ,
117
- new_center_frequency ,
118
214
window ,
119
215
window_shape = 0.25 ,
120
- fft_size = None
216
+ fft_size = None ,
121
217
):
122
218
"""Bandpass SLC for given center frequency and bandwidth
123
219
@@ -129,10 +225,12 @@ def bandpass_spectrum(self,
129
225
low frequency of band to be passed [Hz]
130
226
high_frequency : float
131
227
high frequency band to be passed [Hz]
132
- new_center_frequency : float
133
- new center frequency for bandpass [Hz]
228
+ window: str
229
+ window type {'tukey', 'kaiser', 'cosine'}
134
230
window_shape : float
135
- parameter for the raised cosine filter (e.g. 0 ~ 1)
231
+ parameter for the window shape
232
+ kaiser 0<= window_shape < inf
233
+ tukey and cosine 0 <= window_shape <= 1
136
234
fft_size : int
137
235
fft size.
138
236
@@ -149,11 +247,11 @@ def bandpass_spectrum(self,
149
247
rg_sample_freq = self .rg_sample_freq
150
248
rg_bandwidth = self .rg_bandwidth
151
249
center_frequency = self .center_frequency
152
- diff_frequency = self .center_frequency - new_center_frequency
153
250
height , width = slc_raster .shape
154
251
slc_raster = np .asanyarray (slc_raster , dtype = 'complex' )
155
252
new_bandwidth = high_frequency - low_frequency
156
-
253
+ resampling_scale_factor = rg_bandwidth / new_bandwidth
254
+
157
255
if new_bandwidth < 0 :
158
256
err_str = f"Low frequency is higher than high frequency"
159
257
error_channel .log (err_str )
@@ -167,7 +265,7 @@ def bandpass_spectrum(self,
167
265
error_channel .log (err_str )
168
266
raise ValueError (err_str )
169
267
170
- # construct window to remove window effect in freq domain
268
+ # construct window to be deconvolved from the original SLC in freq domain
171
269
window_target = self .get_range_bandpass_window (
172
270
center_frequency = 0 ,
173
271
frequencyLH = [- rg_bandwidth / 2 ,
@@ -176,7 +274,7 @@ def bandpass_spectrum(self,
176
274
fft_size = fft_size ,
177
275
window_function = window ,
178
276
window_shape = window_shape
179
- )
277
+ )
180
278
# construct window to bandpass spectrum
181
279
# for given low and high frequencies
182
280
window_bandpass = self .get_range_bandpass_window (
@@ -187,10 +285,7 @@ def bandpass_spectrum(self,
187
285
fft_size = fft_size ,
188
286
window_function = window ,
189
287
window_shape = window_shape
190
- )
191
-
192
- resampling_scale_factor = rg_bandwidth / new_bandwidth
193
- sub_fft_size = int (width / resampling_scale_factor )
288
+ )
194
289
195
290
# remove the windowing effect from the spectrum
196
291
spectrum_target = fft (slc_raster , n = fft_size ) / \
@@ -200,23 +295,7 @@ def bandpass_spectrum(self,
200
295
* window_bandpass
201
296
* np .sqrt (resampling_scale_factor ), n = fft_size )
202
297
203
- # demodulate the SLC to be baseband to new center frequency
204
- # if fft_size > width, then crop the spectrum from 0 to width
205
- slc_demodulate = self .demodulate_slc (slc_bp [:, :width ],
206
- diff_frequency ,
207
- rg_sample_freq )
208
-
209
- # resample SLC
210
- filtered_slc = resample (slc_demodulate , sub_fft_size , axis = 1 )
211
-
212
- meta = dict ()
213
- meta ['center_frequency' ] = new_center_frequency
214
- meta ['rg_bandwidth' ] = new_bandwidth
215
- meta ['range_spacing' ] = self .rg_pxl_spacing * resampling_scale_factor
216
- meta ['slant_range' ] = np .linspace (self .slant_range (0 ), self .slant_range (width ),\
217
- sub_fft_size , endpoint = False )
218
-
219
- return filtered_slc , meta
298
+ return slc_bp
220
299
221
300
def demodulate_slc (self , slc_array , diff_frequency , rg_sample_freq ):
222
301
""" Demodulate SLC
@@ -240,9 +319,9 @@ def demodulate_slc(self, slc_array, diff_frequency, rg_sample_freq):
240
319
"""
241
320
height , width = slc_array .shape
242
321
range_time = np .arange (width ) / rg_sample_freq
243
- slc_baseband = slc_array * np .exp (- 1 * 1j * 2.0 * np .pi * - 1
322
+ slc_shifted = slc_array * np .exp (- 1 * 1j * 2.0 * np .pi * - 1
244
323
* diff_frequency * range_time )
245
- return slc_baseband
324
+ return slc_shifted
246
325
247
326
def freq_spectrum (self , cfrequency , dt , fft_size ):
248
327
freq = cfrequency + fftfreq (fft_size , dt )
@@ -282,7 +361,7 @@ def get_range_bandpass_window(self,
282
361
filter_1d : np.ndarray
283
362
one dimensional bandpass filter in frequency domain
284
363
'''
285
- #
364
+ # construct the freqeuncy bin [Hz]
286
365
frequency = self .freq_spectrum (
287
366
cfrequency = center_frequency ,
288
367
dt = 1.0 / sampling_frequency ,
@@ -291,7 +370,8 @@ def get_range_bandpass_window(self,
291
370
292
371
fL , fH = frequencyLH
293
372
window_kind = window_function .lower ()
294
-
373
+
374
+ # Windowing effect will appear from fL to fH for given frequency bin
295
375
if window_kind == 'tukey' :
296
376
if not (0 <= window_shape <= 1 ):
297
377
raise ValueError (f"Expected window_shape between 0 and 1, got { window_shape } ." )
@@ -303,10 +383,8 @@ def get_range_bandpass_window(self,
303
383
)
304
384
305
385
elif window_kind == 'kaiser' or window_kind == 'cosine' :
306
-
307
386
if (window_kind == 'kaiser' ) and not (window_shape > 0 ):
308
387
raise ValueError (f"Expected pedestal bigger than 0, got { window_shape } ." )
309
-
310
388
if (window_kind == 'cosine' ) and not (0 <= window_shape <= 1 ):
311
389
raise ValueError (f"Expected window_shape between 0 and 1, got { window_shape } ." )
312
390
0 commit comments