oscura 0.0.1__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.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.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,498 @@
1
+ """Context-sensitive help and command suggestions.
2
+
3
+ This module provides plain English help, command suggestions based on
4
+ context, and result explanations for non-expert users.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.onboarding import get_help, suggest_commands
9
+ >>> get_help("rise_time")
10
+ >>> suggest_commands(trace)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any
16
+
17
+ # Plain English help database
18
+ HELP_DATABASE: dict[str, dict[str, str | list[str]]] = {
19
+ "rise_time": {
20
+ "summary": "Measures how quickly a signal transitions from low to high",
21
+ "plain_english": """
22
+ Rise time tells you how fast your signal can switch from OFF to ON
23
+ (or from a low voltage to a high voltage). It's measured between
24
+ the 10% and 90% points of the transition by default.
25
+
26
+ In plain terms: A faster rise time means sharper edges on your signal,
27
+ which is important for high-speed digital circuits.
28
+
29
+ Typical values:
30
+ - Slow logic (old TTL): 10-50 nanoseconds
31
+ - Fast logic (modern CMOS): 0.1-2 nanoseconds
32
+ - High-speed serial (USB, PCIe): 50-200 picoseconds
33
+ """,
34
+ "when_to_use": [
35
+ "Characterizing digital buffer performance",
36
+ "Checking if your driver is fast enough for your data rate",
37
+ "Verifying signal integrity (slow rise = possible problems)",
38
+ ],
39
+ "related": ["fall_time", "slew_rate", "frequency"],
40
+ },
41
+ "fall_time": {
42
+ "summary": "Measures how quickly a signal transitions from high to low",
43
+ "plain_english": """
44
+ Fall time is the opposite of rise time - it measures how fast your
45
+ signal switches from ON to OFF (high voltage to low voltage).
46
+
47
+ It's measured between the 90% and 10% points of the transition.
48
+
49
+ Ideally, rise time and fall time should be similar. If they're very
50
+ different, it might indicate an issue with your circuit.
51
+ """,
52
+ "when_to_use": [
53
+ "Checking symmetry of your driver",
54
+ "Verifying output stage performance",
55
+ "Diagnosing asymmetric signal issues",
56
+ ],
57
+ "related": ["rise_time", "slew_rate", "duty_cycle"],
58
+ },
59
+ "frequency": {
60
+ "summary": "Measures how many times per second your signal repeats",
61
+ "plain_english": """
62
+ Frequency tells you how fast your signal is cycling. It's measured
63
+ in Hertz (Hz), which means 'cycles per second'.
64
+
65
+ Common scales:
66
+ - 1 kHz = 1,000 cycles/second (audio frequencies)
67
+ - 1 MHz = 1,000,000 cycles/second (radio, slow digital)
68
+ - 1 GHz = 1,000,000,000 cycles/second (fast digital, RF)
69
+
70
+ Oscura finds frequency by detecting repeated patterns in your signal.
71
+ """,
72
+ "when_to_use": [
73
+ "Verifying clock frequency",
74
+ "Checking oscillator output",
75
+ "Measuring PWM frequency",
76
+ ],
77
+ "related": ["period", "duty_cycle", "fft"],
78
+ },
79
+ "thd": {
80
+ "summary": "Total Harmonic Distortion - measures signal purity",
81
+ "plain_english": """
82
+ THD tells you how 'clean' your signal is. A perfect sine wave has
83
+ 0% THD (or -infinity dB). Real signals have some distortion.
84
+
85
+ THD in dB (decibels):
86
+ - -60 dB or lower: Excellent (high-quality audio)
87
+ - -40 to -60 dB: Good (typical electronics)
88
+ - -20 to -40 dB: Fair (some distortion visible)
89
+ - Above -20 dB: Poor (significant distortion)
90
+
91
+ Note: THD is expressed as a negative number in dB.
92
+ More negative = less distortion = better signal.
93
+ """,
94
+ "when_to_use": [
95
+ "Testing audio amplifier quality",
96
+ "Verifying oscillator purity",
97
+ "Characterizing ADC/DAC performance",
98
+ ],
99
+ "related": ["snr", "sinad", "enob"],
100
+ },
101
+ "snr": {
102
+ "summary": "Signal-to-Noise Ratio - measures how much signal vs noise",
103
+ "plain_english": """
104
+ SNR tells you how much of your signal is actual signal versus noise.
105
+ Higher SNR = cleaner signal with less interference.
106
+
107
+ SNR in dB:
108
+ - 60+ dB: Excellent (barely any noise visible)
109
+ - 40-60 dB: Good (clean signal, some noise)
110
+ - 20-40 dB: Fair (visible noise)
111
+ - Below 20 dB: Poor (noisy signal)
112
+
113
+ In practical terms: Every 6 dB is roughly doubling the signal level
114
+ relative to noise.
115
+ """,
116
+ "when_to_use": [
117
+ "Evaluating measurement system quality",
118
+ "Testing ADC performance",
119
+ "Comparing different signal sources",
120
+ ],
121
+ "related": ["thd", "sinad", "enob"],
122
+ },
123
+ "fft": {
124
+ "summary": "Fast Fourier Transform - shows frequency content of signal",
125
+ "plain_english": """
126
+ FFT transforms your time-domain signal (voltage vs time) into the
127
+ frequency domain (power vs frequency). It's like an equalizer display
128
+ that shows what frequencies are present.
129
+
130
+ Returns two arrays:
131
+ - frequencies: The x-axis values in Hz
132
+ - magnitudes: The strength at each frequency (usually in dB)
133
+
134
+ Peaks in the FFT correspond to dominant frequencies in your signal.
135
+ A pure sine wave shows one peak. Square waves show peaks at odd
136
+ harmonics (1x, 3x, 5x, etc. of the fundamental).
137
+ """,
138
+ "when_to_use": [
139
+ "Finding the frequency of an unknown signal",
140
+ "Looking for interference at specific frequencies",
141
+ "Analyzing modulated signals",
142
+ ],
143
+ "related": ["psd", "thd", "snr", "spectrogram"],
144
+ },
145
+ "load": {
146
+ "summary": "Load a trace file - Oscura's starting point",
147
+ "plain_english": """
148
+ load() reads waveform data from a file. It auto-detects the format,
149
+ so you don't need to specify whether it's CSV, WFM, HDF5, etc.
150
+
151
+ Returns a WaveformTrace or DigitalTrace object containing:
152
+ - data: The actual voltage/value samples
153
+ - metadata: Sample rate, channel info, etc.
154
+ - time_vector: Time axis (computed from sample rate)
155
+
156
+ Supported formats: CSV, Tektronix WFM, Rigol WFM, NumPy NPZ,
157
+ HDF5, Sigrok sessions, VCD, TDMS, and more.
158
+ """,
159
+ "when_to_use": [
160
+ "Starting any Oscura analysis",
161
+ "Loading oscilloscope captures",
162
+ "Importing logic analyzer data",
163
+ ],
164
+ "related": ["get_supported_formats", "WaveformTrace", "DigitalTrace"],
165
+ },
166
+ "measure": {
167
+ "summary": "Run all standard measurements on a trace",
168
+ "plain_english": """
169
+ measure() is a convenience function that runs many common measurements
170
+ at once and returns them as a dictionary.
171
+
172
+ It's like clicking 'Auto-Measure' on an oscilloscope.
173
+
174
+ Measurements include:
175
+ - Timing: rise_time, fall_time, frequency, period, duty_cycle
176
+ - Amplitude: vpp, vmax, vmin, vmean, vrms
177
+ - Waveform quality: overshoot, undershoot
178
+
179
+ Results are returned in a dictionary for easy access.
180
+ """,
181
+ "when_to_use": [
182
+ "Quick signal characterization",
183
+ "Getting an overview of signal properties",
184
+ "When you're not sure which measurements you need",
185
+ ],
186
+ "related": ["rise_time", "frequency", "amplitude", "basic_stats"],
187
+ },
188
+ }
189
+
190
+
191
+ def get_help(topic: str) -> str | None:
192
+ """Get plain English help for a Oscura function or concept.
193
+
194
+ Args:
195
+ topic: Function name or concept to get help for
196
+
197
+ Returns:
198
+ Formatted help text or None if topic not found
199
+
200
+ Example:
201
+ >>> print(get_help("rise_time"))
202
+ """
203
+ topic = topic.lower().strip()
204
+
205
+ if topic in HELP_DATABASE:
206
+ entry = HELP_DATABASE[topic]
207
+ output = []
208
+ output.append(f"Help: {topic}")
209
+ output.append("=" * 50)
210
+ output.append(f"\n{entry['summary']}\n")
211
+ output.append(entry["plain_english"]) # type: ignore[arg-type]
212
+
213
+ if "when_to_use" in entry:
214
+ output.append("\nWhen to use this:")
215
+ for use in entry["when_to_use"]:
216
+ output.append(f" - {use}")
217
+
218
+ if "related" in entry:
219
+ output.append(f"\nRelated: {', '.join(entry['related'])}")
220
+
221
+ return "\n".join(output)
222
+
223
+ # Try to get docstring
224
+ try:
225
+ import oscura as osc
226
+
227
+ if hasattr(osc, topic):
228
+ func = getattr(osc, topic)
229
+ if func.__doc__:
230
+ return f"Help for {topic}:\n\n{func.__doc__}"
231
+ except Exception:
232
+ pass
233
+
234
+ return None
235
+
236
+
237
+ def suggest_commands(trace: Any = None, context: str | None = None) -> list[dict[str, str]]:
238
+ """Suggest next commands based on current context.
239
+
240
+ Args:
241
+ trace: Current trace object (if any)
242
+ context: Description of what user is trying to do
243
+
244
+ Returns:
245
+ List of suggested commands with descriptions
246
+
247
+ Example:
248
+ >>> suggestions = suggest_commands(trace)
249
+ >>> for s in suggestions:
250
+ ... print(f"{s['command']}: {s['description']}")
251
+ """
252
+ suggestions = []
253
+
254
+ if trace is None:
255
+ # No trace loaded - suggest loading
256
+ suggestions.append(
257
+ {
258
+ "command": "trace = load('file.csv')",
259
+ "description": "Load a trace file to get started",
260
+ "reason": "No trace loaded yet",
261
+ }
262
+ )
263
+ suggestions.append(
264
+ {
265
+ "command": "formats = get_supported_formats()",
266
+ "description": "See what file formats are supported",
267
+ "reason": "Helpful for knowing what files you can load",
268
+ }
269
+ )
270
+ return suggestions
271
+
272
+ # Trace is loaded - suggest measurements
273
+ suggestions.append(
274
+ {
275
+ "command": "measure(trace)",
276
+ "description": "Run all standard measurements",
277
+ "reason": "Quick overview of signal properties",
278
+ }
279
+ )
280
+
281
+ # Check if it looks like digital signal
282
+ if hasattr(trace, "data"):
283
+ import numpy as np
284
+
285
+ data = trace.data
286
+ unique_levels = len(np.unique(np.round(data, 2)))
287
+
288
+ if unique_levels < 5:
289
+ # Likely digital
290
+ suggestions.append(
291
+ {
292
+ "command": "digital = to_digital(trace)",
293
+ "description": "Convert to digital trace",
294
+ "reason": "Signal appears to be digital (few voltage levels)",
295
+ }
296
+ )
297
+ suggestions.append(
298
+ {
299
+ "command": "characterize_signal(trace)",
300
+ "description": "Auto-detect signal type and protocol",
301
+ "reason": "May be a protocol like UART, SPI, I2C",
302
+ }
303
+ )
304
+ else:
305
+ # Likely analog
306
+ suggestions.append(
307
+ {
308
+ "command": "freq, mag = fft(trace)",
309
+ "description": "Compute frequency spectrum",
310
+ "reason": "See what frequencies are present",
311
+ }
312
+ )
313
+ suggestions.append(
314
+ {
315
+ "command": "thd(trace)",
316
+ "description": "Measure Total Harmonic Distortion",
317
+ "reason": "Check signal purity",
318
+ }
319
+ )
320
+
321
+ # Always suggest filtering for noisy signals
322
+ suggestions.append(
323
+ {
324
+ "command": "filtered = low_pass(trace, cutoff_hz)",
325
+ "description": "Apply low-pass filter to remove noise",
326
+ "reason": "Clean up high-frequency noise",
327
+ }
328
+ )
329
+
330
+ # Context-specific suggestions
331
+ if context:
332
+ context_lower = context.lower()
333
+ if "uart" in context_lower or "serial" in context_lower:
334
+ suggestions.insert(
335
+ 0,
336
+ {
337
+ "command": "packets = decode_uart(trace)",
338
+ "description": "Decode UART serial data",
339
+ "reason": "You mentioned UART/serial",
340
+ },
341
+ )
342
+ elif "spi" in context_lower:
343
+ suggestions.insert(
344
+ 0,
345
+ {
346
+ "command": "packets = decode_spi(clk_trace, data_trace)",
347
+ "description": "Decode SPI bus",
348
+ "reason": "You mentioned SPI",
349
+ },
350
+ )
351
+ elif "i2c" in context_lower:
352
+ suggestions.insert(
353
+ 0,
354
+ {
355
+ "command": "packets = decode_i2c(scl_trace, sda_trace)",
356
+ "description": "Decode I2C bus",
357
+ "reason": "You mentioned I2C",
358
+ },
359
+ )
360
+
361
+ return suggestions
362
+
363
+
364
+ def explain_result(
365
+ value: Any,
366
+ measurement: str,
367
+ context: dict[str, Any] | None = None,
368
+ ) -> str:
369
+ """Explain a measurement result in plain English.
370
+
371
+ Args:
372
+ value: The measurement value
373
+ measurement: Name of the measurement (e.g., "rise_time")
374
+ context: Additional context (e.g., signal type, expected values)
375
+
376
+ Returns:
377
+ Plain English explanation of the result
378
+
379
+ Example:
380
+ >>> print(explain_result(2.5e-9, "rise_time"))
381
+ "Your rise time is 2.5 nanoseconds, which is..."
382
+ """
383
+ explanations = {
384
+ "rise_time": lambda v: _explain_rise_time(v),
385
+ "fall_time": lambda v: _explain_fall_time(v),
386
+ "frequency": lambda v: _explain_frequency(v),
387
+ "thd": lambda v: _explain_thd(v),
388
+ "snr": lambda v: _explain_snr(v),
389
+ }
390
+
391
+ if measurement.lower() in explanations:
392
+ return explanations[measurement.lower()](value) # type: ignore[no-untyped-call]
393
+
394
+ # Generic explanation
395
+ return f"{measurement}: {value}"
396
+
397
+
398
+ def _explain_rise_time(value: float) -> str:
399
+ """Explain rise time result."""
400
+ if value < 1e-12:
401
+ return f"Rise time: {value * 1e12:.2f} ps - Extremely fast! Sub-picosecond edge."
402
+ elif value < 1e-9:
403
+ return f"Rise time: {value * 1e12:.0f} ps - Very fast, typical of high-speed serial links."
404
+ elif value < 10e-9:
405
+ return f"Rise time: {value * 1e9:.2f} ns - Fast, suitable for most digital circuits."
406
+ elif value < 100e-9:
407
+ return f"Rise time: {value * 1e9:.1f} ns - Moderate, typical of standard logic."
408
+ else:
409
+ return f"Rise time: {value * 1e6:.2f} us - Slow, may limit data rate."
410
+
411
+
412
+ def _explain_fall_time(value: float) -> str:
413
+ """Explain fall time result."""
414
+ if value < 1e-9:
415
+ return f"Fall time: {value * 1e12:.0f} ps - Very fast falling edge."
416
+ elif value < 10e-9:
417
+ return f"Fall time: {value * 1e9:.2f} ns - Fast, good for digital circuits."
418
+ else:
419
+ return f"Fall time: {value * 1e9:.1f} ns - Relatively slow falling edge."
420
+
421
+
422
+ def _explain_frequency(value: float) -> str:
423
+ """Explain frequency result."""
424
+ if value < 1e3:
425
+ return f"Frequency: {value:.1f} Hz - Audio range or very slow signal."
426
+ elif value < 1e6:
427
+ return f"Frequency: {value / 1e3:.2f} kHz - Low frequency signal."
428
+ elif value < 1e9:
429
+ return f"Frequency: {value / 1e6:.2f} MHz - Radio/digital clock range."
430
+ else:
431
+ return f"Frequency: {value / 1e9:.3f} GHz - High-speed digital or RF."
432
+
433
+
434
+ def _explain_thd(value: float) -> str:
435
+ """Explain THD result."""
436
+ if value < -60:
437
+ return f"THD: {value:.1f} dB - Excellent! Very low distortion (high-fidelity)."
438
+ elif value < -40:
439
+ return f"THD: {value:.1f} dB - Good, typical for quality electronics."
440
+ elif value < -20:
441
+ return f"THD: {value:.1f} dB - Fair, some distortion present."
442
+ else:
443
+ return f"THD: {value:.1f} dB - Poor, significant distortion visible."
444
+
445
+
446
+ def _explain_snr(value: float) -> str:
447
+ """Explain SNR result."""
448
+ if value > 60:
449
+ return f"SNR: {value:.1f} dB - Excellent! Very clean signal."
450
+ elif value > 40:
451
+ return f"SNR: {value:.1f} dB - Good signal-to-noise ratio."
452
+ elif value > 20:
453
+ return f"SNR: {value:.1f} dB - Fair, some noise present."
454
+ else:
455
+ return f"SNR: {value:.1f} dB - Poor, noisy signal."
456
+
457
+
458
+ def get_example(function_name: str) -> str | None:
459
+ """Get a code example for a function.
460
+
461
+ Args:
462
+ function_name: Name of the function
463
+
464
+ Returns:
465
+ Example code string or None
466
+ """
467
+ examples = {
468
+ "load": """
469
+ # Load a trace file
470
+ import oscura as osc
471
+ trace = osc.load("capture.csv")
472
+ print(f"Loaded {len(trace.data)} samples")
473
+ """,
474
+ "rise_time": """
475
+ # Measure rise time
476
+ import oscura as osc
477
+ trace = osc.load("signal.csv")
478
+ rt = osc.rise_time(trace)
479
+ print(f"Rise time: {rt*1e9:.2f} ns")
480
+ """,
481
+ "fft": """
482
+ # Compute FFT spectrum
483
+ import oscura as osc
484
+ trace = osc.load("signal.csv")
485
+ freq, mag = osc.fft(trace)
486
+ print(f"Frequency resolution: {freq[1]:.2f} Hz")
487
+ """,
488
+ "measure": """
489
+ # Run all measurements
490
+ import oscura as osc
491
+ trace = osc.load("signal.csv")
492
+ results = osc.measure(trace)
493
+ for name, value in results.items():
494
+ print(f"{name}: {value}")
495
+ """,
496
+ }
497
+
498
+ return examples.get(function_name.lower())