oscura 0.0.1__py3-none-any.whl → 0.1.1__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.1.dist-info/METADATA +300 -0
- oscura-0.1.1.dist-info/RECORD +463 -0
- oscura-0.1.1.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.1.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.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"""Measurement uncertainty propagation and estimation.
|
|
2
|
+
|
|
3
|
+
This module provides data structures and utilities for tracking measurement
|
|
4
|
+
uncertainty through Oscura analysis operations, following GUM (Guide to the
|
|
5
|
+
Expression of Uncertainty in Measurement) principles.
|
|
6
|
+
|
|
7
|
+
References:
|
|
8
|
+
JCGM 100:2008 - Guide to the Expression of Uncertainty in Measurement (GUM)
|
|
9
|
+
ISO/IEC 17025:2017 - General Requirements for Competence of Testing and Calibration Laboratories
|
|
10
|
+
NIST Technical Note 1297 - Guidelines for Evaluating and Expressing Uncertainty
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from numpy.typing import NDArray
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class MeasurementWithUncertainty:
|
|
26
|
+
"""Measurement value with uncertainty estimate.
|
|
27
|
+
|
|
28
|
+
Stores a measurement value along with its associated uncertainty,
|
|
29
|
+
following GUM (Guide to the Expression of Uncertainty in Measurement)
|
|
30
|
+
conventions.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
value: The measured value (best estimate).
|
|
34
|
+
uncertainty: Standard uncertainty (1-sigma, coverage factor k=1).
|
|
35
|
+
unit: Unit of measurement (e.g., "V", "s", "Hz") (optional).
|
|
36
|
+
coverage_factor: Coverage factor for expanded uncertainty (default 1.0).
|
|
37
|
+
confidence_level: Confidence level for expanded uncertainty (default 68.27% for k=1).
|
|
38
|
+
n_samples: Number of samples used in measurement (optional).
|
|
39
|
+
degrees_of_freedom: Effective degrees of freedom (optional).
|
|
40
|
+
|
|
41
|
+
Properties:
|
|
42
|
+
expanded_uncertainty: Uncertainty * coverage_factor.
|
|
43
|
+
relative_uncertainty: uncertainty / |value| if value != 0.
|
|
44
|
+
lower_bound: value - expanded_uncertainty.
|
|
45
|
+
upper_bound: value + expanded_uncertainty.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
>>> result = MeasurementWithUncertainty(value=1.234, uncertainty=0.005, unit="V")
|
|
49
|
+
>>> print(f"{result.value:.3f} ± {result.uncertainty:.3f} {result.unit}")
|
|
50
|
+
1.234 ± 0.005 V
|
|
51
|
+
|
|
52
|
+
Example with expanded uncertainty (k=2, 95.45% confidence):
|
|
53
|
+
>>> result = MeasurementWithUncertainty(
|
|
54
|
+
... value=10.0e6,
|
|
55
|
+
... uncertainty=1000.0,
|
|
56
|
+
... unit="Hz",
|
|
57
|
+
... coverage_factor=2.0,
|
|
58
|
+
... confidence_level=0.9545
|
|
59
|
+
... )
|
|
60
|
+
>>> print(f"{result.value/1e6:.3f} ± {result.expanded_uncertainty/1e6:.3f} MHz (95.45%)")
|
|
61
|
+
10.000 ± 0.002 MHz (95.45%)
|
|
62
|
+
|
|
63
|
+
References:
|
|
64
|
+
JCGM 100:2008 Section 2.3.5 (standard uncertainty)
|
|
65
|
+
JCGM 100:2008 Section 2.3.6 (expanded uncertainty)
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
value: float
|
|
69
|
+
uncertainty: float
|
|
70
|
+
unit: str | None = None
|
|
71
|
+
coverage_factor: float = 1.0
|
|
72
|
+
confidence_level: float = 0.6827 # 68.27% for k=1 (Gaussian)
|
|
73
|
+
n_samples: int | None = None
|
|
74
|
+
degrees_of_freedom: float | None = None
|
|
75
|
+
|
|
76
|
+
def __post_init__(self) -> None:
|
|
77
|
+
"""Validate measurement result after initialization."""
|
|
78
|
+
if not np.isfinite(self.value):
|
|
79
|
+
# Allow NaN/Inf but issue warning
|
|
80
|
+
pass
|
|
81
|
+
if self.uncertainty < 0:
|
|
82
|
+
raise ValueError(f"uncertainty must be non-negative, got {self.uncertainty}")
|
|
83
|
+
if self.coverage_factor <= 0:
|
|
84
|
+
raise ValueError(f"coverage_factor must be positive, got {self.coverage_factor}")
|
|
85
|
+
if not 0 < self.confidence_level <= 1.0:
|
|
86
|
+
raise ValueError(f"confidence_level must be in (0, 1], got {self.confidence_level}")
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def expanded_uncertainty(self) -> float:
|
|
90
|
+
"""Expanded uncertainty (U = k * u).
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Standard uncertainty multiplied by coverage factor.
|
|
94
|
+
|
|
95
|
+
References:
|
|
96
|
+
JCGM 100:2008 Section 6.2.1
|
|
97
|
+
"""
|
|
98
|
+
return self.coverage_factor * self.uncertainty
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def relative_uncertainty(self) -> float:
|
|
102
|
+
"""Relative standard uncertainty (u_r = u / |value|).
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Relative uncertainty, or np.inf if value is zero.
|
|
106
|
+
|
|
107
|
+
References:
|
|
108
|
+
JCGM 100:2008 Section 5.1.6
|
|
109
|
+
"""
|
|
110
|
+
if self.value == 0:
|
|
111
|
+
return np.inf
|
|
112
|
+
return abs(self.uncertainty / self.value)
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def lower_bound(self) -> float:
|
|
116
|
+
"""Lower bound of uncertainty interval.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
value - expanded_uncertainty.
|
|
120
|
+
"""
|
|
121
|
+
return self.value - self.expanded_uncertainty
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def upper_bound(self) -> float:
|
|
125
|
+
"""Upper bound of uncertainty interval.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
value + expanded_uncertainty.
|
|
129
|
+
"""
|
|
130
|
+
return self.value + self.expanded_uncertainty
|
|
131
|
+
|
|
132
|
+
def __str__(self) -> str:
|
|
133
|
+
"""String representation of measurement with uncertainty."""
|
|
134
|
+
unit_str = f" {self.unit}" if self.unit else ""
|
|
135
|
+
if self.coverage_factor == 1.0:
|
|
136
|
+
return f"{self.value:.6g} ± {self.uncertainty:.6g}{unit_str}"
|
|
137
|
+
else:
|
|
138
|
+
return (
|
|
139
|
+
f"{self.value:.6g} ± {self.expanded_uncertainty:.6g}{unit_str} "
|
|
140
|
+
f"(k={self.coverage_factor:.2f}, {self.confidence_level * 100:.2f}%)"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def __repr__(self) -> str:
|
|
144
|
+
"""Detailed representation."""
|
|
145
|
+
return (
|
|
146
|
+
f"MeasurementWithUncertainty(value={self.value:.6g}, "
|
|
147
|
+
f"uncertainty={self.uncertainty:.6g}, "
|
|
148
|
+
f"unit={self.unit!r})"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class UncertaintyEstimator:
|
|
153
|
+
"""Utilities for estimating measurement uncertainty.
|
|
154
|
+
|
|
155
|
+
Provides methods for calculating Type A (statistical) and Type B
|
|
156
|
+
(systematic) uncertainties according to GUM principles.
|
|
157
|
+
|
|
158
|
+
References:
|
|
159
|
+
JCGM 100:2008 Section 4 (Evaluating Standard Uncertainty)
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def type_a_standard_deviation(data: NDArray[np.floating[Any]]) -> float:
|
|
164
|
+
"""Type A uncertainty from sample standard deviation.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
data: Array of repeated measurements.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Standard deviation (Type A uncertainty component).
|
|
171
|
+
|
|
172
|
+
References:
|
|
173
|
+
JCGM 100:2008 Section 4.2 (Type A evaluation)
|
|
174
|
+
"""
|
|
175
|
+
if len(data) < 2:
|
|
176
|
+
return np.nan
|
|
177
|
+
return float(np.std(data, ddof=1)) # Sample std (Bessel correction)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def type_a_standard_error(data: NDArray[np.floating[Any]]) -> float:
|
|
181
|
+
"""Type A uncertainty from standard error of the mean.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
data: Array of repeated measurements.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Standard error (sigma / sqrt(n)), Type A uncertainty of the mean.
|
|
188
|
+
|
|
189
|
+
References:
|
|
190
|
+
JCGM 100:2008 Section 4.2.3
|
|
191
|
+
"""
|
|
192
|
+
if len(data) < 2:
|
|
193
|
+
return np.nan
|
|
194
|
+
return float(np.std(data, ddof=1) / np.sqrt(len(data)))
|
|
195
|
+
|
|
196
|
+
@staticmethod
|
|
197
|
+
def combined_uncertainty(
|
|
198
|
+
uncertainties: list[float], correlation_matrix: NDArray[np.float64] | None = None
|
|
199
|
+
) -> float:
|
|
200
|
+
"""Combine multiple uncertainty sources.
|
|
201
|
+
|
|
202
|
+
Combines uncorrelated or correlated uncertainty components using
|
|
203
|
+
the law of propagation of uncertainty.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
uncertainties: List of standard uncertainties to combine.
|
|
207
|
+
correlation_matrix: Correlation matrix for correlated inputs (optional).
|
|
208
|
+
If None, assumes all inputs are uncorrelated.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Combined standard uncertainty.
|
|
212
|
+
|
|
213
|
+
Example (uncorrelated):
|
|
214
|
+
>>> u1, u2, u3 = 0.01, 0.02, 0.005
|
|
215
|
+
>>> u_combined = UncertaintyEstimator.combined_uncertainty([u1, u2, u3])
|
|
216
|
+
>>> print(f"Combined: {u_combined:.4f}")
|
|
217
|
+
Combined: 0.0233
|
|
218
|
+
|
|
219
|
+
Example (correlated):
|
|
220
|
+
>>> import numpy as np
|
|
221
|
+
>>> u = [0.01, 0.02]
|
|
222
|
+
>>> R = np.array([[1.0, 0.5], [0.5, 1.0]]) # 50% correlation
|
|
223
|
+
>>> u_combined = UncertaintyEstimator.combined_uncertainty(u, R)
|
|
224
|
+
|
|
225
|
+
References:
|
|
226
|
+
JCGM 100:2008 Section 5.1.2 (uncorrelated)
|
|
227
|
+
JCGM 100:2008 Section 5.2.2 (correlated)
|
|
228
|
+
"""
|
|
229
|
+
u_array = np.array(uncertainties, dtype=np.float64)
|
|
230
|
+
|
|
231
|
+
if correlation_matrix is None:
|
|
232
|
+
# Uncorrelated: u_c² = Σ u_i²
|
|
233
|
+
return float(np.sqrt(np.sum(u_array**2)))
|
|
234
|
+
else:
|
|
235
|
+
# Correlated: u_c² = u^T R u
|
|
236
|
+
u_combined_sq = u_array @ correlation_matrix @ u_array
|
|
237
|
+
return float(np.sqrt(u_combined_sq))
|
|
238
|
+
|
|
239
|
+
@staticmethod
|
|
240
|
+
def type_b_rectangular(half_width: float) -> float:
|
|
241
|
+
"""Type B uncertainty from rectangular (uniform) distribution.
|
|
242
|
+
|
|
243
|
+
Used when only min/max bounds are known with equal probability.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
half_width: Half-width of the interval (a).
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Standard uncertainty u = a / √3.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
>>> # Scope resolution ±0.5 LSB
|
|
253
|
+
>>> lsb = 1.0e-3 # 1 mV per bit
|
|
254
|
+
>>> u = UncertaintyEstimator.type_b_rectangular(0.5 * lsb)
|
|
255
|
+
>>> print(f"Quantization uncertainty: {u*1e6:.3f} µV")
|
|
256
|
+
Quantization uncertainty: 288.675 µV
|
|
257
|
+
|
|
258
|
+
References:
|
|
259
|
+
JCGM 100:2008 Section 4.3.7 (rectangular distribution)
|
|
260
|
+
"""
|
|
261
|
+
return float(half_width / np.sqrt(3))
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def type_b_triangular(half_width: float) -> float:
|
|
265
|
+
"""Type B uncertainty from triangular distribution.
|
|
266
|
+
|
|
267
|
+
Used when values near the center are more likely than extremes.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
half_width: Half-width of the interval (a).
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
Standard uncertainty u = a / √6.
|
|
274
|
+
|
|
275
|
+
References:
|
|
276
|
+
JCGM 100:2008 Section 4.3.9 (triangular distribution)
|
|
277
|
+
"""
|
|
278
|
+
return float(half_width / np.sqrt(6))
|
|
279
|
+
|
|
280
|
+
@staticmethod
|
|
281
|
+
def type_b_from_tolerance(tolerance: float, confidence: float = 0.95) -> float:
|
|
282
|
+
"""Type B uncertainty from manufacturer tolerance specification.
|
|
283
|
+
|
|
284
|
+
Assumes Gaussian distribution unless otherwise specified.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
tolerance: Tolerance limit (e.g., ±1% of reading).
|
|
288
|
+
confidence: Confidence level of the tolerance (default 95%).
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
Standard uncertainty.
|
|
292
|
+
|
|
293
|
+
Example:
|
|
294
|
+
>>> # Scope vertical accuracy: ±2% of reading, 95% confidence
|
|
295
|
+
>>> reading = 1.0 # 1V
|
|
296
|
+
>>> tolerance = 0.02 * reading # ±0.02 V
|
|
297
|
+
>>> u = UncertaintyEstimator.type_b_from_tolerance(tolerance, 0.95)
|
|
298
|
+
>>> print(f"Uncertainty: {u:.4f} V")
|
|
299
|
+
Uncertainty: 0.0102 V
|
|
300
|
+
|
|
301
|
+
References:
|
|
302
|
+
JCGM 100:2008 Section 4.3.4
|
|
303
|
+
"""
|
|
304
|
+
# For Gaussian, 95% confidence → k ≈ 1.96
|
|
305
|
+
# For 99% confidence → k ≈ 2.58
|
|
306
|
+
if confidence == 0.95:
|
|
307
|
+
k = 1.96
|
|
308
|
+
elif confidence == 0.99:
|
|
309
|
+
k = 2.58
|
|
310
|
+
elif confidence == 0.6827:
|
|
311
|
+
k = 1.0
|
|
312
|
+
else:
|
|
313
|
+
# General case: approximate using normal distribution
|
|
314
|
+
from scipy import stats
|
|
315
|
+
|
|
316
|
+
k = stats.norm.ppf((1 + confidence) / 2)
|
|
317
|
+
|
|
318
|
+
return float(tolerance / k)
|
|
319
|
+
|
|
320
|
+
@staticmethod
|
|
321
|
+
def time_base_uncertainty(sample_rate: float, timebase_accuracy_ppm: float = 50.0) -> float:
|
|
322
|
+
"""Calculate time base uncertainty from oscilloscope specification.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
sample_rate: Sample rate in Hz.
|
|
326
|
+
timebase_accuracy_ppm: Timebase accuracy in parts per million (typical: 10-50 ppm).
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
Standard uncertainty in time per sample (seconds).
|
|
330
|
+
|
|
331
|
+
Example:
|
|
332
|
+
>>> # 1 GSa/s scope, 25 ppm timebase (typical for OCXO)
|
|
333
|
+
>>> u_t = UncertaintyEstimator.time_base_uncertainty(1e9, 25.0)
|
|
334
|
+
>>> print(f"Timebase uncertainty: {u_t*1e12:.2f} ps per sample")
|
|
335
|
+
Timebase uncertainty: 25.00 ps per sample
|
|
336
|
+
|
|
337
|
+
References:
|
|
338
|
+
IEEE 181-2011 Annex B (Measurement Uncertainty)
|
|
339
|
+
"""
|
|
340
|
+
time_per_sample = 1.0 / sample_rate
|
|
341
|
+
# ppm = parts per million = 1e-6
|
|
342
|
+
relative_uncertainty = timebase_accuracy_ppm * 1e-6
|
|
343
|
+
return time_per_sample * relative_uncertainty
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def vertical_uncertainty(
|
|
347
|
+
reading: float,
|
|
348
|
+
vertical_accuracy_percent: float = 2.0,
|
|
349
|
+
offset_error_volts: float = 0.0,
|
|
350
|
+
) -> float:
|
|
351
|
+
"""Calculate vertical (voltage) uncertainty from oscilloscope specification.
|
|
352
|
+
|
|
353
|
+
Typical scope spec: ±(2% of reading + 0.1% of full scale + 1 mV)
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
reading: Measured voltage value.
|
|
357
|
+
vertical_accuracy_percent: Gain accuracy in percent (e.g., 2.0 for ±2%).
|
|
358
|
+
offset_error_volts: Fixed offset error in volts.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
Standard uncertainty in volts.
|
|
362
|
+
|
|
363
|
+
Example:
|
|
364
|
+
>>> # Tektronix TDS3000 series: ±3% of reading
|
|
365
|
+
>>> reading = 1.5 # 1.5 V
|
|
366
|
+
>>> u_v = UncertaintyEstimator.vertical_uncertainty(reading, 3.0, 0.001)
|
|
367
|
+
>>> print(f"Voltage uncertainty: {u_v*1000:.2f} mV")
|
|
368
|
+
Voltage uncertainty: 45.01 mV
|
|
369
|
+
|
|
370
|
+
References:
|
|
371
|
+
IEEE 1057-2017 Section 4.4 (Amplitude Accuracy)
|
|
372
|
+
"""
|
|
373
|
+
# Gain error
|
|
374
|
+
u_gain = abs(reading) * (vertical_accuracy_percent / 100.0)
|
|
375
|
+
|
|
376
|
+
# Offset error
|
|
377
|
+
u_offset = offset_error_volts
|
|
378
|
+
|
|
379
|
+
# Combine (assume uncorrelated)
|
|
380
|
+
return float(np.sqrt(u_gain**2 + u_offset**2))
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
__all__ = ["MeasurementWithUncertainty", "UncertaintyEstimator"]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Auto-discovery and signal characterization.
|
|
2
|
+
|
|
3
|
+
This module provides intelligent auto-discovery features for non-expert
|
|
4
|
+
users, including signal characterization, anomaly detection, quality
|
|
5
|
+
assessment, and automatic protocol decoding.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> import oscura as osc
|
|
10
|
+
>>> trace = osc.load("capture.wfm")
|
|
11
|
+
>>> result = osc.discovery.characterize_signal(trace)
|
|
12
|
+
>>> print(f"Signal type: {result.signal_type} (confidence: {result.confidence:.2f})")
|
|
13
|
+
|
|
14
|
+
References:
|
|
15
|
+
Oscura Auto-Discovery Requirements
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from oscura.discovery.anomaly_detector import (
|
|
19
|
+
Anomaly,
|
|
20
|
+
find_anomalies,
|
|
21
|
+
)
|
|
22
|
+
from oscura.discovery.auto_decoder import (
|
|
23
|
+
DecodeResult,
|
|
24
|
+
decode_protocol,
|
|
25
|
+
)
|
|
26
|
+
from oscura.discovery.comparison import (
|
|
27
|
+
Difference,
|
|
28
|
+
TraceDiff,
|
|
29
|
+
compare_traces,
|
|
30
|
+
)
|
|
31
|
+
from oscura.discovery.quality_validator import (
|
|
32
|
+
DataQuality,
|
|
33
|
+
assess_data_quality,
|
|
34
|
+
)
|
|
35
|
+
from oscura.discovery.signal_detector import (
|
|
36
|
+
SignalCharacterization,
|
|
37
|
+
characterize_signal,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"Anomaly",
|
|
42
|
+
"DataQuality",
|
|
43
|
+
"DecodeResult",
|
|
44
|
+
"Difference",
|
|
45
|
+
"SignalCharacterization",
|
|
46
|
+
"TraceDiff",
|
|
47
|
+
"assess_data_quality",
|
|
48
|
+
"characterize_signal",
|
|
49
|
+
"compare_traces",
|
|
50
|
+
"decode_protocol",
|
|
51
|
+
"find_anomalies",
|
|
52
|
+
]
|