@@ -56,15 +56,14 @@ def find_zpd(ifg, peak_search):
5656 raise NotImplementedError
5757
5858def wing_size (ifg , zpd ):
59- """Calculate negative and positive wing size (including zpd point)"""
59+ """Calculate negative and positive wing size (including zpd point in both )"""
6060 wing_n = zpd + 1
6161 wing_p = ifg .shape [- 1 ] - zpd
6262 return wing_n , wing_p
6363
64- def apodize (ifg , zpd , apod_func ):
64+ def apodize (ifg , zpd , apod_func , apod_asym ):
6565 """
66- Perform apodization of asymmetric interferogram using selected apodization
67- function
66+ Perform apodization of interferogram using selected apodization function
6867
6968 Args:
7069 ifg (np.array): interferogram array (1D or 2D row-wise)
@@ -74,6 +73,8 @@ def apodize(ifg, zpd, apod_func):
7473 <ApodFunc.BLACKMAN_HARRIS_3: 1> : Blackman-Harris (3-term)
7574 <ApodFunc.BLACKMAN_HARRIS_4: 2> : Blackman-Harris (4-term)
7675 <ApodFunc.BLACKMAN_NUTTALL: 3> : Blackman-Nuttall (Eric Peach implementation)
76+ apod_asym (bool): Apply asymmetric apodization for asymmetric interferometers (s-SNOM, DFTS)
77+ Otherwise, truncate symmetric apodization function as required and apply ramp
7778
7879 Returns:
7980 ifg_apod (np.array): apodized interferogram(s)
@@ -87,8 +88,6 @@ def apodize(ifg, zpd, apod_func):
8788 # correcting zpd from 0-based index
8889 ifg_N = ifg .shape [- 1 ]
8990 wing_n , wing_p = wing_size (ifg , zpd )
90- # Use larger wing to define apodization window width
91- M = max (wing_n , wing_p )
9291
9392 # Generate apodization function
9493 if apod_func == ApodFunc .BLACKMAN_HARRIS_3 :
@@ -118,17 +117,45 @@ def apodize(ifg, zpd, apod_func):
118117 else :
119118 raise ValueError (f"Invalid apodization function { apod_func } " )
120119
121- n = np .arange (1 - M , M , 1 )
122- Bs = A0 \
123- + A1 * np .cos (np .pi * n / (M - 1 )) \
124- + A2 * np .cos (np .pi * 2 * n / (M - 1 )) \
125- + A3 * np .cos (np .pi * 3 * n / (M - 1 ))
126-
127- # Select appropriate subsection of apodization function
128- if wing_n > wing_p :
129- Bs = Bs [:ifg_N ]
120+ if apod_asym :
121+ # Scale window to each wing length (asymmetric interferometer)
122+ n_n = np .arange (wing_n )
123+ n_p = np .arange (wing_p )
124+ Bs_n = A0 \
125+ + A1 * np .cos (np .pi * n_n / wing_n ) \
126+ + A2 * np .cos (np .pi * 2 * n_n / wing_n ) \
127+ + A3 * np .cos (np .pi * 3 * n_n / wing_n )
128+ Bs_p = A0 \
129+ + A1 * np .cos (np .pi * n_p / wing_p ) \
130+ + A2 * np .cos (np .pi * 2 * n_p / wing_p ) \
131+ + A3 * np .cos (np .pi * 3 * n_p / wing_p )
132+ # Flip Bs_n and overlap at zpd (Bs_n[0] == Bs_p[0])
133+ Bs = np .hstack ((Bs_n [::- 1 ], Bs_p [1 :]))
130134 else :
131- Bs = Bs [2 * M - 1 - ifg_N :]
135+ # Use larger wing to define apodization window width (symmetric interferometer)
136+ M = max (wing_n , wing_p )
137+ n = np .arange (1 - M , M , 1 )
138+ Bs = A0 \
139+ + A1 * np .cos (np .pi * n / (M - 1 )) \
140+ + A2 * np .cos (np .pi * 2 * n / (M - 1 )) \
141+ + A3 * np .cos (np .pi * 3 * n / (M - 1 ))
142+
143+ # Select appropriate subsection of apodization function
144+ if wing_n > wing_p :
145+ Bs = Bs [:ifg_N ]
146+ else :
147+ Bs = Bs [2 * M - 1 - ifg_N :]
148+
149+ # Add ramp to avoid uneven counting of truncated section
150+ # Use smaller wing to define symmetric subset size
151+ # Skip if fully symmetric (phase data)
152+ wing_min = min (wing_n , wing_p )
153+ ramp = np .linspace (0 , 1 , 2 * wing_min - 1 )
154+ if wing_n < wing_p :
155+ Bs [..., :ramp .shape [0 ]] *= ramp
156+ elif wing_n > wing_p :
157+ Bs [..., - ramp .shape [0 ]:] *= ramp [::- 1 ]
158+
132159 # Apodize the sampled Interferogram
133160 try :
134161 ifg_apod = ifg * Bs
@@ -231,14 +258,13 @@ def __call__(self, ifg, zpd=None, phase=None):
231258 else :
232259 # Select phase interferogram as copy
233260 # Note that L is now the zpd index
234- Ixs = ifg [self .zpd - L : self .zpd + L ].copy ()
235- ifg = apodize (ifg , self .zpd , self .apod_func )
236- ifg = ramp (ifg , self .zpd )
261+ Ixs = ifg [self .zpd - L : self .zpd + 1 + L ].copy ()
262+ ifg = apodize (ifg , self .zpd , self .apod_func , self .apod_asym )
237263 ifg = zero_fill (ifg , self .zff )
238264 ifg = np .hstack ((ifg [self .zpd :], ifg [0 :self .zpd ]))
239265 Nzff = ifg .shape [0 ]
240266
241- Ixs = apodize (Ixs , L , self .apod_func )
267+ Ixs = apodize (Ixs , L , self .apod_func , self . apod_asym )
242268 # Zero-fill Ixs to same size as ifg (instead of interpolating later)
243269 Ixs = _zero_fill_pad (Ixs , Nzff - Ixs .shape [0 ])
244270 Ixs = np .hstack ((Ixs [L :], Ixs [0 :L ]))
@@ -306,7 +332,7 @@ def __call__(self, ifg, zpd=None, phase=None):
306332 # Calculate phase on interferogram of specified size 2*L
307333 L = self .phase_ifg_size (ifg .shape [1 ])
308334 if L == 0 : # Use full ifg for phase #TODO multi is this code tested
309- ifg = apodize (ifg , self .zpd , self .apod_func )
335+ ifg = apodize (ifg , self .zpd , self .apod_func , self . apod_asym )
310336 ifg = zero_fill (ifg , self .zff )
311337 # Rotate the Complete IFG so that the centerburst is at edges.
312338 ifg = np .hstack ((ifg [self .zpd :], ifg [0 :self .zpd ]))
@@ -318,13 +344,12 @@ def __call__(self, ifg, zpd=None, phase=None):
318344 # Select phase interferogram as copy
319345 # Note that L is now the zpd index
320346 Ixs = ifg [:, self .zpd - L : self .zpd + L ].copy ()
321- ifg = apodize (ifg , self .zpd , self .apod_func )
322- ifg = ramp (ifg , self .zpd )
347+ ifg = apodize (ifg , self .zpd , self .apod_func , self .apod_asym )
323348 ifg = zero_fill (ifg , self .zff )
324349 ifg = np .hstack ((ifg [:, self .zpd :], ifg [:, 0 :self .zpd ]))
325350 Nzff = ifg .shape [1 ]
326351
327- Ixs = apodize (Ixs , L , self .apod_func )
352+ Ixs = apodize (Ixs , L , self .apod_func , self . apod_asym )
328353 # Zero-fill Ixs to same size as ifg (instead of interpolating later)
329354 Ixs = _zero_fill_pad (Ixs , Nzff - Ixs .shape [1 ])
330355 Ixs = np .hstack ((Ixs [:, L :], Ixs [:, 0 :L ]))
@@ -357,7 +382,7 @@ def __call__(self, ifg, zpd=None, phase=None):
357382 else :
358383 self .zpd = find_zpd (ifg , self .peak_search )
359384
360- ifg = apodize (ifg , self .zpd , self .apod_func )
385+ ifg = apodize (ifg , self .zpd , self .apod_func , self . apod_asym )
361386 ifg = zero_fill (ifg , self .zff )
362387 # Rotate the Complete IFG so that the centerburst is at edges.
363388 ifg = np .hstack ((ifg [self .zpd :], ifg [0 :self .zpd ]))
0 commit comments