modusa 0.4.29__py3-none-any.whl → 0.4.30__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/__init__.py +9 -8
- modusa/tools/__init__.py +7 -2
- modusa/tools/ann_saver.py +30 -0
- modusa/tools/audio_recorder.py +0 -1
- modusa/tools/youtube_downloader.py +1 -4
- {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/METADATA +2 -2
- modusa-0.4.30.dist-info/RECORD +21 -0
- pyproject.toml +2 -2
- modusa/config.py +0 -18
- modusa/decorators.py +0 -176
- modusa/devtools/generate_docs_source.py +0 -92
- modusa/devtools/generate_template.py +0 -144
- modusa/devtools/list_authors.py +0 -2
- modusa/devtools/list_plugins.py +0 -60
- modusa/devtools/main.py +0 -45
- modusa/devtools/templates/generator.py +0 -24
- modusa/devtools/templates/io.py +0 -24
- modusa/devtools/templates/model.py +0 -47
- modusa/devtools/templates/plugin.py +0 -41
- modusa/devtools/templates/test.py +0 -10
- modusa/devtools/templates/tool.py +0 -24
- modusa/generators/__init__.py +0 -13
- modusa/generators/audio.py +0 -188
- modusa/generators/audio_waveforms.py +0 -236
- modusa/generators/base.py +0 -29
- modusa/generators/ftds.py +0 -298
- modusa/generators/s1d.py +0 -270
- modusa/generators/s2d.py +0 -300
- modusa/generators/s_ax.py +0 -102
- modusa/generators/t_ax.py +0 -64
- modusa/generators/tds.py +0 -267
- modusa/models/__init__.py +0 -14
- modusa/models/audio.py +0 -90
- modusa/models/base.py +0 -70
- modusa/models/data.py +0 -457
- modusa/models/ftds.py +0 -584
- modusa/models/s1d.py +0 -578
- modusa/models/s2d.py +0 -619
- modusa/models/s_ax.py +0 -448
- modusa/models/t_ax.py +0 -335
- modusa/models/tds.py +0 -465
- modusa/plugins/__init__.py +0 -3
- modusa/plugins/base.py +0 -100
- modusa/tools/_plotter_old.py +0 -629
- modusa/tools/audio_saver.py +0 -30
- modusa/tools/base.py +0 -43
- modusa/tools/math_ops.py +0 -335
- modusa/utils/__init__.py +0 -1
- modusa/utils/config.py +0 -25
- modusa/utils/excp.py +0 -49
- modusa/utils/logger.py +0 -18
- modusa/utils/np_func_cat.py +0 -44
- modusa/utils/plot.py +0 -142
- modusa-0.4.29.dist-info/RECORD +0 -65
- {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/WHEEL +0 -0
- {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/entry_points.txt +0 -0
- {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/licenses/LICENSE.md +0 -0
modusa/models/t_ax.py
DELETED
@@ -1,335 +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 .s_ax import SAx
|
7
|
-
from typing import Self, Any, Callable
|
8
|
-
import numpy as np
|
9
|
-
|
10
|
-
class TAx(SAx):
|
11
|
-
"""
|
12
|
-
A Space to represent time axis.
|
13
|
-
|
14
|
-
Note
|
15
|
-
----
|
16
|
-
- Use :class:`~modusa.generators.t_ax.TAxGen` API to instantiate this class.
|
17
|
-
- It must be uniform with a well-defined sampling rate.
|
18
|
-
- You are likely to be using this axis for most of the cases.
|
19
|
-
- It is numpy compatible, so you can use numpy methods directly on this class object.
|
20
|
-
- Since the object of this class represents time axis, any mathematical operations on it will result in another object of :class:`~modusa.models.tds.TDS` class with `y` being the result of the operation and `t` being the axis itself.
|
21
|
-
|
22
|
-
Parameters
|
23
|
-
----------
|
24
|
-
n_points: int
|
25
|
-
- Number of data points for the time axis.
|
26
|
-
sr: float
|
27
|
-
- Sampling rate.
|
28
|
-
- Default: 1.0
|
29
|
-
t0: float
|
30
|
-
- Start timestamp.
|
31
|
-
- Default: 0.0
|
32
|
-
label: str
|
33
|
-
- Label associated with the time axis.
|
34
|
-
- Default: None => ''
|
35
|
-
- e.g. (Time (sec))
|
36
|
-
"""
|
37
|
-
|
38
|
-
#--------Meta Information----------
|
39
|
-
_name = "Time Axis"
|
40
|
-
_nickname = "axis" # This is to be used in repr/str methods
|
41
|
-
_description = "A Space to represent time axis."
|
42
|
-
_author_name = "Ankit Anand"
|
43
|
-
_author_email = "ankit0.anand0@gmail.com"
|
44
|
-
_created_at = "2025-07-26"
|
45
|
-
#----------------------------------
|
46
|
-
|
47
|
-
@validate_args_type()
|
48
|
-
def __init__(self, n_points, sr=1.0, t0=0.0, label=None):
|
49
|
-
|
50
|
-
# Create `t` time series array
|
51
|
-
t = t0 + np.arange(n_points) / sr
|
52
|
-
|
53
|
-
super().__init__(values=t, label=label) # Instantiating `SAx` class
|
54
|
-
|
55
|
-
# Storing other parameters so that we can use them.
|
56
|
-
self._sr = sr
|
57
|
-
self._t0 = t0
|
58
|
-
|
59
|
-
|
60
|
-
#-----------------------------------
|
61
|
-
# Properties (User Facing)
|
62
|
-
#-----------------------------------
|
63
|
-
|
64
|
-
@property
|
65
|
-
def values(self) -> np.ndarray:
|
66
|
-
return self._values
|
67
|
-
|
68
|
-
@property
|
69
|
-
def label(self) -> str:
|
70
|
-
return self._label
|
71
|
-
|
72
|
-
@property
|
73
|
-
def shape(self) -> tuple:
|
74
|
-
return self.values.shape
|
75
|
-
|
76
|
-
@property
|
77
|
-
def ndim(self) -> int:
|
78
|
-
return self.values.ndim # Should be 1
|
79
|
-
|
80
|
-
@property
|
81
|
-
def size(self) -> int:
|
82
|
-
return self.values.size
|
83
|
-
|
84
|
-
@property
|
85
|
-
def sr(self) -> float:
|
86
|
-
return self._sr
|
87
|
-
|
88
|
-
@property
|
89
|
-
def t0(self) -> float:
|
90
|
-
return self._t0
|
91
|
-
|
92
|
-
@property
|
93
|
-
def end_time(self) -> float:
|
94
|
-
return float(self.values[-1])
|
95
|
-
|
96
|
-
@property
|
97
|
-
def duration(self) -> float:
|
98
|
-
return float(self.end_time - self.t0)
|
99
|
-
|
100
|
-
def __len__(self) -> int:
|
101
|
-
return len(self.values)
|
102
|
-
|
103
|
-
#===================================
|
104
|
-
|
105
|
-
#------------------------------------
|
106
|
-
# Utility methods
|
107
|
-
#------------------------------------
|
108
|
-
|
109
|
-
def is_same_as(self, other) -> bool:
|
110
|
-
"""
|
111
|
-
Compare it with another SAx object.
|
112
|
-
|
113
|
-
Parameters
|
114
|
-
----------
|
115
|
-
other: SAx
|
116
|
-
Another object to compare with.
|
117
|
-
|
118
|
-
Returns
|
119
|
-
-------
|
120
|
-
bool
|
121
|
-
True if same ow False
|
122
|
-
|
123
|
-
Note
|
124
|
-
----
|
125
|
-
- We check the shape and all the values.
|
126
|
-
- We are not checking the labels for now.
|
127
|
-
"""
|
128
|
-
|
129
|
-
if other.size == 1: # Meaning it is scalar
|
130
|
-
return True
|
131
|
-
|
132
|
-
axis1_arr = np.asarray(self)
|
133
|
-
axis2_arr = np.asarray(other)
|
134
|
-
|
135
|
-
if not isinstance(axis2_arr, type(axis1_arr)):
|
136
|
-
return False
|
137
|
-
if axis1_arr.shape != axis2_arr.shape:
|
138
|
-
return False
|
139
|
-
if not np.allclose(axis1_arr, axis2_arr):
|
140
|
-
return False
|
141
|
-
|
142
|
-
return True
|
143
|
-
|
144
|
-
def copy(self) -> Self:
|
145
|
-
"""
|
146
|
-
Return a new copy of SAx object.
|
147
|
-
|
148
|
-
Returns
|
149
|
-
-------
|
150
|
-
SAx
|
151
|
-
A new copy of the SAx object.
|
152
|
-
"""
|
153
|
-
|
154
|
-
return self.__class__(n_points=self.shape[0], sr=self.sr, t0=self.t0, label=self.label)
|
155
|
-
|
156
|
-
|
157
|
-
def set_meta_info(self, label):
|
158
|
-
"""
|
159
|
-
Set meta info for the axis.
|
160
|
-
|
161
|
-
Parameters
|
162
|
-
----------
|
163
|
-
label: str
|
164
|
-
Label for the axis (e.g. "Time (sec)").
|
165
|
-
Returns
|
166
|
-
-------
|
167
|
-
Self
|
168
|
-
A new Self instance with new label.
|
169
|
-
|
170
|
-
.. code-block:: python
|
171
|
-
|
172
|
-
import modusa as ms
|
173
|
-
x = ms.sax.linear(100, 10)
|
174
|
-
print(x)
|
175
|
-
x = x.set_meta_info("My Axis (unit)")
|
176
|
-
print(x)
|
177
|
-
|
178
|
-
# I personally prefer setting it inline
|
179
|
-
x = ms.sax.linear(100, 10).set_meta_info("My Axis (unit)")
|
180
|
-
print(x)
|
181
|
-
|
182
|
-
"""
|
183
|
-
|
184
|
-
if label is None:
|
185
|
-
return self
|
186
|
-
else:
|
187
|
-
return self.__class__(n_points=self.shape[0], sr=self.sr, t0=self.t0, label=label)
|
188
|
-
|
189
|
-
def translate(self, n_samples):
|
190
|
-
"""
|
191
|
-
Translate the time axis by `n_samples`.
|
192
|
-
|
193
|
-
Note
|
194
|
-
----
|
195
|
-
- `n_samples` can be both positive and negative.
|
196
|
-
- You might end up getting -ve time values as we are not checking for the values rn.
|
197
|
-
|
198
|
-
Parameters
|
199
|
-
----------
|
200
|
-
n_samples: int
|
201
|
-
- Number of samples to move the signal.
|
202
|
-
- +ve => moving signal forward.
|
203
|
-
- -ve => moving signal backward.
|
204
|
-
|
205
|
-
Returns
|
206
|
-
-------
|
207
|
-
TAx
|
208
|
-
Translated axis.
|
209
|
-
"""
|
210
|
-
|
211
|
-
new_t0 = self.t0 + (n_samples / self.sr)
|
212
|
-
|
213
|
-
return self.__class__(n_points=self.shape[0], sr=self.sr, t0=new_t0, label=self.label)
|
214
|
-
|
215
|
-
#===================================
|
216
|
-
|
217
|
-
|
218
|
-
#-------------------------------
|
219
|
-
# NumPy Protocol
|
220
|
-
#-------------------------------
|
221
|
-
def __array__(self, dtype=None) -> np.ndarray:
|
222
|
-
return np.asarray(self.values, dtype=dtype)
|
223
|
-
|
224
|
-
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
|
225
|
-
"""
|
226
|
-
Provides operation support for the universal functions
|
227
|
-
on the TAx object.
|
228
|
-
"""
|
229
|
-
from .tds import TDS
|
230
|
-
from .data import Data
|
231
|
-
|
232
|
-
raw_inputs = [t.values if isinstance(t, type(self)) else t for t in inputs]
|
233
|
-
|
234
|
-
# Call the actual ufunc
|
235
|
-
result = getattr(ufunc, method)(*raw_inputs, **kwargs)
|
236
|
-
|
237
|
-
if isinstance(result, (np.ndarray, np.generic)):
|
238
|
-
y = Data(values=result, label=None)
|
239
|
-
t = self
|
240
|
-
return TDS(y=y, t=t, title=None)
|
241
|
-
else:
|
242
|
-
return result
|
243
|
-
|
244
|
-
def __array_function__(self, func, types, args, kwargs):
|
245
|
-
"""
|
246
|
-
Additional numpy function support.
|
247
|
-
"""
|
248
|
-
from modusa.utils import np_func_cat as nfc
|
249
|
-
from .data import Data
|
250
|
-
|
251
|
-
if not all(issubclass(t, type(self)) for t in types):
|
252
|
-
return NotImplemented
|
253
|
-
|
254
|
-
# Not supporting concatenate like operations as axis any random axis can't be concatenated
|
255
|
-
if func in nfc.CONCAT_FUNCS:
|
256
|
-
raise NotImplementedError(f"`{func.__name__}` is not yet tested on modusa signal, please create a GitHub issue.")
|
257
|
-
|
258
|
-
# Single signal input expected
|
259
|
-
t = args[0]
|
260
|
-
t_arr = np.asarray(t)
|
261
|
-
result = func(t_arr, **kwargs)
|
262
|
-
|
263
|
-
if func in nfc.REDUCTION_FUNCS:
|
264
|
-
# If the number of dimensions is reduced
|
265
|
-
if result.ndim == 0:
|
266
|
-
return Data(values=result, label=None)
|
267
|
-
else:
|
268
|
-
raise RuntimeError(f"Unexpected result: `result` has more than 0 dimensions, {result.ndim}")
|
269
|
-
|
270
|
-
elif func in nfc.X_NEEDS_ADJUSTMENT_FUNCS:
|
271
|
-
# You must define logic for adjusting x
|
272
|
-
raise NotImplementedError(f"{func.__name__} requires x-axis adjustment logic.")
|
273
|
-
|
274
|
-
else:
|
275
|
-
raise NotImplementedError(f"`{func.__name__}` is not yet tested on modusa signal, please create a GitHub issue.")
|
276
|
-
|
277
|
-
#================================
|
278
|
-
|
279
|
-
|
280
|
-
#-----------------------------------
|
281
|
-
# Indexing
|
282
|
-
#-----------------------------------
|
283
|
-
|
284
|
-
def __getitem__(self, key) -> Self:
|
285
|
-
"""
|
286
|
-
Defining how to index SAx instance.
|
287
|
-
|
288
|
-
.. code-block:: python
|
289
|
-
|
290
|
-
import modusa as ms
|
291
|
-
x = ms.sax.linear(100, 10)
|
292
|
-
print(x)
|
293
|
-
print(x[10:20])
|
294
|
-
|
295
|
-
Parameters
|
296
|
-
----------
|
297
|
-
key: int | slice
|
298
|
-
What can go inside the square bracket [] for indexing.
|
299
|
-
|
300
|
-
Returns
|
301
|
-
-------
|
302
|
-
SAx:
|
303
|
-
Sliced instance of the axis.
|
304
|
-
"""
|
305
|
-
if not isinstance(key, (int, slice, tuple)):
|
306
|
-
raise TypeError(f"Invalid key type {type(key)}")
|
307
|
-
|
308
|
-
if isinstance(key, int):
|
309
|
-
sliced_value = self.values[key]
|
310
|
-
new_t0 = sliced_value
|
311
|
-
return self.__class__(n_points=1, sr=self.sr, t0=new_t0, label=self.label)
|
312
|
-
|
313
|
-
elif isinstance(key, slice):
|
314
|
-
step = key.step or 1
|
315
|
-
if step < 0:
|
316
|
-
raise ValueError("Reversed slicing of time axis is not allowed.")
|
317
|
-
|
318
|
-
sliced_values = self.values[key]
|
319
|
-
new_n_points = len(sliced_values)
|
320
|
-
new_sr = self.sr / step
|
321
|
-
new_t0 = sliced_values[0]
|
322
|
-
|
323
|
-
return self.__class__(n_points=new_n_points, sr=new_sr, t0=new_t0, label=self.label)
|
324
|
-
|
325
|
-
|
326
|
-
def __setitem__(self, key, value):
|
327
|
-
"""
|
328
|
-
Raises error if trying to set values
|
329
|
-
of an axis.
|
330
|
-
|
331
|
-
Meaningful axis are not meant to be altered.
|
332
|
-
"""
|
333
|
-
raise TypeError("Time axis does not support item assignment.")
|
334
|
-
|
335
|
-
#===============================
|