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.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,466 @@
1
+ """Interactive analysis wizard for guided signal analysis.
2
+
3
+ This module provides step-by-step guided analysis wizards that help
4
+ non-expert users analyze their signals with intelligent recommendations.
5
+
6
+ - Step-by-step guidance
7
+ - Intelligent defaults
8
+ - Context-aware recommendations
9
+ - Result interpretation
10
+
11
+ Example:
12
+ >>> from oscura.onboarding import run_wizard
13
+ >>> run_wizard(trace)
14
+ Analysis Wizard
15
+ Step 1: What type of signal is this?
16
+ ...
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from dataclasses import dataclass, field
22
+ from enum import Enum
23
+ from typing import TYPE_CHECKING, Any
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Callable
27
+
28
+
29
+ class WizardAction(Enum):
30
+ """Actions the wizard can perform."""
31
+
32
+ MEASURE = "measure"
33
+ CHARACTERIZE = "characterize"
34
+ DECODE = "decode"
35
+ FILTER = "filter"
36
+ SPECTRAL = "spectral"
37
+ COMPARE = "compare"
38
+
39
+
40
+ @dataclass
41
+ class WizardStep:
42
+ """A step in the analysis wizard.
43
+
44
+ Attributes:
45
+ title: Step title
46
+ question: Question to ask user
47
+ options: Available options
48
+ action: Action to perform based on choice
49
+ help_text: Additional help for this step
50
+ """
51
+
52
+ title: str
53
+ question: str
54
+ options: list[str]
55
+ action: Callable[[int], None] | None = None
56
+ help_text: str = ""
57
+ skip_condition: Callable[[Any], bool] | None = None
58
+
59
+
60
+ @dataclass
61
+ class WizardResult:
62
+ """Result from wizard analysis.
63
+
64
+ Attributes:
65
+ steps_completed: Number of steps completed
66
+ measurements: Collected measurements
67
+ recommendations: Analysis recommendations
68
+ summary: Human-readable summary
69
+ """
70
+
71
+ steps_completed: int = 0
72
+ measurements: dict[str, Any] = field(default_factory=dict)
73
+ recommendations: list[str] = field(default_factory=list)
74
+ summary: str = ""
75
+
76
+
77
+ class AnalysisWizard:
78
+ """Interactive analysis wizard.
79
+
80
+ Guides users through signal analysis with intelligent
81
+ recommendations and plain English explanations.
82
+ """
83
+
84
+ def __init__(self, trace: Any) -> None:
85
+ """Initialize wizard with a trace.
86
+
87
+ Args:
88
+ trace: WaveformTrace or DigitalTrace to analyze
89
+ """
90
+ self.trace = trace
91
+ self.result = WizardResult()
92
+ self.steps: list[WizardStep] = self._build_steps()
93
+ self.current_step = 0
94
+
95
+ def _build_steps(self) -> list[WizardStep]:
96
+ """Build the wizard steps based on trace characteristics."""
97
+ steps = [
98
+ WizardStep(
99
+ title="Signal Type Detection",
100
+ question="What type of analysis do you want to perform?",
101
+ options=[
102
+ "Auto-detect (let TraceKit figure it out)",
103
+ "Digital signal analysis",
104
+ "Analog/waveform analysis",
105
+ "Protocol decoding",
106
+ "Power analysis",
107
+ ],
108
+ action=self._handle_signal_type,
109
+ help_text="Not sure? Choose 'Auto-detect' and we'll analyze your signal.",
110
+ ),
111
+ WizardStep(
112
+ title="Basic Measurements",
113
+ question="Would you like to run basic measurements?",
114
+ options=[
115
+ "Yes, run all standard measurements",
116
+ "Yes, but only timing measurements",
117
+ "Yes, but only amplitude measurements",
118
+ "No, skip this step",
119
+ ],
120
+ action=self._handle_measurements,
121
+ help_text="Basic measurements give you an overview of your signal.",
122
+ ),
123
+ WizardStep(
124
+ title="Spectral Analysis",
125
+ question="Would you like to analyze the frequency content?",
126
+ options=[
127
+ "Yes, compute FFT spectrum",
128
+ "Yes, compute power spectral density",
129
+ "Yes, both FFT and PSD",
130
+ "No, skip spectral analysis",
131
+ ],
132
+ action=self._handle_spectral,
133
+ help_text="Spectral analysis shows what frequencies are in your signal.",
134
+ ),
135
+ WizardStep(
136
+ title="Signal Quality",
137
+ question="Would you like to assess signal quality?",
138
+ options=[
139
+ "Yes, measure THD and SNR",
140
+ "Yes, check for anomalies",
141
+ "Yes, full quality assessment",
142
+ "No, skip quality check",
143
+ ],
144
+ action=self._handle_quality,
145
+ help_text="Quality metrics help identify issues with your signal.",
146
+ ),
147
+ ]
148
+ return steps
149
+
150
+ def run(self, interactive: bool = True) -> WizardResult:
151
+ """Run the analysis wizard.
152
+
153
+ Args:
154
+ interactive: If True, prompt for user input
155
+
156
+ Returns:
157
+ WizardResult with all collected data
158
+ """
159
+ print("\n" + "=" * 60)
160
+ print("TraceKit Analysis Wizard")
161
+ print("=" * 60)
162
+ print("Let's analyze your signal step by step.\n")
163
+
164
+ # Show trace summary
165
+ self._show_trace_summary()
166
+
167
+ for i, step in enumerate(self.steps):
168
+ # Check skip condition
169
+ if step.skip_condition and step.skip_condition(self.result):
170
+ continue
171
+
172
+ print(f"\n{'=' * 60}")
173
+ print(f"Step {i + 1}/{len(self.steps)}: {step.title}")
174
+ print("=" * 60)
175
+
176
+ if step.help_text:
177
+ print(f"Tip: {step.help_text}\n")
178
+
179
+ print(step.question)
180
+ for j, option in enumerate(step.options, 1):
181
+ print(f" {j}. {option}")
182
+
183
+ if interactive:
184
+ choice = self._get_user_choice(len(step.options))
185
+ else:
186
+ choice = 1 # Auto-select first option
187
+
188
+ if step.action:
189
+ step.action(choice)
190
+
191
+ self.result.steps_completed = i + 1
192
+
193
+ # Generate summary
194
+ self._generate_summary()
195
+
196
+ print("\n" + "=" * 60)
197
+ print("Analysis Complete!")
198
+ print("=" * 60)
199
+ print(self.result.summary)
200
+
201
+ if self.result.recommendations:
202
+ print("\nRecommendations:")
203
+ for rec in self.result.recommendations:
204
+ print(f" - {rec}")
205
+
206
+ return self.result
207
+
208
+ def _show_trace_summary(self) -> None:
209
+ """Show a summary of the loaded trace."""
210
+ trace = self.trace
211
+ print("Loaded trace summary:")
212
+
213
+ if hasattr(trace, "data"):
214
+ print(f" Samples: {len(trace.data):,}")
215
+
216
+ if hasattr(trace, "metadata"):
217
+ meta = trace.metadata
218
+ if hasattr(meta, "sample_rate") and meta.sample_rate:
219
+ rate = meta.sample_rate
220
+ if rate >= 1e9:
221
+ print(f" Sample rate: {rate / 1e9:.3f} GSa/s")
222
+ elif rate >= 1e6:
223
+ print(f" Sample rate: {rate / 1e6:.3f} MSa/s")
224
+ else:
225
+ print(f" Sample rate: {rate / 1e3:.3f} kSa/s")
226
+
227
+ if hasattr(meta, "channel_name") and meta.channel_name:
228
+ print(f" Channel: {meta.channel_name}")
229
+
230
+ if hasattr(trace, "data"):
231
+ import numpy as np
232
+
233
+ data = trace.data
234
+ print(f" Value range: {np.min(data):.4g} to {np.max(data):.4g}")
235
+
236
+ def _get_user_choice(self, max_options: int) -> int:
237
+ """Get user's choice with validation."""
238
+ while True:
239
+ try:
240
+ choice_str = input(f"\nEnter choice (1-{max_options}): ")
241
+ choice = int(choice_str)
242
+ if 1 <= choice <= max_options:
243
+ return choice
244
+ print(f"Please enter a number between 1 and {max_options}")
245
+ except ValueError:
246
+ print("Please enter a valid number")
247
+
248
+ def _handle_signal_type(self, choice: int) -> None:
249
+ """Handle signal type selection."""
250
+ if choice == 1: # Auto-detect
251
+ print("\nAuto-detecting signal type...")
252
+ try:
253
+ from oscura.discovery import characterize_signal
254
+
255
+ result = characterize_signal(self.trace)
256
+ self.result.measurements["signal_type"] = result.signal_type
257
+ self.result.measurements["signal_confidence"] = result.confidence
258
+ print(f"Detected: {result.signal_type} (confidence: {result.confidence:.0%})")
259
+
260
+ if result.confidence < 0.8:
261
+ self.result.recommendations.append(
262
+ f"Signal type detection has low confidence. "
263
+ f"Consider alternatives: {[a.signal_type for a in result.alternatives[:2]]}" # type: ignore[attr-defined]
264
+ )
265
+ except Exception as e:
266
+ print(f"Auto-detection failed: {e}")
267
+ self.result.measurements["signal_type"] = "unknown"
268
+
269
+ elif choice == 2: # Digital
270
+ self.result.measurements["signal_type"] = "digital"
271
+ print("\nDigital analysis mode selected.")
272
+
273
+ elif choice == 3: # Analog
274
+ self.result.measurements["signal_type"] = "analog"
275
+ print("\nAnalog/waveform analysis mode selected.")
276
+
277
+ elif choice == 4: # Protocol
278
+ self.result.measurements["signal_type"] = "protocol"
279
+ print("\nProtocol decoding mode selected.")
280
+ self.result.recommendations.append(
281
+ "For protocol decoding, try: decode_uart(), decode_spi(), decode_i2c()"
282
+ )
283
+
284
+ elif choice == 5: # Power
285
+ self.result.measurements["signal_type"] = "power"
286
+ print("\nPower analysis mode selected.")
287
+
288
+ def _handle_measurements(self, choice: int) -> None:
289
+ """Handle measurement selection."""
290
+ import oscura as tk
291
+
292
+ if choice == 4: # Skip
293
+ print("\nSkipping measurements.")
294
+ return
295
+
296
+ print("\nRunning measurements...")
297
+
298
+ try:
299
+ if choice == 1: # All
300
+ results = tk.measure(self.trace)
301
+ elif choice == 2: # Timing only
302
+ results = {
303
+ "rise_time": tk.rise_time(self.trace),
304
+ "fall_time": tk.fall_time(self.trace),
305
+ "frequency": tk.frequency(self.trace),
306
+ "period": tk.period(self.trace),
307
+ "duty_cycle": tk.duty_cycle(self.trace),
308
+ }
309
+ elif choice == 3: # Amplitude only
310
+ results = {
311
+ "amplitude": tk.amplitude(self.trace),
312
+ "rms": tk.rms(self.trace),
313
+ "mean": tk.mean(self.trace),
314
+ "overshoot": tk.overshoot(self.trace),
315
+ "undershoot": tk.undershoot(self.trace),
316
+ }
317
+
318
+ self.result.measurements.update(results)
319
+
320
+ print("\nMeasurement results:")
321
+ for name, value in results.items():
322
+ if isinstance(value, float):
323
+ print(f" {name}: {value:.4g}")
324
+ else:
325
+ print(f" {name}: {value}")
326
+
327
+ except Exception as e:
328
+ print(f"Measurement error: {e}")
329
+
330
+ def _handle_spectral(self, choice: int) -> None:
331
+ """Handle spectral analysis selection."""
332
+ import numpy as np
333
+
334
+ import oscura as tk
335
+
336
+ if choice == 4: # Skip
337
+ print("\nSkipping spectral analysis.")
338
+ return
339
+
340
+ print("\nRunning spectral analysis...")
341
+
342
+ try:
343
+ if choice in (1, 3): # FFT
344
+ freq, mag = tk.fft(self.trace) # type: ignore[misc]
345
+ peak_idx = np.argmax(mag)
346
+ self.result.measurements["fft_peak_freq"] = freq[peak_idx]
347
+ self.result.measurements["fft_peak_mag"] = mag[peak_idx]
348
+ print(f" FFT peak: {freq[peak_idx] / 1e6:.3f} MHz at {mag[peak_idx]:.1f} dB")
349
+
350
+ if choice in (2, 3): # PSD
351
+ freq, _psd_vals = tk.psd(self.trace)
352
+ self.result.measurements["psd_computed"] = True
353
+ print(f" PSD computed over {len(freq)} frequency bins")
354
+
355
+ except Exception as e:
356
+ print(f"Spectral analysis error: {e}")
357
+
358
+ def _handle_quality(self, choice: int) -> None:
359
+ """Handle quality assessment selection."""
360
+ import oscura as tk
361
+
362
+ if choice == 4: # Skip
363
+ print("\nSkipping quality assessment.")
364
+ return
365
+
366
+ print("\nAssessing signal quality...")
367
+
368
+ try:
369
+ if choice in (1, 3): # THD and SNR
370
+ thd_val = tk.thd(self.trace)
371
+ snr_val = tk.snr(self.trace)
372
+ self.result.measurements["thd"] = thd_val
373
+ self.result.measurements["snr"] = snr_val
374
+ print(f" THD: {thd_val:.1f} dB")
375
+ print(f" SNR: {snr_val:.1f} dB")
376
+
377
+ # Recommendations based on quality
378
+ if thd_val > -40:
379
+ self.result.recommendations.append(
380
+ f"THD is {thd_val:.1f} dB - consider filtering to reduce distortion"
381
+ )
382
+ if snr_val < 40:
383
+ self.result.recommendations.append(
384
+ f"SNR is {snr_val:.1f} dB - signal is noisy, try averaging or filtering"
385
+ )
386
+
387
+ if choice in (2, 3): # Anomalies
388
+ from oscura.discovery import find_anomalies
389
+
390
+ anomalies = find_anomalies(self.trace)
391
+ self.result.measurements["anomaly_count"] = len(anomalies)
392
+ print(f" Found {len(anomalies)} anomalies")
393
+
394
+ if anomalies:
395
+ self.result.recommendations.append(
396
+ f"Found {len(anomalies)} anomalies - review the anomaly list for issues"
397
+ )
398
+
399
+ except Exception as e:
400
+ print(f"Quality assessment error: {e}")
401
+
402
+ def _generate_summary(self) -> None:
403
+ """Generate a human-readable summary of the analysis."""
404
+ lines = ["Analysis Summary:"]
405
+
406
+ if "signal_type" in self.result.measurements:
407
+ lines.append(f" Signal type: {self.result.measurements['signal_type']}")
408
+
409
+ if "frequency" in self.result.measurements:
410
+ freq = self.result.measurements["frequency"]
411
+ # Handle dict format from measure()
412
+ if isinstance(freq, dict):
413
+ freq = freq.get("value", 0)
414
+
415
+ if freq >= 1e6:
416
+ lines.append(f" Frequency: {freq / 1e6:.3f} MHz")
417
+ elif freq >= 1e3:
418
+ lines.append(f" Frequency: {freq / 1e3:.3f} kHz")
419
+ else:
420
+ lines.append(f" Frequency: {freq:.1f} Hz")
421
+
422
+ if "rise_time" in self.result.measurements:
423
+ rt = self.result.measurements["rise_time"]
424
+ # Handle dict format from measure()
425
+ if isinstance(rt, dict):
426
+ rt = rt.get("value", 0)
427
+
428
+ lines.append(f" Rise time: {rt * 1e9:.2f} ns")
429
+
430
+ if "thd" in self.result.measurements:
431
+ thd = self.result.measurements["thd"]
432
+ # Handle dict format
433
+ if isinstance(thd, dict):
434
+ thd = thd.get("value", 0)
435
+ lines.append(f" THD: {thd:.1f} dB")
436
+
437
+ if "snr" in self.result.measurements:
438
+ snr = self.result.measurements["snr"]
439
+ # Handle dict format
440
+ if isinstance(snr, dict):
441
+ snr = snr.get("value", 0)
442
+ lines.append(f" SNR: {snr:.1f} dB")
443
+
444
+ self.result.summary = "\n".join(lines)
445
+
446
+
447
+ def run_wizard(trace: Any, interactive: bool = True) -> WizardResult:
448
+ """Run the analysis wizard on a trace.
449
+
450
+ This is the main entry point for guided analysis.
451
+
452
+ Args:
453
+ trace: WaveformTrace or DigitalTrace to analyze
454
+ interactive: If True, prompt for user input
455
+
456
+ Returns:
457
+ WizardResult with measurements, recommendations, and summary
458
+
459
+ Example:
460
+ >>> import oscura as tk
461
+ >>> from oscura.onboarding import run_wizard
462
+ >>> trace = tk.load("signal.csv")
463
+ >>> result = run_wizard(trace)
464
+ """
465
+ wizard = AnalysisWizard(trace)
466
+ return wizard.run(interactive=interactive)
@@ -0,0 +1,19 @@
1
+ """Parameter optimization and search algorithms.
2
+
3
+ This module provides grid search and randomized search for finding optimal
4
+ analysis parameters.
5
+ """
6
+
7
+ from oscura.optimization.search import (
8
+ GridSearchCV,
9
+ RandomizedSearchCV,
10
+ ScoringFunction,
11
+ SearchResult,
12
+ )
13
+
14
+ __all__ = [
15
+ "GridSearchCV",
16
+ "RandomizedSearchCV",
17
+ "ScoringFunction",
18
+ "SearchResult",
19
+ ]