oscura 0.7.0__py3-none-any.whl → 0.10.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.
- oscura/__init__.py +19 -19
- oscura/analyzers/__init__.py +2 -0
- oscura/analyzers/digital/extraction.py +2 -3
- oscura/analyzers/digital/quality.py +1 -1
- oscura/analyzers/digital/timing.py +1 -1
- oscura/analyzers/eye/__init__.py +5 -1
- oscura/analyzers/eye/generation.py +501 -0
- oscura/analyzers/jitter/__init__.py +6 -6
- oscura/analyzers/jitter/timing.py +419 -0
- oscura/analyzers/patterns/__init__.py +94 -0
- oscura/analyzers/patterns/reverse_engineering.py +991 -0
- oscura/analyzers/power/__init__.py +35 -12
- oscura/analyzers/power/basic.py +3 -3
- oscura/analyzers/power/soa.py +1 -1
- oscura/analyzers/power/switching.py +3 -3
- oscura/analyzers/signal_classification.py +529 -0
- oscura/analyzers/signal_integrity/sparams.py +3 -3
- oscura/analyzers/statistics/__init__.py +4 -0
- oscura/analyzers/statistics/basic.py +152 -0
- oscura/analyzers/statistics/correlation.py +47 -6
- oscura/analyzers/validation.py +1 -1
- oscura/analyzers/waveform/__init__.py +2 -0
- oscura/analyzers/waveform/measurements.py +329 -163
- oscura/analyzers/waveform/measurements_with_uncertainty.py +91 -35
- oscura/analyzers/waveform/spectral.py +498 -54
- oscura/api/dsl/commands.py +15 -6
- oscura/api/server/templates/base.html +137 -146
- oscura/api/server/templates/export.html +84 -110
- oscura/api/server/templates/home.html +248 -267
- oscura/api/server/templates/protocols.html +44 -48
- oscura/api/server/templates/reports.html +27 -35
- oscura/api/server/templates/session_detail.html +68 -78
- oscura/api/server/templates/sessions.html +62 -72
- oscura/api/server/templates/waveforms.html +54 -64
- oscura/automotive/__init__.py +1 -1
- oscura/automotive/can/session.py +1 -1
- oscura/automotive/dbc/generator.py +638 -23
- oscura/automotive/dtc/data.json +102 -17
- oscura/automotive/uds/decoder.py +99 -6
- oscura/cli/analyze.py +8 -2
- oscura/cli/batch.py +36 -5
- oscura/cli/characterize.py +18 -4
- oscura/cli/export.py +47 -5
- oscura/cli/main.py +2 -0
- oscura/cli/onboarding/wizard.py +10 -6
- oscura/cli/pipeline.py +585 -0
- oscura/cli/visualize.py +6 -4
- oscura/convenience.py +400 -32
- oscura/core/config/loader.py +0 -1
- oscura/core/measurement_result.py +286 -0
- oscura/core/progress.py +1 -1
- oscura/core/schemas/device_mapping.json +8 -2
- oscura/core/schemas/packet_format.json +24 -4
- oscura/core/schemas/protocol_definition.json +12 -2
- oscura/core/types.py +300 -199
- oscura/correlation/multi_protocol.py +1 -1
- oscura/export/legacy/__init__.py +11 -0
- oscura/export/legacy/wav.py +75 -0
- oscura/exporters/__init__.py +19 -0
- oscura/exporters/wireshark.py +809 -0
- oscura/hardware/acquisition/file.py +5 -19
- oscura/hardware/acquisition/saleae.py +10 -10
- oscura/hardware/acquisition/socketcan.py +4 -6
- oscura/hardware/acquisition/synthetic.py +1 -5
- oscura/hardware/acquisition/visa.py +6 -6
- oscura/hardware/security/side_channel_detector.py +5 -508
- oscura/inference/message_format.py +686 -1
- oscura/jupyter/display.py +2 -2
- oscura/jupyter/magic.py +3 -3
- oscura/loaders/__init__.py +17 -12
- oscura/loaders/binary.py +1 -1
- oscura/loaders/chipwhisperer.py +1 -2
- oscura/loaders/configurable.py +1 -1
- oscura/loaders/csv_loader.py +2 -2
- oscura/loaders/hdf5_loader.py +1 -1
- oscura/loaders/lazy.py +6 -1
- oscura/loaders/mmap_loader.py +0 -1
- oscura/loaders/numpy_loader.py +8 -7
- oscura/loaders/preprocessing.py +3 -5
- oscura/loaders/rigol.py +21 -7
- oscura/loaders/sigrok.py +2 -5
- oscura/loaders/tdms.py +3 -2
- oscura/loaders/tektronix.py +38 -32
- oscura/loaders/tss.py +20 -27
- oscura/loaders/vcd.py +13 -8
- oscura/loaders/wav.py +1 -6
- oscura/pipeline/__init__.py +76 -0
- oscura/pipeline/handlers/__init__.py +165 -0
- oscura/pipeline/handlers/analyzers.py +1045 -0
- oscura/pipeline/handlers/decoders.py +899 -0
- oscura/pipeline/handlers/exporters.py +1103 -0
- oscura/pipeline/handlers/filters.py +891 -0
- oscura/pipeline/handlers/loaders.py +640 -0
- oscura/pipeline/handlers/transforms.py +768 -0
- oscura/reporting/__init__.py +88 -1
- oscura/reporting/automation.py +348 -0
- oscura/reporting/citations.py +374 -0
- oscura/reporting/core.py +54 -0
- oscura/reporting/formatting/__init__.py +11 -0
- oscura/reporting/formatting/measurements.py +320 -0
- oscura/reporting/html.py +57 -0
- oscura/reporting/interpretation.py +431 -0
- oscura/reporting/summary.py +329 -0
- oscura/reporting/templates/enhanced/protocol_re.html +504 -503
- oscura/reporting/visualization.py +542 -0
- oscura/side_channel/__init__.py +38 -57
- oscura/utils/builders/signal_builder.py +5 -5
- oscura/utils/comparison/compare.py +7 -9
- oscura/utils/comparison/golden.py +1 -1
- oscura/utils/filtering/convenience.py +2 -2
- oscura/utils/math/arithmetic.py +38 -62
- oscura/utils/math/interpolation.py +20 -20
- oscura/utils/pipeline/__init__.py +4 -17
- oscura/utils/progressive.py +1 -4
- oscura/utils/triggering/edge.py +1 -1
- oscura/utils/triggering/pattern.py +2 -2
- oscura/utils/triggering/pulse.py +2 -2
- oscura/utils/triggering/window.py +3 -3
- oscura/validation/hil_testing.py +11 -11
- oscura/visualization/__init__.py +47 -284
- oscura/visualization/batch.py +160 -0
- oscura/visualization/plot.py +542 -53
- oscura/visualization/styles.py +184 -318
- oscura/workflows/__init__.py +2 -0
- oscura/workflows/batch/advanced.py +1 -1
- oscura/workflows/batch/aggregate.py +7 -8
- oscura/workflows/complete_re.py +251 -23
- oscura/workflows/digital.py +27 -4
- oscura/workflows/multi_trace.py +136 -17
- oscura/workflows/waveform.py +788 -0
- {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/METADATA +59 -79
- {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/RECORD +135 -149
- oscura/side_channel/dpa.py +0 -1025
- oscura/utils/optimization/__init__.py +0 -19
- oscura/utils/optimization/parallel.py +0 -443
- oscura/utils/optimization/search.py +0 -532
- oscura/utils/pipeline/base.py +0 -338
- oscura/utils/pipeline/composition.py +0 -248
- oscura/utils/pipeline/parallel.py +0 -449
- oscura/utils/pipeline/pipeline.py +0 -375
- oscura/utils/search/__init__.py +0 -16
- oscura/utils/search/anomaly.py +0 -424
- oscura/utils/search/context.py +0 -294
- oscura/utils/search/pattern.py +0 -288
- oscura/utils/storage/__init__.py +0 -61
- oscura/utils/storage/database.py +0 -1166
- oscura/visualization/accessibility.py +0 -526
- oscura/visualization/annotations.py +0 -371
- oscura/visualization/axis_scaling.py +0 -305
- oscura/visualization/colors.py +0 -451
- oscura/visualization/digital.py +0 -436
- oscura/visualization/eye.py +0 -571
- oscura/visualization/histogram.py +0 -281
- oscura/visualization/interactive.py +0 -1035
- oscura/visualization/jitter.py +0 -1042
- oscura/visualization/keyboard.py +0 -394
- oscura/visualization/layout.py +0 -400
- oscura/visualization/optimization.py +0 -1079
- oscura/visualization/palettes.py +0 -446
- oscura/visualization/power.py +0 -508
- oscura/visualization/power_extended.py +0 -955
- oscura/visualization/presets.py +0 -469
- oscura/visualization/protocols.py +0 -1246
- oscura/visualization/render.py +0 -223
- oscura/visualization/rendering.py +0 -444
- oscura/visualization/reverse_engineering.py +0 -838
- oscura/visualization/signal_integrity.py +0 -989
- oscura/visualization/specialized.py +0 -643
- oscura/visualization/spectral.py +0 -1226
- oscura/visualization/thumbnails.py +0 -340
- oscura/visualization/time_axis.py +0 -351
- oscura/visualization/waveform.py +0 -454
- {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/WHEEL +0 -0
- {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/entry_points.txt +0 -0
- {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
"""Histogram utilities with automatic bin optimization.
|
|
2
|
-
|
|
3
|
-
This module provides intelligent histogram bin calculation using
|
|
4
|
-
established statistical rules.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Example:
|
|
8
|
-
>>> from oscura.visualization.histogram import calculate_optimal_bins
|
|
9
|
-
>>> bins = calculate_optimal_bins(data, method="freedman-diaconis")
|
|
10
|
-
|
|
11
|
-
References:
|
|
12
|
-
Sturges' rule (1926)
|
|
13
|
-
Freedman-Diaconis rule (1981)
|
|
14
|
-
Scott's rule (1979)
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from __future__ import annotations
|
|
18
|
-
|
|
19
|
-
from typing import TYPE_CHECKING, Literal
|
|
20
|
-
|
|
21
|
-
import numpy as np
|
|
22
|
-
|
|
23
|
-
if TYPE_CHECKING:
|
|
24
|
-
from numpy.typing import NDArray
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def calculate_optimal_bins(
|
|
28
|
-
data: NDArray[np.float64],
|
|
29
|
-
*,
|
|
30
|
-
method: Literal["auto", "sturges", "freedman-diaconis", "scott"] = "auto",
|
|
31
|
-
min_bins: int = 5,
|
|
32
|
-
max_bins: int = 200,
|
|
33
|
-
) -> int:
|
|
34
|
-
"""Calculate optimal histogram bin count using statistical rules.
|
|
35
|
-
|
|
36
|
-
: Automatically calculate optimal histogram bin count
|
|
37
|
-
using Sturges, Freedman-Diaconis, or Scott's rule.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
data: Input data array
|
|
41
|
-
method: Binning method to use
|
|
42
|
-
- "auto": Auto-select based on data characteristics
|
|
43
|
-
- "sturges": Sturges' rule (good for normal distributions)
|
|
44
|
-
- "freedman-diaconis": Freedman-Diaconis rule (robust to outliers)
|
|
45
|
-
- "scott": Scott's rule (good for smooth distributions)
|
|
46
|
-
min_bins: Minimum number of bins (default: 5)
|
|
47
|
-
max_bins: Maximum number of bins (default: 200)
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
Optimal number of bins (clamped to [min_bins, max_bins])
|
|
51
|
-
|
|
52
|
-
Raises:
|
|
53
|
-
ValueError: If data is empty or invalid
|
|
54
|
-
|
|
55
|
-
Example:
|
|
56
|
-
>>> data = np.random.randn(1000)
|
|
57
|
-
>>> bins = calculate_optimal_bins(data, method="freedman-diaconis")
|
|
58
|
-
>>> hist, edges = np.histogram(data, bins=bins)
|
|
59
|
-
|
|
60
|
-
>>> # Auto-select method
|
|
61
|
-
>>> bins = calculate_optimal_bins(data, method="auto")
|
|
62
|
-
|
|
63
|
-
References:
|
|
64
|
-
VIS-025: Histogram Bin Optimization
|
|
65
|
-
Sturges (1926): k = ceil(log2(n) + 1)
|
|
66
|
-
Freedman-Diaconis (1981): h = 2 * IQR * n^(-1/3)
|
|
67
|
-
Scott (1979): h = 3.5 * std * n^(-1/3)
|
|
68
|
-
"""
|
|
69
|
-
if len(data) == 0:
|
|
70
|
-
raise ValueError("Data array cannot be empty")
|
|
71
|
-
if min_bins < 1:
|
|
72
|
-
raise ValueError("min_bins must be >= 1")
|
|
73
|
-
if max_bins < min_bins:
|
|
74
|
-
raise ValueError("max_bins must be >= min_bins")
|
|
75
|
-
|
|
76
|
-
# Remove NaN values
|
|
77
|
-
clean_data = data[~np.isnan(data)]
|
|
78
|
-
|
|
79
|
-
if len(clean_data) < 2:
|
|
80
|
-
return min_bins
|
|
81
|
-
|
|
82
|
-
# Auto-select method based on data characteristics
|
|
83
|
-
if method == "auto":
|
|
84
|
-
method = _auto_select_method(clean_data)
|
|
85
|
-
|
|
86
|
-
# Calculate bins using selected method
|
|
87
|
-
if method == "sturges":
|
|
88
|
-
bins = _sturges_bins(clean_data)
|
|
89
|
-
elif method == "freedman-diaconis":
|
|
90
|
-
bins = _freedman_diaconis_bins(clean_data)
|
|
91
|
-
elif method == "scott":
|
|
92
|
-
bins = _scott_bins(clean_data)
|
|
93
|
-
else:
|
|
94
|
-
raise ValueError(f"Unknown method: {method}")
|
|
95
|
-
|
|
96
|
-
# Clamp to valid range
|
|
97
|
-
bins = max(min_bins, min(max_bins, bins))
|
|
98
|
-
|
|
99
|
-
return bins
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def calculate_bin_edges(
|
|
103
|
-
data: NDArray[np.float64],
|
|
104
|
-
n_bins: int,
|
|
105
|
-
) -> NDArray[np.float64]:
|
|
106
|
-
"""Calculate histogram bin edges for given bin count.
|
|
107
|
-
|
|
108
|
-
Args:
|
|
109
|
-
data: Input data array
|
|
110
|
-
n_bins: Number of bins
|
|
111
|
-
|
|
112
|
-
Returns:
|
|
113
|
-
Array of bin edges (length n_bins + 1)
|
|
114
|
-
|
|
115
|
-
Raises:
|
|
116
|
-
ValueError: If data is empty or n_bins < 1.
|
|
117
|
-
|
|
118
|
-
Example:
|
|
119
|
-
>>> data = np.random.randn(1000)
|
|
120
|
-
>>> n_bins = calculate_optimal_bins(data)
|
|
121
|
-
>>> edges = calculate_bin_edges(data, n_bins)
|
|
122
|
-
"""
|
|
123
|
-
if len(data) == 0:
|
|
124
|
-
raise ValueError("Data array cannot be empty")
|
|
125
|
-
if n_bins < 1:
|
|
126
|
-
raise ValueError("n_bins must be >= 1")
|
|
127
|
-
|
|
128
|
-
# Remove NaN values
|
|
129
|
-
clean_data = data[~np.isnan(data)]
|
|
130
|
-
|
|
131
|
-
if len(clean_data) == 0:
|
|
132
|
-
return np.array([0.0, 1.0])
|
|
133
|
-
|
|
134
|
-
# Calculate edges
|
|
135
|
-
data_min = np.min(clean_data)
|
|
136
|
-
data_max = np.max(clean_data)
|
|
137
|
-
|
|
138
|
-
# Handle single-value data
|
|
139
|
-
if data_min == data_max:
|
|
140
|
-
return np.array([data_min - 0.5, data_max + 0.5])
|
|
141
|
-
|
|
142
|
-
edges: NDArray[np.float64] = np.linspace(data_min, data_max, n_bins + 1)
|
|
143
|
-
return edges
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def _sturges_bins(data: NDArray[np.float64]) -> int:
|
|
147
|
-
"""Calculate bins using Sturges' rule.
|
|
148
|
-
|
|
149
|
-
Sturges' rule: k = ceil(log2(n) + 1)
|
|
150
|
-
|
|
151
|
-
Good for: Normal distributions, small to moderate sample sizes
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
data: Input data
|
|
155
|
-
|
|
156
|
-
Returns:
|
|
157
|
-
Number of bins
|
|
158
|
-
"""
|
|
159
|
-
n = len(data)
|
|
160
|
-
bins = int(np.ceil(np.log2(n) + 1))
|
|
161
|
-
return bins
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def _freedman_diaconis_bins(data: NDArray[np.float64]) -> int:
|
|
165
|
-
"""Calculate bins using Freedman-Diaconis rule.
|
|
166
|
-
|
|
167
|
-
Freedman-Diaconis rule: h = 2 * IQR(x) / n^(1/3)
|
|
168
|
-
where h is bin width and IQR is interquartile range
|
|
169
|
-
|
|
170
|
-
Good for: Robust estimation, data with outliers
|
|
171
|
-
|
|
172
|
-
Args:
|
|
173
|
-
data: Input data
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
Number of bins
|
|
177
|
-
"""
|
|
178
|
-
n = len(data)
|
|
179
|
-
|
|
180
|
-
# Calculate IQR
|
|
181
|
-
q75, q25 = np.percentile(data, [75, 25])
|
|
182
|
-
iqr = q75 - q25
|
|
183
|
-
|
|
184
|
-
if iqr == 0:
|
|
185
|
-
# Fall back to Sturges if IQR is zero
|
|
186
|
-
return _sturges_bins(data)
|
|
187
|
-
|
|
188
|
-
# Calculate bin width
|
|
189
|
-
bin_width = 2.0 * iqr / (n ** (1.0 / 3.0))
|
|
190
|
-
|
|
191
|
-
# Calculate number of bins
|
|
192
|
-
data_range = np.ptp(data) # peak-to-peak (max - min)
|
|
193
|
-
|
|
194
|
-
if bin_width == 0:
|
|
195
|
-
return _sturges_bins(data)
|
|
196
|
-
|
|
197
|
-
bins = int(np.ceil(data_range / bin_width))
|
|
198
|
-
|
|
199
|
-
return max(1, bins)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def _scott_bins(data: NDArray[np.float64]) -> int:
|
|
203
|
-
"""Calculate bins using Scott's rule.
|
|
204
|
-
|
|
205
|
-
Scott's rule: h = 3.5 * std(x) / n^(1/3)
|
|
206
|
-
where h is bin width
|
|
207
|
-
|
|
208
|
-
Good for: Smooth distributions, normally distributed data
|
|
209
|
-
|
|
210
|
-
Args:
|
|
211
|
-
data: Input data
|
|
212
|
-
|
|
213
|
-
Returns:
|
|
214
|
-
Number of bins
|
|
215
|
-
"""
|
|
216
|
-
n = len(data)
|
|
217
|
-
|
|
218
|
-
# Calculate standard deviation
|
|
219
|
-
std = np.std(data)
|
|
220
|
-
|
|
221
|
-
if std == 0:
|
|
222
|
-
# Fall back to Sturges if std is zero
|
|
223
|
-
return _sturges_bins(data)
|
|
224
|
-
|
|
225
|
-
# Calculate bin width
|
|
226
|
-
bin_width = 3.5 * std / (n ** (1.0 / 3.0))
|
|
227
|
-
|
|
228
|
-
# Calculate number of bins
|
|
229
|
-
data_range = np.ptp(data)
|
|
230
|
-
|
|
231
|
-
if bin_width == 0:
|
|
232
|
-
return _sturges_bins(data)
|
|
233
|
-
|
|
234
|
-
bins = int(np.ceil(data_range / bin_width))
|
|
235
|
-
|
|
236
|
-
return max(1, bins)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def _auto_select_method(
|
|
240
|
-
data: NDArray[np.float64],
|
|
241
|
-
) -> Literal["sturges", "freedman-diaconis", "scott"]:
|
|
242
|
-
"""Auto-select binning method based on data characteristics.
|
|
243
|
-
|
|
244
|
-
Selection criteria:
|
|
245
|
-
- Use Sturges for small samples (n < 100)
|
|
246
|
-
- Use Freedman-Diaconis for data with outliers (high skewness)
|
|
247
|
-
- Use Scott for smooth, normal-like distributions
|
|
248
|
-
|
|
249
|
-
Args:
|
|
250
|
-
data: Input data
|
|
251
|
-
|
|
252
|
-
Returns:
|
|
253
|
-
Selected method name
|
|
254
|
-
"""
|
|
255
|
-
n = len(data)
|
|
256
|
-
|
|
257
|
-
# Small samples: use Sturges
|
|
258
|
-
if n < 100:
|
|
259
|
-
return "sturges"
|
|
260
|
-
|
|
261
|
-
# Calculate skewness to detect outliers
|
|
262
|
-
mean = np.mean(data)
|
|
263
|
-
std = np.std(data)
|
|
264
|
-
|
|
265
|
-
if std == 0:
|
|
266
|
-
return "sturges"
|
|
267
|
-
|
|
268
|
-
skewness = np.mean(((data - mean) / std) ** 3)
|
|
269
|
-
|
|
270
|
-
# High skewness indicates outliers: use Freedman-Diaconis (robust)
|
|
271
|
-
if abs(skewness) > 0.5:
|
|
272
|
-
return "freedman-diaconis"
|
|
273
|
-
|
|
274
|
-
# Normal-like distribution: use Scott
|
|
275
|
-
return "scott"
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
__all__ = [
|
|
279
|
-
"calculate_bin_edges",
|
|
280
|
-
"calculate_optimal_bins",
|
|
281
|
-
]
|