Skip to content

Commit dd02da6

Browse files
committed
revised docstring, window, and redundant lines
1 parent 5dabe81 commit dd02da6

File tree

2 files changed

+153
-76
lines changed

2 files changed

+153
-76
lines changed

python/packages/isce3/splitspectrum/splitspectrum.py

Lines changed: 133 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,47 @@
22
import journal
33
from scipy.fft import fft, ifft, fftfreq
44
from scipy.signal import resample
5+
from dataclasses import dataclass
56

67
import isce3
78
from nisar.workflows.focus import cosine_window
89

910

10-
def get_meta_data_bandpass(slc_product, freq):
11-
"""Get meta data from SLC object.
12-
13-
Parameters
14-
----------
15-
slc_product : nisar.products.readers.SLC
16-
slc object
17-
freq : {'A', 'B'}
18-
frequency band
19-
20-
Returns
21-
-------
22-
meta_data : dict
23-
dict containing meta_data
24-
"""
25-
meta_data = dict()
26-
rdr_grid = slc_product.getRadarGrid(freq)
27-
meta_data['rg_pxl_spacing'] = rdr_grid.range_pixel_spacing
28-
meta_data['wavelength'] = rdr_grid.wavelength
29-
meta_data['rg_sample_freq'] = isce3.core.speed_of_light * \
30-
0.5 / meta_data['rg_pxl_spacing']
31-
meta_data['rg_bandwidth'] = slc_product.getSwathMetadata(
32-
freq).processed_range_bandwidth
33-
meta_data['center_frequency'] = isce3.core.speed_of_light / \
34-
meta_data['wavelength']
35-
meta_data['slant_range'] = rdr_grid.slant_range
36-
return meta_data
11+
@dataclass(frozen=True)
12+
class bandpass_meta_data:
13+
# slant range spacing
14+
rg_pxl_spacing: float
15+
# wavelength
16+
wavelength: float
17+
# sampling frequency
18+
rg_sample_freq: float
19+
#bandiwdth
20+
rg_bandwidth: float
21+
#center frequency
22+
center_freq: float
23+
#slant range
24+
slant_range: 'method'
25+
26+
@classmethod
27+
def load_from_slc(cls, slc_product, freq):
28+
"""Get meta data from SLC object.
29+
Parameters
30+
----------
31+
slc_product : nisar.products.readers.SLC
32+
slc object
33+
freq : {'A', 'B'}
34+
frequency band
35+
Returns
36+
-------
37+
meta_data : bandpass_meta_data
38+
bandpass meta data object
39+
"""
40+
rdr_grid = slc_product.getRadarGrid(freq)
41+
rg_sample_freq = isce3.core.speed_of_light * 0.5 / rdr_grid.range_pixel_spacing
42+
rg_bandwidth = slc_product.getSwathMetadata(freq).processed_range_bandwidth
43+
center_frequency = isce3.core.speed_of_light / rdr_grid.wavelength
44+
return cls(rdr_grid.range_pixel_spacing, rdr_grid.wavelength, rg_sample_freq,
45+
rg_bandwidth, center_frequency, rdr_grid.slant_range)
3746

3847

3948
def check_range_bandwidth_overlap(ref_slc, sec_slc, pols):
@@ -61,14 +70,14 @@ def check_range_bandwidth_overlap(ref_slc, sec_slc, pols):
6170
mode = dict()
6271

