modusa 0.2.22__py3-none-any.whl → 0.3__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.
- modusa/.DS_Store +0 -0
- modusa/__init__.py +8 -1
- modusa/decorators.py +4 -4
- modusa/devtools/generate_docs_source.py +96 -0
- modusa/devtools/generate_template.py +13 -13
- modusa/devtools/main.py +4 -3
- modusa/devtools/templates/generator.py +1 -1
- modusa/devtools/templates/io.py +1 -1
- modusa/devtools/templates/{signal.py → model.py} +18 -11
- modusa/devtools/templates/plugin.py +1 -1
- modusa/devtools/templates/test.py +2 -3
- modusa/devtools/templates/{engine.py → tool.py} +3 -8
- modusa/generators/__init__.py +9 -1
- modusa/generators/audio.py +188 -0
- modusa/generators/audio_waveforms.py +22 -13
- modusa/generators/base.py +1 -1
- modusa/generators/ftds.py +298 -0
- modusa/generators/s1d.py +270 -0
- modusa/generators/s2d.py +300 -0
- modusa/generators/s_ax.py +102 -0
- modusa/generators/t_ax.py +64 -0
- modusa/generators/tds.py +267 -0
- modusa/main.py +0 -30
- modusa/models/__init__.py +14 -0
- modusa/models/__pycache__/signal1D.cpython-312.pyc.4443461152 +0 -0
- modusa/models/audio.py +90 -0
- modusa/models/base.py +70 -0
- modusa/models/data.py +457 -0
- modusa/models/ftds.py +584 -0
- modusa/models/s1d.py +578 -0
- modusa/models/s2d.py +619 -0
- modusa/models/s_ax.py +448 -0
- modusa/models/t_ax.py +335 -0
- modusa/models/tds.py +465 -0
- modusa/plugins/__init__.py +3 -1
- modusa/tmp.py +98 -0
- modusa/tools/__init__.py +7 -0
- modusa/tools/audio_converter.py +73 -0
- modusa/tools/audio_loader.py +90 -0
- modusa/tools/audio_player.py +89 -0
- modusa/tools/base.py +43 -0
- modusa/tools/math_ops.py +335 -0
- modusa/tools/plotter.py +351 -0
- modusa/tools/youtube_downloader.py +72 -0
- modusa/utils/excp.py +15 -42
- modusa/utils/np_func_cat.py +44 -0
- modusa/utils/plot.py +142 -0
- {modusa-0.2.22.dist-info → modusa-0.3.dist-info}/METADATA +5 -16
- modusa-0.3.dist-info/RECORD +60 -0
- modusa/engines/.DS_Store +0 -0
- modusa/engines/__init__.py +0 -3
- modusa/engines/base.py +0 -14
- modusa/io/__init__.py +0 -9
- modusa/io/audio_converter.py +0 -76
- modusa/io/audio_loader.py +0 -214
- modusa/io/audio_player.py +0 -72
- modusa/io/base.py +0 -43
- modusa/io/plotter.py +0 -430
- modusa/io/youtube_downloader.py +0 -139
- modusa/signals/__init__.py +0 -7
- modusa/signals/audio_signal.py +0 -483
- modusa/signals/base.py +0 -34
- modusa/signals/frequency_domain_signal.py +0 -329
- modusa/signals/signal_ops.py +0 -158
- modusa/signals/spectrogram.py +0 -465
- modusa/signals/time_domain_signal.py +0 -309
- modusa-0.2.22.dist-info/RECORD +0 -47
- {modusa-0.2.22.dist-info → modusa-0.3.dist-info}/WHEEL +0 -0
- {modusa-0.2.22.dist-info → modusa-0.3.dist-info}/entry_points.txt +0 -0
- {modusa-0.2.22.dist-info → modusa-0.3.dist-info}/licenses/LICENSE.md +0 -0
modusa/signals/spectrogram.py
DELETED
|
@@ -1,465 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from modusa import excp
|
|
5
|
-
from modusa.decorators import immutable_property, validate_args_type
|
|
6
|
-
from modusa.signals.base import ModusaSignal
|
|
7
|
-
from typing import Self, Any
|
|
8
|
-
import numpy as np
|
|
9
|
-
import matplotlib.pyplot as plt
|
|
10
|
-
|
|
11
|
-
class Spectrogram(ModusaSignal):
|
|
12
|
-
"""
|
|
13
|
-
A 2D time–frequency representation of a signal.
|
|
14
|
-
|
|
15
|
-
Parameters
|
|
16
|
-
----------
|
|
17
|
-
S : np.ndarray
|
|
18
|
-
2D matrix representing the spectrogram (shape: [n_freqs, n_frames]).
|
|
19
|
-
f : np.ndarray
|
|
20
|
-
Frequency axis corresponding to the rows of `S` (shape: [n_freqs]).
|
|
21
|
-
t : np.ndarray
|
|
22
|
-
Time axis corresponding to the columns of `S` (shape: [n_frames]).
|
|
23
|
-
title : str, optional
|
|
24
|
-
Optional title for the spectrogram (e.g., used in plotting).
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
#--------Meta Information----------
|
|
28
|
-
_name = "Spectrogram"
|
|
29
|
-
_description = ""
|
|
30
|
-
_author_name = "Ankit Anand"
|
|
31
|
-
_author_email = "ankit0.anand0@gmail.com"
|
|
32
|
-
_created_at = "2025-07-07"
|
|
33
|
-
#----------------------------------
|
|
34
|
-
|
|
35
|
-
@validate_args_type()
|
|
36
|
-
def __init__(self, S: np.ndarray, f: np.ndarray, t: np.ndarray, title: str | None = None):
|
|
37
|
-
super().__init__() # Instantiating `ModusaSignal` class
|
|
38
|
-
|
|
39
|
-
if S.ndim != 2:
|
|
40
|
-
raise excp.InputValueError(f"`S` must have 2 dimension, got {S.ndim}.")
|
|
41
|
-
if f.ndim != 1:
|
|
42
|
-
raise excp.InputValueError(f"`f` must have 1 dimension, got {f.ndim}.")
|
|
43
|
-
if t.ndim != 1:
|
|
44
|
-
raise excp.InputValueError(f"`t` must have 1 dimension, got {t.ndim}.")
|
|
45
|
-
|
|
46
|
-
if t.shape[0] != S.shape[1] or f.shape[0] != S.shape[0]:
|
|
47
|
-
raise excp.InputValueError(f"`f` and `t` shape do not match with `S` {S.shape}, got {(f.shape[0], t.shape[0])}")
|
|
48
|
-
|
|
49
|
-
if S.shape[1] == 0:
|
|
50
|
-
raise excp.InputValueError("`S` must have at least one time frame")
|
|
51
|
-
|
|
52
|
-
if t.shape[0] >= 2:
|
|
53
|
-
dts = np.diff(t)
|
|
54
|
-
if not np.allclose(dts, dts[0]):
|
|
55
|
-
raise excp.InputValueError("`t` must be equally spaced")
|
|
56
|
-
|
|
57
|
-
self._S = S
|
|
58
|
-
self._f = f
|
|
59
|
-
self._t = t
|
|
60
|
-
self.title = title or self._name
|
|
61
|
-
|
|
62
|
-
#----------------------
|
|
63
|
-
# Properties
|
|
64
|
-
#----------------------
|
|
65
|
-
@immutable_property("Create a new object instead.")
|
|
66
|
-
def S(self) -> np.ndarray:
|
|
67
|
-
"""Spectrogram matrix (freq × time)."""
|
|
68
|
-
return self._S
|
|
69
|
-
|
|
70
|
-
@immutable_property("Create a new object instead.")
|
|
71
|
-
def f(self) -> np.ndarray:
|
|
72
|
-
"""Frequency axis."""
|
|
73
|
-
return self._f
|
|
74
|
-
|
|
75
|
-
@immutable_property("Create a new object instead.")
|
|
76
|
-
def t(self) -> np.ndarray:
|
|
77
|
-
"""Time axis."""
|
|
78
|
-
return self._t
|
|
79
|
-
|
|
80
|
-
@immutable_property("Read only property.")
|
|
81
|
-
def shape(self) -> np.ndarray:
|
|
82
|
-
"""Shape of the spectrogram (freqs, frames)."""
|
|
83
|
-
return self.S.shape
|
|
84
|
-
|
|
85
|
-
@immutable_property("Read only property.")
|
|
86
|
-
def ndim(self) -> np.ndarray:
|
|
87
|
-
"""Number of dimensions (always 2)."""
|
|
88
|
-
return self.S.ndim
|
|
89
|
-
|
|
90
|
-
@immutable_property("Mutation not allowed.")
|
|
91
|
-
def info(self) -> None:
|
|
92
|
-
"""Print key information about the spectrogram signal."""
|
|
93
|
-
time_resolution = self.t[1] - self.t[0]
|
|
94
|
-
n_freq_bins = self.S.shape[0]
|
|
95
|
-
|
|
96
|
-
# Estimate NFFT size
|
|
97
|
-
nfft = (n_freq_bins - 1) * 2
|
|
98
|
-
|
|
99
|
-
print("-"*50)
|
|
100
|
-
print(f"{'Title':<20}: {self.title}")
|
|
101
|
-
print(f"{'Kind':<20}: {self._name}")
|
|
102
|
-
print(f"{'Shape':<20}: {self.S.shape} (freq bins × time frames)")
|
|
103
|
-
print(f"{'Time resolution':<20}: {time_resolution:.4f} sec ({time_resolution * 1000:.2f} ms)")
|
|
104
|
-
print(f"{'Freq resolution':<20}: {(self.f[1] - self.f[0]):.2f} Hz")
|
|
105
|
-
print("-"*50)
|
|
106
|
-
#------------------------
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
#------------------------
|
|
110
|
-
# Useful tools
|
|
111
|
-
#------------------------
|
|
112
|
-
|
|
113
|
-
def __getitem__(self, key: tuple[int | slice, int | slice]) -> "Spectrogram | FrequencyDomainSignal | TimeDomainSignal":
|
|
114
|
-
"""
|
|
115
|
-
Enable 2D indexing: signal[f_idx, t_idx]
|
|
116
|
-
|
|
117
|
-
Returns:
|
|
118
|
-
- Spectrogram when both f and t are slices
|
|
119
|
-
- FrequencyDomainSignal when t is int (i.e., fixed time)
|
|
120
|
-
- TimeDomainSignal when f is int (i.e., fixed frequency)
|
|
121
|
-
"""
|
|
122
|
-
from modusa.signals.time_domain_signal import TimeDomainSignal
|
|
123
|
-
from modusa.signals.frequency_domain_signal import FrequencyDomainSignal
|
|
124
|
-
|
|
125
|
-
if isinstance(key, tuple) and len(key) == 2:
|
|
126
|
-
f_key, t_key = key
|
|
127
|
-
|
|
128
|
-
sliced_data = self.S[f_key, t_key]
|
|
129
|
-
sliced_f = self.f[f_key]
|
|
130
|
-
sliced_t = self.t[t_key]
|
|
131
|
-
|
|
132
|
-
# Case 1: Scalar value → return plain numpy scalar
|
|
133
|
-
if np.isscalar(sliced_data):
|
|
134
|
-
return np.array(sliced_data)
|
|
135
|
-
|
|
136
|
-
# Case 2: frequency slice at a single time (→ FrequencyDomainSignal)
|
|
137
|
-
elif isinstance(t_key, int):
|
|
138
|
-
if not isinstance(f_key, int): # already handled scalar case
|
|
139
|
-
sliced_data = np.asarray(sliced_data).flatten()
|
|
140
|
-
sliced_f = np.asarray(sliced_f)
|
|
141
|
-
t0 = float(self.t[t_key])
|
|
142
|
-
return FrequencyDomainSignal(
|
|
143
|
-
spectrum=sliced_data,
|
|
144
|
-
f=sliced_f,
|
|
145
|
-
t0=t0,
|
|
146
|
-
title=self.title + f" [t = {t0:.2f} sec]"
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
# Case 3: time slice at a single frequency (→ TimeDomainSignal)
|
|
150
|
-
elif isinstance(f_key, int):
|
|
151
|
-
sliced_data = np.asarray(sliced_data).flatten()
|
|
152
|
-
sliced_t = np.asarray(sliced_t)
|
|
153
|
-
sr = 1.0 / np.mean(np.diff(self.t)) # assume uniform time axis
|
|
154
|
-
t0 = float(self.t[0])
|
|
155
|
-
f_val = float(self.f[f_key])
|
|
156
|
-
return TimeDomainSignal(
|
|
157
|
-
y=sliced_data,
|
|
158
|
-
sr=sr,
|
|
159
|
-
t0=t0,
|
|
160
|
-
title=self.title + f" [f = {f_val:.2f} Hz]"
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
# Case 4: 2D slice → Spectrogram
|
|
164
|
-
else:
|
|
165
|
-
return self.__class__(
|
|
166
|
-
S=sliced_data,
|
|
167
|
-
f=sliced_f,
|
|
168
|
-
t=sliced_t,
|
|
169
|
-
title=self.title
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
raise TypeError("Expected 2D indexing: signal[f_idx, t_idx]")
|
|
173
|
-
|
|
174
|
-
def crop(
|
|
175
|
-
self,
|
|
176
|
-
f_min: float | None = None,
|
|
177
|
-
f_max: float | None = None,
|
|
178
|
-
t_min: float | None = None,
|
|
179
|
-
t_max: float | None = None
|
|
180
|
-
) -> "Spectrogram":
|
|
181
|
-
"""
|
|
182
|
-
Crop the spectrogram to a rectangular region in frequency-time space.
|
|
183
|
-
|
|
184
|
-
.. code-block:: python
|
|
185
|
-
|
|
186
|
-
cropped = spec.crop(f_min=100, f_max=1000, t_min=5.0, t_max=10.0)
|
|
187
|
-
|
|
188
|
-
Parameters
|
|
189
|
-
----------
|
|
190
|
-
f_min : float or None
|
|
191
|
-
Inclusive lower frequency bound. If None, no lower bound.
|
|
192
|
-
f_max : float or None
|
|
193
|
-
Exclusive upper frequency bound. If None, no upper bound.
|
|
194
|
-
t_min : float or None
|
|
195
|
-
Inclusive lower time bound. If None, no lower bound.
|
|
196
|
-
t_max : float or None
|
|
197
|
-
Exclusive upper time bound. If None, no upper bound.
|
|
198
|
-
|
|
199
|
-
Returns
|
|
200
|
-
-------
|
|
201
|
-
Spectrogram
|
|
202
|
-
Cropped spectrogram.
|
|
203
|
-
"""
|
|
204
|
-
S = self.S
|
|
205
|
-
f = self.f
|
|
206
|
-
t = self.t
|
|
207
|
-
|
|
208
|
-
f_mask = (f >= f_min) if f_min is not None else np.ones_like(f, dtype=bool)
|
|
209
|
-
f_mask &= (f < f_max) if f_max is not None else f_mask
|
|
210
|
-
|
|
211
|
-
t_mask = (t >= t_min) if t_min is not None else np.ones_like(t, dtype=bool)
|
|
212
|
-
t_mask &= (t < t_max) if t_max is not None else t_mask
|
|
213
|
-
|
|
214
|
-
cropped_S = S[np.ix_(f_mask, t_mask)]
|
|
215
|
-
cropped_f = f[f_mask]
|
|
216
|
-
cropped_t = t[t_mask]
|
|
217
|
-
|
|
218
|
-
return self.__class__(S=cropped_S, f=cropped_f, t=cropped_t, title=self.title)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def plot(
|
|
222
|
-
self,
|
|
223
|
-
log_compression_factor: int | float | None = None,
|
|
224
|
-
ax: plt.Axes | None = None,
|
|
225
|
-
cmap: str = "gray_r",
|
|
226
|
-
title: str | None = None,
|
|
227
|
-
Mlabel: str | None = None,
|
|
228
|
-
ylabel: str | None = "Frequency (hz)",
|
|
229
|
-
xlabel: str | None = "Time (sec)",
|
|
230
|
-
ylim: tuple[float, float] | None = None,
|
|
231
|
-
xlim: tuple[float, float] | None = None,
|
|
232
|
-
highlight: list[tuple[float, float, float, float]] | None = None,
|
|
233
|
-
origin: str = "lower", # or "lower"
|
|
234
|
-
show_colorbar: bool = True,
|
|
235
|
-
cax: plt.Axes | None = None,
|
|
236
|
-
show_grid: bool = True,
|
|
237
|
-
tick_mode: str = "center", # "center" or "edge"
|
|
238
|
-
n_ticks: tuple[int, int] | None = None,
|
|
239
|
-
) -> plt.Figure:
|
|
240
|
-
"""
|
|
241
|
-
Plot the spectrogram using Matplotlib.
|
|
242
|
-
|
|
243
|
-
.. code-block:: python
|
|
244
|
-
|
|
245
|
-
fig = spec.plot(log_compression_factor=10, title="Log-scaled Spectrogram")
|
|
246
|
-
|
|
247
|
-
Parameters
|
|
248
|
-
----------
|
|
249
|
-
log_compression_factor : float or int, optional
|
|
250
|
-
If specified, apply log-compression using log(1 + S * factor).
|
|
251
|
-
ax : matplotlib.axes.Axes, optional
|
|
252
|
-
Axes to draw on. If None, a new figure and axes are created.
|
|
253
|
-
cmap : str, default "gray_r"
|
|
254
|
-
Colormap used for the image.
|
|
255
|
-
title : str, optional
|
|
256
|
-
Title to use for the plot. Defaults to the signal's title.
|
|
257
|
-
Mlabel : str, optional
|
|
258
|
-
Label for the colorbar (e.g., "Magnitude", "dB").
|
|
259
|
-
ylabel : str, optional
|
|
260
|
-
Label for the y-axis. Default is "Frequency (hz)".
|
|
261
|
-
xlabel : str, optional
|
|
262
|
-
Label for the x-axis. Default is "Time (sec)".
|
|
263
|
-
ylim : tuple of float, optional
|
|
264
|
-
Limits for the y-axis (frequency).
|
|
265
|
-
xlim : tuple of float, optional
|
|
266
|
-
Limits for the x-axis (time).
|
|
267
|
-
highlight : list of (x, y, w, h), optional
|
|
268
|
-
Rectangular regions to highlight, specified in data coordinates.
|
|
269
|
-
origin : {"lower", "upper"}, default "lower"
|
|
270
|
-
Origin position for the image (for flipping vertical axis).
|
|
271
|
-
show_colorbar : bool, default True
|
|
272
|
-
Whether to display the colorbar.
|
|
273
|
-
cax : matplotlib.axes.Axes, optional
|
|
274
|
-
Axis to draw the colorbar on. If None, uses default placement.
|
|
275
|
-
show_grid : bool, default True
|
|
276
|
-
Whether to show the major gridlines.
|
|
277
|
-
tick_mode : {"center", "edge"}, default "center"
|
|
278
|
-
Whether to place ticks at bin centers or edges.
|
|
279
|
-
n_ticks : tuple of int, optional
|
|
280
|
-
Number of ticks (y_ticks, x_ticks) to display on each axis.
|
|
281
|
-
|
|
282
|
-
Returns
|
|
283
|
-
-------
|
|
284
|
-
matplotlib.figure.Figure
|
|
285
|
-
The figure object containing the plot.
|
|
286
|
-
"""
|
|
287
|
-
from modusa.io import Plotter
|
|
288
|
-
|
|
289
|
-
title = title or self.title
|
|
290
|
-
|
|
291
|
-
fig = Plotter.plot_matrix(
|
|
292
|
-
M=self.S,
|
|
293
|
-
r=self.f,
|
|
294
|
-
c=self.t,
|
|
295
|
-
log_compression_factor=log_compression_factor,
|
|
296
|
-
ax=ax,
|
|
297
|
-
cmap=cmap,
|
|
298
|
-
title=title,
|
|
299
|
-
Mlabel=Mlabel,
|
|
300
|
-
rlabel=ylabel,
|
|
301
|
-
clabel=xlabel,
|
|
302
|
-
rlim=ylim,
|
|
303
|
-
clim=xlim,
|
|
304
|
-
highlight=highlight,
|
|
305
|
-
origin=origin,
|
|
306
|
-
show_colorbar=show_colorbar,
|
|
307
|
-
cax=cax,
|
|
308
|
-
show_grid=show_grid,
|
|
309
|
-
tick_mode=tick_mode,
|
|
310
|
-
n_ticks=n_ticks
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
return fig
|
|
314
|
-
|
|
315
|
-
#----------------------------
|
|
316
|
-
# Math ops
|
|
317
|
-
#----------------------------
|
|
318
|
-
|
|
319
|
-
def __array__(self, dtype=None):
|
|
320
|
-
return np.asarray(self._S, dtype=dtype)
|
|
321
|
-
|
|
322
|
-
def __add__(self, other):
|
|
323
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
324
|
-
result = np.add(self.S, other_data)
|
|
325
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
326
|
-
|
|
327
|
-
def __radd__(self, other):
|
|
328
|
-
result = np.add(other, self.S)
|
|
329
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
330
|
-
|
|
331
|
-
def __sub__(self, other):
|
|
332
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
333
|
-
result = np.subtract(self.S, other_data)
|
|
334
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
335
|
-
|
|
336
|
-
def __rsub__(self, other):
|
|
337
|
-
result = np.subtract(other, self.S)
|
|
338
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
339
|
-
|
|
340
|
-
def __mul__(self, other):
|
|
341
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
342
|
-
result = np.multiply(self.S, other_data)
|
|
343
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
344
|
-
|
|
345
|
-
def __rmul__(self, other):
|
|
346
|
-
result = np.multiply(other, self.S)
|
|
347
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
348
|
-
|
|
349
|
-
def __truediv__(self, other):
|
|
350
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
351
|
-
result = np.true_divide(self.S, other_data)
|
|
352
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
353
|
-
|
|
354
|
-
def __rtruediv__(self, other):
|
|
355
|
-
result = np.true_divide(other, self.S)
|
|
356
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
357
|
-
|
|
358
|
-
def __floordiv__(self, other):
|
|
359
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
360
|
-
result = np.floor_divide(self.S, other_data)
|
|
361
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
362
|
-
|
|
363
|
-
def __rfloordiv__(self, other):
|
|
364
|
-
result = np.floor_divide(other, self.S)
|
|
365
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
366
|
-
|
|
367
|
-
def __pow__(self, other):
|
|
368
|
-
other_data = other.S if isinstance(other, self.__class__) else other
|
|
369
|
-
result = np.power(self.S, other_data)
|
|
370
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
371
|
-
|
|
372
|
-
def __rpow__(self, other):
|
|
373
|
-
result = np.power(other, self.S)
|
|
374
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
375
|
-
|
|
376
|
-
def __abs__(self):
|
|
377
|
-
result = np.abs(self.S)
|
|
378
|
-
return self.__class__(S=result, f=self.f, t=self.t, title=self.title)
|
|
379
|
-
|
|
380
|
-
def sin(self):
|
|
381
|
-
"""Element-wise sine of the spectrogram."""
|
|
382
|
-
return self.__class__(S=np.sin(self.S), f=self.f, t=self.t, title=self.title)
|
|
383
|
-
|
|
384
|
-
def cos(self):
|
|
385
|
-
"""Element-wise cosine of the spectrogram."""
|
|
386
|
-
return self.__class__(S=np.cos(self.S), f=self.f, t=self.t, title=self.title)
|
|
387
|
-
|
|
388
|
-
def exp(self):
|
|
389
|
-
"""Element-wise exponential of the spectrogram."""
|
|
390
|
-
return self.__class__(S=np.exp(self.S), f=self.f, t=self.t, title=self.title)
|
|
391
|
-
|
|
392
|
-
def tanh(self):
|
|
393
|
-
"""Element-wise hyperbolic tangent of the spectrogram."""
|
|
394
|
-
return self.__class__(S=np.tanh(self.S), f=self.f, t=self.t, title=self.title)
|
|
395
|
-
|
|
396
|
-
def log(self):
|
|
397
|
-
"""Element-wise natural logarithm of the spectrogram."""
|
|
398
|
-
return self.__class__(S=np.log(self.S), f=self.f, t=self.t, title=self.title)
|
|
399
|
-
|
|
400
|
-
def log1p(self):
|
|
401
|
-
"""Element-wise log(1 + M) of the spectrogram."""
|
|
402
|
-
return self.__class__(S=np.log1p(self.S), f=self.f, t=self.t, title=self.title)
|
|
403
|
-
|
|
404
|
-
def log10(self):
|
|
405
|
-
"""Element-wise base-10 logarithm of the spectrogram."""
|
|
406
|
-
return self.__class__(S=np.log10(self.S), f=self.f, t=self.t, title=self.title)
|
|
407
|
-
|
|
408
|
-
def log2(self):
|
|
409
|
-
"""Element-wise base-2 logarithm of the spectrogram."""
|
|
410
|
-
return self.__class__(S=np.log2(self.S), f=self.f, t=self.t, title=self.title)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
def mean(self) -> float:
|
|
414
|
-
"""Return the mean of the spectrogram values."""
|
|
415
|
-
return float(np.mean(self.S))
|
|
416
|
-
|
|
417
|
-
def std(self) -> float:
|
|
418
|
-
"""Return the standard deviation of the spectrogram values."""
|
|
419
|
-
return float(np.std(self.S))
|
|
420
|
-
|
|
421
|
-
def min(self) -> float:
|
|
422
|
-
"""Return the minimum value in the spectrogram."""
|
|
423
|
-
return float(np.min(self.S))
|
|
424
|
-
|
|
425
|
-
def max(self) -> float:
|
|
426
|
-
"""Return the maximum value in the spectrogram."""
|
|
427
|
-
return float(np.max(self.S))
|
|
428
|
-
|
|
429
|
-
def sum(self) -> float:
|
|
430
|
-
"""Return the sum of the spectrogram values."""
|
|
431
|
-
return float(np.sum(self.S))
|
|
432
|
-
|
|
433
|
-
#-----------------------------------
|
|
434
|
-
# Repr
|
|
435
|
-
#-----------------------------------
|
|
436
|
-
|
|
437
|
-
def __str__(self):
|
|
438
|
-
cls = self.__class__.__name__
|
|
439
|
-
data = self.S
|
|
440
|
-
|
|
441
|
-
arr_str = np.array2string(
|
|
442
|
-
data,
|
|
443
|
-
separator=", ",
|
|
444
|
-
threshold=50, # limit number of elements shown
|
|
445
|
-
edgeitems=3, # show first/last 3 rows and columns
|
|
446
|
-
max_line_width=120, # avoid wrapping
|
|
447
|
-
formatter={'float_kind': lambda x: f"{x:.4g}"}
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
return f"Signal({arr_str}, shape={data.shape}, kind={cls})"
|
|
451
|
-
|
|
452
|
-
def __repr__(self):
|
|
453
|
-
cls = self.__class__.__name__
|
|
454
|
-
data = self.S
|
|
455
|
-
|
|
456
|
-
arr_str = np.array2string(
|
|
457
|
-
data,
|
|
458
|
-
separator=", ",
|
|
459
|
-
threshold=50, # limit number of elements shown
|
|
460
|
-
edgeitems=3, # show first/last 3 rows and columns
|
|
461
|
-
max_line_width=120, # avoid wrapping
|
|
462
|
-
formatter={'float_kind': lambda x: f"{x:.4g}"}
|
|
463
|
-
)
|
|
464
|
-
|
|
465
|
-
return f"Signal({arr_str}, shape={data.shape}, kind={cls})"
|