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,368 @@
|
|
|
1
|
+
"""Natural language summary generation for signal analysis.
|
|
2
|
+
|
|
3
|
+
This module generates human-readable descriptions of measurements and analysis
|
|
4
|
+
results that avoid jargon and explain findings in accessible language.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.reporting import generate_summary
|
|
9
|
+
>>> trace = load("capture.wfm")
|
|
10
|
+
>>> summary = generate_summary(trace)
|
|
11
|
+
>>> print(summary.text)
|
|
12
|
+
|
|
13
|
+
References:
|
|
14
|
+
TraceKit Auto-Discovery Specification
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from oscura.core.types import WaveformTrace
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class Finding:
|
|
30
|
+
"""Individual analysis finding.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
title: Short title for the finding.
|
|
34
|
+
description: Plain language description.
|
|
35
|
+
confidence: Confidence score (0.0-1.0).
|
|
36
|
+
severity: Severity level (INFO, WARNING, CRITICAL).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
title: str
|
|
40
|
+
description: str
|
|
41
|
+
confidence: float = 1.0
|
|
42
|
+
severity: str = "INFO"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class Summary:
|
|
47
|
+
"""Natural language summary of signal analysis.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
text: Complete summary text (2-3 sentences, 100-200 words).
|
|
51
|
+
overview: High-level overview sentence.
|
|
52
|
+
findings: List of key findings (minimum 3).
|
|
53
|
+
recommendations: Actionable insights and next steps.
|
|
54
|
+
word_count: Number of words in summary text.
|
|
55
|
+
grade_level: Flesch-Kincaid grade level.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
text: str
|
|
59
|
+
overview: str
|
|
60
|
+
findings: list[Finding] = field(default_factory=list)
|
|
61
|
+
recommendations: list[str] = field(default_factory=list)
|
|
62
|
+
word_count: int = 0
|
|
63
|
+
grade_level: float = 0.0
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _estimate_grade_level(text: str) -> float:
|
|
67
|
+
"""Estimate Flesch-Kincaid grade level.
|
|
68
|
+
|
|
69
|
+
Simple approximation based on sentence and word length.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
text: Text to analyze.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Estimated grade level.
|
|
76
|
+
"""
|
|
77
|
+
# Split into sentences (simple split on period)
|
|
78
|
+
sentences = [s.strip() for s in text.split(".") if s.strip()]
|
|
79
|
+
if not sentences:
|
|
80
|
+
return 0.0
|
|
81
|
+
|
|
82
|
+
# Split into words
|
|
83
|
+
words = text.split()
|
|
84
|
+
if not words:
|
|
85
|
+
return 0.0
|
|
86
|
+
|
|
87
|
+
# Count syllables (approximation: count vowel groups)
|
|
88
|
+
total_syllables = 0
|
|
89
|
+
for word in words:
|
|
90
|
+
word_lower = word.lower()
|
|
91
|
+
syllable_count = 0
|
|
92
|
+
previous_was_vowel = False
|
|
93
|
+
|
|
94
|
+
for char in word_lower:
|
|
95
|
+
is_vowel = char in "aeiouy"
|
|
96
|
+
if is_vowel and not previous_was_vowel:
|
|
97
|
+
syllable_count += 1
|
|
98
|
+
previous_was_vowel = is_vowel
|
|
99
|
+
|
|
100
|
+
# Minimum 1 syllable per word
|
|
101
|
+
total_syllables += max(1, syllable_count)
|
|
102
|
+
|
|
103
|
+
# Flesch-Kincaid formula
|
|
104
|
+
avg_words_per_sentence = len(words) / len(sentences)
|
|
105
|
+
avg_syllables_per_word = total_syllables / len(words)
|
|
106
|
+
|
|
107
|
+
grade_level = 0.39 * avg_words_per_sentence + 11.8 * avg_syllables_per_word - 15.59
|
|
108
|
+
|
|
109
|
+
return max(0.0, grade_level)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _characterize_signal_type(trace: WaveformTrace) -> tuple[str, float]:
|
|
113
|
+
"""Characterize basic signal type.
|
|
114
|
+
|
|
115
|
+
Simple heuristic-based signal type detection.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
trace: Waveform to analyze.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Tuple of (signal_type, confidence).
|
|
122
|
+
"""
|
|
123
|
+
data = trace.data.astype(np.float64)
|
|
124
|
+
|
|
125
|
+
# Check if digital (only 2-3 distinct levels)
|
|
126
|
+
unique_values = len(np.unique(np.round(data, decimals=2)))
|
|
127
|
+
value_range = np.ptp(data)
|
|
128
|
+
|
|
129
|
+
if unique_values <= 3 and value_range > 0.1:
|
|
130
|
+
# Likely digital
|
|
131
|
+
return "digital", 0.85
|
|
132
|
+
elif value_range < 0.01:
|
|
133
|
+
# Constant signal
|
|
134
|
+
return "DC level", 0.90
|
|
135
|
+
else:
|
|
136
|
+
# Analog
|
|
137
|
+
# Check for periodicity
|
|
138
|
+
if len(data) > 100:
|
|
139
|
+
autocorr = np.correlate(data - np.mean(data), data - np.mean(data), mode="full")
|
|
140
|
+
autocorr = autocorr[len(autocorr) // 2 :]
|
|
141
|
+
autocorr = autocorr / autocorr[0]
|
|
142
|
+
|
|
143
|
+
# Look for peaks in autocorrelation
|
|
144
|
+
if len(autocorr) > 10 and np.max(autocorr[10:]) > 0.5:
|
|
145
|
+
return "periodic analog", 0.75
|
|
146
|
+
return "analog", 0.70
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _assess_quality(trace: WaveformTrace) -> tuple[str, list[str]]:
|
|
150
|
+
"""Assess signal quality.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
trace: Waveform to analyze.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Tuple of (quality_level, issues).
|
|
157
|
+
"""
|
|
158
|
+
data = trace.data.astype(np.float64)
|
|
159
|
+
issues = []
|
|
160
|
+
|
|
161
|
+
# Check for sufficient data
|
|
162
|
+
if len(data) < 100:
|
|
163
|
+
issues.append("Very short capture (less than 100 samples)")
|
|
164
|
+
|
|
165
|
+
# Check noise level (standard deviation relative to range)
|
|
166
|
+
data_range = np.ptp(data)
|
|
167
|
+
if data_range > 0:
|
|
168
|
+
noise_ratio = np.std(data) / data_range
|
|
169
|
+
if noise_ratio > 0.2:
|
|
170
|
+
issues.append("High noise level detected")
|
|
171
|
+
|
|
172
|
+
# Check for clipping
|
|
173
|
+
if len(data) > 0:
|
|
174
|
+
data_min = np.min(data)
|
|
175
|
+
data_max = np.max(data)
|
|
176
|
+
|
|
177
|
+
# Check if many samples at min/max (possible clipping)
|
|
178
|
+
at_min = np.sum(data == data_min)
|
|
179
|
+
at_max = np.sum(data == data_max)
|
|
180
|
+
|
|
181
|
+
if at_min > len(data) * 0.05:
|
|
182
|
+
issues.append("Possible clipping at minimum level")
|
|
183
|
+
if at_max > len(data) * 0.05:
|
|
184
|
+
issues.append("Possible clipping at maximum level")
|
|
185
|
+
|
|
186
|
+
# Determine quality level
|
|
187
|
+
if not issues:
|
|
188
|
+
quality = "excellent"
|
|
189
|
+
elif len(issues) == 1:
|
|
190
|
+
quality = "good"
|
|
191
|
+
elif len(issues) == 2:
|
|
192
|
+
quality = "fair"
|
|
193
|
+
else:
|
|
194
|
+
quality = "poor"
|
|
195
|
+
|
|
196
|
+
return quality, issues
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _format_frequency(freq_hz: float) -> str:
|
|
200
|
+
"""Format frequency in human-readable form.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
freq_hz: Frequency in Hz.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Formatted string.
|
|
207
|
+
"""
|
|
208
|
+
if freq_hz >= 1e9:
|
|
209
|
+
return f"{freq_hz / 1e9:.1f} GHz"
|
|
210
|
+
elif freq_hz >= 1e6:
|
|
211
|
+
return f"{freq_hz / 1e6:.1f} MHz"
|
|
212
|
+
elif freq_hz >= 1e3:
|
|
213
|
+
return f"{freq_hz / 1e3:.1f} kHz"
|
|
214
|
+
else:
|
|
215
|
+
return f"{freq_hz:.1f} Hz"
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def generate_summary(
|
|
219
|
+
trace: WaveformTrace,
|
|
220
|
+
*,
|
|
221
|
+
context: dict[str, Any] | None = None,
|
|
222
|
+
detail_level: str = "summary",
|
|
223
|
+
max_words: int = 200,
|
|
224
|
+
include_sections: list[str] | None = None,
|
|
225
|
+
) -> Summary:
|
|
226
|
+
"""Generate natural language summary of signal analysis.
|
|
227
|
+
|
|
228
|
+
Creates a plain-English description of the signal and analysis results,
|
|
229
|
+
avoiding technical jargon and explaining findings in accessible terms.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
trace: Waveform to summarize.
|
|
233
|
+
context: Optional analysis context (characterization, anomalies, etc.).
|
|
234
|
+
detail_level: Summary detail level ("summary", "intermediate", "expert").
|
|
235
|
+
max_words: Maximum word count for summary text.
|
|
236
|
+
include_sections: Sections to include (default: all).
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Summary object with natural language description.
|
|
240
|
+
|
|
241
|
+
Example:
|
|
242
|
+
>>> trace = load("uart_signal.wfm")
|
|
243
|
+
>>> summary = generate_summary(trace)
|
|
244
|
+
>>> print(summary.text)
|
|
245
|
+
This is a digital signal with two voltage levels...
|
|
246
|
+
|
|
247
|
+
References:
|
|
248
|
+
DISC-003: Natural Language Summaries
|
|
249
|
+
"""
|
|
250
|
+
context = context or {}
|
|
251
|
+
include_sections = include_sections or ["overview", "findings", "recommendations"]
|
|
252
|
+
|
|
253
|
+
# Characterize signal type
|
|
254
|
+
signal_type, type_confidence = _characterize_signal_type(trace)
|
|
255
|
+
|
|
256
|
+
# Assess quality
|
|
257
|
+
quality_level, quality_issues = _assess_quality(trace)
|
|
258
|
+
|
|
259
|
+
# Build overview
|
|
260
|
+
sample_rate = trace.metadata.sample_rate
|
|
261
|
+
duration_ms = len(trace.data) / sample_rate * 1000
|
|
262
|
+
|
|
263
|
+
overview = f"This is a {signal_type} signal captured at {_format_frequency(sample_rate)} sample rate for {duration_ms:.1f} milliseconds."
|
|
264
|
+
|
|
265
|
+
# Build findings
|
|
266
|
+
findings = []
|
|
267
|
+
|
|
268
|
+
# Signal type finding
|
|
269
|
+
findings.append(
|
|
270
|
+
Finding(
|
|
271
|
+
title="Signal Type",
|
|
272
|
+
description=f"Identified as {signal_type}",
|
|
273
|
+
confidence=type_confidence,
|
|
274
|
+
severity="INFO",
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Quality finding
|
|
279
|
+
quality_desc = f"Signal quality is {quality_level}"
|
|
280
|
+
if quality_issues:
|
|
281
|
+
quality_desc += f" with {len(quality_issues)} issue(s) noted"
|
|
282
|
+
|
|
283
|
+
findings.append(
|
|
284
|
+
Finding(
|
|
285
|
+
title="Signal Quality",
|
|
286
|
+
description=quality_desc,
|
|
287
|
+
confidence=0.85,
|
|
288
|
+
severity="WARNING" if quality_issues else "INFO",
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# Voltage levels
|
|
293
|
+
v_min = float(np.min(trace.data))
|
|
294
|
+
v_max = float(np.max(trace.data))
|
|
295
|
+
v_range = v_max - v_min
|
|
296
|
+
|
|
297
|
+
findings.append(
|
|
298
|
+
Finding(
|
|
299
|
+
title="Voltage Range",
|
|
300
|
+
description=f"Signal ranges from {v_min:.3f}V to {v_max:.3f}V (swing: {v_range:.3f}V)",
|
|
301
|
+
confidence=1.0,
|
|
302
|
+
severity="INFO",
|
|
303
|
+
)
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Build recommendations
|
|
307
|
+
recommendations = []
|
|
308
|
+
|
|
309
|
+
if "very short" in str(quality_issues).lower():
|
|
310
|
+
recommendations.append("Capture a longer duration to enable more detailed analysis")
|
|
311
|
+
|
|
312
|
+
if "noise" in str(quality_issues).lower():
|
|
313
|
+
recommendations.append(
|
|
314
|
+
"Check signal integrity and consider using better probes or shielding"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
if "clipping" in str(quality_issues).lower():
|
|
318
|
+
recommendations.append("Adjust voltage range to prevent signal clipping and data loss")
|
|
319
|
+
|
|
320
|
+
if signal_type == "digital" and not recommendations:
|
|
321
|
+
recommendations.append("Signal appears clean and suitable for digital protocol analysis")
|
|
322
|
+
elif signal_type in ["analog", "periodic analog"] and not recommendations:
|
|
323
|
+
recommendations.append("Consider spectral analysis to identify frequency components")
|
|
324
|
+
|
|
325
|
+
# Build complete summary text
|
|
326
|
+
summary_parts = []
|
|
327
|
+
|
|
328
|
+
if "overview" in include_sections:
|
|
329
|
+
summary_parts.append(overview)
|
|
330
|
+
|
|
331
|
+
if "findings" in include_sections and findings:
|
|
332
|
+
key_findings = findings[:3] # Top 3 findings
|
|
333
|
+
findings_text = " ".join(
|
|
334
|
+
[f"{finding.title}: {finding.description}." for finding in key_findings]
|
|
335
|
+
)
|
|
336
|
+
summary_parts.append(findings_text)
|
|
337
|
+
|
|
338
|
+
if "recommendations" in include_sections and recommendations:
|
|
339
|
+
rec_text = "Recommended next steps: " + "; ".join(recommendations[:2]) + "."
|
|
340
|
+
summary_parts.append(rec_text)
|
|
341
|
+
|
|
342
|
+
full_text = " ".join(summary_parts)
|
|
343
|
+
|
|
344
|
+
# Truncate to max_words if needed
|
|
345
|
+
words = full_text.split()
|
|
346
|
+
if len(words) > max_words:
|
|
347
|
+
words = words[:max_words]
|
|
348
|
+
full_text = " ".join(words) + "..."
|
|
349
|
+
|
|
350
|
+
# Calculate statistics
|
|
351
|
+
word_count = len(full_text.split())
|
|
352
|
+
grade_level = _estimate_grade_level(full_text)
|
|
353
|
+
|
|
354
|
+
return Summary(
|
|
355
|
+
text=full_text,
|
|
356
|
+
overview=overview,
|
|
357
|
+
findings=findings,
|
|
358
|
+
recommendations=recommendations,
|
|
359
|
+
word_count=word_count,
|
|
360
|
+
grade_level=grade_level,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
__all__ = [
|
|
365
|
+
"Finding",
|
|
366
|
+
"Summary",
|
|
367
|
+
"generate_summary",
|
|
368
|
+
]
|