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.
@@ -6,4 +6,4 @@ from .reconstruction_utils import *
6
6
  from .culculate_refractiveindex import *
7
7
  from .evaluation import *
8
8
 
9
- __version__ = '0.0.2'
9
+ __version__ = '0.0.3'
@@ -137,7 +137,7 @@ import mpl_toolkits.axes_grid1
137
137
  # neighbor_density_array = np.asarray(neighbor_density)
138
138
  # return neighbor_density_array
139
139
 
140
- # def _normalize(self,data):
140
+ # def _normalize(data):
141
141
  # """
142
142
  # Min-Maxスケーリングを使用してデータを正規化します。
143
143
  # """
@@ -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 : np.ndarray, exp_array : np.ndarray):
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
- gpass, gstop = 2, 60
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
- order, nyq = 8, 0.5 * 1
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
- sin_ref, cos_ref = ref, np.gradient(ref) / (f1 * 2 * np.pi)
178
- cos_phi, sin_phi = lowpass(sin_ref * exp, f1), lowpass(cos_ref * exp, f1)
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
- f1 = freq_finder(ref_array[:, 100])
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: BOSlib
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: the library of Background Oriented Schlieren
5
5
  Home-page: https://github.com/ogayuuki0202/BOSlib
6
6
  Download-URL: https://github.com/ogayuuki0202/BOSlib
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: BOSlib
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: the library of Background Oriented Schlieren
5
5
  Home-page: https://github.com/ogayuuki0202/BOSlib
6
6
  Download-URL: https://github.com/ogayuuki0202/BOSlib
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes