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,405 @@
|
|
|
1
|
+
"""Interactive tutorial system for TraceKit.
|
|
2
|
+
|
|
3
|
+
This module provides step-by-step interactive tutorials for new users,
|
|
4
|
+
covering common analysis workflows.
|
|
5
|
+
|
|
6
|
+
- Interactive tutorial system
|
|
7
|
+
- Step-by-step guidance
|
|
8
|
+
- Code examples with explanations
|
|
9
|
+
- Progress tracking
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
>>> from oscura.onboarding import run_tutorial
|
|
13
|
+
>>> run_tutorial("getting_started")
|
|
14
|
+
Welcome to TraceKit!
|
|
15
|
+
Step 1/5: Loading a trace file
|
|
16
|
+
...
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from typing import TYPE_CHECKING
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import Callable
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class TutorialStep:
|
|
30
|
+
"""A single step in a tutorial.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
title: Step title
|
|
34
|
+
description: Detailed description with plain English explanation
|
|
35
|
+
code: Example code to run
|
|
36
|
+
expected_output: What the user should see
|
|
37
|
+
hints: Optional hints if stuck
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
title: str
|
|
41
|
+
description: str
|
|
42
|
+
code: str
|
|
43
|
+
expected_output: str = ""
|
|
44
|
+
hints: list[str] = field(default_factory=list)
|
|
45
|
+
validation_fn: Callable[..., bool] | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class Tutorial:
|
|
50
|
+
"""An interactive tutorial.
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
id: Unique tutorial identifier
|
|
54
|
+
title: Human-readable title
|
|
55
|
+
description: Tutorial overview
|
|
56
|
+
steps: List of tutorial steps
|
|
57
|
+
difficulty: beginner, intermediate, or advanced
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
id: str
|
|
61
|
+
title: str
|
|
62
|
+
description: str
|
|
63
|
+
steps: list[TutorialStep]
|
|
64
|
+
difficulty: str = "beginner"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Built-in tutorials
|
|
68
|
+
TUTORIALS: dict[str, Tutorial] = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _register_getting_started() -> None:
|
|
72
|
+
"""Register the getting started tutorial."""
|
|
73
|
+
steps = [
|
|
74
|
+
TutorialStep(
|
|
75
|
+
title="Loading a Trace File",
|
|
76
|
+
description="""
|
|
77
|
+
TraceKit can load waveform data from many file formats.
|
|
78
|
+
The simplest way is to use the load() function, which auto-detects the format.
|
|
79
|
+
|
|
80
|
+
Think of a trace like a recording of an electrical signal over time -
|
|
81
|
+
similar to how an audio file stores sound waves.
|
|
82
|
+
""",
|
|
83
|
+
code="""
|
|
84
|
+
import oscura as tk
|
|
85
|
+
|
|
86
|
+
# Load a waveform file (replace with your file path)
|
|
87
|
+
trace = tk.load("signal.csv")
|
|
88
|
+
|
|
89
|
+
# See basic info
|
|
90
|
+
print(f"Loaded {len(trace.data)} samples")
|
|
91
|
+
print(f"Sample rate: {trace.metadata.sample_rate} Hz")
|
|
92
|
+
""",
|
|
93
|
+
expected_output="Loaded 10000 samples\nSample rate: 1000000.0 Hz",
|
|
94
|
+
hints=[
|
|
95
|
+
"Try loading a CSV file with two columns: time and voltage",
|
|
96
|
+
"Supported formats: .csv, .wfm, .npz, .hdf5, and more",
|
|
97
|
+
],
|
|
98
|
+
),
|
|
99
|
+
TutorialStep(
|
|
100
|
+
title="Making Basic Measurements",
|
|
101
|
+
description="""
|
|
102
|
+
Once you have a trace, you can measure things like:
|
|
103
|
+
- Rise time: How fast a signal goes from low to high
|
|
104
|
+
- Frequency: How many times per second the signal repeats
|
|
105
|
+
- Amplitude: The voltage difference between high and low
|
|
106
|
+
|
|
107
|
+
These are the same measurements an oscilloscope would show you!
|
|
108
|
+
""",
|
|
109
|
+
code="""
|
|
110
|
+
import oscura as tk
|
|
111
|
+
|
|
112
|
+
trace = tk.load("signal.csv")
|
|
113
|
+
|
|
114
|
+
# Measure rise time (10% to 90% transition)
|
|
115
|
+
rt = tk.rise_time(trace)
|
|
116
|
+
print(f"Rise time: {rt*1e9:.2f} nanoseconds")
|
|
117
|
+
|
|
118
|
+
# Measure frequency
|
|
119
|
+
freq = tk.frequency(trace)
|
|
120
|
+
print(f"Frequency: {freq/1e6:.2f} MHz")
|
|
121
|
+
|
|
122
|
+
# Get all measurements at once
|
|
123
|
+
results = tk.measure(trace)
|
|
124
|
+
for name, value in results.items():
|
|
125
|
+
print(f"{name}: {value}")
|
|
126
|
+
""",
|
|
127
|
+
expected_output="Rise time: 2.50 nanoseconds\nFrequency: 10.00 MHz",
|
|
128
|
+
hints=[
|
|
129
|
+
"rise_time() measures 10%-90% transition by default",
|
|
130
|
+
"Use measure() to get all measurements in one call",
|
|
131
|
+
],
|
|
132
|
+
),
|
|
133
|
+
TutorialStep(
|
|
134
|
+
title="Spectral Analysis (Frequency Domain)",
|
|
135
|
+
description="""
|
|
136
|
+
Spectral analysis shows you what frequencies are present in your signal.
|
|
137
|
+
This is useful for:
|
|
138
|
+
- Finding the main frequency of a clock signal
|
|
139
|
+
- Detecting noise at specific frequencies
|
|
140
|
+
- Measuring signal quality (THD, SNR)
|
|
141
|
+
|
|
142
|
+
It's like looking at a music equalizer that shows bass, mid, and treble!
|
|
143
|
+
""",
|
|
144
|
+
code="""
|
|
145
|
+
import oscura as tk
|
|
146
|
+
|
|
147
|
+
trace = tk.load("signal.csv")
|
|
148
|
+
|
|
149
|
+
# Compute FFT (Fast Fourier Transform)
|
|
150
|
+
freq, magnitude = tk.fft(trace)
|
|
151
|
+
|
|
152
|
+
# Find the dominant frequency
|
|
153
|
+
import numpy as np
|
|
154
|
+
peak_idx = np.argmax(magnitude)
|
|
155
|
+
print(f"Dominant frequency: {freq[peak_idx]/1e6:.2f} MHz")
|
|
156
|
+
|
|
157
|
+
# Measure signal quality
|
|
158
|
+
thd_value = tk.thd(trace)
|
|
159
|
+
snr_value = tk.snr(trace)
|
|
160
|
+
print(f"THD: {thd_value:.1f} dB")
|
|
161
|
+
print(f"SNR: {snr_value:.1f} dB")
|
|
162
|
+
""",
|
|
163
|
+
expected_output="Dominant frequency: 10.00 MHz\nTHD: -45.2 dB\nSNR: 52.3 dB",
|
|
164
|
+
hints=[
|
|
165
|
+
"THD (Total Harmonic Distortion) should be negative in dB - more negative is better",
|
|
166
|
+
"SNR (Signal-to-Noise Ratio) should be positive - higher is better",
|
|
167
|
+
],
|
|
168
|
+
),
|
|
169
|
+
TutorialStep(
|
|
170
|
+
title="Protocol Decoding",
|
|
171
|
+
description="""
|
|
172
|
+
If your signal is a digital communication protocol like UART, SPI, or I2C,
|
|
173
|
+
TraceKit can decode it to show you the actual data being transmitted.
|
|
174
|
+
|
|
175
|
+
Think of it like translating Morse code back into text!
|
|
176
|
+
""",
|
|
177
|
+
code="""
|
|
178
|
+
import oscura as tk
|
|
179
|
+
|
|
180
|
+
# Load a UART signal
|
|
181
|
+
trace = tk.load("uart_signal.csv")
|
|
182
|
+
|
|
183
|
+
# Decode UART (auto-detects baud rate!)
|
|
184
|
+
from oscura.analyzers.protocols import decode_uart
|
|
185
|
+
packets = decode_uart(trace)
|
|
186
|
+
|
|
187
|
+
# Show decoded bytes
|
|
188
|
+
for pkt in packets[:5]: # First 5 packets
|
|
189
|
+
print(f"Time: {pkt.timestamp:.6f}s, Data: 0x{pkt.data:02X} ('{chr(pkt.data)}')")
|
|
190
|
+
""",
|
|
191
|
+
expected_output="Time: 0.000001s, Data: 0x48 ('H')\nTime: 0.000086s, Data: 0x65 ('e')",
|
|
192
|
+
hints=[
|
|
193
|
+
"UART baud rate is auto-detected by default",
|
|
194
|
+
"Supported protocols: UART, SPI, I2C, CAN, and many more",
|
|
195
|
+
],
|
|
196
|
+
),
|
|
197
|
+
TutorialStep(
|
|
198
|
+
title="Auto-Discovery for Beginners",
|
|
199
|
+
description="""
|
|
200
|
+
Not sure what your signal is? TraceKit can analyze it automatically!
|
|
201
|
+
|
|
202
|
+
The characterize_signal() function examines your trace and tells you:
|
|
203
|
+
- What type of signal it likely is
|
|
204
|
+
- Key parameters (voltage, frequency, etc.)
|
|
205
|
+
- Suggestions for further analysis
|
|
206
|
+
|
|
207
|
+
It's like having an expert look at your signal and give you hints!
|
|
208
|
+
""",
|
|
209
|
+
code="""
|
|
210
|
+
import oscura as tk
|
|
211
|
+
from oscura.discovery import characterize_signal
|
|
212
|
+
|
|
213
|
+
trace = tk.load("mystery_signal.csv")
|
|
214
|
+
|
|
215
|
+
# Auto-characterize the signal
|
|
216
|
+
result = characterize_signal(trace)
|
|
217
|
+
|
|
218
|
+
print(f"Signal type: {result.signal_type}")
|
|
219
|
+
print(f"Confidence: {result.confidence:.1%}")
|
|
220
|
+
print(f"Voltage range: {result.voltage_low:.2f}V to {result.voltage_high:.2f}V")
|
|
221
|
+
|
|
222
|
+
if result.confidence >= 0.8:
|
|
223
|
+
print("High confidence - proceed with suggested analysis")
|
|
224
|
+
else:
|
|
225
|
+
print("Consider alternatives:")
|
|
226
|
+
for alt in result.alternatives:
|
|
227
|
+
print(f" - {alt.signal_type}: {alt.confidence:.1%}")
|
|
228
|
+
""",
|
|
229
|
+
expected_output="Signal type: digital\nConfidence: 94.0%",
|
|
230
|
+
hints=[
|
|
231
|
+
"Confidence >= 80% means high confidence in the detection",
|
|
232
|
+
"Low confidence? Check the alternatives for other possibilities",
|
|
233
|
+
],
|
|
234
|
+
),
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
tutorial = Tutorial(
|
|
238
|
+
id="getting_started",
|
|
239
|
+
title="Getting Started with TraceKit",
|
|
240
|
+
description="""
|
|
241
|
+
Welcome to TraceKit! This tutorial will teach you the basics of
|
|
242
|
+
signal analysis in 5 easy steps:
|
|
243
|
+
|
|
244
|
+
1. Loading trace files
|
|
245
|
+
2. Making basic measurements
|
|
246
|
+
3. Spectral analysis
|
|
247
|
+
4. Protocol decoding
|
|
248
|
+
5. Auto-discovery
|
|
249
|
+
|
|
250
|
+
No prior signal analysis experience required!
|
|
251
|
+
""",
|
|
252
|
+
steps=steps,
|
|
253
|
+
difficulty="beginner",
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
TUTORIALS[tutorial.id] = tutorial
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _register_spectral_analysis() -> None:
|
|
260
|
+
"""Register the spectral analysis tutorial."""
|
|
261
|
+
steps = [
|
|
262
|
+
TutorialStep(
|
|
263
|
+
title="Understanding FFT",
|
|
264
|
+
description="""
|
|
265
|
+
The Fast Fourier Transform (FFT) converts a time-domain signal into
|
|
266
|
+
its frequency components. Think of it as breaking a chord into individual notes.
|
|
267
|
+
""",
|
|
268
|
+
code="""
|
|
269
|
+
import oscura as tk
|
|
270
|
+
import numpy as np
|
|
271
|
+
|
|
272
|
+
trace = tk.load("signal.csv")
|
|
273
|
+
freq, mag = tk.fft(trace)
|
|
274
|
+
|
|
275
|
+
# Magnitude is in dB (decibels)
|
|
276
|
+
# 0 dB = full scale, -20 dB = 10x smaller, -40 dB = 100x smaller
|
|
277
|
+
print(f"Frequency range: 0 to {freq[-1]/1e6:.1f} MHz")
|
|
278
|
+
print(f"Peak magnitude: {np.max(mag):.1f} dB")
|
|
279
|
+
""",
|
|
280
|
+
expected_output="Frequency range: 0 to 50.0 MHz\nPeak magnitude: -3.2 dB",
|
|
281
|
+
),
|
|
282
|
+
TutorialStep(
|
|
283
|
+
title="Power Spectral Density",
|
|
284
|
+
description="""
|
|
285
|
+
PSD shows power distribution across frequencies. Unlike FFT magnitude,
|
|
286
|
+
PSD is normalized per Hz, making it easier to compare signals with
|
|
287
|
+
different durations or sample rates.
|
|
288
|
+
""",
|
|
289
|
+
code="""
|
|
290
|
+
import oscura as tk
|
|
291
|
+
|
|
292
|
+
trace = tk.load("signal.csv")
|
|
293
|
+
freq, psd = tk.psd(trace)
|
|
294
|
+
|
|
295
|
+
# Find where most power is concentrated
|
|
296
|
+
import numpy as np
|
|
297
|
+
total_power = np.sum(psd)
|
|
298
|
+
cumsum = np.cumsum(psd) / total_power
|
|
299
|
+
|
|
300
|
+
# 90% of power is below this frequency
|
|
301
|
+
idx_90 = np.searchsorted(cumsum, 0.9)
|
|
302
|
+
print(f"90% of signal power below {freq[idx_90]/1e6:.1f} MHz")
|
|
303
|
+
""",
|
|
304
|
+
expected_output="90% of signal power below 15.2 MHz",
|
|
305
|
+
),
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
tutorial = Tutorial(
|
|
309
|
+
id="spectral_analysis",
|
|
310
|
+
title="Spectral Analysis Deep Dive",
|
|
311
|
+
description="Learn advanced spectral analysis techniques.",
|
|
312
|
+
steps=steps,
|
|
313
|
+
difficulty="intermediate",
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
TUTORIALS[tutorial.id] = tutorial
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# Register built-in tutorials
|
|
320
|
+
_register_getting_started()
|
|
321
|
+
_register_spectral_analysis()
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def list_tutorials() -> list[dict[str, str]]:
|
|
325
|
+
"""List all available tutorials.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
List of tutorial info dictionaries with id, title, difficulty
|
|
329
|
+
"""
|
|
330
|
+
return [
|
|
331
|
+
{
|
|
332
|
+
"id": t.id,
|
|
333
|
+
"title": t.title,
|
|
334
|
+
"difficulty": t.difficulty,
|
|
335
|
+
"steps": len(t.steps), # type: ignore[dict-item]
|
|
336
|
+
}
|
|
337
|
+
for t in TUTORIALS.values()
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def get_tutorial(tutorial_id: str) -> Tutorial | None:
|
|
342
|
+
"""Get a tutorial by ID.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
tutorial_id: Tutorial identifier
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Tutorial object or None if not found
|
|
349
|
+
"""
|
|
350
|
+
return TUTORIALS.get(tutorial_id)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def run_tutorial(tutorial_id: str, interactive: bool = True) -> None:
|
|
354
|
+
"""Run an interactive tutorial.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
tutorial_id: Tutorial to run (e.g., "getting_started")
|
|
358
|
+
interactive: If True, pause between steps for user input
|
|
359
|
+
|
|
360
|
+
Example:
|
|
361
|
+
>>> run_tutorial("getting_started")
|
|
362
|
+
"""
|
|
363
|
+
tutorial = get_tutorial(tutorial_id)
|
|
364
|
+
if tutorial is None:
|
|
365
|
+
print(f"Tutorial '{tutorial_id}' not found.")
|
|
366
|
+
print("Available tutorials:")
|
|
367
|
+
for t in list_tutorials():
|
|
368
|
+
print(f" - {t['id']}: {t['title']}")
|
|
369
|
+
return
|
|
370
|
+
|
|
371
|
+
print("=" * 60)
|
|
372
|
+
print(f"Tutorial: {tutorial.title}")
|
|
373
|
+
print(f"Difficulty: {tutorial.difficulty}")
|
|
374
|
+
print("=" * 60)
|
|
375
|
+
print(tutorial.description)
|
|
376
|
+
print()
|
|
377
|
+
|
|
378
|
+
for i, step in enumerate(tutorial.steps, 1):
|
|
379
|
+
print(f"\n{'=' * 60}")
|
|
380
|
+
print(f"Step {i}/{len(tutorial.steps)}: {step.title}")
|
|
381
|
+
print("=" * 60)
|
|
382
|
+
print(step.description)
|
|
383
|
+
print("\nCode:")
|
|
384
|
+
print("-" * 40)
|
|
385
|
+
print(step.code)
|
|
386
|
+
print("-" * 40)
|
|
387
|
+
|
|
388
|
+
if step.expected_output:
|
|
389
|
+
print(f"\nExpected output:\n{step.expected_output}")
|
|
390
|
+
|
|
391
|
+
if step.hints:
|
|
392
|
+
print("\nHints:")
|
|
393
|
+
for hint in step.hints:
|
|
394
|
+
print(f" - {hint}")
|
|
395
|
+
|
|
396
|
+
if interactive:
|
|
397
|
+
input("\nPress Enter to continue...")
|
|
398
|
+
|
|
399
|
+
print("\n" + "=" * 60)
|
|
400
|
+
print("Tutorial Complete!")
|
|
401
|
+
print("=" * 60)
|
|
402
|
+
print("Next steps:")
|
|
403
|
+
print(" - Try the examples with your own data")
|
|
404
|
+
print(" - Run 'list_tutorials()' to see more tutorials")
|
|
405
|
+
print(" - Use 'get_help(function_name)' for detailed help")
|