oscura 0.0.1__py3-none-any.whl → 0.1.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 +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.0.dist-info/METADATA +300 -0
- oscura-0.1.0.dist-info/RECORD +463 -0
- oscura-0.1.0.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Waveform measurements with uncertainty propagation.
|
|
2
|
+
|
|
3
|
+
This module extends the standard measurements module with uncertainty
|
|
4
|
+
estimation following GUM (Guide to the Expression of Uncertainty in Measurement)
|
|
5
|
+
principles.
|
|
6
|
+
|
|
7
|
+
All measurements return MeasurementResult objects that include both the
|
|
8
|
+
value and its associated uncertainty.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> from oscura.analyzers.waveform import measurements_with_uncertainty as meas_u
|
|
12
|
+
>>> result = meas_u.rise_time(trace)
|
|
13
|
+
>>> print(f"Rise time: {result.value*1e9:.2f} ± {result.uncertainty*1e9:.2f} ns")
|
|
14
|
+
Rise time: 2.34 ± 0.12 ns
|
|
15
|
+
|
|
16
|
+
References:
|
|
17
|
+
JCGM 100:2008 - Guide to the Expression of Uncertainty in Measurement (GUM)
|
|
18
|
+
IEEE 181-2011 - Standard for Transitional Waveform Definitions (Annex B: Uncertainty)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from typing import TYPE_CHECKING
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
|
|
27
|
+
from oscura.analyzers.waveform import measurements as meas
|
|
28
|
+
from oscura.core.uncertainty import MeasurementWithUncertainty, UncertaintyEstimator
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from oscura.core.types import WaveformTrace
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def rise_time(
|
|
35
|
+
trace: WaveformTrace,
|
|
36
|
+
*,
|
|
37
|
+
ref_levels: tuple[float, float] = (0.1, 0.9),
|
|
38
|
+
include_uncertainty: bool = True,
|
|
39
|
+
) -> MeasurementWithUncertainty:
|
|
40
|
+
"""Measure rise time with uncertainty estimation.
|
|
41
|
+
|
|
42
|
+
Uncertainty sources:
|
|
43
|
+
- Time base accuracy (from calibration info if available)
|
|
44
|
+
- Sample interpolation error (sub-sample timing)
|
|
45
|
+
- Noise-induced edge jitter (from signal SNR)
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
trace: Input waveform trace.
|
|
49
|
+
ref_levels: Reference levels as fractions (0.0 to 1.0).
|
|
50
|
+
include_uncertainty: If False, only return value estimate (faster).
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
MeasurementResult with value and uncertainty.
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
>>> result = rise_time(trace)
|
|
57
|
+
>>> print(f"t_rise = {result.value*1e9:.2f} ± {result.uncertainty*1e9:.2f} ns")
|
|
58
|
+
|
|
59
|
+
References:
|
|
60
|
+
IEEE 181-2011 Section 5.2 (rise time)
|
|
61
|
+
IEEE 181-2011 Annex B (measurement uncertainty)
|
|
62
|
+
"""
|
|
63
|
+
# Get the measurement value
|
|
64
|
+
value = meas.rise_time(trace, ref_levels=ref_levels)
|
|
65
|
+
|
|
66
|
+
if not include_uncertainty or np.isnan(value):
|
|
67
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="s")
|
|
68
|
+
|
|
69
|
+
# Estimate uncertainty components
|
|
70
|
+
uncertainties = []
|
|
71
|
+
|
|
72
|
+
# 1. Time base uncertainty (Type B)
|
|
73
|
+
if trace.metadata.calibration_info is not None:
|
|
74
|
+
# Use calibration info if available
|
|
75
|
+
# Typical scope: 25-50 ppm timebase accuracy
|
|
76
|
+
timebase_ppm = 25.0 # Conservative estimate
|
|
77
|
+
u_timebase = UncertaintyEstimator.time_base_uncertainty(
|
|
78
|
+
trace.metadata.sample_rate, timebase_ppm
|
|
79
|
+
)
|
|
80
|
+
# Rise time involves 2 samples (start and stop), so uncertainty scales
|
|
81
|
+
u_timebase_rise = u_timebase * np.sqrt(2)
|
|
82
|
+
uncertainties.append(u_timebase_rise)
|
|
83
|
+
else:
|
|
84
|
+
# No calibration info - use conservative estimate
|
|
85
|
+
u_timebase_rise = (1.0 / trace.metadata.sample_rate) * 50e-6 # 50 ppm
|
|
86
|
+
uncertainties.append(u_timebase_rise)
|
|
87
|
+
|
|
88
|
+
# 2. Interpolation uncertainty (Type B - rectangular distribution)
|
|
89
|
+
# Linear interpolation error: typically ±0.5 samples worst case
|
|
90
|
+
sample_period = trace.metadata.time_base
|
|
91
|
+
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
92
|
+
uncertainties.append(u_interp)
|
|
93
|
+
|
|
94
|
+
# 3. Noise-induced uncertainty (Type A equivalent)
|
|
95
|
+
# Estimate from local signal noise
|
|
96
|
+
# Find the data region near the edge
|
|
97
|
+
data_slice = trace.data # Could refine to edge region
|
|
98
|
+
if len(data_slice) > 10:
|
|
99
|
+
noise_estimate = np.std(data_slice[:10]) if len(data_slice) >= 10 else 0.0
|
|
100
|
+
# Noise-to-slew-rate ratio gives time uncertainty
|
|
101
|
+
amplitude = np.ptp(trace.data)
|
|
102
|
+
if amplitude > 0:
|
|
103
|
+
# Approximate slew rate: amplitude / rise_time
|
|
104
|
+
slew_rate = amplitude / value if value > 0 else np.inf
|
|
105
|
+
u_noise = noise_estimate / slew_rate if slew_rate != np.inf else 0.0
|
|
106
|
+
uncertainties.append(u_noise)
|
|
107
|
+
|
|
108
|
+
# Combine all uncertainty sources (uncorrelated)
|
|
109
|
+
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
110
|
+
|
|
111
|
+
return MeasurementWithUncertainty(
|
|
112
|
+
value=float(value),
|
|
113
|
+
uncertainty=total_uncertainty,
|
|
114
|
+
unit="s",
|
|
115
|
+
n_samples=len(trace.data),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def fall_time(
|
|
120
|
+
trace: WaveformTrace,
|
|
121
|
+
*,
|
|
122
|
+
ref_levels: tuple[float, float] = (0.9, 0.1),
|
|
123
|
+
include_uncertainty: bool = True,
|
|
124
|
+
) -> MeasurementWithUncertainty:
|
|
125
|
+
"""Measure fall time with uncertainty estimation.
|
|
126
|
+
|
|
127
|
+
Similar uncertainty sources as rise_time().
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
trace: Input waveform trace.
|
|
131
|
+
ref_levels: Reference levels as fractions (0.0 to 1.0).
|
|
132
|
+
include_uncertainty: If False, only return value estimate (faster).
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
MeasurementResult with value and uncertainty.
|
|
136
|
+
|
|
137
|
+
References:
|
|
138
|
+
IEEE 181-2011 Section 5.2
|
|
139
|
+
"""
|
|
140
|
+
value = meas.fall_time(trace, ref_levels=ref_levels)
|
|
141
|
+
|
|
142
|
+
if not include_uncertainty or np.isnan(value):
|
|
143
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="s")
|
|
144
|
+
|
|
145
|
+
# Similar uncertainty calculation as rise_time
|
|
146
|
+
uncertainties = []
|
|
147
|
+
|
|
148
|
+
# Time base uncertainty
|
|
149
|
+
timebase_ppm = 25.0
|
|
150
|
+
u_timebase = UncertaintyEstimator.time_base_uncertainty(
|
|
151
|
+
trace.metadata.sample_rate, timebase_ppm
|
|
152
|
+
)
|
|
153
|
+
uncertainties.append(u_timebase * np.sqrt(2))
|
|
154
|
+
|
|
155
|
+
# Interpolation uncertainty
|
|
156
|
+
sample_period = trace.metadata.time_base
|
|
157
|
+
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
158
|
+
uncertainties.append(u_interp)
|
|
159
|
+
|
|
160
|
+
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
161
|
+
|
|
162
|
+
return MeasurementWithUncertainty(
|
|
163
|
+
value=float(value),
|
|
164
|
+
uncertainty=total_uncertainty,
|
|
165
|
+
unit="s",
|
|
166
|
+
n_samples=len(trace.data),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def frequency(
|
|
171
|
+
trace: WaveformTrace, *, include_uncertainty: bool = True
|
|
172
|
+
) -> MeasurementWithUncertainty:
|
|
173
|
+
"""Measure frequency with uncertainty estimation.
|
|
174
|
+
|
|
175
|
+
Uncertainty sources:
|
|
176
|
+
- Time base accuracy
|
|
177
|
+
- Period measurement uncertainty
|
|
178
|
+
- Allan variance (short-term stability)
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
trace: Input waveform trace.
|
|
182
|
+
include_uncertainty: If False, only return value estimate (faster).
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
MeasurementResult with value and uncertainty in Hz.
|
|
186
|
+
|
|
187
|
+
Example:
|
|
188
|
+
>>> result = frequency(trace)
|
|
189
|
+
>>> print(f"f = {result.value/1e6:.6f} ± {result.relative_uncertainty*100:.2f}% MHz")
|
|
190
|
+
|
|
191
|
+
References:
|
|
192
|
+
IEEE 181-2011 Section 5.3
|
|
193
|
+
IEEE 1057-2017 Section 4.3
|
|
194
|
+
"""
|
|
195
|
+
value = meas.frequency(trace)
|
|
196
|
+
|
|
197
|
+
if not include_uncertainty or np.isnan(value):
|
|
198
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="Hz")
|
|
199
|
+
|
|
200
|
+
# Frequency is 1/period, so uncertainty propagation:
|
|
201
|
+
# u(f) = f^2 * u(T) where T is period
|
|
202
|
+
period = 1.0 / value if value != 0 else np.nan
|
|
203
|
+
|
|
204
|
+
if np.isnan(period):
|
|
205
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="Hz")
|
|
206
|
+
|
|
207
|
+
# Estimate period uncertainty
|
|
208
|
+
uncertainties = []
|
|
209
|
+
|
|
210
|
+
# Time base uncertainty
|
|
211
|
+
timebase_ppm = 25.0
|
|
212
|
+
# Period measurement spans multiple cycles, typically more accurate
|
|
213
|
+
u_period_timebase = period * (timebase_ppm * 1e-6)
|
|
214
|
+
uncertainties.append(u_period_timebase)
|
|
215
|
+
|
|
216
|
+
# Interpolation uncertainty for edge detection
|
|
217
|
+
sample_period = trace.metadata.time_base
|
|
218
|
+
u_interp = UncertaintyEstimator.type_b_rectangular(0.5 * sample_period)
|
|
219
|
+
# Two edges per period
|
|
220
|
+
u_period_interp = u_interp * np.sqrt(2)
|
|
221
|
+
uncertainties.append(u_period_interp)
|
|
222
|
+
|
|
223
|
+
# Combine to get period uncertainty
|
|
224
|
+
u_period = UncertaintyEstimator.combined_uncertainty([float(u) for u in uncertainties])
|
|
225
|
+
|
|
226
|
+
# Propagate to frequency: u(f) = |df/dT| * u(T) = f^2 * u(T)
|
|
227
|
+
u_frequency = float((value**2) * u_period)
|
|
228
|
+
|
|
229
|
+
return MeasurementWithUncertainty(
|
|
230
|
+
value=float(value), uncertainty=u_frequency, unit="Hz", n_samples=len(trace.data)
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def amplitude(
|
|
235
|
+
trace: WaveformTrace, *, include_uncertainty: bool = True
|
|
236
|
+
) -> MeasurementWithUncertainty:
|
|
237
|
+
"""Measure amplitude (Vpp) with uncertainty estimation.
|
|
238
|
+
|
|
239
|
+
Uncertainty sources:
|
|
240
|
+
- Vertical gain accuracy (from calibration info)
|
|
241
|
+
- Vertical offset error
|
|
242
|
+
- Quantization noise (ADC resolution)
|
|
243
|
+
- Signal noise (statistical)
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
trace: Input waveform trace.
|
|
247
|
+
include_uncertainty: If False, only return value estimate (faster).
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
MeasurementResult with value and uncertainty in volts.
|
|
251
|
+
|
|
252
|
+
References:
|
|
253
|
+
IEEE 1057-2017 Section 4.2 (amplitude measurement)
|
|
254
|
+
IEEE 1057-2017 Section 4.4 (amplitude accuracy)
|
|
255
|
+
"""
|
|
256
|
+
value = meas.amplitude(trace)
|
|
257
|
+
|
|
258
|
+
if not include_uncertainty or np.isnan(value):
|
|
259
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="V")
|
|
260
|
+
|
|
261
|
+
uncertainties = []
|
|
262
|
+
|
|
263
|
+
# 1. Vertical accuracy (Type B)
|
|
264
|
+
# Typical scope: ±2% of reading ± 0.1% of full scale
|
|
265
|
+
vertical_accuracy_pct = 2.0 # Conservative
|
|
266
|
+
if trace.metadata.vertical_scale is not None:
|
|
267
|
+
full_scale = trace.metadata.vertical_scale * 10 # 10 divisions typical
|
|
268
|
+
offset_error = full_scale * 0.001 # 0.1%
|
|
269
|
+
else:
|
|
270
|
+
offset_error = 0.001 # 1 mV default
|
|
271
|
+
|
|
272
|
+
u_vertical = UncertaintyEstimator.vertical_uncertainty(
|
|
273
|
+
float(value), vertical_accuracy_pct, offset_error
|
|
274
|
+
)
|
|
275
|
+
uncertainties.append(u_vertical)
|
|
276
|
+
|
|
277
|
+
# 2. Quantization uncertainty (Type B - rectangular)
|
|
278
|
+
if (
|
|
279
|
+
trace.metadata.calibration_info is not None
|
|
280
|
+
and trace.metadata.calibration_info.vertical_resolution is not None
|
|
281
|
+
):
|
|
282
|
+
bits = trace.metadata.calibration_info.vertical_resolution
|
|
283
|
+
vertical_range = np.ptp(trace.data) # Simplification
|
|
284
|
+
lsb = vertical_range / (2**bits)
|
|
285
|
+
u_quant = UncertaintyEstimator.type_b_rectangular(0.5 * lsb)
|
|
286
|
+
uncertainties.append(u_quant)
|
|
287
|
+
else:
|
|
288
|
+
# Default: 8-bit ADC assumption
|
|
289
|
+
vertical_range = np.ptp(trace.data)
|
|
290
|
+
lsb = vertical_range / 256
|
|
291
|
+
u_quant = UncertaintyEstimator.type_b_rectangular(0.5 * lsb)
|
|
292
|
+
uncertainties.append(u_quant)
|
|
293
|
+
|
|
294
|
+
# 3. Signal noise (Type A)
|
|
295
|
+
# Estimate from flat regions (if available)
|
|
296
|
+
# Simplified: use standard deviation as proxy
|
|
297
|
+
if len(trace.data) > 100:
|
|
298
|
+
# Sample first and last 50 points (assume flat regions)
|
|
299
|
+
noise_start = np.std(trace.data[:50])
|
|
300
|
+
noise_end = np.std(trace.data[-50:])
|
|
301
|
+
u_noise = np.mean([noise_start, noise_end])
|
|
302
|
+
# Amplitude involves max and min, so sqrt(2) factor
|
|
303
|
+
uncertainties.append(u_noise * np.sqrt(2))
|
|
304
|
+
|
|
305
|
+
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
306
|
+
|
|
307
|
+
return MeasurementWithUncertainty(
|
|
308
|
+
value=float(value),
|
|
309
|
+
uncertainty=total_uncertainty,
|
|
310
|
+
unit="V",
|
|
311
|
+
n_samples=len(trace.data),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def rms(
|
|
316
|
+
trace: WaveformTrace,
|
|
317
|
+
*,
|
|
318
|
+
ac_coupled: bool = False,
|
|
319
|
+
include_uncertainty: bool = True,
|
|
320
|
+
) -> MeasurementWithUncertainty:
|
|
321
|
+
"""Measure RMS voltage with uncertainty estimation.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
trace: Input waveform trace.
|
|
325
|
+
ac_coupled: If True, remove DC component before calculating RMS.
|
|
326
|
+
include_uncertainty: If False, only return value estimate (faster).
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
MeasurementResult with value and uncertainty in volts RMS.
|
|
330
|
+
|
|
331
|
+
References:
|
|
332
|
+
IEEE 1057-2017 Section 4.3
|
|
333
|
+
"""
|
|
334
|
+
value = meas.rms(trace, ac_coupled=ac_coupled)
|
|
335
|
+
|
|
336
|
+
if not include_uncertainty or np.isnan(value):
|
|
337
|
+
return MeasurementWithUncertainty(value=float(value), uncertainty=float(np.nan), unit="V")
|
|
338
|
+
|
|
339
|
+
uncertainties = []
|
|
340
|
+
|
|
341
|
+
# Vertical accuracy
|
|
342
|
+
vertical_accuracy_pct = 2.0
|
|
343
|
+
offset_error = 0.001 # 1 mV
|
|
344
|
+
u_vertical = UncertaintyEstimator.vertical_uncertainty(
|
|
345
|
+
float(value), vertical_accuracy_pct, offset_error
|
|
346
|
+
)
|
|
347
|
+
uncertainties.append(u_vertical)
|
|
348
|
+
|
|
349
|
+
# Statistical uncertainty (Type A)
|
|
350
|
+
# RMS of N samples: u(RMS) ≈ RMS / sqrt(2N) for Gaussian noise
|
|
351
|
+
n = len(trace.data)
|
|
352
|
+
u_statistical = value / np.sqrt(2 * n) if n > 0 else 0.0
|
|
353
|
+
uncertainties.append(u_statistical)
|
|
354
|
+
|
|
355
|
+
total_uncertainty = UncertaintyEstimator.combined_uncertainty(uncertainties)
|
|
356
|
+
|
|
357
|
+
return MeasurementWithUncertainty(
|
|
358
|
+
value=float(value),
|
|
359
|
+
uncertainty=total_uncertainty,
|
|
360
|
+
unit="V",
|
|
361
|
+
n_samples=len(trace.data),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
__all__ = [
|
|
366
|
+
"amplitude",
|
|
367
|
+
"fall_time",
|
|
368
|
+
"frequency",
|
|
369
|
+
"rise_time",
|
|
370
|
+
"rms",
|
|
371
|
+
]
|