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,363 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://tracekit.io/schemas/protocol_definition.json",
|
|
4
|
+
"title": "Protocol Definition Schema",
|
|
5
|
+
"description": "Schema for validating protocol DSL definitions for automatic decoder/encoder generation (CFG-001).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "settings", "framing", "fields"],
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Protocol identifier",
|
|
13
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
|
|
14
|
+
"minLength": 1
|
|
15
|
+
},
|
|
16
|
+
"version": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Protocol version",
|
|
19
|
+
"pattern": "^\\d+\\.\\d+$"
|
|
20
|
+
},
|
|
21
|
+
"description": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Human-readable description"
|
|
24
|
+
},
|
|
25
|
+
"settings": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"description": "Global protocol settings",
|
|
28
|
+
"properties": {
|
|
29
|
+
"endian": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"enum": ["big", "little", "native"],
|
|
32
|
+
"description": "Default byte order"
|
|
33
|
+
},
|
|
34
|
+
"alignment": {
|
|
35
|
+
"type": "integer",
|
|
36
|
+
"minimum": 1,
|
|
37
|
+
"description": "Byte alignment (1 = no padding)"
|
|
38
|
+
},
|
|
39
|
+
"strict": {
|
|
40
|
+
"type": "boolean",
|
|
41
|
+
"description": "Fail on unknown fields or extra data"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
},
|
|
46
|
+
"framing": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"description": "Message framing and boundary detection",
|
|
49
|
+
"required": ["type"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"type": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": ["delimiter", "length_prefix", "fixed"],
|
|
54
|
+
"description": "Framing method"
|
|
55
|
+
},
|
|
56
|
+
"sync": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"description": "Synchronization pattern",
|
|
59
|
+
"properties": {
|
|
60
|
+
"pattern": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"description": "Sync byte pattern",
|
|
63
|
+
"items": { "type": "integer", "minimum": 0, "maximum": 255 }
|
|
64
|
+
},
|
|
65
|
+
"required": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"description": "Whether sync pattern is mandatory"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"additionalProperties": false
|
|
71
|
+
},
|
|
72
|
+
"length_field": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"description": "Length field specification (for length_prefix framing)",
|
|
75
|
+
"properties": {
|
|
76
|
+
"offset": {
|
|
77
|
+
"type": "integer",
|
|
78
|
+
"minimum": 0,
|
|
79
|
+
"description": "Offset from start of message"
|
|
80
|
+
},
|
|
81
|
+
"size": {
|
|
82
|
+
"type": "integer",
|
|
83
|
+
"minimum": 1,
|
|
84
|
+
"maximum": 8,
|
|
85
|
+
"description": "Length field size in bytes"
|
|
86
|
+
},
|
|
87
|
+
"endian": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"enum": ["big", "little", "native"],
|
|
90
|
+
"description": "Byte order for length field"
|
|
91
|
+
},
|
|
92
|
+
"includes_header": {
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"description": "Whether length includes header bytes"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"additionalProperties": false
|
|
98
|
+
},
|
|
99
|
+
"delimiter": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"description": "Delimiter specification (for delimiter framing)",
|
|
102
|
+
"properties": {
|
|
103
|
+
"pattern": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"description": "Delimiter byte pattern",
|
|
106
|
+
"items": { "type": "integer", "minimum": 0, "maximum": 255 }
|
|
107
|
+
},
|
|
108
|
+
"escape": {
|
|
109
|
+
"type": "integer",
|
|
110
|
+
"minimum": 0,
|
|
111
|
+
"maximum": 255,
|
|
112
|
+
"description": "Escape byte for escaped delimiters"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"additionalProperties": false
|
|
116
|
+
},
|
|
117
|
+
"fixed_size": {
|
|
118
|
+
"type": "integer",
|
|
119
|
+
"minimum": 1,
|
|
120
|
+
"description": "Fixed message size (for fixed framing)"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"additionalProperties": false
|
|
124
|
+
},
|
|
125
|
+
"fields": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"description": "Field definitions in order",
|
|
128
|
+
"minItems": 1,
|
|
129
|
+
"items": {
|
|
130
|
+
"allOf": [{ "$ref": "#/definitions/field" }, { "required": ["name"] }]
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"computed_fields": {
|
|
134
|
+
"type": "array",
|
|
135
|
+
"description": "Computed/virtual fields derived from other fields",
|
|
136
|
+
"items": {
|
|
137
|
+
"type": "object",
|
|
138
|
+
"required": ["name", "expression"],
|
|
139
|
+
"properties": {
|
|
140
|
+
"name": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
|
|
143
|
+
},
|
|
144
|
+
"expression": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"description": "Expression to compute value"
|
|
147
|
+
},
|
|
148
|
+
"description": {
|
|
149
|
+
"type": "string"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"additionalProperties": false
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"decoding": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"description": "Decoding hints and configuration",
|
|
158
|
+
"properties": {
|
|
159
|
+
"min_header_size": {
|
|
160
|
+
"type": "integer",
|
|
161
|
+
"minimum": 1,
|
|
162
|
+
"description": "Minimum bytes to determine message length"
|
|
163
|
+
},
|
|
164
|
+
"max_message_size": {
|
|
165
|
+
"type": "integer",
|
|
166
|
+
"minimum": 1,
|
|
167
|
+
"description": "Maximum allowed message size"
|
|
168
|
+
},
|
|
169
|
+
"resync_on_error": {
|
|
170
|
+
"type": "boolean",
|
|
171
|
+
"description": "Attempt to resynchronize on errors"
|
|
172
|
+
},
|
|
173
|
+
"max_resync_distance": {
|
|
174
|
+
"type": "integer",
|
|
175
|
+
"minimum": 1,
|
|
176
|
+
"description": "Maximum bytes to search for resync"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"additionalProperties": false
|
|
180
|
+
},
|
|
181
|
+
"encoding": {
|
|
182
|
+
"type": "object",
|
|
183
|
+
"description": "Encoding rules for encoder generation",
|
|
184
|
+
"properties": {
|
|
185
|
+
"auto_fill": {
|
|
186
|
+
"type": "object",
|
|
187
|
+
"description": "Fields to auto-fill when encoding",
|
|
188
|
+
"additionalProperties": { "type": "boolean" }
|
|
189
|
+
},
|
|
190
|
+
"validate_required_fields": {
|
|
191
|
+
"type": "boolean",
|
|
192
|
+
"description": "Validate all required fields present"
|
|
193
|
+
},
|
|
194
|
+
"validate_field_ranges": {
|
|
195
|
+
"type": "boolean",
|
|
196
|
+
"description": "Validate field values in valid ranges"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"additionalProperties": false
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"definitions": {
|
|
203
|
+
"field": {
|
|
204
|
+
"type": "object",
|
|
205
|
+
"required": ["type"],
|
|
206
|
+
"properties": {
|
|
207
|
+
"name": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"description": "Field name (optional for array elements)",
|
|
210
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
|
|
211
|
+
},
|
|
212
|
+
"type": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"enum": [
|
|
215
|
+
"uint8",
|
|
216
|
+
"uint16",
|
|
217
|
+
"uint32",
|
|
218
|
+
"uint64",
|
|
219
|
+
"int8",
|
|
220
|
+
"int16",
|
|
221
|
+
"int32",
|
|
222
|
+
"int64",
|
|
223
|
+
"float32",
|
|
224
|
+
"float64",
|
|
225
|
+
"bytes",
|
|
226
|
+
"string",
|
|
227
|
+
"array",
|
|
228
|
+
"struct",
|
|
229
|
+
"bitfield"
|
|
230
|
+
],
|
|
231
|
+
"description": "Field data type"
|
|
232
|
+
},
|
|
233
|
+
"size": {
|
|
234
|
+
"description": "Field size (bytes for bytes type, can be expression)",
|
|
235
|
+
"oneOf": [{ "type": "integer", "minimum": 1 }, { "type": "string" }]
|
|
236
|
+
},
|
|
237
|
+
"endian": {
|
|
238
|
+
"type": "string",
|
|
239
|
+
"enum": ["big", "little", "native"],
|
|
240
|
+
"description": "Byte order override"
|
|
241
|
+
},
|
|
242
|
+
"value": {
|
|
243
|
+
"description": "Expected constant value for validation",
|
|
244
|
+
"oneOf": [
|
|
245
|
+
{ "type": "integer" },
|
|
246
|
+
{ "type": "number" },
|
|
247
|
+
{ "type": "string" },
|
|
248
|
+
{ "type": "array" }
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
"condition": {
|
|
252
|
+
"type": "string",
|
|
253
|
+
"description": "Conditional expression - field only present if true"
|
|
254
|
+
},
|
|
255
|
+
"description": {
|
|
256
|
+
"type": "string",
|
|
257
|
+
"description": "Field description"
|
|
258
|
+
},
|
|
259
|
+
"enum": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"description": "Enumeration value to name mappings (keys can be integers or hex strings)",
|
|
262
|
+
"additionalProperties": {
|
|
263
|
+
"type": "object",
|
|
264
|
+
"required": ["name"],
|
|
265
|
+
"properties": {
|
|
266
|
+
"name": { "type": "string" },
|
|
267
|
+
"description": { "type": "string" }
|
|
268
|
+
},
|
|
269
|
+
"additionalProperties": false
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"fields": {
|
|
273
|
+
"description": "Nested fields (for bitfield or struct types)",
|
|
274
|
+
"oneOf": [
|
|
275
|
+
{
|
|
276
|
+
"type": "object",
|
|
277
|
+
"description": "Bitfield extraction",
|
|
278
|
+
"patternProperties": {
|
|
279
|
+
"^[a-zA-Z][a-zA-Z0-9_]*$": {
|
|
280
|
+
"type": "object",
|
|
281
|
+
"properties": {
|
|
282
|
+
"bit": {
|
|
283
|
+
"type": "integer",
|
|
284
|
+
"minimum": 0,
|
|
285
|
+
"description": "Single bit position"
|
|
286
|
+
},
|
|
287
|
+
"bits": {
|
|
288
|
+
"type": "array",
|
|
289
|
+
"items": { "type": "integer", "minimum": 0 },
|
|
290
|
+
"minItems": 2,
|
|
291
|
+
"maxItems": 2,
|
|
292
|
+
"description": "Bit range [start, end]"
|
|
293
|
+
},
|
|
294
|
+
"description": { "type": "string" }
|
|
295
|
+
},
|
|
296
|
+
"oneOf": [{ "required": ["bit"] }, { "required": ["bits"] }]
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"type": "array",
|
|
302
|
+
"description": "Struct fields",
|
|
303
|
+
"items": { "$ref": "#/definitions/field" }
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
},
|
|
307
|
+
"count_field": {
|
|
308
|
+
"type": ["string", "null"],
|
|
309
|
+
"description": "Field name containing array count (for array type)"
|
|
310
|
+
},
|
|
311
|
+
"element": {
|
|
312
|
+
"description": "Array element definition (for array type)",
|
|
313
|
+
"$ref": "#/definitions/field"
|
|
314
|
+
},
|
|
315
|
+
"encoding": {
|
|
316
|
+
"type": "string",
|
|
317
|
+
"description": "Character encoding (for string type)",
|
|
318
|
+
"enum": ["utf-8", "ascii", "latin-1", "utf-16", "utf-32"]
|
|
319
|
+
},
|
|
320
|
+
"validation": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"description": "Field validation rules",
|
|
323
|
+
"properties": {
|
|
324
|
+
"min": {
|
|
325
|
+
"type": "number",
|
|
326
|
+
"description": "Minimum value"
|
|
327
|
+
},
|
|
328
|
+
"max": {
|
|
329
|
+
"type": "number",
|
|
330
|
+
"description": "Maximum value"
|
|
331
|
+
},
|
|
332
|
+
"expected": {
|
|
333
|
+
"description": "Expected value",
|
|
334
|
+
"oneOf": [
|
|
335
|
+
{ "type": "integer" },
|
|
336
|
+
{ "type": "number" },
|
|
337
|
+
{ "type": "string" },
|
|
338
|
+
{ "type": "array" }
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
"on_mismatch": {
|
|
342
|
+
"type": "string",
|
|
343
|
+
"enum": ["error", "warn", "ignore"],
|
|
344
|
+
"description": "Action on validation failure"
|
|
345
|
+
},
|
|
346
|
+
"algorithm": {
|
|
347
|
+
"type": "string",
|
|
348
|
+
"enum": ["crc16_ccitt", "crc32", "md5", "sha1"],
|
|
349
|
+
"description": "Checksum algorithm"
|
|
350
|
+
},
|
|
351
|
+
"scope": {
|
|
352
|
+
"type": "string",
|
|
353
|
+
"enum": ["all_prior", "message", "payload"],
|
|
354
|
+
"description": "Scope for checksum calculation"
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"additionalProperties": false
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
"additionalProperties": false
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Pattern search and anomaly detection for TraceKit.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
This module enables efficient pattern matching, anomaly detection, and
|
|
5
|
+
context extraction for debugging and analysis workflows.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from oscura.search.anomaly import find_anomalies
|
|
9
|
+
from oscura.search.context import extract_context
|
|
10
|
+
from oscura.search.pattern import find_pattern
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"extract_context",
|
|
14
|
+
"find_anomalies",
|
|
15
|
+
"find_pattern",
|
|
16
|
+
]
|
oscura/search/anomaly.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""Anomaly detection in signal traces.
|
|
2
|
+
|
|
3
|
+
This module provides automated detection of glitches, timing violations,
|
|
4
|
+
and protocol errors with context extraction for debugging.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numpy.typing import NDArray
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def find_anomalies(
|
|
14
|
+
trace: NDArray[np.float64],
|
|
15
|
+
anomaly_type: str = "glitch",
|
|
16
|
+
*,
|
|
17
|
+
threshold: float | None = None,
|
|
18
|
+
min_width: float | None = None,
|
|
19
|
+
max_width: float | None = None,
|
|
20
|
+
sample_rate: float | None = None,
|
|
21
|
+
context_samples: int = 100,
|
|
22
|
+
**kwargs: Any,
|
|
23
|
+
) -> list[dict[str, Any]]:
|
|
24
|
+
"""Find glitches, timing violations, or protocol errors in traces.
|
|
25
|
+
|
|
26
|
+
Anomaly detection with context extraction.
|
|
27
|
+
Integrates with QUAL-005 glitch detection for signal quality analysis.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
trace: Input signal trace
|
|
31
|
+
anomaly_type: Type of anomaly to detect:
|
|
32
|
+
- 'glitch': Short-duration voltage spikes/dips
|
|
33
|
+
- 'timing': Edge timing violations (requires sample_rate)
|
|
34
|
+
- 'protocol': Protocol-level errors (requires decoded data)
|
|
35
|
+
threshold: Detection threshold. Meaning depends on anomaly_type:
|
|
36
|
+
- glitch: Voltage deviation from expected level
|
|
37
|
+
- timing: Timing violation threshold in seconds
|
|
38
|
+
min_width: Minimum anomaly width in seconds (requires sample_rate)
|
|
39
|
+
max_width: Maximum anomaly width in seconds (requires sample_rate)
|
|
40
|
+
sample_rate: Sample rate in Hz (required for timing analysis)
|
|
41
|
+
context_samples: Number of samples to include before/after anomaly
|
|
42
|
+
for context extraction (default: 100)
|
|
43
|
+
**kwargs: Additional type-specific parameters
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
List of anomaly dictionaries, each containing:
|
|
47
|
+
- index: Sample index where anomaly occurs
|
|
48
|
+
- type: Anomaly type
|
|
49
|
+
- severity: Severity score (0-1, higher is worse)
|
|
50
|
+
- duration: Duration in samples
|
|
51
|
+
- amplitude: Amplitude deviation (for glitches)
|
|
52
|
+
- context: ±context_samples around anomaly
|
|
53
|
+
- description: Human-readable description
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ValueError: If invalid anomaly_type or missing required parameters
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
>>> # Detect voltage glitches
|
|
60
|
+
>>> trace = np.array([0, 0, 0, 0.8, 0, 0, 0]) # Spike at index 3
|
|
61
|
+
>>> anomalies = find_anomalies(
|
|
62
|
+
... trace,
|
|
63
|
+
... anomaly_type='glitch',
|
|
64
|
+
... threshold=0.5,
|
|
65
|
+
... sample_rate=1e6
|
|
66
|
+
... )
|
|
67
|
+
>>> print(f"Found {len(anomalies)} glitches")
|
|
68
|
+
|
|
69
|
+
>>> # Detect timing violations
|
|
70
|
+
>>> anomalies = find_anomalies(
|
|
71
|
+
... trace,
|
|
72
|
+
... anomaly_type='timing',
|
|
73
|
+
... min_width=10e-9, # 10 ns minimum
|
|
74
|
+
... max_width=100e-9, # 100 ns maximum
|
|
75
|
+
... sample_rate=1e9
|
|
76
|
+
... )
|
|
77
|
+
|
|
78
|
+
Notes:
|
|
79
|
+
- Glitch detection uses derivative and threshold methods
|
|
80
|
+
- Timing detection requires sample_rate for width calculations
|
|
81
|
+
- Context extraction handles edge cases at trace boundaries
|
|
82
|
+
- Integrates with QUAL-005 for comprehensive signal quality analysis
|
|
83
|
+
|
|
84
|
+
References:
|
|
85
|
+
SRCH-002: Anomaly Search
|
|
86
|
+
QUAL-005: Glitch Detection
|
|
87
|
+
"""
|
|
88
|
+
if trace.size == 0:
|
|
89
|
+
return []
|
|
90
|
+
|
|
91
|
+
valid_types = {"glitch", "timing", "protocol"}
|
|
92
|
+
if anomaly_type not in valid_types:
|
|
93
|
+
raise ValueError(f"Invalid anomaly_type '{anomaly_type}'. Must be one of: {valid_types}")
|
|
94
|
+
|
|
95
|
+
anomalies: list[dict[str, Any]] = []
|
|
96
|
+
|
|
97
|
+
if anomaly_type == "glitch":
|
|
98
|
+
anomalies = _detect_glitches(
|
|
99
|
+
trace,
|
|
100
|
+
threshold=threshold,
|
|
101
|
+
min_width=min_width,
|
|
102
|
+
max_width=max_width,
|
|
103
|
+
sample_rate=sample_rate,
|
|
104
|
+
context_samples=context_samples,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
elif anomaly_type == "timing":
|
|
108
|
+
if sample_rate is None:
|
|
109
|
+
raise ValueError("sample_rate required for timing anomaly detection")
|
|
110
|
+
|
|
111
|
+
anomalies = _detect_timing_violations(
|
|
112
|
+
trace,
|
|
113
|
+
sample_rate=sample_rate,
|
|
114
|
+
min_width=min_width,
|
|
115
|
+
max_width=max_width,
|
|
116
|
+
context_samples=context_samples,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
elif anomaly_type == "protocol":
|
|
120
|
+
# Protocol error detection would integrate with protocol decoders
|
|
121
|
+
# For now, return empty list with note
|
|
122
|
+
anomalies = []
|
|
123
|
+
|
|
124
|
+
return anomalies
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _detect_glitches(
|
|
128
|
+
trace: NDArray[np.float64],
|
|
129
|
+
threshold: float | None,
|
|
130
|
+
min_width: float | None,
|
|
131
|
+
max_width: float | None,
|
|
132
|
+
sample_rate: float | None,
|
|
133
|
+
context_samples: int,
|
|
134
|
+
) -> list[dict[str, Any]]:
|
|
135
|
+
"""Detect voltage glitches using derivative method."""
|
|
136
|
+
glitches: list[dict[str, Any]] = []
|
|
137
|
+
|
|
138
|
+
# Auto-threshold if not provided
|
|
139
|
+
threshold_value: float
|
|
140
|
+
if threshold is None:
|
|
141
|
+
# Use 3 sigma as default threshold
|
|
142
|
+
threshold_value = float(3 * np.std(trace))
|
|
143
|
+
else:
|
|
144
|
+
threshold_value = threshold
|
|
145
|
+
|
|
146
|
+
# Compute derivative to find rapid changes
|
|
147
|
+
derivative = np.diff(trace)
|
|
148
|
+
abs_derivative = np.abs(derivative)
|
|
149
|
+
|
|
150
|
+
# Find points where derivative exceeds threshold
|
|
151
|
+
glitch_candidates = np.where(abs_derivative > threshold_value)[0]
|
|
152
|
+
|
|
153
|
+
if len(glitch_candidates) == 0:
|
|
154
|
+
return glitches
|
|
155
|
+
|
|
156
|
+
# Group consecutive points into glitch events
|
|
157
|
+
glitch_groups = []
|
|
158
|
+
current_group = [glitch_candidates[0]]
|
|
159
|
+
|
|
160
|
+
for idx in glitch_candidates[1:]:
|
|
161
|
+
if idx == current_group[-1] + 1:
|
|
162
|
+
current_group.append(idx)
|
|
163
|
+
else:
|
|
164
|
+
glitch_groups.append(current_group)
|
|
165
|
+
current_group = [idx]
|
|
166
|
+
|
|
167
|
+
if current_group:
|
|
168
|
+
glitch_groups.append(current_group)
|
|
169
|
+
|
|
170
|
+
# Compute baseline once for all glitches (performance optimization)
|
|
171
|
+
# For very large arrays (>1M samples), use percentile approximation
|
|
172
|
+
if len(trace) > 1_000_000:
|
|
173
|
+
# Fast approximation: 50th percentile with linear interpolation
|
|
174
|
+
baseline = float(np.percentile(trace, 50, method="linear"))
|
|
175
|
+
else:
|
|
176
|
+
baseline = float(np.median(trace))
|
|
177
|
+
|
|
178
|
+
# Filter by width if specified
|
|
179
|
+
for group in glitch_groups:
|
|
180
|
+
start_idx = group[0]
|
|
181
|
+
end_idx = group[-1] + 1
|
|
182
|
+
duration_samples = end_idx - start_idx
|
|
183
|
+
|
|
184
|
+
# Check width constraints
|
|
185
|
+
if sample_rate is not None:
|
|
186
|
+
duration_seconds = duration_samples / sample_rate
|
|
187
|
+
|
|
188
|
+
if min_width is not None and duration_seconds < min_width:
|
|
189
|
+
continue
|
|
190
|
+
if max_width is not None and duration_seconds > max_width:
|
|
191
|
+
continue
|
|
192
|
+
|
|
193
|
+
# Extract context
|
|
194
|
+
ctx_start = max(0, start_idx - context_samples)
|
|
195
|
+
ctx_end = min(len(trace), end_idx + context_samples)
|
|
196
|
+
context = trace[ctx_start:ctx_end].copy()
|
|
197
|
+
|
|
198
|
+
# Compute amplitude deviation (baseline computed once above)
|
|
199
|
+
amplitude = np.max(np.abs(trace[start_idx:end_idx] - baseline))
|
|
200
|
+
|
|
201
|
+
# Severity: normalized amplitude
|
|
202
|
+
severity = min(1.0, amplitude / (threshold_value * 3))
|
|
203
|
+
|
|
204
|
+
glitches.append(
|
|
205
|
+
{
|
|
206
|
+
"index": start_idx,
|
|
207
|
+
"type": "glitch",
|
|
208
|
+
"severity": float(severity),
|
|
209
|
+
"duration": duration_samples,
|
|
210
|
+
"amplitude": float(amplitude),
|
|
211
|
+
"context": context,
|
|
212
|
+
"description": f"Glitch at sample {start_idx}, amplitude {amplitude:.3g}",
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return glitches
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _detect_timing_violations(
|
|
220
|
+
trace: NDArray[np.float64],
|
|
221
|
+
sample_rate: float,
|
|
222
|
+
min_width: float | None,
|
|
223
|
+
max_width: float | None,
|
|
224
|
+
context_samples: int,
|
|
225
|
+
) -> list[dict[str, Any]]:
|
|
226
|
+
"""Detect timing violations (pulse width violations)."""
|
|
227
|
+
violations = []
|
|
228
|
+
|
|
229
|
+
# Simple threshold for digital signal
|
|
230
|
+
threshold = (np.max(trace) + np.min(trace)) / 2
|
|
231
|
+
digital = (trace >= threshold).astype(int)
|
|
232
|
+
|
|
233
|
+
# Find edges
|
|
234
|
+
edges = np.diff(digital)
|
|
235
|
+
rising_edges = np.where(edges == 1)[0]
|
|
236
|
+
falling_edges = np.where(edges == -1)[0]
|
|
237
|
+
|
|
238
|
+
# Measure pulse widths
|
|
239
|
+
for rise in rising_edges:
|
|
240
|
+
# Find next falling edge
|
|
241
|
+
next_fall = falling_edges[falling_edges > rise]
|
|
242
|
+
if len(next_fall) == 0:
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
fall = next_fall[0]
|
|
246
|
+
pulse_width_samples = fall - rise
|
|
247
|
+
pulse_width_seconds = pulse_width_samples / sample_rate
|
|
248
|
+
|
|
249
|
+
# Check violations
|
|
250
|
+
violated = False
|
|
251
|
+
violation_type = ""
|
|
252
|
+
|
|
253
|
+
if min_width is not None and pulse_width_seconds < min_width:
|
|
254
|
+
violated = True
|
|
255
|
+
violation_type = "too_short"
|
|
256
|
+
|
|
257
|
+
if max_width is not None and pulse_width_seconds > max_width:
|
|
258
|
+
violated = True
|
|
259
|
+
violation_type = "too_long"
|
|
260
|
+
|
|
261
|
+
if violated:
|
|
262
|
+
# Extract context
|
|
263
|
+
ctx_start = max(0, rise - context_samples)
|
|
264
|
+
ctx_end = min(len(trace), fall + context_samples)
|
|
265
|
+
context = trace[ctx_start:ctx_end].copy()
|
|
266
|
+
|
|
267
|
+
# Severity based on deviation
|
|
268
|
+
if min_width is not None:
|
|
269
|
+
deviation = abs(pulse_width_seconds - min_width) / min_width
|
|
270
|
+
elif max_width is not None:
|
|
271
|
+
deviation = abs(pulse_width_seconds - max_width) / max_width
|
|
272
|
+
else:
|
|
273
|
+
deviation = 0.0
|
|
274
|
+
|
|
275
|
+
severity = min(1.0, deviation)
|
|
276
|
+
|
|
277
|
+
violations.append(
|
|
278
|
+
{
|
|
279
|
+
"index": rise,
|
|
280
|
+
"type": f"timing_{violation_type}",
|
|
281
|
+
"severity": float(severity),
|
|
282
|
+
"duration": pulse_width_samples,
|
|
283
|
+
"amplitude": float(pulse_width_seconds),
|
|
284
|
+
"context": context,
|
|
285
|
+
"description": (
|
|
286
|
+
f"Timing violation at sample {rise}: "
|
|
287
|
+
f"pulse width {pulse_width_seconds * 1e9:.1f} ns ({violation_type})"
|
|
288
|
+
),
|
|
289
|
+
}
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return violations
|