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
|
@@ -61,28 +61,41 @@ def rise_time(
|
|
|
61
61
|
IEEE 181-2011 Annex B (measurement uncertainty)
|
|
62
62
|
"""
|
|
63
63
|
# Get the measurement value
|
|
64
|
-
|
|
64
|
+
result = meas.rise_time(trace, ref_levels=ref_levels)
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
# Extract value from MeasurementResult
|
|
67
|
+
if not result["applicable"]:
|
|
68
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="s")
|
|
69
|
+
|
|
70
|
+
value = result["value"]
|
|
71
|
+
|
|
72
|
+
if value is None:
|
|
73
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="s")
|
|
74
|
+
|
|
75
|
+
if not include_uncertainty:
|
|
76
|
+
return MeasurementWithUncertainty(
|
|
77
|
+
value=float(value),
|
|
78
|
+
uncertainty=float(np.nan),
|
|
79
|
+
unit="s",
|
|
80
|
+
)
|
|
68
81
|
|
|
69
82
|
# Estimate uncertainty components
|
|
70
83
|
uncertainties = []
|
|
71
84
|
|
|
72
85
|
# 1. Time base uncertainty (Type B)
|
|
73
86
|
if (
|
|
74
|
-
trace.metadata.
|
|
75
|
-
and trace.metadata.
|
|
87
|
+
trace.metadata.calibration is not None
|
|
88
|
+
and trace.metadata.calibration.timebase_accuracy is not None
|
|
76
89
|
):
|
|
77
90
|
# Use calibration timebase accuracy if available
|
|
78
|
-
timebase_ppm = trace.metadata.
|
|
91
|
+
timebase_ppm = trace.metadata.calibration.timebase_accuracy
|
|
79
92
|
u_timebase = UncertaintyEstimator.time_base_uncertainty(
|
|
80
93
|
trace.metadata.sample_rate, timebase_ppm
|
|
81
94
|
)
|
|
82
95
|
# Rise time involves 2 samples (start and stop), so uncertainty scales
|
|
83
96
|
u_timebase_rise = u_timebase * np.sqrt(2)
|
|
84
97
|
uncertainties.append(u_timebase_rise)
|
|
85
|
-
elif trace.metadata.
|
|
98
|
+
elif trace.metadata.calibration is not None:
|
|
86
99
|
# Use conservative estimate if calibration present but no timebase accuracy
|
|
87
100
|
timebase_ppm = 25.0 # Typical scope: 25-50 ppm
|
|
88
101
|
u_timebase = UncertaintyEstimator.time_base_uncertainty(
|
|
@@ -97,7 +110,7 @@ def rise_time(
|
|
|
97
110
|
|
|
98
111
|
# 2. Interpolation uncertainty (Type B - rectangular distribution)
|
|
99
112
|
# Linear interpolation error: typically ±0.5 samples worst case
|
|
100
|
-
sample_period = trace.metadata.
|
|
113
|
+
sample_period = 1.0 / trace.metadata.sample_rate
|
|
101
114
|
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
102
115
|
uncertainties.append(u_interp)
|
|
103
116
|
|
|
@@ -147,20 +160,33 @@ def fall_time(
|
|
|
147
160
|
References:
|
|
148
161
|
IEEE 181-2011 Section 5.2
|
|
149
162
|
"""
|
|
150
|
-
|
|
163
|
+
result = meas.fall_time(trace, ref_levels=ref_levels)
|
|
164
|
+
|
|
165
|
+
# Extract value from MeasurementResult
|
|
166
|
+
if not result["applicable"]:
|
|
167
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="s")
|
|
151
168
|
|
|
152
|
-
|
|
153
|
-
|
|
169
|
+
value = result["value"]
|
|
170
|
+
|
|
171
|
+
if value is None:
|
|
172
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="s")
|
|
173
|
+
|
|
174
|
+
if not include_uncertainty:
|
|
175
|
+
return MeasurementWithUncertainty(
|
|
176
|
+
value=float(value),
|
|
177
|
+
uncertainty=float(np.nan),
|
|
178
|
+
unit="s",
|
|
179
|
+
)
|
|
154
180
|
|
|
155
181
|
# Similar uncertainty calculation as rise_time
|
|
156
182
|
uncertainties = []
|
|
157
183
|
|
|
158
184
|
# Time base uncertainty
|
|
159
185
|
if (
|
|
160
|
-
trace.metadata.
|
|
161
|
-
and trace.metadata.
|
|
186
|
+
trace.metadata.calibration is not None
|
|
187
|
+
and trace.metadata.calibration.timebase_accuracy is not None
|
|
162
188
|
):
|
|
163
|
-
timebase_ppm = trace.metadata.
|
|
189
|
+
timebase_ppm = trace.metadata.calibration.timebase_accuracy
|
|
164
190
|
else:
|
|
165
191
|
timebase_ppm = 25.0 # Conservative default
|
|
166
192
|
u_timebase = UncertaintyEstimator.time_base_uncertainty(
|
|
@@ -169,7 +195,7 @@ def fall_time(
|
|
|
169
195
|
uncertainties.append(u_timebase * np.sqrt(2))
|
|
170
196
|
|
|
171
197
|
# Interpolation uncertainty
|
|
172
|
-
sample_period = trace.metadata.
|
|
198
|
+
sample_period = 1.0 / trace.metadata.sample_rate
|
|
173
199
|
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
174
200
|
uncertainties.append(u_interp)
|
|
175
201
|
|
|
@@ -208,9 +234,18 @@ def frequency(
|
|
|
208
234
|
IEEE 181-2011 Section 5.3
|
|
209
235
|
IEEE 1057-2017 Section 4.3
|
|
210
236
|
"""
|
|
211
|
-
|
|
237
|
+
result = meas.frequency(trace)
|
|
238
|
+
|
|
239
|
+
# Extract value from MeasurementResult
|
|
240
|
+
if not result["applicable"]:
|
|
241
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="Hz")
|
|
242
|
+
|
|
243
|
+
value = result["value"]
|
|
212
244
|
|
|
213
|
-
if
|
|
245
|
+
if value is None:
|
|
246
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="Hz")
|
|
247
|
+
|
|
248
|
+
if not include_uncertainty:
|
|
214
249
|
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="Hz")
|
|
215
250
|
|
|
216
251
|
# Frequency is 1/period, so uncertainty propagation:
|
|
@@ -225,10 +260,10 @@ def frequency(
|
|
|
225
260
|
|
|
226
261
|
# Time base uncertainty
|
|
227
262
|
if (
|
|
228
|
-
trace.metadata.
|
|
229
|
-
and trace.metadata.
|
|
263
|
+
trace.metadata.calibration is not None
|
|
264
|
+
and trace.metadata.calibration.timebase_accuracy is not None
|
|
230
265
|
):
|
|
231
|
-
timebase_ppm = trace.metadata.
|
|
266
|
+
timebase_ppm = trace.metadata.calibration.timebase_accuracy
|
|
232
267
|
else:
|
|
233
268
|
timebase_ppm = 25.0 # Conservative default
|
|
234
269
|
# Period measurement spans multiple cycles, typically more accurate
|
|
@@ -236,7 +271,7 @@ def frequency(
|
|
|
236
271
|
uncertainties.append(u_period_timebase)
|
|
237
272
|
|
|
238
273
|
# Interpolation uncertainty for edge detection
|
|
239
|
-
sample_period = trace.metadata.
|
|
274
|
+
sample_period = 1.0 / trace.metadata.sample_rate
|
|
240
275
|
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
241
276
|
# Two edges per period
|
|
242
277
|
u_period_interp = u_interp * np.sqrt(2)
|
|
@@ -246,10 +281,11 @@ def frequency(
|
|
|
246
281
|
u_period = UncertaintyEstimator.combined_uncertainty([float(u) for u in uncertainties])
|
|
247
282
|
|
|
248
283
|
# Propagate to frequency: u(f) = |df/dT| * u(T) = f^2 * u(T)
|
|
249
|
-
|
|
284
|
+
value_float = float(value) # Already checked for None above
|
|
285
|
+
u_frequency = float((value_float**2) * u_period)
|
|
250
286
|
|
|
251
287
|
return MeasurementWithUncertainty(
|
|
252
|
-
value=
|
|
288
|
+
value=value_float, uncertainty=u_frequency, unit="Hz", n_samples=len(trace.data)
|
|
253
289
|
)
|
|
254
290
|
|
|
255
291
|
|
|
@@ -275,9 +311,18 @@ def amplitude(
|
|
|
275
311
|
IEEE 1057-2017 Section 4.2 (amplitude measurement)
|
|
276
312
|
IEEE 1057-2017 Section 4.4 (amplitude accuracy)
|
|
277
313
|
"""
|
|
278
|
-
|
|
314
|
+
result = meas.amplitude(trace)
|
|
315
|
+
|
|
316
|
+
# Extract value from MeasurementResult
|
|
317
|
+
if not result["applicable"]:
|
|
318
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="V")
|
|
319
|
+
|
|
320
|
+
value = result["value"]
|
|
279
321
|
|
|
280
|
-
if
|
|
322
|
+
if value is None:
|
|
323
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="V")
|
|
324
|
+
|
|
325
|
+
if not include_uncertainty:
|
|
281
326
|
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="V")
|
|
282
327
|
|
|
283
328
|
uncertainties = []
|
|
@@ -291,17 +336,18 @@ def amplitude(
|
|
|
291
336
|
else:
|
|
292
337
|
offset_error = 0.001 # 1 mV default
|
|
293
338
|
|
|
339
|
+
value_float = float(value) # Already checked for None
|
|
294
340
|
u_vertical = UncertaintyEstimator.vertical_uncertainty(
|
|
295
|
-
|
|
341
|
+
value_float, vertical_accuracy_pct, offset_error
|
|
296
342
|
)
|
|
297
343
|
uncertainties.append(u_vertical)
|
|
298
344
|
|
|
299
345
|
# 2. Quantization uncertainty (Type B - rectangular)
|
|
300
346
|
if (
|
|
301
|
-
trace.metadata.
|
|
302
|
-
and trace.metadata.
|
|
347
|
+
trace.metadata.calibration is not None
|
|
348
|
+
and trace.metadata.calibration.vertical_resolution is not None
|
|
303
349
|
):
|
|
304
|
-
bits = trace.metadata.
|
|
350
|
+
bits = trace.metadata.calibration.vertical_resolution
|
|
305
351
|
vertical_range = np.ptp(trace.data) # Simplification
|
|
306
352
|
lsb = vertical_range / (2**bits)
|
|
307
353
|
u_quant = UncertaintyEstimator.type_b_rectangular(0.5 * lsb)
|
|
@@ -321,7 +367,7 @@ def amplitude(
|
|
|
321
367
|
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
322
368
|
|
|
323
369
|
return MeasurementWithUncertainty(
|
|
324
|
-
value=
|
|
370
|
+
value=value_float,
|
|
325
371
|
uncertainty=total_uncertainty,
|
|
326
372
|
unit="V",
|
|
327
373
|
n_samples=len(trace.data),
|
|
@@ -347,9 +393,18 @@ def rms(
|
|
|
347
393
|
References:
|
|
348
394
|
IEEE 1057-2017 Section 4.3
|
|
349
395
|
"""
|
|
350
|
-
|
|
396
|
+
result = meas.rms(trace, ac_coupled=ac_coupled)
|
|
351
397
|
|
|
352
|
-
|
|
398
|
+
# Extract value from MeasurementResult
|
|
399
|
+
if not result["applicable"]:
|
|
400
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="V")
|
|
401
|
+
|
|
402
|
+
value = result["value"]
|
|
403
|
+
|
|
404
|
+
if value is None:
|
|
405
|
+
return MeasurementWithUncertainty(value=float(np.nan), uncertainty=float(np.nan), unit="V")
|
|
406
|
+
|
|
407
|
+
if not include_uncertainty:
|
|
353
408
|
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="V")
|
|
354
409
|
|
|
355
410
|
uncertainties = []
|
|
@@ -357,21 +412,22 @@ def rms(
|
|
|
357
412
|
# Vertical accuracy
|
|
358
413
|
vertical_accuracy_pct = 2.0
|
|
359
414
|
offset_error = 0.001 # 1 mV
|
|
415
|
+
value_float = float(value) # Already checked for None
|
|
360
416
|
u_vertical = UncertaintyEstimator.vertical_uncertainty(
|
|
361
|
-
|
|
417
|
+
value_float, vertical_accuracy_pct, offset_error
|
|
362
418
|
)
|
|
363
419
|
uncertainties.append(u_vertical)
|
|
364
420
|
|
|
365
421
|
# Statistical uncertainty (Type A)
|
|
366
422
|
# RMS of N samples: u(RMS) ≈ RMS / sqrt(2N) for Gaussian noise
|
|
367
423
|
n = len(trace.data)
|
|
368
|
-
u_statistical =
|
|
424
|
+
u_statistical = value_float / np.sqrt(2 * n) if n > 0 else 0.0
|
|
369
425
|
uncertainties.append(u_statistical)
|
|
370
426
|
|
|
371
427
|
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
372
428
|
|
|
373
429
|
return MeasurementWithUncertainty(
|
|
374
|
-
value=
|
|
430
|
+
value=value_float,
|
|
375
431
|
uncertainty=total_uncertainty,
|
|
376
432
|
unit="V",
|
|
377
433
|
n_samples=len(trace.data),
|