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,481 @@
|
|
|
1
|
+
"""Visualization utilities for trace comparison.
|
|
2
|
+
|
|
3
|
+
This module provides visualization functions for comparing traces including
|
|
4
|
+
overlay plots, difference plots, and comparison heat maps.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.comparison.visualization import (
|
|
9
|
+
... plot_overlay,
|
|
10
|
+
... plot_difference,
|
|
11
|
+
... plot_comparison_heatmap
|
|
12
|
+
... )
|
|
13
|
+
>>> fig = plot_overlay(trace1, trace2)
|
|
14
|
+
>>> fig = plot_difference(trace1, trace2)
|
|
15
|
+
|
|
16
|
+
References:
|
|
17
|
+
- Tufte, E. R. (2001). The Visual Display of Quantitative Information
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import TYPE_CHECKING, Any
|
|
23
|
+
|
|
24
|
+
import matplotlib.pyplot as plt
|
|
25
|
+
import numpy as np
|
|
26
|
+
from matplotlib.gridspec import GridSpec
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from matplotlib.figure import Figure
|
|
30
|
+
|
|
31
|
+
from oscura.comparison.compare import ComparisonResult
|
|
32
|
+
from oscura.core.types import WaveformTrace
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def plot_overlay(
|
|
36
|
+
trace1: WaveformTrace,
|
|
37
|
+
trace2: WaveformTrace,
|
|
38
|
+
*,
|
|
39
|
+
labels: tuple[str, str] = ("Trace 1", "Trace 2"),
|
|
40
|
+
title: str = "Trace Comparison - Overlay",
|
|
41
|
+
highlight_differences: bool = True,
|
|
42
|
+
difference_threshold: float | None = None,
|
|
43
|
+
figsize: tuple[float, float] = (10, 6),
|
|
44
|
+
**kwargs: Any,
|
|
45
|
+
) -> Figure:
|
|
46
|
+
"""Create overlay plot showing both traces.
|
|
47
|
+
|
|
48
|
+
: Overlay plot with difference highlighting.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
trace1: First trace
|
|
52
|
+
trace2: Second trace
|
|
53
|
+
labels: Labels for the two traces
|
|
54
|
+
title: Plot title
|
|
55
|
+
highlight_differences: Highlight regions where traces differ
|
|
56
|
+
difference_threshold: Threshold for highlighting (default: auto)
|
|
57
|
+
figsize: Figure size (width, height)
|
|
58
|
+
**kwargs: Additional arguments passed to plot()
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Matplotlib Figure object
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
>>> from oscura.comparison.visualization import plot_overlay
|
|
65
|
+
>>> fig = plot_overlay(measured, reference,
|
|
66
|
+
... labels=("Measured", "Reference"))
|
|
67
|
+
>>> plt.show()
|
|
68
|
+
|
|
69
|
+
References:
|
|
70
|
+
CMP-003: Overlay plot with difference highlighting
|
|
71
|
+
"""
|
|
72
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
73
|
+
|
|
74
|
+
# Get data
|
|
75
|
+
data1 = trace1.data.astype(np.float64)
|
|
76
|
+
data2 = trace2.data.astype(np.float64)
|
|
77
|
+
|
|
78
|
+
# Align lengths
|
|
79
|
+
min_len = min(len(data1), len(data2))
|
|
80
|
+
data1 = data1[:min_len]
|
|
81
|
+
data2 = data2[:min_len]
|
|
82
|
+
|
|
83
|
+
# Create time axis
|
|
84
|
+
if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
|
|
85
|
+
sample_rate = trace1.metadata.sample_rate
|
|
86
|
+
time = np.arange(min_len) / sample_rate
|
|
87
|
+
xlabel = "Time (s)"
|
|
88
|
+
else:
|
|
89
|
+
time = np.arange(min_len, dtype=np.float64)
|
|
90
|
+
xlabel = "Sample"
|
|
91
|
+
|
|
92
|
+
# Plot traces
|
|
93
|
+
ax.plot(time, data1, label=labels[0], alpha=0.7, linewidth=1.5, **kwargs)
|
|
94
|
+
ax.plot(time, data2, label=labels[1], alpha=0.7, linewidth=1.5, **kwargs)
|
|
95
|
+
|
|
96
|
+
# Highlight differences
|
|
97
|
+
if highlight_differences:
|
|
98
|
+
diff = np.abs(data1 - data2)
|
|
99
|
+
if difference_threshold is None:
|
|
100
|
+
# Auto threshold: mean + 2*std of difference
|
|
101
|
+
difference_threshold = float(np.mean(diff) + 2 * np.std(diff))
|
|
102
|
+
|
|
103
|
+
# Find regions with significant difference
|
|
104
|
+
diff_mask = diff > difference_threshold
|
|
105
|
+
if np.any(diff_mask):
|
|
106
|
+
# Highlight regions with vertical spans
|
|
107
|
+
in_region = False
|
|
108
|
+
start_idx = 0
|
|
109
|
+
for i in range(len(diff_mask)):
|
|
110
|
+
if diff_mask[i] and not in_region:
|
|
111
|
+
start_idx = i
|
|
112
|
+
in_region = True
|
|
113
|
+
elif not diff_mask[i] and in_region:
|
|
114
|
+
ax.axvspan(
|
|
115
|
+
time[start_idx],
|
|
116
|
+
time[i - 1],
|
|
117
|
+
alpha=0.2,
|
|
118
|
+
color="red",
|
|
119
|
+
label="Difference" if start_idx == 0 else "",
|
|
120
|
+
)
|
|
121
|
+
in_region = False
|
|
122
|
+
# Handle last region
|
|
123
|
+
if in_region:
|
|
124
|
+
ax.axvspan(time[start_idx], time[-1], alpha=0.2, color="red")
|
|
125
|
+
|
|
126
|
+
ax.set_xlabel(xlabel)
|
|
127
|
+
ax.set_ylabel("Amplitude")
|
|
128
|
+
ax.set_title(title)
|
|
129
|
+
ax.legend()
|
|
130
|
+
ax.grid(True, alpha=0.3)
|
|
131
|
+
plt.tight_layout()
|
|
132
|
+
|
|
133
|
+
return fig
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def plot_difference(
|
|
137
|
+
trace1: WaveformTrace,
|
|
138
|
+
trace2: WaveformTrace,
|
|
139
|
+
*,
|
|
140
|
+
title: str = "Trace Comparison - Difference",
|
|
141
|
+
normalize: bool = False,
|
|
142
|
+
show_statistics: bool = True,
|
|
143
|
+
figsize: tuple[float, float] = (10, 6),
|
|
144
|
+
**kwargs: Any,
|
|
145
|
+
) -> Figure:
|
|
146
|
+
"""Create difference plot (trace1 - trace2).
|
|
147
|
+
|
|
148
|
+
: Difference trace visualization.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
trace1: First trace
|
|
152
|
+
trace2: Second trace
|
|
153
|
+
title: Plot title
|
|
154
|
+
normalize: Normalize difference to percentage
|
|
155
|
+
show_statistics: Show statistics text box
|
|
156
|
+
figsize: Figure size
|
|
157
|
+
**kwargs: Additional arguments passed to plot()
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Matplotlib Figure object
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> from oscura.comparison.visualization import plot_difference
|
|
164
|
+
>>> fig = plot_difference(measured, reference, normalize=True)
|
|
165
|
+
>>> plt.show()
|
|
166
|
+
|
|
167
|
+
References:
|
|
168
|
+
CMP-003: Comparison Visualization
|
|
169
|
+
"""
|
|
170
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
171
|
+
|
|
172
|
+
# Get data
|
|
173
|
+
data1 = trace1.data.astype(np.float64)
|
|
174
|
+
data2 = trace2.data.astype(np.float64)
|
|
175
|
+
|
|
176
|
+
# Align lengths
|
|
177
|
+
min_len = min(len(data1), len(data2))
|
|
178
|
+
data1 = data1[:min_len]
|
|
179
|
+
data2 = data2[:min_len]
|
|
180
|
+
|
|
181
|
+
# Compute difference
|
|
182
|
+
diff = data1 - data2
|
|
183
|
+
|
|
184
|
+
if normalize:
|
|
185
|
+
# Normalize to percentage of reference range
|
|
186
|
+
ref_range = np.ptp(data2)
|
|
187
|
+
if ref_range > 0:
|
|
188
|
+
diff = (diff / ref_range) * 100.0
|
|
189
|
+
ylabel = "Difference (%)"
|
|
190
|
+
else:
|
|
191
|
+
ylabel = "Difference"
|
|
192
|
+
|
|
193
|
+
# Create time axis
|
|
194
|
+
if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
|
|
195
|
+
sample_rate = trace1.metadata.sample_rate
|
|
196
|
+
time = np.arange(min_len) / sample_rate
|
|
197
|
+
xlabel = "Time (s)"
|
|
198
|
+
else:
|
|
199
|
+
time = np.arange(min_len, dtype=np.float64)
|
|
200
|
+
xlabel = "Sample"
|
|
201
|
+
|
|
202
|
+
# Plot difference
|
|
203
|
+
ax.plot(time, diff, label="Difference", **kwargs)
|
|
204
|
+
ax.axhline(y=0, color="k", linestyle="--", alpha=0.5, linewidth=1)
|
|
205
|
+
|
|
206
|
+
# Add statistics text box
|
|
207
|
+
if show_statistics:
|
|
208
|
+
max_diff = float(np.max(np.abs(diff)))
|
|
209
|
+
rms_diff = float(np.sqrt(np.mean(diff**2)))
|
|
210
|
+
mean_diff = float(np.mean(diff))
|
|
211
|
+
std_diff = float(np.std(diff))
|
|
212
|
+
|
|
213
|
+
stats_text = (
|
|
214
|
+
f"Max: {max_diff:.3f}\nRMS: {rms_diff:.3f}\nMean: {mean_diff:.3f}\nStd: {std_diff:.3f}"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
ax.text(
|
|
218
|
+
0.02,
|
|
219
|
+
0.98,
|
|
220
|
+
stats_text,
|
|
221
|
+
transform=ax.transAxes,
|
|
222
|
+
verticalalignment="top",
|
|
223
|
+
bbox={"boxstyle": "round", "facecolor": "wheat", "alpha": 0.8},
|
|
224
|
+
fontsize=9,
|
|
225
|
+
family="monospace",
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
ax.set_xlabel(xlabel)
|
|
229
|
+
ax.set_ylabel(ylabel)
|
|
230
|
+
ax.set_title(title)
|
|
231
|
+
ax.grid(True, alpha=0.3)
|
|
232
|
+
plt.tight_layout()
|
|
233
|
+
|
|
234
|
+
return fig
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def plot_comparison_heatmap(
|
|
238
|
+
trace1: WaveformTrace,
|
|
239
|
+
trace2: WaveformTrace,
|
|
240
|
+
*,
|
|
241
|
+
title: str = "Trace Comparison - Difference Heatmap",
|
|
242
|
+
window_size: int = 100,
|
|
243
|
+
figsize: tuple[float, float] = (10, 8),
|
|
244
|
+
**kwargs: Any,
|
|
245
|
+
) -> Figure:
|
|
246
|
+
"""Create difference heatmap showing where changes occur.
|
|
247
|
+
|
|
248
|
+
: Difference heat map showing where changes occur.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
trace1: First trace
|
|
252
|
+
trace2: Second trace
|
|
253
|
+
title: Plot title
|
|
254
|
+
window_size: Window size for heatmap bins
|
|
255
|
+
figsize: Figure size
|
|
256
|
+
**kwargs: Additional arguments passed to imshow()
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Matplotlib Figure object
|
|
260
|
+
|
|
261
|
+
Example:
|
|
262
|
+
>>> from oscura.comparison.visualization import plot_comparison_heatmap
|
|
263
|
+
>>> fig = plot_comparison_heatmap(trace1, trace2, window_size=50)
|
|
264
|
+
>>> plt.show()
|
|
265
|
+
|
|
266
|
+
References:
|
|
267
|
+
CMP-003: Difference heat map showing where changes occur
|
|
268
|
+
"""
|
|
269
|
+
fig = plt.figure(figsize=figsize)
|
|
270
|
+
gs = GridSpec(2, 1, height_ratios=[3, 1], hspace=0.3)
|
|
271
|
+
ax_heat = fig.add_subplot(gs[0])
|
|
272
|
+
ax_trace = fig.add_subplot(gs[1], sharex=ax_heat)
|
|
273
|
+
|
|
274
|
+
# Get data
|
|
275
|
+
data1 = trace1.data.astype(np.float64)
|
|
276
|
+
data2 = trace2.data.astype(np.float64)
|
|
277
|
+
|
|
278
|
+
# Align lengths
|
|
279
|
+
min_len = min(len(data1), len(data2))
|
|
280
|
+
data1 = data1[:min_len]
|
|
281
|
+
data2 = data2[:min_len]
|
|
282
|
+
|
|
283
|
+
# Compute difference
|
|
284
|
+
diff = np.abs(data1 - data2)
|
|
285
|
+
|
|
286
|
+
# Create windowed heatmap
|
|
287
|
+
n_windows = min_len // window_size
|
|
288
|
+
if n_windows == 0:
|
|
289
|
+
n_windows = 1
|
|
290
|
+
window_size = min_len
|
|
291
|
+
|
|
292
|
+
heatmap_data = np.zeros((10, n_windows))
|
|
293
|
+
for i in range(n_windows):
|
|
294
|
+
start = i * window_size
|
|
295
|
+
end = min(start + window_size, min_len)
|
|
296
|
+
window_diff = diff[start:end]
|
|
297
|
+
|
|
298
|
+
# Bin into 10 levels based on amplitude
|
|
299
|
+
window_data1 = data1[start:end]
|
|
300
|
+
window_data2 = data2[start:end]
|
|
301
|
+
y_min = min(np.min(window_data1), np.min(window_data2))
|
|
302
|
+
y_max = max(np.max(window_data1), np.max(window_data2))
|
|
303
|
+
|
|
304
|
+
if y_max - y_min > 0:
|
|
305
|
+
bins = np.linspace(y_min, y_max, 11)
|
|
306
|
+
for sample_idx in range(len(window_diff)):
|
|
307
|
+
y_val = window_data1[sample_idx] # window_data1 is already sliced
|
|
308
|
+
bin_idx = np.digitize(y_val, bins) - 1
|
|
309
|
+
bin_idx = max(0, min(9, bin_idx))
|
|
310
|
+
heatmap_data[bin_idx, i] += window_diff[sample_idx]
|
|
311
|
+
|
|
312
|
+
# Normalize heatmap
|
|
313
|
+
heatmap_data = heatmap_data / window_size
|
|
314
|
+
|
|
315
|
+
# Plot heatmap
|
|
316
|
+
im = ax_heat.imshow(
|
|
317
|
+
heatmap_data,
|
|
318
|
+
aspect="auto",
|
|
319
|
+
cmap="hot",
|
|
320
|
+
origin="lower",
|
|
321
|
+
interpolation="nearest",
|
|
322
|
+
**kwargs,
|
|
323
|
+
)
|
|
324
|
+
plt.colorbar(im, ax=ax_heat, label="Average Difference")
|
|
325
|
+
|
|
326
|
+
ax_heat.set_ylabel("Amplitude Bin")
|
|
327
|
+
ax_heat.set_title(title)
|
|
328
|
+
|
|
329
|
+
# Plot difference trace below
|
|
330
|
+
if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
|
|
331
|
+
sample_rate = trace1.metadata.sample_rate
|
|
332
|
+
time = np.arange(min_len) / sample_rate
|
|
333
|
+
xlabel = "Time (s)"
|
|
334
|
+
else:
|
|
335
|
+
time = np.arange(min_len, dtype=np.float64)
|
|
336
|
+
xlabel = "Sample"
|
|
337
|
+
|
|
338
|
+
ax_trace.plot(time, diff, linewidth=0.5)
|
|
339
|
+
ax_trace.set_xlabel(xlabel)
|
|
340
|
+
ax_trace.set_ylabel("Difference")
|
|
341
|
+
ax_trace.grid(True, alpha=0.3)
|
|
342
|
+
|
|
343
|
+
plt.tight_layout()
|
|
344
|
+
return fig
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def plot_comparison_summary(
|
|
348
|
+
result: ComparisonResult,
|
|
349
|
+
*,
|
|
350
|
+
title: str = "Trace Comparison Summary",
|
|
351
|
+
figsize: tuple[float, float] = (12, 8),
|
|
352
|
+
) -> Figure:
|
|
353
|
+
"""Create comprehensive comparison summary figure.
|
|
354
|
+
|
|
355
|
+
: Summary table of key differences.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
result: ComparisonResult from compare_traces()
|
|
359
|
+
title: Plot title
|
|
360
|
+
figsize: Figure size
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Matplotlib Figure object
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
>>> from oscura.comparison import compare_traces
|
|
367
|
+
>>> from oscura.comparison.visualization import plot_comparison_summary
|
|
368
|
+
>>> result = compare_traces(trace1, trace2)
|
|
369
|
+
>>> fig = plot_comparison_summary(result)
|
|
370
|
+
>>> plt.show()
|
|
371
|
+
|
|
372
|
+
References:
|
|
373
|
+
CMP-003: Summary table of key differences
|
|
374
|
+
"""
|
|
375
|
+
fig = plt.figure(figsize=figsize)
|
|
376
|
+
gs = GridSpec(3, 2, hspace=0.4, wspace=0.3)
|
|
377
|
+
|
|
378
|
+
# Statistics table
|
|
379
|
+
ax_stats = fig.add_subplot(gs[0, :])
|
|
380
|
+
ax_stats.axis("off")
|
|
381
|
+
|
|
382
|
+
stats_data = [
|
|
383
|
+
["Match Status", "PASS ✓" if result.match else "FAIL ✗"],
|
|
384
|
+
["Similarity Score", f"{result.similarity:.4f}"],
|
|
385
|
+
["Correlation", f"{result.correlation:.4f}"],
|
|
386
|
+
["Max Difference", f"{result.max_difference:.6f}"],
|
|
387
|
+
["RMS Difference", f"{result.rms_difference:.6f}"],
|
|
388
|
+
]
|
|
389
|
+
|
|
390
|
+
if result.statistics:
|
|
391
|
+
stats_data.extend(
|
|
392
|
+
[
|
|
393
|
+
["Mean Difference", f"{result.statistics['mean_difference']:.6f}"],
|
|
394
|
+
["Violations", f"{result.statistics['num_violations']}"],
|
|
395
|
+
["Violation Rate", f"{result.statistics['violation_rate'] * 100:.2f}%"],
|
|
396
|
+
]
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
table = ax_stats.table(
|
|
400
|
+
cellText=stats_data,
|
|
401
|
+
colLabels=["Metric", "Value"],
|
|
402
|
+
cellLoc="left",
|
|
403
|
+
loc="center",
|
|
404
|
+
bbox=[0, 0, 1, 1], # type: ignore[arg-type]
|
|
405
|
+
)
|
|
406
|
+
table.auto_set_font_size(False)
|
|
407
|
+
table.set_fontsize(10)
|
|
408
|
+
table.scale(1, 2)
|
|
409
|
+
|
|
410
|
+
# Color code match status
|
|
411
|
+
if result.match:
|
|
412
|
+
table[(1, 1)].set_facecolor("#90EE90") # Light green
|
|
413
|
+
else:
|
|
414
|
+
table[(1, 1)].set_facecolor("#FFB6C1") # Light red
|
|
415
|
+
|
|
416
|
+
ax_stats.set_title(title, fontsize=14, fontweight="bold", pad=20)
|
|
417
|
+
|
|
418
|
+
# Overlay plot
|
|
419
|
+
if result.difference_trace is not None:
|
|
420
|
+
# Plot difference trace
|
|
421
|
+
ax_overlay = fig.add_subplot(gs[1, :])
|
|
422
|
+
n_samples = len(result.difference_trace.data)
|
|
423
|
+
time = np.arange(n_samples)
|
|
424
|
+
ax_overlay.plot(time, result.difference_trace.data, label="Difference")
|
|
425
|
+
ax_overlay.axhline(y=0, color="k", linestyle="--", alpha=0.5)
|
|
426
|
+
ax_overlay.set_xlabel("Sample")
|
|
427
|
+
ax_overlay.set_ylabel("Difference")
|
|
428
|
+
ax_overlay.set_title("Difference Trace")
|
|
429
|
+
ax_overlay.legend()
|
|
430
|
+
ax_overlay.grid(True, alpha=0.3)
|
|
431
|
+
|
|
432
|
+
# Histogram of differences
|
|
433
|
+
if result.difference_trace is not None:
|
|
434
|
+
ax_hist = fig.add_subplot(gs[2, 0])
|
|
435
|
+
diff_data = result.difference_trace.data
|
|
436
|
+
ax_hist.hist(diff_data, bins=50, edgecolor="black", alpha=0.7)
|
|
437
|
+
ax_hist.axvline(x=0, color="r", linestyle="--", linewidth=2, label="Zero difference")
|
|
438
|
+
ax_hist.set_xlabel("Difference")
|
|
439
|
+
ax_hist.set_ylabel("Count")
|
|
440
|
+
ax_hist.set_title("Difference Distribution")
|
|
441
|
+
ax_hist.legend()
|
|
442
|
+
ax_hist.grid(True, alpha=0.3)
|
|
443
|
+
|
|
444
|
+
# Violation locations
|
|
445
|
+
ax_viol = fig.add_subplot(gs[2, 1])
|
|
446
|
+
if result.violations is not None and len(result.violations) > 0:
|
|
447
|
+
ax_viol.scatter(
|
|
448
|
+
result.violations,
|
|
449
|
+
np.ones_like(result.violations),
|
|
450
|
+
marker="|",
|
|
451
|
+
s=100,
|
|
452
|
+
color="red",
|
|
453
|
+
alpha=0.5,
|
|
454
|
+
)
|
|
455
|
+
ax_viol.set_xlim(0, len(result.difference_trace.data) if result.difference_trace else 1000)
|
|
456
|
+
ax_viol.set_ylim(0.5, 1.5)
|
|
457
|
+
ax_viol.set_xlabel("Sample Index")
|
|
458
|
+
ax_viol.set_title(f"Violation Locations ({len(result.violations)} total)")
|
|
459
|
+
ax_viol.set_yticks([])
|
|
460
|
+
else:
|
|
461
|
+
ax_viol.text(
|
|
462
|
+
0.5,
|
|
463
|
+
0.5,
|
|
464
|
+
"No Violations",
|
|
465
|
+
ha="center",
|
|
466
|
+
va="center",
|
|
467
|
+
fontsize=14,
|
|
468
|
+
color="green",
|
|
469
|
+
)
|
|
470
|
+
ax_viol.axis("off")
|
|
471
|
+
|
|
472
|
+
plt.tight_layout()
|
|
473
|
+
return fig
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
__all__ = [
|
|
477
|
+
"plot_comparison_heatmap",
|
|
478
|
+
"plot_comparison_summary",
|
|
479
|
+
"plot_difference",
|
|
480
|
+
"plot_overlay",
|
|
481
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""EMC/EMI compliance testing module.
|
|
2
|
+
|
|
3
|
+
This module provides regulatory compliance testing capabilities including
|
|
4
|
+
limit masks, compliance testing, and report generation for FCC, CE/CISPR,
|
|
5
|
+
and MIL-STD standards.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> import oscura as osc
|
|
10
|
+
>>> from oscura.compliance import load_limit_mask, check_compliance, generate_compliance_report
|
|
11
|
+
>>>
|
|
12
|
+
>>> trace = osc.load('emissions.wfm')
|
|
13
|
+
>>> mask = load_limit_mask('FCC_Part15_ClassB')
|
|
14
|
+
>>> result = check_compliance(trace, mask)
|
|
15
|
+
>>> generate_compliance_report(result, 'compliance_report.html')
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from oscura.compliance.advanced import (
|
|
19
|
+
ComplianceTestConfig,
|
|
20
|
+
ComplianceTestRunner,
|
|
21
|
+
ComplianceTestSuite,
|
|
22
|
+
InterpolationMethod,
|
|
23
|
+
LimitInterpolator,
|
|
24
|
+
QPDetectorBand,
|
|
25
|
+
QPDetectorParams,
|
|
26
|
+
QuasiPeakDetector,
|
|
27
|
+
interpolate_limit,
|
|
28
|
+
)
|
|
29
|
+
from oscura.compliance.masks import (
|
|
30
|
+
AVAILABLE_MASKS,
|
|
31
|
+
LimitMask,
|
|
32
|
+
create_custom_mask,
|
|
33
|
+
load_limit_mask,
|
|
34
|
+
)
|
|
35
|
+
from oscura.compliance.reporting import (
|
|
36
|
+
ComplianceReportFormat,
|
|
37
|
+
generate_compliance_report,
|
|
38
|
+
)
|
|
39
|
+
from oscura.compliance.testing import (
|
|
40
|
+
ComplianceResult,
|
|
41
|
+
ComplianceViolation,
|
|
42
|
+
DetectorType,
|
|
43
|
+
check_compliance,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
# Masks (EMC-001)
|
|
48
|
+
"AVAILABLE_MASKS",
|
|
49
|
+
"ComplianceReportFormat",
|
|
50
|
+
"ComplianceResult",
|
|
51
|
+
# Advanced Compliance (COMP-005, 006, 007)
|
|
52
|
+
"ComplianceTestConfig",
|
|
53
|
+
"ComplianceTestRunner",
|
|
54
|
+
"ComplianceTestSuite",
|
|
55
|
+
"ComplianceViolation",
|
|
56
|
+
"DetectorType",
|
|
57
|
+
"InterpolationMethod",
|
|
58
|
+
"LimitInterpolator",
|
|
59
|
+
"LimitMask",
|
|
60
|
+
"QPDetectorBand",
|
|
61
|
+
"QPDetectorParams",
|
|
62
|
+
"QuasiPeakDetector",
|
|
63
|
+
# Testing (EMC-002)
|
|
64
|
+
"check_compliance",
|
|
65
|
+
"create_custom_mask",
|
|
66
|
+
# Reporting (EMC-003)
|
|
67
|
+
"generate_compliance_report",
|
|
68
|
+
"interpolate_limit",
|
|
69
|
+
"load_limit_mask",
|
|
70
|
+
]
|