proadv 2.0.2__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.
- proadv/__init__.py +0 -0
- proadv/filtration/__init__.py +0 -0
- proadv/filtration/detection/__init__.py +0 -0
- proadv/filtration/detection/acceleration.py +65 -0
- proadv/filtration/detection/bivariatekernel.py +53 -0
- proadv/filtration/detection/correlation.py +78 -0
- proadv/filtration/detection/phasespace.py +173 -0
- proadv/filtration/detection/poincare.py +46 -0
- proadv/filtration/detection/pollution.py +32 -0
- proadv/filtration/detection/spherical.py +181 -0
- proadv/filtration/detection/trivariatekernel.py +521 -0
- proadv/filtration/replacement/__init__.py +0 -0
- proadv/filtration/replacement/replacements.py +187 -0
- proadv/kernel/__init__.py +0 -0
- proadv/kernel/bivariate.py +437 -0
- proadv/statistics/__init__.py +0 -0
- proadv/statistics/descriptive.py +328 -0
- proadv/statistics/distributions/__init__.py +1 -0
- proadv/statistics/distributions/normal.py +126 -0
- proadv/statistics/moment.py +122 -0
- proadv/statistics/series.py +337 -0
- proadv/statistics/spread.py +119 -0
- proadv/tests/__init__.py +0 -0
- proadv/tests/statistics/__init__.py +0 -0
- proadv/tests/statistics/descriptive/__init__.py +0 -0
- proadv/tests/statistics/descriptive/test_max.py +36 -0
- proadv/tests/statistics/descriptive/test_mean.py +37 -0
- proadv/tests/statistics/descriptive/test_median.py +26 -0
- proadv/tests/statistics/descriptive/test_min.py +36 -0
- proadv/tests/statistics/descriptive/test_mode.py +34 -0
- proadv-2.0.2.dist-info/METADATA +167 -0
- proadv-2.0.2.dist-info/RECORD +34 -0
- proadv-2.0.2.dist-info/WHEEL +5 -0
- proadv-2.0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy import linalg
|
|
3
|
+
from scipy.stats._stats import gaussian_kernel_estimate as gke
|
|
4
|
+
from scipy.stats import gaussian_kde as kde
|
|
5
|
+
from proadv.statistics.spread import std
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _derivatives(data):
|
|
9
|
+
"""
|
|
10
|
+
Calculate time-independent first and second order derivatives of the input data.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
------
|
|
14
|
+
data (array_like): Input data.
|
|
15
|
+
|
|
16
|
+
Returns
|
|
17
|
+
------
|
|
18
|
+
dc (array_like): First derivative of the input data.
|
|
19
|
+
dc2 (array_like): Second derivative of the input data.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# Initialize arrays for first and second derivatives
|
|
23
|
+
dc = np.zeros_like(data)
|
|
24
|
+
dc2 = np.zeros_like(data)
|
|
25
|
+
|
|
26
|
+
# Calculate first derivative
|
|
27
|
+
for i in range(1, data.size - 1):
|
|
28
|
+
dc[i] = (data[i + 1] - data[i - 1]) / 2
|
|
29
|
+
|
|
30
|
+
# Calculate second derivative
|
|
31
|
+
for i in range(1, data.size - 1):
|
|
32
|
+
dc2[i] = (dc[i + 1] - dc[i - 1]) / 2
|
|
33
|
+
|
|
34
|
+
return dc, dc2
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _rotation(u1, w1):
|
|
38
|
+
"""
|
|
39
|
+
Calculate rotation angle theta between vectors u1 and w1.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
------
|
|
43
|
+
u1 (array_like): Vector u1.
|
|
44
|
+
w1 (array_like): Vector w1.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
------
|
|
48
|
+
theta (float): Rotation angle.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# Compute data size
|
|
52
|
+
data_size = u1.size
|
|
53
|
+
|
|
54
|
+
# Calculate theta using the arctan2 function
|
|
55
|
+
theta = np.arctan2((data_size * np.sum(u1 * w1) - np.sum(u1) * np.sum(w1)),
|
|
56
|
+
(data_size * np.sum(u1 * u1) - np.sum(u1) * np.sum(u1)))
|
|
57
|
+
|
|
58
|
+
return theta
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _transform(x, y, theta):
|
|
62
|
+
"""
|
|
63
|
+
Transform coordinates (x, y) using rotation angle theta.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
------
|
|
67
|
+
x (array_like): x-coordinate.
|
|
68
|
+
y (array_like): y-coordinate.
|
|
69
|
+
theta (float): Rotation angle
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
------
|
|
73
|
+
xt, yt (array_like): Transformed coordinates.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
# Apply rotation transformation
|
|
77
|
+
xt = x * np.cos(theta) + y * np.sin(theta)
|
|
78
|
+
yt = -x * np.sin(theta) + y * np.cos(theta)
|
|
79
|
+
|
|
80
|
+
return xt, yt
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _scaling(x, y, grid):
|
|
84
|
+
"""
|
|
85
|
+
Scale coordinates (x, y) into a grid.
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
------
|
|
89
|
+
x (array_like): x-coordinate.
|
|
90
|
+
y (array_like): y-coordinate.
|
|
91
|
+
grid (int): Number of grid points.
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
------
|
|
95
|
+
Meshgrid of scaled coordinates.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
xmin = x.min()
|
|
99
|
+
xmax = x.max()
|
|
100
|
+
ymin = y.min()
|
|
101
|
+
ymax = y.max()
|
|
102
|
+
|
|
103
|
+
# Generate a meshgrid of scaled coordinates
|
|
104
|
+
return np.mgrid[xmin:xmax:grid * 1j, ymin:ymax:grid * 1j]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _profile(meshgrid_x, meshgrid_y):
|
|
108
|
+
"""
|
|
109
|
+
Extract profile coordinates from meshgrid.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
------
|
|
113
|
+
meshgrid_x (array_like): Meshgrid of x-coordinates.
|
|
114
|
+
meshgrid_y (array_like): Meshgrid of y-coordinates.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
------
|
|
118
|
+
Profile coordinates.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
# Extract profile coordinates from meshgrid
|
|
122
|
+
return meshgrid_x[:, 0], meshgrid_y[0, :]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _position(meshgrid_x, meshgrid_y, trans_x, trans_y):
|
|
126
|
+
"""
|
|
127
|
+
Generate positions and values for interpolation.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
------
|
|
131
|
+
meshgrid_x (array_like): Meshgrid of x-coordinates.
|
|
132
|
+
meshgrid_y (array_like): Meshgrid of y-coordinates.
|
|
133
|
+
trans_x (array_like): Transformed x-coordinates.
|
|
134
|
+
trans_y (array_like): Transformed y-coordinates.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
------
|
|
138
|
+
Positions and values for interpolation.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
# Stack meshgrid coordinates and transformed coordinates
|
|
142
|
+
positions = np.vstack([meshgrid_x.ravel(), meshgrid_y.ravel()])
|
|
143
|
+
values = np.vstack([trans_x, trans_y])
|
|
144
|
+
|
|
145
|
+
return positions, values
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _factor(rows, cols):
|
|
149
|
+
"""
|
|
150
|
+
Calculate covariance factor based on rows and columns.
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
------
|
|
154
|
+
rows (int): Number of rows.
|
|
155
|
+
cols (int): Number of columns.
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
------
|
|
159
|
+
Factor.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
# Calculate the covariance factor
|
|
163
|
+
return np.power(cols, -1. / (rows + 4))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _weight(cols):
|
|
167
|
+
"""
|
|
168
|
+
Generate weights.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
------
|
|
172
|
+
cols (int): Number of columns.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
------
|
|
176
|
+
Array of weights.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
# Generate equal weights
|
|
180
|
+
return np.ones(cols) / cols
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _cov(data, aweights):
|
|
184
|
+
"""
|
|
185
|
+
Compute the weighted covariance matrix.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
------
|
|
189
|
+
data (array_like): Input data.
|
|
190
|
+
aweights (array_like): Array of weights.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
------
|
|
194
|
+
Weighted covariance matrix.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
# Compute the weighted covariance matrix
|
|
198
|
+
return np.atleast_2d(np.cov(data, rowvar=1, bias=False, aweights=aweights))
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _cholesky(data):
|
|
202
|
+
"""
|
|
203
|
+
Compute the Cholesky decomposition of a matrix.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
------
|
|
207
|
+
data (array_like): Input matrix.
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
------
|
|
211
|
+
Cholesky decomposition of the input matrix.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
# Compute the Cholesky decomposition
|
|
215
|
+
return linalg.cholesky(data)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _determination(data):
|
|
219
|
+
"""
|
|
220
|
+
Compute the determinant of a matrix.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
------
|
|
224
|
+
data (array_like): Input matrix.
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
------
|
|
228
|
+
Determinant of the input matrix.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
# Compute the determinant
|
|
232
|
+
return 2 * np.sum(np.log(np.diag(data * np.sqrt(np.pi * 2))))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _covariance(data, rows, cols):
|
|
236
|
+
"""
|
|
237
|
+
Calculate the covariance and Cholesky decomposition.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
------
|
|
241
|
+
data (array_like): Input data
|
|
242
|
+
rows (int): Number of rows.
|
|
243
|
+
cols (int): Number of columns.
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
------
|
|
247
|
+
Dictionary containing computed factors, weights, net, covariance, Cholesky decomposition, and log.
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
# Compute factors and weights
|
|
251
|
+
weight = _weight(cols)
|
|
252
|
+
|
|
253
|
+
# Compute net and adjust factor
|
|
254
|
+
net = np.power(np.sum(weight ** 2), -1)
|
|
255
|
+
factor = _factor(rows, net)
|
|
256
|
+
|
|
257
|
+
# Compute covariance matrix and its Cholesky decomposition
|
|
258
|
+
cov = _cov(data, weight)
|
|
259
|
+
sky = _cholesky(cov)
|
|
260
|
+
|
|
261
|
+
# Adjust covariance and Cholesky decomposition
|
|
262
|
+
covariance = cov * factor ** 2
|
|
263
|
+
cholesky = sky * factor
|
|
264
|
+
cholesky.dtype = np.float64
|
|
265
|
+
|
|
266
|
+
# Compute log
|
|
267
|
+
log = _determination(cholesky)
|
|
268
|
+
|
|
269
|
+
# Return computed values as a dictionary
|
|
270
|
+
compute = {
|
|
271
|
+
"factor": factor,
|
|
272
|
+
"weight": weight,
|
|
273
|
+
"net": net,
|
|
274
|
+
"covariance": covariance,
|
|
275
|
+
"cholesky": cholesky,
|
|
276
|
+
"log": log
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return compute
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _type(cov, scatt):
|
|
283
|
+
"""
|
|
284
|
+
Determine the data type and size.
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
------
|
|
288
|
+
cov (array_like): Covariance matrix.
|
|
289
|
+
scatt (array_like): Scattering data.
|
|
290
|
+
|
|
291
|
+
Returns
|
|
292
|
+
------
|
|
293
|
+
Data type and size.
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
data_type = np.common_type(cov, scatt)
|
|
297
|
+
data_size = np.dtype(data_type).itemsize
|
|
298
|
+
if data_size == 4:
|
|
299
|
+
data_size = 'float'
|
|
300
|
+
elif data_size == 8:
|
|
301
|
+
data_size = 'double'
|
|
302
|
+
elif data_size in (12, 16):
|
|
303
|
+
data_size = 'long double'
|
|
304
|
+
return data_type, data_size
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _density(values):
|
|
308
|
+
"""
|
|
309
|
+
Compute the density estimation.
|
|
310
|
+
|
|
311
|
+
Parameters
|
|
312
|
+
------
|
|
313
|
+
values (array_like): Values for density estimation.
|
|
314
|
+
|
|
315
|
+
Returns
|
|
316
|
+
------
|
|
317
|
+
Dictionary containing the density estimation results.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
dataset = np.atleast_2d(np.asarray(values))
|
|
321
|
+
if dataset.size < 1:
|
|
322
|
+
raise ValueError("Dataset should have more than one element.")
|
|
323
|
+
rows, cols = dataset.shape
|
|
324
|
+
if rows > cols:
|
|
325
|
+
raise ValueError("Number of dimensions exceeds the number of samples.")
|
|
326
|
+
evals = _covariance(dataset, rows, cols)
|
|
327
|
+
return evals
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _estimation(krn, x):
|
|
331
|
+
"""
|
|
332
|
+
Perform density estimation.
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
------
|
|
336
|
+
krn (array_like): Kernel density estimation.
|
|
337
|
+
x (array_like): Input data.
|
|
338
|
+
|
|
339
|
+
Returns
|
|
340
|
+
------
|
|
341
|
+
Estimated density.
|
|
342
|
+
"""
|
|
343
|
+
return np.reshape(krn, x.shape)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _extraction(dataset, parameters, poses):
|
|
347
|
+
"""
|
|
348
|
+
Extract necessary data for extraction.
|
|
349
|
+
|
|
350
|
+
Parameters
|
|
351
|
+
------
|
|
352
|
+
dataset (array_like): Input dataset.
|
|
353
|
+
parameters (dict): Parameters dictionary containing covariance and scattering data.
|
|
354
|
+
poses (array_like): Scattering positions.
|
|
355
|
+
|
|
356
|
+
Returns
|
|
357
|
+
------
|
|
358
|
+
Extracted dataset components.
|
|
359
|
+
"""
|
|
360
|
+
scatt = np.atleast_2d(np.asarray(poses))
|
|
361
|
+
data_type, data_mode = _type(parameters["covariance"], scatt)
|
|
362
|
+
return dataset.T, parameters["weight"][:, None], poses.T, parameters["cholesky"].T, data_type, data_mode
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _evolve(dataset, poses, computations):
|
|
366
|
+
"""
|
|
367
|
+
Evolve the dataset based on computed parameters.
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
------
|
|
371
|
+
dataset (array_like): Input dataset.
|
|
372
|
+
poses (array_like): Scattering poses.
|
|
373
|
+
computations (dict): Computed parameters.
|
|
374
|
+
|
|
375
|
+
Returns
|
|
376
|
+
------
|
|
377
|
+
Evolved dataset.
|
|
378
|
+
"""
|
|
379
|
+
dataset = _extraction(dataset, computations, poses)
|
|
380
|
+
dens = gke[dataset[5]](
|
|
381
|
+
dataset[0],
|
|
382
|
+
dataset[1],
|
|
383
|
+
dataset[2],
|
|
384
|
+
dataset[3],
|
|
385
|
+
dataset[4])
|
|
386
|
+
return dens[:, 0]
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _peak(pdf):
|
|
390
|
+
"""
|
|
391
|
+
Find the peak in the probability density function.
|
|
392
|
+
|
|
393
|
+
Parameters
|
|
394
|
+
------
|
|
395
|
+
pdf (array_like): Probability density function.
|
|
396
|
+
|
|
397
|
+
Returns
|
|
398
|
+
------
|
|
399
|
+
Peak and its indices.
|
|
400
|
+
"""
|
|
401
|
+
peak = pdf.max()
|
|
402
|
+
up, wp = np.where(pdf == peak)[0][0], np.where(pdf == peak)[1][0]
|
|
403
|
+
fu = pdf[:, wp]
|
|
404
|
+
fw = pdf[up, :]
|
|
405
|
+
return peak, up, wp, fu, fw
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _cutoff(density_profile, velocity_profile, c1_threshold, c2_threshold, force_profile, peak_index, grid):
|
|
409
|
+
"""
|
|
410
|
+
Find the lower and upper cutoff velocities based on specified criteria.
|
|
411
|
+
|
|
412
|
+
Parameters
|
|
413
|
+
------
|
|
414
|
+
density_profile (array_like): Density profile of the system.
|
|
415
|
+
velocity_profile (array_like): Velocity profile of the system.
|
|
416
|
+
c1_threshold (float): Threshold ratio for force compared to peak force.
|
|
417
|
+
c2_threshold (float): Threshold for absolute change in force.
|
|
418
|
+
force_profile (array_like): Force profile of the system.
|
|
419
|
+
peak_index (int): Index of the peak force in the force profile.
|
|
420
|
+
grid (int): Grid spacing or resolution.
|
|
421
|
+
|
|
422
|
+
Returns
|
|
423
|
+
------
|
|
424
|
+
lower_cutoff_velocity, upper_cutoff_velocity: A tuple containing the lower and upper cutoff velocities.
|
|
425
|
+
|
|
426
|
+
Note
|
|
427
|
+
------
|
|
428
|
+
This function assumes that the input arrays (density_profile, velocity_profile, and force_profile)
|
|
429
|
+
are of the same length.
|
|
430
|
+
length.
|
|
431
|
+
The density profile, velocity profile, and force profile should be consistent and correspond to
|
|
432
|
+
each other at each index.
|
|
433
|
+
"""
|
|
434
|
+
|
|
435
|
+
profile_length = force_profile.size
|
|
436
|
+
delta_force = np.append([0], np.diff(force_profile)) * grid / density_profile
|
|
437
|
+
|
|
438
|
+
# Find lower cutoff index
|
|
439
|
+
for i in range(peak_index - 1, 0, -1):
|
|
440
|
+
if force_profile[i] / force_profile[peak_index] <= c1_threshold and abs(delta_force[i]) <= c2_threshold:
|
|
441
|
+
lower_cutoff_index = i
|
|
442
|
+
break
|
|
443
|
+
else:
|
|
444
|
+
lower_cutoff_index = 1
|
|
445
|
+
|
|
446
|
+
# Find upper cutoff index
|
|
447
|
+
for i in range(peak_index + 1, profile_length - 1):
|
|
448
|
+
if force_profile[i] / force_profile[peak_index] <= c1_threshold and abs(delta_force[i]) <= c2_threshold:
|
|
449
|
+
upper_cutoff_index = i
|
|
450
|
+
break
|
|
451
|
+
else:
|
|
452
|
+
upper_cutoff_index = profile_length - 1
|
|
453
|
+
|
|
454
|
+
lower_cutoff_velocity = velocity_profile[lower_cutoff_index]
|
|
455
|
+
upper_cutoff_velocity = velocity_profile[upper_cutoff_index]
|
|
456
|
+
|
|
457
|
+
return lower_cutoff_velocity, upper_cutoff_velocity
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def kernel(u1, w1, grid):
|
|
461
|
+
"""
|
|
462
|
+
Perform kernel computation.
|
|
463
|
+
|
|
464
|
+
Parameters
|
|
465
|
+
------
|
|
466
|
+
u1 (array_like): Input velocity component.
|
|
467
|
+
w1 (array_like): Input velocity component.
|
|
468
|
+
grid (int): Grid size.
|
|
469
|
+
|
|
470
|
+
Returns
|
|
471
|
+
------
|
|
472
|
+
Spieks Indices and estimation.
|
|
473
|
+
"""
|
|
474
|
+
|
|
475
|
+
dataset = np.array([u1, w1])
|
|
476
|
+
theta = _rotation(u1, w1)
|
|
477
|
+
ut, wt = _transform(u1, w1, theta)
|
|
478
|
+
mesh_u, mesh_w = _scaling(ut, wt, grid)
|
|
479
|
+
uf, wf = _profile(mesh_u, mesh_w)
|
|
480
|
+
positions, values = _position(mesh_u, mesh_w, ut, wt)
|
|
481
|
+
evals = _density(values)
|
|
482
|
+
evole = _evolve(dataset, positions, evals)
|
|
483
|
+
estimation = _estimation(evole.T, mesh_u)
|
|
484
|
+
density = np.reshape(kde(values)(positions).T, mesh_u.shape)
|
|
485
|
+
peak, up, wp, fu, fw = _peak(density)
|
|
486
|
+
lambda_ = np.sqrt(2 * np.log(u1.size))
|
|
487
|
+
stdu = std(u1)
|
|
488
|
+
stdw = std(w1)
|
|
489
|
+
cu = lambda_ * stdu / np.sqrt(u1.size)
|
|
490
|
+
cw = lambda_ * stdw / np.sqrt(u1.size)
|
|
491
|
+
ul, uu = _cutoff(peak, uf, cu, cu, fu, up, grid)
|
|
492
|
+
wl, wu = _cutoff(peak, wf, cw, cw, fw, wp, grid)
|
|
493
|
+
uu1 = uu - 0.5 * (uu + ul)
|
|
494
|
+
wu1 = wu - 0.5 * (wu + wl)
|
|
495
|
+
Ut1 = ut - 0.5 * (uu + ul)
|
|
496
|
+
Wt1 = wt - 0.5 * (wu + wl)
|
|
497
|
+
rho = (Ut1 / uu1) ** 2 + (Wt1 / wu1) ** 2
|
|
498
|
+
id_ = np.where(rho > 1)[0]
|
|
499
|
+
|
|
500
|
+
return id_, estimation
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def three_dimensional_kernel(data, grid):
|
|
504
|
+
"""
|
|
505
|
+
Perform three-dimensional kernel computation.
|
|
506
|
+
|
|
507
|
+
Parameters
|
|
508
|
+
------
|
|
509
|
+
data (array_like): Input data.
|
|
510
|
+
grid (int): Grid size.
|
|
511
|
+
|
|
512
|
+
Returns
|
|
513
|
+
------
|
|
514
|
+
Spikes indices.
|
|
515
|
+
"""
|
|
516
|
+
dc, dc2 = _derivatives(data)
|
|
517
|
+
x1, _ = kernel(data, dc, grid)
|
|
518
|
+
x2, _ = kernel(data, dc2, grid)
|
|
519
|
+
x3, _ = kernel(dc, dc2, grid)
|
|
520
|
+
kde3d_indices = np.sort(np.unique(np.concatenate((x1, x2, x3))))
|
|
521
|
+
return kde3d_indices
|
|
File without changes
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from proadv.statistics.descriptive import mean
|
|
3
|
+
from scipy.interpolate import interp1d
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def last_valid_data(velocities, spike_indices):
|
|
7
|
+
"""
|
|
8
|
+
Replace spike values in velocities array with the last valid data before each.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
------
|
|
12
|
+
velocities (array_like): Array of velocity data.
|
|
13
|
+
An array-like object containing velocity values.
|
|
14
|
+
spike_indices (array_like): Indices of spikes.
|
|
15
|
+
An array-like object containing the indices of detected spikes.
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
------
|
|
19
|
+
modified_data (array_like): Modified data with spikes replaced by last valid values.
|
|
20
|
+
An array containing the modified data.
|
|
21
|
+
"""
|
|
22
|
+
# Create a copy of the original data
|
|
23
|
+
modified_data = np.copy(velocities)
|
|
24
|
+
|
|
25
|
+
# Replace values at spikes indices with the last valid value
|
|
26
|
+
for idx in spike_indices:
|
|
27
|
+
modified_data[idx] = modified_data[idx - 1]
|
|
28
|
+
|
|
29
|
+
return modified_data
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def mean_value(velocities, spike_indices):
|
|
33
|
+
"""
|
|
34
|
+
Replace spike values in velocities array with the mean value of velocity component.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
------
|
|
38
|
+
velocities (array_like): Array of velocity data.
|
|
39
|
+
An array-like object containing velocity values.
|
|
40
|
+
spike_indices (array_like): Indices of spikes.
|
|
41
|
+
An array-like object containing the indices of detected spikes.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
------
|
|
45
|
+
modified_data (array_like): Modified data with spikes replaced by mean value of velocity component.
|
|
46
|
+
An array containing the modified data.
|
|
47
|
+
"""
|
|
48
|
+
# Create a copy of the original data
|
|
49
|
+
modified_data = np.copy(velocities)
|
|
50
|
+
|
|
51
|
+
# Replace values at spikes indices with the mean value
|
|
52
|
+
modified_data[spike_indices] = mean(velocities)
|
|
53
|
+
|
|
54
|
+
return modified_data
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def linear_interpolation(velocities, spike_indices, decimals=4):
|
|
58
|
+
"""
|
|
59
|
+
Perform linear interpolation to replace spike values in velocity data.
|
|
60
|
+
|
|
61
|
+
This function identifies spikes in the velocity data and replaces them with
|
|
62
|
+
linearly interpolated values based on the nearest valid data points before
|
|
63
|
+
and after each spike. If a spike occurs at the end of the data, it is replaced
|
|
64
|
+
with the mean of the entire dataset. The function is robust to handle individual
|
|
65
|
+
spikes as well as sequences of consecutive spikes.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
------
|
|
69
|
+
velocities : (array_like)
|
|
70
|
+
An array-like object containing velocity values. It should be a one-dimensional
|
|
71
|
+
array of numerical data representing velocities.
|
|
72
|
+
spike_indices : (array_like)
|
|
73
|
+
An array-like object containing the indices of detected spike events. It should
|
|
74
|
+
be a one-dimensional array of integers where each integer represents the index
|
|
75
|
+
in 'velocities' that corresponds to a spike.
|
|
76
|
+
decimals : int, optional
|
|
77
|
+
The number of decimal places to round the interpolated values to. This allows
|
|
78
|
+
the output data to be presented with a consistent level of precision. The default
|
|
79
|
+
value is 4, but this can be adjusted as needed.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
------
|
|
83
|
+
modified_data (array_like):
|
|
84
|
+
An array containing the modified velocity data with spikes replaced by
|
|
85
|
+
interpolated values. The shape and type of the array are the same as the
|
|
86
|
+
input 'velocities' array.
|
|
87
|
+
|
|
88
|
+
Notes
|
|
89
|
+
------
|
|
90
|
+
The function uses linear interpolation to estimate the values of spikes based on the
|
|
91
|
+
surrounding non-spike data. For spikes at the beginning or end of the data where a
|
|
92
|
+
neighboring non-spike value is not available, the function uses the mean of the entire
|
|
93
|
+
dataset as a replacement value. This approach ensures that the data remains as accurate
|
|
94
|
+
and representative of the original dataset as possible.
|
|
95
|
+
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# Create a copy of the velocity data to avoid modifying the original array
|
|
99
|
+
modified_data = np.copy(velocities)
|
|
100
|
+
|
|
101
|
+
# Initialize spike values with NaN to facilitate interpolation
|
|
102
|
+
modified_data[spike_indices] = np.nan
|
|
103
|
+
|
|
104
|
+
# Calculate differences between consecutive spike indices
|
|
105
|
+
spike_diff = np.diff(spike_indices)
|
|
106
|
+
# Identify the start index of each spike sequence
|
|
107
|
+
spike_starts = spike_indices[np.insert(spike_diff > 1, 0, True)]
|
|
108
|
+
# Identify the end index of each spike sequence
|
|
109
|
+
spike_ends = spike_indices[np.append(spike_diff > 1, True)]
|
|
110
|
+
|
|
111
|
+
# Iterate over each spike sequence for interpolation
|
|
112
|
+
for start, end in zip(spike_starts, spike_ends):
|
|
113
|
+
# Find the valid data point immediately before the spike sequence
|
|
114
|
+
valid_start = modified_data[start - 1] if start > 0 else np.nan
|
|
115
|
+
# Find the valid data point immediately after the spike sequence
|
|
116
|
+
valid_end = modified_data[end + 1] if end < len(velocities) - 1 else np.nan
|
|
117
|
+
|
|
118
|
+
# If valid start and end points are found, perform linear interpolation
|
|
119
|
+
if not np.isnan(valid_start) and not np.isnan(valid_end):
|
|
120
|
+
# Calculate the interpolation step size
|
|
121
|
+
step = (valid_end - valid_start) / (end - start + 2)
|
|
122
|
+
# Apply linear interpolation across the spike sequence
|
|
123
|
+
for i, idx in enumerate(range(start, end + 1)):
|
|
124
|
+
modified_data[idx] = valid_start + step * (i + 1)
|
|
125
|
+
elif np.isnan(valid_end): # Handle spike sequences at the end of the data
|
|
126
|
+
# Replace end spikes with the mean of non-NaN values in the dataset
|
|
127
|
+
modified_data[start:end + 1] = mean(velocities[~np.isnan(velocities)])
|
|
128
|
+
else:
|
|
129
|
+
# Use the mean of valid start and end points as a fallback
|
|
130
|
+
fallback_value = np.nanmean([valid_start, valid_end])
|
|
131
|
+
modified_data[start:end + 1] = fallback_value
|
|
132
|
+
|
|
133
|
+
# Round the interpolated values to the specified number of decimal places
|
|
134
|
+
return np.around(modified_data, decimals=decimals)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def cubic_12points_polynomial(velocities, spike_indices, decimals=4):
|
|
138
|
+
"""
|
|
139
|
+
Interpolates missing data points in a velocity array using cubic polynomial interpolation.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
------
|
|
143
|
+
velocities (array_like): Array of velocity data. It should be a one-dimensional array-like object.
|
|
144
|
+
This function assumes the input velocities array has at least 25 data points.
|
|
145
|
+
spike_indices (array_like): Indices where data is missing (spikes). It should be a one-dimensional array-like
|
|
146
|
+
object containing integers representing the indices of missing data points (spikes).
|
|
147
|
+
If spike_indices contains invalid indices (e.g., negative values or indices exceeding the array size),
|
|
148
|
+
a ValueError will be raised.
|
|
149
|
+
decimals (int, optional): Number of decimal places to round the result to. Default is 4.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
------
|
|
153
|
+
modified_data (array_like): Array of velocities with missing data interpolated. The interpolated values
|
|
154
|
+
are calculated based on cubic polynomial interpolation using neighboring data points.
|
|
155
|
+
|
|
156
|
+
Raises
|
|
157
|
+
------
|
|
158
|
+
ValueError: If spike_indices contains invalid indices or if velocities is not a one-dimensional array-like object.
|
|
159
|
+
|
|
160
|
+
Notes
|
|
161
|
+
------
|
|
162
|
+
- This function uses cubic polynomial interpolation to estimate missing data points based on neighboring values.
|
|
163
|
+
- If a missing data point (spike) occurs near the boundaries of the velocities array, linear interpolation
|
|
164
|
+
is used instead of cubic polynomial interpolation.
|
|
165
|
+
- The input velocities array is modified in-place to replace missing data points with interpolated values.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
# Make a copy of velocities to preserve original data
|
|
169
|
+
modified_data = velocities.copy()
|
|
170
|
+
|
|
171
|
+
# Replace spike indices with NaN values
|
|
172
|
+
modified_data[spike_indices] = np.nan
|
|
173
|
+
|
|
174
|
+
# Generate x values for interpolation
|
|
175
|
+
x = np.array(list(range(1, 13)) + list(range(14, 26)))
|
|
176
|
+
|
|
177
|
+
for i in spike_indices:
|
|
178
|
+
# Check if index is near the boundaries
|
|
179
|
+
if i <= 30 or i >= (len(velocities) - 30):
|
|
180
|
+
# Use linear interpolation near the boundaries
|
|
181
|
+
modified_data[i] = np.around((velocities[i - 1] + modified_data[i:][~np.isnan(modified_data[i:])][0]) / 2, 4)
|
|
182
|
+
else:
|
|
183
|
+
# Use cubic polynomial interpolation
|
|
184
|
+
yint = np.delete(np.append(velocities[i - 13:i], modified_data[i:][~np.isnan(modified_data[i:])][0:12]), 12)
|
|
185
|
+
f = interp1d(x, yint, 3)
|
|
186
|
+
modified_data[i] = f(13)
|
|
187
|
+
return np.around(modified_data, decimals=decimals)
|
|
File without changes
|