BOSlib 0.0.2__tar.gz → 0.0.3__tar.gz
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.
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/__init__.py +1 -1
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/evaluation.py +1 -1
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/shift.py +165 -7
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib.egg-info/PKG-INFO +1 -1
- {boslib-0.0.2 → boslib-0.0.3}/PKG-INFO +1 -1
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/culculate_refractiveindex.py +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/reconstruction.py +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/reconstruction_utils.py +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/shift_utils.py +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib/utils.py +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib.egg-info/SOURCES.txt +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib.egg-info/dependency_links.txt +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib.egg-info/requires.txt +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/BOSlib.egg-info/top_level.txt +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/LICENSE +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/README.md +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/setup.cfg +0 -0
- {boslib-0.0.2 → boslib-0.0.3}/setup.py +0 -0
@@ -129,65 +129,223 @@ def SP_BOS(ref_array : np.ndarray, exp_array : np.ndarray, binarization : str ="
|
|
129
129
|
|
130
130
|
return diff_comp
|
131
131
|
|
132
|
-
def S_BOS(ref_array
|
132
|
+
def S_BOS(ref_array: np.ndarray, exp_array: np.ndarray,freq_sample_area):
|
133
|
+
"""
|
134
|
+
Compute the phase difference and corresponding displacement (delta_h)
|
135
|
+
between reference and experimental signal arrays using a 1D Background
|
136
|
+
Oriented Schlieren (BOS) process.
|
137
|
+
|
138
|
+
Parameters:
|
139
|
+
-----------
|
140
|
+
ref_array : np.ndarray
|
141
|
+
2D numpy array containing reference signals, where each column is a distinct signal.
|
142
|
+
exp_array : np.ndarray
|
143
|
+
2D numpy array containing experimental signals, matching the dimensions of ref_array.
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
--------
|
147
|
+
delta_h : np.ndarray
|
148
|
+
2D numpy array representing the displacement computed from the phase differences.
|
149
|
+
"""
|
150
|
+
|
133
151
|
def freq_finder(sig):
|
152
|
+
"""
|
153
|
+
Identify the dominant frequency in the signal using the FFT.
|
154
|
+
|
155
|
+
Parameters:
|
156
|
+
-----------
|
157
|
+
sig : np.ndarray
|
158
|
+
1D numpy array representing a signal.
|
159
|
+
|
160
|
+
Returns:
|
161
|
+
--------
|
162
|
+
float
|
163
|
+
The dominant frequency (above 0.01 Hz) based on amplitude.
|
164
|
+
"""
|
165
|
+
# Compute FFT frequencies
|
134
166
|
freq = np.fft.fftfreq(sig.shape[0])
|
167
|
+
# Compute FFT of the signal and normalize the amplitude
|
135
168
|
fk = np.fft.fft(sig)
|
136
169
|
fk = abs(fk / (sig.shape[0] / 2))
|
170
|
+
# Combine frequencies and amplitudes into a DataFrame
|
137
171
|
fk_df = pd.DataFrame(np.vstack([freq, fk]).T, columns=["freq", "amp"])
|
172
|
+
# Sort DataFrame by frequency and keep only non-negative frequencies
|
138
173
|
fk_df = fk_df.sort_values('freq')
|
139
174
|
fk_df = fk_df[fk_df["freq"] >= 0]
|
175
|
+
# Select frequencies above 0.01 Hz and sort by amplitude in descending order
|
140
176
|
freq_search = fk_df[fk_df["freq"] >= 0.01].sort_values('amp', ascending=False)
|
177
|
+
# Return the frequency corresponding to the highest amplitude
|
141
178
|
return freq_search.iloc[0, 0]
|
142
179
|
|
143
180
|
def bandpass(x, fa, fb):
|
144
|
-
|
181
|
+
"""
|
182
|
+
Apply a bandpass Butterworth filter to the signal.
|
183
|
+
|
184
|
+
Parameters:
|
185
|
+
-----------
|
186
|
+
x : np.ndarray
|
187
|
+
Input signal.
|
188
|
+
fa : float
|
189
|
+
Lower cutoff frequency multiplier.
|
190
|
+
fb : float
|
191
|
+
Upper cutoff frequency multiplier.
|
192
|
+
|
193
|
+
Returns:
|
194
|
+
--------
|
195
|
+
np.ndarray
|
196
|
+
The bandpass-filtered signal.
|
197
|
+
"""
|
198
|
+
gpass, gstop = 2, 60 # Passband and stopband gains (dB)
|
145
199
|
fp, fs = np.array([fa, fb]), np.array([fa / 2, fb * 2])
|
146
|
-
fn = 1 / 2
|
200
|
+
fn = 1 / 2 # Nyquist frequency (assuming a normalized sample rate)
|
147
201
|
wp, ws = fp / fn, fs / fn
|
202
|
+
# Determine the minimum filter order that meets the specifications
|
148
203
|
N, Wn = signal.buttord(wp, ws, gpass, gstop)
|
204
|
+
# Get the filter coefficients for a Butterworth filter
|
149
205
|
b, a = signal.butter(N, Wn, "band")
|
206
|
+
# Apply the filter forward and backward to avoid phase distortion
|
150
207
|
return signal.filtfilt(b, a, x)
|
151
208
|
|
152
209
|
def lowpass(x, lowcut):
|
153
|
-
|
210
|
+
"""
|
211
|
+
Apply a lowpass Butterworth filter to the signal.
|
212
|
+
|
213
|
+
Parameters:
|
214
|
+
-----------
|
215
|
+
x : np.ndarray
|
216
|
+
Input signal.
|
217
|
+
lowcut : float
|
218
|
+
The low cutoff frequency.
|
219
|
+
|
220
|
+
Returns:
|
221
|
+
--------
|
222
|
+
np.ndarray
|
223
|
+
The lowpass-filtered signal.
|
224
|
+
"""
|
225
|
+
order, nyq = 8, 0.5 * 1 # Order and Nyquist frequency (assuming sample rate = 1)
|
154
226
|
low = lowcut / nyq
|
227
|
+
# Get the filter coefficients for a lowpass Butterworth filter
|
155
228
|
b, a = signal.butter(order, low, btype='low')
|
229
|
+
# Apply the filter with zero-phase distortion
|
156
230
|
return signal.filtfilt(b, a, x)
|
157
231
|
|
158
232
|
def signal_separate(sig, f1):
|
233
|
+
"""
|
234
|
+
Separate the signal into a constant (mean) component and a bandpass-filtered component.
|
235
|
+
|
236
|
+
Parameters:
|
237
|
+
-----------
|
238
|
+
sig : np.ndarray
|
239
|
+
Input signal.
|
240
|
+
f1 : float
|
241
|
+
Base frequency used to define the bandpass range.
|
242
|
+
|
243
|
+
Returns:
|
244
|
+
--------
|
245
|
+
np.ndarray
|
246
|
+
2D array where the first column is the signal mean and the second column is the bandpass-filtered signal.
|
247
|
+
"""
|
159
248
|
sig_f = np.zeros([sig.shape[0], 2])
|
249
|
+
# First column: constant value equal to the mean of the signal
|
160
250
|
sig_f[:, 0] = sig.mean()
|
251
|
+
# Second column: bandpass filtered signal using a frequency window around f1
|
161
252
|
sig_f[:, 1] = bandpass(sig, f1 * 0.7, f1 * 1.5)
|
162
253
|
return sig_f
|
163
254
|
|
164
255
|
def signal_scale_normalize(sig, f):
|
256
|
+
"""
|
257
|
+
Normalize the signal based on a rolling maximum amplitude and add a sine correction.
|
258
|
+
|
259
|
+
Parameters:
|
260
|
+
-----------
|
261
|
+
sig : np.ndarray
|
262
|
+
Input signal.
|
263
|
+
f : float
|
264
|
+
Frequency used to calculate the sine correction.
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
--------
|
268
|
+
np.ndarray
|
269
|
+
The normalized signal.
|
270
|
+
"""
|
271
|
+
# Calculate the rolling maximum absolute value over a window of 0.5/f samples
|
165
272
|
sig_abs = np.array(pd.Series(abs(sig)).rolling(int(0.5 / f), center=True).max())
|
273
|
+
# Suppress parts of the signal where the amplitude is significantly below the mean
|
166
274
|
sig[sig_abs < np.nanmean(sig_abs) * 0.5] = 0
|
167
275
|
y = np.arange(0, sig.shape[0], 1)
|
276
|
+
# Generate a sine wave for phase correction
|
168
277
|
S = np.sin(2 * np.pi * f * y)
|
278
|
+
# Create a correction term based on the amplitude threshold
|
169
279
|
S1 = (1 - (sig_abs > np.nanmean(sig_abs * 0.5))) * S
|
280
|
+
# Add the correction term to the signal
|
170
281
|
sig = sig + S1
|
282
|
+
# Avoid division by very small numbers
|
171
283
|
sig_abs[sig_abs < np.nanmean(sig_abs * 0.5)] = 1
|
284
|
+
# Normalize the signal
|
172
285
|
sig_norm = sig / sig_abs
|
173
286
|
sig_norm[np.isnan(sig_norm)] = 0
|
174
287
|
return sig_norm
|
175
288
|
|
176
289
|
def phase_calculate(ref, exp, f1):
|
177
|
-
|
178
|
-
|
290
|
+
"""
|
291
|
+
Calculate the phase difference between the reference and experimental signals.
|
292
|
+
|
293
|
+
Parameters:
|
294
|
+
-----------
|
295
|
+
ref : np.ndarray
|
296
|
+
Normalized reference signal.
|
297
|
+
exp : np.ndarray
|
298
|
+
Normalized experimental signal.
|
299
|
+
f1 : float
|
300
|
+
Base frequency.
|
301
|
+
|
302
|
+
Returns:
|
303
|
+
--------
|
304
|
+
np.ndarray
|
305
|
+
The phase difference calculated using lowpass filtered sine and cosine components.
|
306
|
+
"""
|
307
|
+
# Compute sine and its gradient (approximation for cosine)
|
308
|
+
sin_ref = ref
|
309
|
+
cos_ref = np.gradient(ref) / (f1 * 2 * np.pi)
|
310
|
+
# Compute lowpass filtered products to obtain sine and cosine components of the phase difference
|
311
|
+
cos_phi = lowpass(sin_ref * exp, f1)
|
312
|
+
sin_phi = lowpass(cos_ref * exp, f1)
|
313
|
+
# Calculate the phase difference using arctan2 for correct quadrant determination
|
179
314
|
return np.arctan2(sin_phi, cos_phi)
|
180
315
|
|
181
316
|
def phase_1DBOS_process(sig_ref, sig_exp, f1):
|
317
|
+
"""
|
318
|
+
Process a pair of reference and experimental signals to compute the phase difference.
|
319
|
+
|
320
|
+
Parameters:
|
321
|
+
-----------
|
322
|
+
sig_ref : np.ndarray
|
323
|
+
Single column from the reference signal array.
|
324
|
+
sig_exp : np.ndarray
|
325
|
+
Corresponding column from the experimental signal array.
|
326
|
+
f1 : float
|
327
|
+
Base frequency obtained from the reference array.
|
328
|
+
|
329
|
+
Returns:
|
330
|
+
--------
|
331
|
+
np.ndarray
|
332
|
+
The phase difference between the processed reference and experimental signals.
|
333
|
+
"""
|
334
|
+
# Separate the signal into mean and bandpass-filtered components and normalize them
|
182
335
|
separate_sig_ref = signal_scale_normalize(signal_separate(sig_ref, f1)[:, 1], f1)
|
183
336
|
separate_sig_exp = signal_scale_normalize(signal_separate(sig_exp, f1)[:, 1], f1)
|
337
|
+
# Calculate the phase difference between the normalized signals
|
184
338
|
return phase_calculate(separate_sig_ref, separate_sig_exp, f1)
|
185
339
|
|
186
|
-
|
340
|
+
# Determine the dominant frequency from a representative column (column 100) of the reference array
|
341
|
+
f1 = freq_finder(ref_array[freq_sample_area])
|
342
|
+
# Initialize a 2D array to store phase differences for each column
|
187
343
|
phi_2D = np.zeros([ref_array.shape[0], ref_array.shape[1]]).astype("float64")
|
188
344
|
|
345
|
+
# Process each column of the reference and experimental arrays
|
189
346
|
for x in range(ref_array.shape[1]):
|
190
347
|
phi_2D[:, x] = phase_1DBOS_process(ref_array[:, x], exp_array[:, x], f1)
|
191
348
|
|
349
|
+
# Convert phase differences into displacement by dividing by (2*pi*f1)
|
192
350
|
delta_h = phi_2D / (2 * np.pi * f1)
|
193
351
|
return delta_h
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|