6372
for freq, pol_list in pols.items():
64-
ref_meta_data = get_meta_data_bandpass(ref_slc, freq)
65-
sec_meta_data = get_meta_data_bandpass(sec_slc, freq)
66-
67-
ref_wvl = ref_meta_data['wavelength']
68-
sec_wvl = sec_meta_data['wavelength']
69-
ref_bw = ref_meta_data['rg_bandwidth']
70-
sec_bw = sec_meta_data['rg_bandwidth']
71-
73+
ref_meta_data = bandpass_meta_data.load_from_slc(ref_slc, freq)
74+
sec_meta_data = bandpass_meta_data.load_from_slc(sec_slc, freq)
75+
76+
ref_wvl = ref_meta_data.wavelength
77+
sec_wvl = sec_meta_data.wavelength
78+
ref_bw = ref_meta_data.rg_bandwidth
79+
sec_bw = sec_meta_data.rg_bandwidth
80+
7281
# check if two SLCs have same bandwidth and center frequency
7382
if (ref_wvl != sec_wvl) or (ref_bw != sec_bw):
7483
if ref_bw > sec_bw:
@@ -133,7 +142,7 @@ def bandpass_shift_spectrum(self,
133142
high_frequency : float
134143
high frequency band to be passed [Hz]
135144
new_center_frequency : float
136-
new center frequency for bandpass [Hz]
145+
new center frequency for new bandpassed slc [Hz]
137146
window_function : str
138147
window type {tukey, kaiser, cosine}
139148
window_shape : float
@@ -148,8 +157,8 @@ def bandpass_shift_spectrum(self,
148157
-------
149158
resampled_slc or slc_demodulate: numpy.ndarray
150159
numpy array of bandpassed slc
151-
if resampling is True, return resampled_slc
152-
if resampling is False, return slc_demodulate
160+
if resampling is True, return resampled slc with bandpass and demodulation
161+
if resampling is False, return slc with bandpass and demodulation without resampling
153162
meta : dict
154163
dict containing meta data of bandpassed slc
155164
center_frequency, rg_bandwidth, range_spacing, slant_range
@@ -237,11 +246,8 @@ def bandpass_spectrum(self,
237246
238247
Returns
239248
-------
240-
filtered_slc : numpy.ndarray
249+
slc_bandpassed : numpy.ndarray
241250
numpy array of bandpassed slc
242-
meta : dict
243-
dict containing meta data of bandpassed slc
244-
center_frequency, rg_bandwidth, range_spacing, slant_range
245251
"""
246252
error_channel = journal.error('splitspectrum.bandpass_spectrum')
247253

@@ -292,11 +298,11 @@ def bandpass_spectrum(self,
292298
spectrum_target = fft(slc_raster, n=fft_size) / \
293299
window_target
294300
# apply new bandpass window to spectrum
295-
slc_bp = ifft(spectrum_target
301+
slc_bandpassed = ifft(spectrum_target
296302
* window_bandpass
297303
* np.sqrt(resampling_scale_factor), n=fft_size)
298304

299-
return slc_bp
305+
return slc_bandpassed
300306

301307
def demodulate_slc(self, slc_array, diff_frequency, rg_sample_freq):
302308
""" Demodulate SLC
@@ -404,32 +410,99 @@ def get_range_bandpass_window(self,
404410
window_shape=window_shape
405411
)
406412

407-
elif window_kind == 'kaiser' or window_kind == 'cosine':
408-
if (window_kind == 'kaiser') and not (window_shape > 0):
413+
elif window_kind == 'kaiser':
414+
if not (window_shape > 0):
409415
err_str = f"Expected pedestal bigger than 0, got {window_shape}."
410416
error_channel.log(err_str)
411417
raise ValueError(err_str)
412-
if (window_kind == 'cosine') and not (0 <= window_shape <= 1):
418+
419+
filter_1d = self.construct_range_bandpass_kaiser(
420+
frequency_range=frequency,
421+
freq_low=freq_low,
422+
freq_high=freq_high,
423+
window_shape=window_shape
424+
)
425+
426+
elif window_kind == 'cosine':
427+
if not (0 <= window_shape <= 1):
413428
err_str = f"Expected window_shape between 0 and 1, got {window_shape}."
414429
error_channel.log(err_str)
415430
raise ValueError(err_str)
416-
417-
filter_1d = self.construct_range_bandpass_kaiser_cosine(
431+
filter_1d = self.construct_range_bandpass_cosine(
418432
frequency_range=frequency,
419433
freq_low=freq_low,
420434
freq_high=freq_high,
421-
window_function=window_kind,
422435
window_shape=window_shape
423-
)
424-
436+
)
437+
425438
else:
426439
err_str = f"window {window_kind} not in (Kaiser, Cosine, Tukey)."
427440
error_channel.log(err_str)
428441
raise ValueError(err_str)
429442

430443
return filter_1d
431444

432-
def construct_range_bandpass_kaiser_cosine(self,
445+
def construct_range_bandpass_cosine(self,
446+
frequency_range,
447+
freq_low,
448+
freq_high,
449+
window_shape):
450+
'''Generate a Cosine bandpass window
451+
452+
Parameters
453+
----------
454+
frequency_range : np.ndarray
455+
Discrete Fourier Transform sample frequency range bins[Hz]
456+
freq_low : float
457+
low frequency to be passed [Hz]
458+
freq_high: float
459+
high frequency to be passed [Hz]
460+
window_shape : float
461+
parameter for the cosine window
462+
463+
Returns
464+
-------
465+
filter_1d : np.ndarray
466+
one dimensional Cosine bandpass filter in frequency domain
467+
'''
468+
filter_1d = self._construct_range_bandpass_kaiser_cosine(frequency_range,
469+
freq_low,
470+
freq_high,
471+
cosine_window,
472+
window_shape)
473+
return filter_1d
474+
475+
def construct_range_bandpass_kaiser(self,
476+
frequency_range,
477+
freq_low,
478+
freq_high,
479+
window_shape):
480+
'''Generate a Kaiser bandpass window
481+
482+
Parameters
483+
----------
484+
frequency_range : np.ndarray
485+
Discrete Fourier Transform sample frequency range bins[Hz]
486+
freq_low : float
487+
low frequency to be passed [Hz]
488+
freq_high: float
489+
high frequency to be passed [Hz]
490+
window_shape : float
491+
parameter for the kaiser window
492+
493+
Returns
494+
-------
495+
filter_1d : np.ndarray
496+
one dimensional kaiser bandpass filter in frequency domain
497+
'''
498+
filter_1d = self._construct_range_bandpass_kaiser_cosine(frequency_range,
499+
freq_low,
500+
freq_high,
501+
np.kaiser,
502+
window_shape)
503+
return filter_1d
504+
505+
def _construct_range_bandpass_kaiser_cosine(self,
433506
frequency_range,
434507
freq_low,
435508
freq_high,
@@ -445,8 +518,8 @@ def construct_range_bandpass_kaiser_cosine(self,
445518
low frequency to be passed [Hz]
446519
freq_high: float
447520
high frequency to be passed [Hz]
448-
window_function : str
449-
window type {kaiser, cosine}
521+
window_function : class function
522+
window type {np.kaiser, cosine_window}
450523
window_shape : float
451524
parameter for the kaiser window
452525
@@ -484,11 +557,10 @@ def construct_range_bandpass_kaiser_cosine(self,
484557
subband_length = idx_freq_high - idx_freq_low + 1
485558

486559
filter_1d = np.zeros([fft_size], dtype='complex')
487-
if window_function == 'kaiser':
488-
subwindow = np.kaiser(subband_length, window_shape)
489-
elif window_function == 'cosine':
490-
subwindow = cosine_window(subband_length, window_shape)
491-
560+
561+
# window_function is function class {np.kaiser or consine}
562+
subwindow = window_function(subband_length, window_shape)
563+
492564
if idx_freq_low >= idx_freq_high:
493565
filter_1d[idx_freq_low :] = subwindow[0 : fft_size - idx_freq_low]
494566
filter_1d[: idx_freq_high + 1] = subwindow[fft_size - idx_freq_low:]
@@ -531,7 +603,7 @@ def construct_range_bandpass_tukey(self,
531603
# Get the absolute value of shifted frequency
532604
freq = frequency_range[i]
533605
freqabs = np.abs(freq - freq_mid)
534-
# Passband. Pass original signals within a selected range of frequencies
606+
# Passband. i.e. range of frequencies that can pass through a filter
535607
if (freq <= (freq_high - df)) and (freq >= (freq_low + df)):
536608
filter_1d[i] = 1
537609
# Transition region

python/packages/nisar/workflows/bandpass_insar.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ def run(cfg: dict):
3939
t_all = time.time()
4040

4141
# check if bandpass is necessary
42-
bandpass_modes = splitspectrum.check_range_bandwidth_overlap(ref_slc,
43-
sec_slc,
44-
freq_pols)
42+
bandpass_modes = splitspectrum.check_range_bandwidth_overlap(
43+
ref_slc=ref_slc,
44+
sec_slc=sec_slc,
45+
pols=freq_pols)
4546

4647
# check if user provided path to raster(s) is a file or directory
4748
bandpass_slc_path = pathlib.Path(f"{scratch_path}/bandpass/")
@@ -82,21 +83,25 @@ def run(cfg: dict):
8283
os.remove(target_output)
8384

8485
# meta data extraction
85-
base_meta_data = splitspectrum.get_meta_data_bandpass(base_slc, freq)
86-
target_meta_data = splitspectrum.get_meta_data_bandpass(target_slc, freq)
87-
88-
bandwidth_half = 0.5 * base_meta_data['rg_bandwidth']
89-
low_frequency_base = base_meta_data['center_frequency'] - \
86+
base_meta_data = splitspectrum.bandpass_meta_data.load_from_slc(
87+
slc_product=base_slc,
88+
freq=freq)
89+
target_meta_data = splitspectrum.bandpass_meta_data.load_from_slc(
90+
slc_product=target_slc,
91+
freq=freq)
92+
93+
bandwidth_half = 0.5 * base_meta_data.rg_bandwidth
94+
low_frequency_base = base_meta_data.center_freq - \
9095
bandwidth_half
91-
high_frequency_base = base_meta_data['center_frequency'] + \
96+
high_frequency_base = base_meta_data.center_freq + \
9297
bandwidth_half
9398

9499
# Initialize bandpass instance
95100
# Specify meta parameters of SLC to be bandpassed
96-
bandpass = splitspectrum.SplitSpectrum(rg_sample_freq=target_meta_data['rg_sample_freq'],
97-
rg_bandwidth=target_meta_data['rg_bandwidth'],
98-
center_frequency=target_meta_data['center_frequency'],
99-
slant_range=target_meta_data['slant_range'],
101+
bandpass = splitspectrum.SplitSpectrum(rg_sample_freq=target_meta_data.rg_sample_freq,
102+
rg_bandwidth=target_meta_data.rg_bandwidth,
103+
center_frequency=target_meta_data.center_freq,
104+
slant_range=target_meta_data.slant_range,
100105
freq=freq)
101106

102107
dest_freq_path = f"/science/LSAR/SLC/swaths/frequency{freq}"
@@ -135,7 +140,7 @@ def run(cfg: dict):
135140
slc_raster=target_slc_image,
136141
low_frequency=low_frequency_base,
137142
high_frequency=high_frequency_base,
138-
new_center_frequency=base_meta_data['center_frequency'],
143+
new_center_frequency=base_meta_data.center_freq,
139144
fft_size=fft_size,
140145
window_shape=window_shape,
141146
window_function=window_function,
@@ -162,7 +167,7 @@ def run(cfg: dict):
162167
data = dst_h5[f"{dest_freq_path}/slantRangeSpacing"]
163168
data[...] = bandpass_meta['range_spacing']
164169
data = dst_h5[f"{dest_freq_path}/processedRangeBandwidth"]
165-
data[...] = base_meta_data['rg_bandwidth']
170+
data[...] = base_meta_data.rg_bandwidth
166171
del dst_h5[f"{dest_freq_path}/slantRange"]
167172
dst_h5.create_dataset(f"{dest_freq_path}/slantRange",
168173
data=bandpass_meta['slant_range'])

0 commit comments

Comments
 (0)