paradigma 1.0.4__py3-none-any.whl → 1.1.0__py3-none-any.whl

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.
@@ -1,5 +1,3 @@
1
- from typing import Tuple
2
-
3
1
  import numpy as np
4
2
  from scipy import signal
5
3
 
@@ -42,9 +40,8 @@ def assign_sqa_label(
42
40
 
43
41
  for i in range(n_samples):
44
42
  # Start and end indices for current epoch
45
- start_idx = max(
46
- 0, int((i - (samples_per_epoch - samples_shift)) // fs)
47
- ) # max to handle first epochs
43
+ # Max to handle first epochs
44
+ start_idx = max(0, int((i - (samples_per_epoch - samples_shift)) // fs))
48
45
  end_idx = min(int(i // fs), len(ppg_prob)) # min to handle last epochs
49
46
 
50
47
  # Extract probabilities and labels for the current epoch
@@ -64,7 +61,7 @@ def assign_sqa_label(
64
61
 
65
62
  def extract_pr_segments(
66
63
  sqa_label: np.ndarray, min_pr_samples: int
67
- ) -> Tuple[np.ndarray, np.ndarray]:
64
+ ) -> tuple[np.ndarray, np.ndarray]:
68
65
  """
69
66
  Extracts pulse rate segments based on the SQA label.
70
67
 
@@ -106,16 +103,19 @@ def extract_pr_from_segment(
106
103
  Parameters
107
104
  ----------
108
105
  ppg : np.ndarray
109
- The preprocessed PPG segment with 2 seconds of padding on both sides to reduce boundary effects.
106
+ The preprocessed PPG segment with 2 seconds of padding on both sides
107
+ to reduce boundary effects.
110
108
  tfd_length : int
111
- Length of each segment (in seconds) to calculate the time-frequency distribution.
109
+ Length of each segment (in seconds) to calculate the time-frequency
110
+ distribution.
112
111
  fs : int
113
112
  The sampling frequency of the PPG signal.
114
113
  kern_type : str
115
- Type of TFD kernel to use (e.g., 'wvd' for Wigner-Ville distribution).
114
+ Type of TFD kernel to use (e.g., 'wvd' for Wigner-Ville
115
+ distribution).
116
116
  kern_params : dict
117
- Parameters for the specified kernel. Not required for 'wvd', but relevant for other
118
- kernels like 'spwvd' or 'swvd'. Default is None.
117
+ Parameters for the specified kernel. Not required for 'wvd', but
118
+ relevant for other kernels like 'spwvd' or 'swvd'. Default is None.
119
119
 
120
120
  Returns
121
121
  -------
@@ -157,8 +157,8 @@ def extract_pr_with_tfd(
157
157
  ppg: np.ndarray, fs: int, kern_type: str, kern_params: dict
158
158
  ) -> np.ndarray:
159
159
  """
160
- Estimate pulse rate (PR) from a PPG segment using a TFD method with optional
161
- moving average filtering.
160
+ Estimate pulse rate (PR) from a PPG segment using a TFD method with
161
+ optional moving average filtering.
162
162
 
163
163
  Parameters
164
164
  ----------
@@ -174,7 +174,8 @@ def extract_pr_with_tfd(
174
174
  Returns
175
175
  -------
176
176
  pr_smooth_tfd : np.ndarray
177
- Estimated pr values (in beats per minute) for each 2-second segment of the PPG signal.
177
+ Estimated pr values (in beats per minute) for each 2-second segment
178
+ of the PPG signal.
178
179
  """
179
180
  # Generate the TFD matrix using the specified kernel
180
181
  tfd_obj = TimeFreqDistr()
@@ -204,22 +205,34 @@ def extract_pr_with_tfd(
204
205
  class TimeFreqDistr:
205
206
  def __init__(self):
206
207
  """
207
- This module contains the implementation of the Generalized Time-Frequency Distribution (TFD) computation using non-separable kernels.
208
- This is a Python implementation of the MATLAB code provided by John O Toole in the following repository: https://github.com/otoolej/memeff_TFDs
209
-
210
- The following functions are implemented for the computation of the TFD:
211
- - nonsep_gdtfd: Computes the generalized time-frequency distribution using a non-separable kernel.
212
- - get_analytic_signal: Generates the analytic signal of the input signal.
213
- - gen_analytic: Generates the analytic signal by zero-padding and performing FFT.
214
- - gen_time_lag: Generates the time-lag distribution of the analytic signal.
215
- - multiply_kernel_signal: Multiplies the TFD by the Doppler-lag kernel.
216
- - gen_doppler_lag_kern: Generates the Doppler-lag kernel based on kernel type and parameters.
208
+ This module contains the implementation of the Generalized
209
+ Time-Frequency Distribution (TFD) computation using non-separable
210
+ kernels. This is a Python implementation of the MATLAB code provided
211
+ by John O Toole in the following repository:
212
+ https://github.com/otoolej/memeff_TFDs
213
+
214
+ The following functions are implemented for the computation of the
215
+ TFD:
216
+ - nonsep_gdtfd: Computes the generalized time-frequency
217
+ distribution using a non-separable kernel.
218
+ - get_analytic_signal: Generates the analytic signal of the input
219
+ signal.
220
+ - gen_analytic: Generates the analytic signal by zero-padding and
221
+ performing FFT.
222
+ - gen_time_lag: Generates the time-lag distribution of the
223
+ analytic signal.
224
+ - multiply_kernel_signal: Multiplies the TFD by the Doppler-lag
225
+ kernel.
226
+ - gen_doppler_lag_kern: Generates the Doppler-lag kernel based on
227
+ kernel type and parameters.
217
228
  - get_kern: Gets the kernel based on the provided kernel type.
218
229
  - get_window: General function to calculate a window function.
219
230
  - get_win: Helper function to create the specified window type.
220
- - shift_window: Shifts the window so that positive indices appear first.
231
+ - shift_window: Shifts the window so that positive indices appear
232
+ first.
221
233
  - pad_window: Zero-pads the window to a specified length.
222
- - compute_tfd: Finalizes the time-frequency distribution computation.
234
+ - compute_tfd: Finalizes the time-frequency distribution
235
+ computation.
223
236
  """
224
237
  pass
225
238
 
@@ -230,7 +243,8 @@ class TimeFreqDistr:
230
243
  kern_params: None | dict = None,
231
244
  ):
232
245
  """
233
- Computes the generalized time-frequency distribution (TFD) using a non-separable kernel.
246
+ Computes the generalized time-frequency distribution (TFD) using a
247
+ non-separable kernel.
234
248
 
235
249
  Parameters:
236
250
  -----------
@@ -247,16 +261,20 @@ class TimeFreqDistr:
247
261
  sep - kernel for separable kernel (combintation of SWVD and PWVD)
248
262
 
249
263
  kern_params : dict, optional
250
- Dictionary of parameters specific to the kernel type. Default is None.
251
- The structure of the dictionary depends on the selected kernel type:
264
+ Dictionary of parameters specific to the kernel type. Default is
265
+ None. The structure of the dictionary depends on the selected
266
+ kernel type:
252
267
  - wvd:
253
268
  An empty dictionary, as no additional parameters are required.
254
269
  - swvd:
255
270
  Dictionary with the following keys:
256
271
  'win_length': Length of the smoothing window.
257
- 'win_type': Type of window function (e.g., 'hamm', 'hann').
258
- 'win_param' (optional): Additional parameters for the window.
259
- 'win_param2' (optional): 0 for time-domain window or 1 for Doppler-domain window.
272
+ 'win_type': Type of window function (e.g., 'hamm',
273
+ 'hann').
274
+ 'win_param' (optional): Additional parameters for the
275
+ window.
276
+ 'win_param2' (optional): 0 for time-domain window or 1
277
+ for Doppler-domain window.
260
278
 
261
279
  Example:
262
280
  ```python
@@ -272,7 +290,8 @@ class TimeFreqDistr:
272
290
  'win_length': Length of the smoothing window.
273
291
  'win_type': Type of window function (e.g., 'cosh').
274
292
  'win_param' (optional): Additional parameters for the window.
275
- 'win_param2' (optional): 0 for time-domain window or 1 for Doppler-domain window.
293
+ 'win_param2' (optional): 0 for time-domain window or 1 for
294
+ Doppler-domain window.
276
295
  Example:
277
296
  ```python
278
297
  kern_params = {
@@ -282,18 +301,23 @@ class TimeFreqDistr:
282
301
  }
283
302
  ```
284
303
  - sep:
285
- Dictionary containing two nested dictionaries, one for the Doppler window and one for the lag window:
304
+ Dictionary containing two nested dictionaries, one for the Doppler
305
+ window and one for the lag window:
286
306
  'doppler': {
287
307
  'win_length': Length of the Doppler-domain window.
288
308
  'win_type': Type of Doppler-domain window function.
289
- 'win_param' (optional): Additional parameters for the Doppler window.
290
- 'win_param2' (optional): 0 for time-domain window or 1 for Doppler-domain window.
309
+ 'win_param' (optional): Additional parameters for the
310
+ Doppler window.
311
+ 'win_param2' (optional): 0 for time-domain window or 1
312
+ for Doppler-domain window.
291
313
  }
292
314
  'lag': {
293
315
  'win_length': Length of the lag-domain window.
294
316
  'win_type': Type of lag-domain window function.
295
- 'win_param' (optional): Additional parameters for the lag window.
296
- 'win_param2' (optional): 0 for time-domain window or 1 for Doppler-domain window.
317
+ 'win_param' (optional): Additional parameters for the lag
318
+ window.
319
+ 'win_param2' (optional): 0 for time-domain window or 1
320
+ for Doppler-domain window.
297
321
  }
298
322
  Example:
299
323
  ```python
@@ -315,17 +339,17 @@ class TimeFreqDistr:
315
339
  The computed time-frequency distribution.
316
340
  """
317
341
  z = self.get_analytic_signal(x)
318
- N = len(z) // 2 # Since z is a signal of length 2N
319
- Nh = int(np.ceil(N / 2))
342
+ n_len = len(z) // 2 # Since z is a signal of length 2*n_len
343
+ n_half = int(np.ceil(n_len / 2))
320
344
 
321
345
  # Generate the time-lag distribution of the analytic signal
322
346
  tfd = self.gen_time_lag(z)
323
347
 
324
348
  # Multiply the TFD by the Doppler-lag kernel
325
- tfd = self.multiply_kernel_signal(tfd, kern_type, kern_params, N, Nh)
349
+ tfd = self.multiply_kernel_signal(tfd, kern_type, kern_params, n_len, n_half)
326
350
 
327
351
  # Finalize the TFD computation
328
- tfd = self.compute_tfd(N, Nh, tfd)
352
+ tfd = self.compute_tfd(n_len, n_half, tfd)
329
353
 
330
354
  return tfd
331
355
 
@@ -343,14 +367,15 @@ class TimeFreqDistr:
343
367
  z : ndarray
344
368
  Analytic signal with zero-padded imaginary part.
345
369
  """
346
- N = len(x)
370
+ n_len = len(x)
347
371
 
348
- # Ensure the signal length is even by trimming one sample if odd, since the gen_time_lag function requires an even-length signal
349
- if N % 2 != 0:
372
+ # Ensure the signal length is even by trimming one sample if odd,
373
+ # since the gen_time_lag function requires an even-length signal
374
+ if n_len % 2 != 0:
350
375
  x = x[:-1]
351
376
 
352
- # Make the analytical signal of the real-valued signal z (preprocessed PPG signal)
353
- # doesn't work for input of complex numbers
377
+ # Make the analytical signal of the real-valued signal z
378
+ # (preprocessed PPG signal). Doesn't work for input of complex numbers
354
379
  z = self.gen_analytic(x)
355
380
 
356
381
  return z
@@ -369,22 +394,22 @@ class TimeFreqDistr:
369
394
  z : ndarray
370
395
  Analytic signal in the time domain with zeroed second half.
371
396
  """
372
- N = len(x)
397
+ n_len = len(x)
373
398
 
374
399
  # Zero-pad the signal to double its length
375
- x = np.concatenate((np.real(x), np.zeros(N)))
400
+ x = np.concatenate((np.real(x), np.zeros(n_len)))
376
401
  x_fft = np.fft.fft(x)
377
402
 
378
403
  # Generate the analytic signal in the frequency domain
379
- H = np.empty(2 * N) # Preallocate an array of size 2*N
380
- H[0] = 1 # First element
381
- H[1:N] = 2 # Next N-1 elements
382
- H[N] = 1 # Middle element
383
- H[N + 1 :] = 0 # Last N-1 elements
384
- z_cb = np.fft.ifft(x_fft * H)
404
+ h_analytic = np.empty(2 * n_len) # Preallocate an array of size 2*n_len
405
+ h_analytic[0] = 1 # First element
406
+ h_analytic[1:n_len] = 2 # Next n_len-1 elements
407
+ h_analytic[n_len] = 1 # Middle element
408
+ h_analytic[n_len + 1 :] = 0 # Last n_len-1 elements
409
+ z_cb = np.fft.ifft(x_fft * h_analytic)
385
410
 
386
411
  # Force the second half of the time-domain signal to zero
387
- z = np.concatenate((z_cb[:N], np.zeros(N)))
412
+ z = np.concatenate((z_cb[:n_len], np.zeros(n_len)))
388
413
 
389
414
  return z
390
415
 
@@ -403,30 +428,35 @@ class TimeFreqDistr:
403
428
  Time-lag distribution of the analytic signal z.
404
429
 
405
430
  """
406
- N = len(z) // 2 # Assuming z is a signal of length 2N
407
- Nh = int(np.ceil(N / 2))
431
+ n_len = len(z) // 2 # Assuming z is a signal of length 2*n_len
432
+ n_half = int(np.ceil(n_len / 2))
408
433
 
409
434
  # Initialize the time-frequency distribution (TFD) matrix
410
- tfd = np.zeros((N, N), dtype=complex)
435
+ tfd = np.zeros((n_len, n_len), dtype=complex)
411
436
 
412
- m = np.arange(Nh)
437
+ m = np.arange(n_half)
413
438
 
414
439
  # Loop over time indices
415
- for n in range(N):
416
- inp = np.mod(n + m, 2 * N)
417
- inn = np.mod(n - m, 2 * N)
440
+ for n in range(n_len):
441
+ inp = np.mod(n + m, 2 * n_len)
442
+ inn = np.mod(n - m, 2 * n_len)
418
443
 
419
444
  # Extract the time slice from the analytic signal
420
- K_time_slice = z[inp] * np.conj(z[inn])
445
+ k_time_slice = z[inp] * np.conj(z[inn])
421
446
 
422
447
  # Store real and imaginary parts
423
- tfd[n, :Nh] = np.real(K_time_slice)
424
- tfd[n, Nh:] = np.imag(K_time_slice)
448
+ tfd[n, :n_half] = np.real(k_time_slice)
449
+ tfd[n, n_half:] = np.imag(k_time_slice)
425
450
 
426
451
  return tfd
427
452
 
428
453
  def multiply_kernel_signal(
429
- self, tfd: np.ndarray, kern_type: str, kern_params: dict, N: int, Nh: int
454
+ self,
455
+ tfd: np.ndarray,
456
+ kern_type: str,
457
+ kern_params: dict,
458
+ n_len: int,
459
+ n_half: int,
430
460
  ) -> np.ndarray:
431
461
  """
432
462
  Multiplies the TFD by the Doppler-lag kernel.
@@ -450,24 +480,24 @@ class TimeFreqDistr:
450
480
  Modified TFD after kernel multiplication.
451
481
  """
452
482
  # Loop over lag indices
453
- for m in range(Nh):
483
+ for m in range(n_half):
454
484
  # Generate the Doppler-lag kernel for each lag index
455
- g_lag_slice = self.gen_doppler_lag_kern(kern_type, kern_params, N, m)
485
+ g_lag_slice = self.gen_doppler_lag_kern(kern_type, kern_params, n_len, m)
456
486
 
457
487
  # Extract and transform the TFD slice for this lag
458
- tfd_slice = np.fft.fft(tfd[:, m]) + 1j * np.fft.fft(tfd[:, Nh + m])
488
+ tfd_slice = np.fft.fft(tfd[:, m]) + 1j * np.fft.fft(tfd[:, n_half + m])
459
489
 
460
490
  # Multiply by the kernel and perform inverse FFT
461
- R_lag_slice = np.fft.ifft(tfd_slice * g_lag_slice)
491
+ r_lag_slice = np.fft.ifft(tfd_slice * g_lag_slice)
462
492
 
463
493
  # Store real and imaginary parts back into the TFD
464
- tfd[:, m] = np.real(R_lag_slice)
465
- tfd[:, Nh + m] = np.imag(R_lag_slice)
494
+ tfd[:, m] = np.real(r_lag_slice)
495
+ tfd[:, n_half + m] = np.imag(r_lag_slice)
466
496
 
467
497
  return tfd
468
498
 
469
499
  def gen_doppler_lag_kern(
470
- self, kern_type: str, kern_params: dict, N: int, lag_index: int
500
+ self, kern_type: str, kern_params: dict, n_len: int, lag_index: int
471
501
  ):
472
502
  """
473
503
  Generate the Doppler-lag kernel based on kernel type and parameters.
@@ -478,7 +508,7 @@ class TimeFreqDistr:
478
508
  Type of kernel (e.g., 'wvd', 'swvd', 'pwvd', etc.).
479
509
  kern_params : dict
480
510
  Parameters for the kernel.
481
- N : int
511
+ n_len : int
482
512
  Signal length.
483
513
  lag_index : int
484
514
  Current lag index.
@@ -488,15 +518,20 @@ class TimeFreqDistr:
488
518
  g : ndarray
489
519
  Doppler-lag kernel for the given lag.
490
520
  """
491
- g = np.zeros(N, dtype=complex) # Initialize the kernel
521
+ g = np.zeros(n_len, dtype=complex) # Initialize the kernel
492
522
 
493
523
  # Get kernel based on the type
494
- g = self.get_kern(g, lag_index, kern_type, kern_params, N)
524
+ g = self.get_kern(g, lag_index, kern_type, kern_params, n_len)
495
525
 
496
526
  return np.real(g) # All kernels are real valued
497
527
 
498
528
  def get_kern(
499
- self, g: np.ndarray, lag_index: int, kern_type: str, kern_params: dict, N: int
529
+ self,
530
+ g: np.ndarray,
531
+ lag_index: int,
532
+ kern_type: str,
533
+ kern_params: dict,
534
+ n_len: int,
500
535
  ) -> np.ndarray:
501
536
  """
502
537
  Get the kernel based on the provided kernel type.
@@ -511,7 +546,7 @@ class TimeFreqDistr:
511
546
  Type of kernel to use (now included: 'wvd', 'swvd', 'pwvd', 'sep').
512
547
  kern_params : dict
513
548
  Parameters for the specified kernel.
514
- N : int
549
+ n_len : int
515
550
  Signal length.
516
551
 
517
552
  Returns:
@@ -541,12 +576,13 @@ class TimeFreqDistr:
541
576
  g1 = np.copy(g) # Create a new array for g1
542
577
  g2 = np.copy(g) # Create a new array for g2
543
578
 
544
- # Call recursively to obtain g1 and g2 kernels (no in-place modification of g)
579
+ # Call recursively to obtain g1 and g2 kernels (no in-place
580
+ # modification of g)
545
581
  g1 = self.get_kern(
546
- g1, lag_index, "swvd", kern_params["lag"], N
582
+ g1, lag_index, "swvd", kern_params["lag"], n_len
547
583
  ) # Generate the first kernel
548
584
  g2 = self.get_kern(
549
- g2, lag_index, "pwvd", kern_params["doppler"], N
585
+ g2, lag_index, "pwvd", kern_params["doppler"], n_len
550
586
  ) # Generate the second kernel
551
587
  g = g1 * g2 # Multiply the two kernels to obtain the separable kernel
552
588
 
@@ -561,16 +597,16 @@ class TimeFreqDistr:
561
597
  win_param = kern_params["win_param"] if "win_param" in kern_params else 0
562
598
  win_param2 = kern_params["win_param2"] if "win_param2" in kern_params else 1
563
599
 
564
- G = self.get_window(win_length, win_type, win_param)
565
- G = self.pad_window(G, N)
600
+ g_window = self.get_window(win_length, win_type, win_param)
601
+ g_window = self.pad_window(g_window, n_len)
566
602
 
567
603
  if kern_type == "swvd" and win_param2 == 0:
568
- G = np.fft.fft(G)
569
- if G[0] != 0: # add this check to avoid division by zero
570
- G /= G[0]
571
- G = G[lag_index]
604
+ g_window = np.fft.fft(g_window)
605
+ if g_window[0] != 0: # add this check to avoid division by zero
606
+ g_window /= g_window[0]
607
+ g_window = g_window[lag_index]
572
608
 
573
- g[:] = G
609
+ g[:] = g_window
574
610
 
575
611
  return g
576
612
 
@@ -580,7 +616,7 @@ class TimeFreqDistr:
580
616
  win_type: str,
581
617
  win_param: float | None = None,
582
618
  dft_window: bool = False,
583
- Npad: int = 0,
619
+ n_pad: int = 0,
584
620
  ) -> np.ndarray:
585
621
  """
586
622
  General function to calculate a window function.
@@ -596,8 +632,8 @@ class TimeFreqDistr:
596
632
  Window parameter (e.g., alpha for Gaussian window). Default is None.
597
633
  dft_window : bool, optional
598
634
  If True, returns the DFT of the window. Default is False.
599
- Npad : int, optional
600
- If greater than 0, zero-pads the window to length Npad. Default is 0.
635
+ n_pad : int, optional
636
+ If greater than 0, zero-pads the window to length n_pad. Default is 0.
601
637
 
602
638
  Returns:
603
639
  --------
@@ -611,9 +647,9 @@ class TimeFreqDistr:
611
647
  # Shift the window so that positive indices are first
612
648
  win = self.shift_window(win)
613
649
 
614
- # Zero-pad the window to length Npad if necessary
615
- if Npad > 0:
616
- win = self.pad_window(win, Npad)
650
+ # Zero-pad the window to length n_pad if necessary
651
+ if n_pad > 0:
652
+ win = self.pad_window(win, n_pad)
617
653
 
618
654
  return win
619
655
 
@@ -634,7 +670,8 @@ class TimeFreqDistr:
634
670
  win_type : str
635
671
  Type of window.
636
672
  win_param : float, optional
637
- Additional parameter for certain window types (e.g., Gaussian alpha). Default is None.
673
+ Additional parameter for certain window types (e.g., Gaussian
674
+ alpha). Default is None.
638
675
  dft_window : bool, optional
639
676
  If True, returns the DFT of the window. Default is False.
640
677
 
@@ -688,10 +725,10 @@ class TimeFreqDistr:
688
725
  w_shifted : ndarray
689
726
  Shifted window with positive indices first.
690
727
  """
691
- N = len(w)
692
- return np.roll(w, N // 2)
728
+ n_len = len(w)
729
+ return np.roll(w, n_len // 2)
693
730
 
694
- def pad_window(self, w: np.ndarray, Npad: int) -> np.ndarray:
731
+ def pad_window(self, w: np.ndarray, n_pad: int) -> np.ndarray:
695
732
  """
696
733
  Zero-pad the window to a specified length.
697
734
 
@@ -699,49 +736,49 @@ class TimeFreqDistr:
699
736
  -----------
700
737
  w : ndarray
701
738
  The original window.
702
- Npad : int
739
+ n_pad : int
703
740
  Length to zero-pad the window to.
704
741
 
705
742
  Returns:
706
743
  --------
707
744
  w_pad : ndarray
708
- Zero-padded window of length Npad.
745
+ Zero-padded window of length n_pad.
709
746
 
710
747
  Raises:
711
748
  -------
712
749
  ValueError:
713
- If Npad is less than the original window length.
750
+ If n_pad is less than the original window length.
714
751
  """
715
- N = len(w)
716
- w_pad = np.zeros(Npad)
717
- Nh = N // 2
752
+ n_len = len(w)
753
+ w_pad = np.zeros(n_pad)
754
+ n_half = n_len // 2
718
755
 
719
- if Npad < N:
720
- raise ValueError("Npad must be greater than or equal to the window length")
756
+ if n_pad < n_len:
757
+ raise ValueError("n_pad must be greater than or equal to the window length")
721
758
 
722
- if N == Npad:
759
+ if n_len == n_pad:
723
760
  return w
724
761
 
725
- if N % 2 == 1: # For odd N
726
- w_pad[: Nh + 1] = w[: Nh + 1]
727
- w_pad[-Nh:] = w[-Nh:]
728
- else: # For even N
729
- w_pad[:Nh] = w[:Nh]
730
- w_pad[Nh] = w[Nh] / 2
731
- w_pad[-Nh:] = w[-Nh:]
732
- w_pad[-Nh] = w[Nh] / 2
762
+ if n_len % 2 == 1: # For odd n_len
763
+ w_pad[: n_half + 1] = w[: n_half + 1]
764
+ w_pad[-n_half:] = w[-n_half:]
765
+ else: # For even n_len
766
+ w_pad[:n_half] = w[:n_half]
767
+ w_pad[n_half] = w[n_half] / 2
768
+ w_pad[-n_half:] = w[-n_half:]
769
+ w_pad[-n_half] = w[n_half] / 2
733
770
 
734
771
  return w_pad
735
772
 
736
- def compute_tfd(self, N: int, Nh: int, tfd: np.ndarray):
773
+ def compute_tfd(self, n_len: int, n_half: int, tfd: np.ndarray):
737
774
  """
738
775
  Finalizes the time-frequency distribution computation.
739
776
 
740
777
  Parameters:
741
778
  -----------
742
- N : int
779
+ n_len : int
743
780
  Size of the TFD.
744
- Nh : int
781
+ n_half : int
745
782
  Half-length parameter.
746
783
  tfd : np.ndarray
747
784
  Time-frequency distribution to be finalized.
@@ -749,34 +786,36 @@ class TimeFreqDistr:
749
786
  Returns:
750
787
  --------
751
788
  tfd : np.ndarray
752
- Final computed TFD (N,N).
789
+ Final computed TFD (n_len, n_len).
753
790
  """
754
- m = np.arange(0, Nh) # m = 0:(Nh-1)
755
- mb = np.arange(1, Nh) # mb = 1:(Nh-1)
791
+ m = np.arange(0, n_half) # m = 0:(n_half-1)
792
+ mb = np.arange(1, n_half) # mb = 1:(n_half-1)
756
793
 
757
- for n in range(0, N - 1, 2): # for n=0:2:N-2
758
- R_even_half = np.complex128(tfd[n, :Nh]) + 1j * np.complex128(tfd[n, Nh:])
759
- R_odd_half = np.complex128(tfd[n + 1, :Nh]) + 1j * np.complex128(
760
- tfd[n + 1, Nh:]
794
+ for n in range(0, n_len - 1, 2): # for n=0:2:n_len-2
795
+ r_even_half = np.complex128(tfd[n, :n_half]) + 1j * np.complex128(
796
+ tfd[n, n_half:]
797
+ )
798
+ r_odd_half = np.complex128(tfd[n + 1, :n_half]) + 1j * np.complex128(
799
+ tfd[n + 1, n_half:]
761
800
  )
762
801
 
763
- R_tslice_even = np.zeros(N, dtype=np.complex128)
764
- R_tslice_odd = np.zeros(N, dtype=np.complex128)
802
+ r_tslice_even = np.zeros(n_len, dtype=np.complex128)
803
+ r_tslice_odd = np.zeros(n_len, dtype=np.complex128)
765
804
 
766
- R_tslice_even[m] = R_even_half
767
- R_tslice_odd[m] = R_odd_half
805
+ r_tslice_even[m] = r_even_half
806
+ r_tslice_odd[m] = r_odd_half
768
807
 
769
- R_tslice_even[N - mb] = np.conj(R_even_half[mb])
770
- R_tslice_odd[N - mb] = np.conj(R_odd_half[mb])
808
+ r_tslice_even[n_len - mb] = np.conj(r_even_half[mb])
809
+ r_tslice_odd[n_len - mb] = np.conj(r_odd_half[mb])
771
810
 
772
811
  # Perform FFT to compute time slices
773
- tfd_time_slice = np.fft.fft(R_tslice_even + 1j * R_tslice_odd)
812
+ tfd_time_slice = np.fft.fft(r_tslice_even + 1j * r_tslice_odd)
774
813
 
775
814
  tfd[n, :] = np.real(tfd_time_slice)
776
815
  tfd[n + 1, :] = np.imag(tfd_time_slice)
777
816
 
778
- tfd = tfd / N # Normalize the TFD
779
- tfd = (
780
- tfd.transpose()
781
- ) # Transpose the TFD to have the time on the x-axis and frequency on the y-axis
817
+ tfd = tfd / n_len # Normalize the TFD
818
+ # Transpose the TFD to have the time on the x-axis and frequency on
819
+ # the y-axis
820
+ tfd = tfd.transpose()
782
821
  return tfd