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,32 @@
1
+ """Jupyter and IPython integration for Oscura.
2
+
3
+ This package provides IPython magic commands, rich display integration,
4
+ and Jupyter notebook-specific features.
5
+
6
+ - IPython magic commands (%oscura, %%analyze)
7
+ - Rich HTML display for results
8
+ - Inline plot rendering
9
+ - Progress bars (tqdm integration)
10
+ """
11
+
12
+ from oscura.jupyter.display import (
13
+ MeasurementDisplay,
14
+ TraceDisplay,
15
+ display_measurements,
16
+ display_spectrum,
17
+ display_trace,
18
+ )
19
+ from oscura.jupyter.magic import (
20
+ OscuraMagics,
21
+ load_ipython_extension,
22
+ )
23
+
24
+ __all__ = [
25
+ "MeasurementDisplay",
26
+ "OscuraMagics",
27
+ "TraceDisplay",
28
+ "display_measurements",
29
+ "display_spectrum",
30
+ "display_trace",
31
+ "load_ipython_extension",
32
+ ]
@@ -0,0 +1,268 @@
1
+ """Rich display integration for Jupyter notebooks.
2
+
3
+ This module provides rich HTML display for Oscura objects including
4
+ traces, measurements, and spectral data.
5
+
6
+ - HTML tables for measurements
7
+ - Inline plot rendering
8
+ - Interactive result display
9
+
10
+ Example:
11
+ In [1]: from oscura.jupyter.display import display_trace
12
+ In [2]: display_trace(trace) # Shows rich HTML summary
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any
18
+
19
+ try:
20
+ from IPython.display import HTML, SVG, display
21
+
22
+ IPYTHON_AVAILABLE = True
23
+ except ImportError:
24
+ IPYTHON_AVAILABLE = False
25
+
26
+ class HTML: # type: ignore[no-redef]
27
+ """Fallback HTML class when IPython not available."""
28
+
29
+ def __init__(self, data: str) -> None:
30
+ self.data = data
31
+
32
+ class SVG: # type: ignore[no-redef]
33
+ """Fallback SVG class when IPython not available."""
34
+
35
+ def __init__(self, data: str) -> None:
36
+ self.data = data
37
+
38
+ def display(*args: Any, **kwargs: Any) -> None: # type: ignore[no-redef,misc]
39
+ """Fallback display when IPython not available."""
40
+ for arg in args:
41
+ print(arg)
42
+
43
+
44
+ class TraceDisplay:
45
+ """Rich display wrapper for trace objects.
46
+
47
+ Provides _repr_html_ for Jupyter notebook rendering.
48
+ """
49
+
50
+ def __init__(self, trace: Any, title: str = "Trace") -> None:
51
+ """Initialize trace display.
52
+
53
+ Args:
54
+ trace: WaveformTrace or DigitalTrace object
55
+ title: Display title
56
+ """
57
+ self.trace = trace
58
+ self.title = title
59
+
60
+ def _repr_html_(self) -> str:
61
+ """Generate HTML representation for Jupyter."""
62
+ trace = self.trace
63
+
64
+ # Build info rows
65
+ rows = []
66
+
67
+ if hasattr(trace, "data"):
68
+ rows.append(("Samples", f"{len(trace.data):,}"))
69
+
70
+ if hasattr(trace, "metadata"):
71
+ meta = trace.metadata
72
+ if hasattr(meta, "sample_rate") and meta.sample_rate:
73
+ rate = meta.sample_rate
74
+ if rate >= 1e9:
75
+ rate_str = f"{rate / 1e9:.3f} GSa/s"
76
+ elif rate >= 1e6:
77
+ rate_str = f"{rate / 1e6:.3f} MSa/s"
78
+ else:
79
+ rate_str = f"{rate / 1e3:.3f} kSa/s"
80
+ rows.append(("Sample Rate", rate_str))
81
+
82
+ if hasattr(meta, "channel_name") and meta.channel_name:
83
+ rows.append(("Channel", meta.channel_name))
84
+
85
+ if hasattr(meta, "source_file") and meta.source_file:
86
+ rows.append(("Source", meta.source_file))
87
+
88
+ # Calculate duration if possible
89
+ if hasattr(trace, "data") and hasattr(trace, "metadata"):
90
+ if hasattr(trace.metadata, "sample_rate") and trace.metadata.sample_rate:
91
+ duration = len(trace.data) / trace.metadata.sample_rate
92
+ if duration >= 1:
93
+ dur_str = f"{duration:.3f} s"
94
+ elif duration >= 1e-3:
95
+ dur_str = f"{duration * 1e3:.3f} ms"
96
+ elif duration >= 1e-6:
97
+ dur_str = f"{duration * 1e6:.3f} us"
98
+ else:
99
+ dur_str = f"{duration * 1e9:.3f} ns"
100
+ rows.append(("Duration", dur_str))
101
+
102
+ # Data statistics
103
+ if hasattr(trace, "data"):
104
+ import numpy as np
105
+
106
+ data = trace.data
107
+ rows.append(("Min", f"{np.min(data):.4g}"))
108
+ rows.append(("Max", f"{np.max(data):.4g}"))
109
+ rows.append(("Mean", f"{np.mean(data):.4g}"))
110
+ rows.append(("Std Dev", f"{np.std(data):.4g}"))
111
+
112
+ # Build HTML table
113
+ html = f"""
114
+ <div style="border: 1px solid #ccc; border-radius: 4px; padding: 10px; max-width: 400px;">
115
+ <h4 style="margin: 0 0 10px 0; color: #333;">{self.title}</h4>
116
+ <table style="width: 100%; border-collapse: collapse;">
117
+ """
118
+ for label, value in rows:
119
+ html += f"""
120
+ <tr>
121
+ <td style="padding: 4px 8px; border-bottom: 1px solid #eee; font-weight: bold; color: #666;">{label}</td>
122
+ <td style="padding: 4px 8px; border-bottom: 1px solid #eee;">{value}</td>
123
+ </tr>
124
+ """
125
+ html += """
126
+ </table>
127
+ </div>
128
+ """
129
+ return html
130
+
131
+
132
+ class MeasurementDisplay:
133
+ """Rich display wrapper for measurement results.
134
+
135
+ Provides _repr_html_ for Jupyter notebook rendering.
136
+ """
137
+
138
+ def __init__(self, measurements: dict[str, Any], title: str = "Measurements") -> None:
139
+ """Initialize measurement display.
140
+
141
+ Args:
142
+ measurements: Dictionary of measurement name -> value
143
+ title: Display title
144
+ """
145
+ self.measurements = measurements
146
+ self.title = title
147
+
148
+ def _format_value(self, value: Any) -> str:
149
+ """Format a measurement value with appropriate units."""
150
+ if isinstance(value, float):
151
+ # Determine scale and units for common measurements
152
+ abs_val = abs(value)
153
+ if abs_val == 0:
154
+ return "0"
155
+ elif abs_val >= 1e9:
156
+ return f"{value / 1e9:.3f} G"
157
+ elif abs_val >= 1e6:
158
+ return f"{value / 1e6:.3f} M"
159
+ elif abs_val >= 1e3:
160
+ return f"{value / 1e3:.3f} k"
161
+ elif abs_val >= 1:
162
+ return f"{value:.4f}"
163
+ elif abs_val >= 1e-3:
164
+ return f"{value * 1e3:.3f} m"
165
+ elif abs_val >= 1e-6:
166
+ return f"{value * 1e6:.3f} u"
167
+ elif abs_val >= 1e-9:
168
+ return f"{value * 1e9:.3f} n"
169
+ elif abs_val >= 1e-12:
170
+ return f"{value * 1e12:.3f} p"
171
+ else:
172
+ return f"{value:.3e}"
173
+ else:
174
+ return str(value)
175
+
176
+ def _repr_html_(self) -> str:
177
+ """Generate HTML representation for Jupyter."""
178
+ html = f"""
179
+ <div style="border: 1px solid #ccc; border-radius: 4px; padding: 10px; max-width: 500px;">
180
+ <h4 style="margin: 0 0 10px 0; color: #333;">{self.title}</h4>
181
+ <table style="width: 100%; border-collapse: collapse;">
182
+ <tr style="background-color: #f5f5f5;">
183
+ <th style="padding: 8px; text-align: left; border-bottom: 2px solid #ddd;">Measurement</th>
184
+ <th style="padding: 8px; text-align: right; border-bottom: 2px solid #ddd;">Value</th>
185
+ </tr>
186
+ """
187
+ for name, value in self.measurements.items():
188
+ formatted = self._format_value(value)
189
+ html += f"""
190
+ <tr>
191
+ <td style="padding: 6px 8px; border-bottom: 1px solid #eee;">{name}</td>
192
+ <td style="padding: 6px 8px; border-bottom: 1px solid #eee; text-align: right; font-family: monospace;">{formatted}</td>
193
+ </tr>
194
+ """
195
+ html += """
196
+ </table>
197
+ </div>
198
+ """
199
+ return html
200
+
201
+
202
+ def display_trace(trace: Any, title: str = "Trace") -> None:
203
+ """Display a trace with rich HTML formatting.
204
+
205
+ Args:
206
+ trace: WaveformTrace or DigitalTrace object
207
+ title: Display title
208
+ """
209
+ wrapper = TraceDisplay(trace, title)
210
+ if IPYTHON_AVAILABLE:
211
+ display(HTML(wrapper._repr_html_())) # type: ignore[no-untyped-call]
212
+ else:
213
+ print(wrapper._repr_html_())
214
+
215
+
216
+ def display_measurements(measurements: dict[str, Any], title: str = "Measurements") -> None:
217
+ """Display measurements with rich HTML formatting.
218
+
219
+ Args:
220
+ measurements: Dictionary of measurement name -> value
221
+ title: Display title
222
+ """
223
+ wrapper = MeasurementDisplay(measurements, title)
224
+ if IPYTHON_AVAILABLE:
225
+ display(HTML(wrapper._repr_html_())) # type: ignore[no-untyped-call]
226
+ else:
227
+ for name, value in measurements.items():
228
+ print(f"{name}: {value}")
229
+
230
+
231
+ def display_spectrum(
232
+ frequencies: Any,
233
+ magnitudes: Any,
234
+ title: str = "Spectrum",
235
+ log_scale: bool = True,
236
+ figsize: tuple[int, int] = (10, 4),
237
+ ) -> None:
238
+ """Display a spectrum plot inline in Jupyter.
239
+
240
+ Args:
241
+ frequencies: Frequency array (Hz)
242
+ magnitudes: Magnitude array (dB or linear)
243
+ title: Plot title
244
+ log_scale: Use log scale for x-axis
245
+ figsize: Figure size tuple
246
+ """
247
+ import matplotlib.pyplot as plt
248
+ import numpy as np
249
+
250
+ _fig, ax = plt.subplots(figsize=figsize)
251
+
252
+ if log_scale and np.min(frequencies[frequencies > 0]) > 0:
253
+ ax.semilogx(frequencies, magnitudes)
254
+ else:
255
+ ax.plot(frequencies, magnitudes)
256
+
257
+ ax.set_xlabel("Frequency (Hz)")
258
+ ax.set_ylabel("Magnitude (dB)")
259
+ ax.set_title(title)
260
+ ax.grid(True, alpha=0.3)
261
+
262
+ plt.tight_layout()
263
+
264
+ if IPYTHON_AVAILABLE:
265
+ # Display inline
266
+ plt.show()
267
+ else:
268
+ plt.show()
@@ -0,0 +1,334 @@
1
+ """IPython magic commands for Oscura.
2
+
3
+ This module provides IPython/Jupyter magic commands for convenient
4
+ trace analysis in notebooks.
5
+
6
+ - %oscura load <file> - Load a trace file
7
+ - %oscura measure - Run measurements on current trace
8
+ - %%analyze - Multi-line analysis cell
9
+ - Auto-display of results with rich HTML
10
+
11
+ Example:
12
+ In [1]: %load_ext oscura
13
+
14
+ In [2]: %oscura load capture.wfm
15
+ Loaded: WaveformTrace with 10000 samples @ 1 GSa/s
16
+
17
+ In [3]: %oscura measure rise_time fall_time
18
+ rise_time: 2.5 ns
19
+ fall_time: 2.8 ns
20
+
21
+ In [4]: %%analyze
22
+ ...: trace = load("capture.wfm")
23
+ ...: print(f"THD: {thd(trace):.2f} dB")
24
+
25
+ References:
26
+ - IPython Magic Commands documentation
27
+ - Jupyter display architecture
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from typing import TYPE_CHECKING, Any
33
+
34
+ if TYPE_CHECKING:
35
+ from IPython.core.interactiveshell import InteractiveShell
36
+
37
+
38
+ # Store current trace for magic commands
39
+ _current_trace: Any = None
40
+ _current_file: str | None = None
41
+
42
+
43
+ def get_current_trace() -> Any:
44
+ """Get the currently loaded trace from magic commands."""
45
+ return _current_trace
46
+
47
+
48
+ def set_current_trace(trace: Any, filename: str | None = None) -> None:
49
+ """Set the current trace for magic commands."""
50
+ global _current_trace, _current_file
51
+ _current_trace = trace
52
+ _current_file = filename
53
+
54
+
55
+ try:
56
+ from IPython.core.magic import (
57
+ Magics,
58
+ cell_magic,
59
+ line_magic,
60
+ magics_class,
61
+ )
62
+ from IPython.display import HTML, display # noqa: F401
63
+
64
+ IPYTHON_AVAILABLE = True
65
+ except ImportError:
66
+ IPYTHON_AVAILABLE = False
67
+
68
+ class Magics: # type: ignore[no-redef]
69
+ """Fallback Magics class when IPython not available."""
70
+
71
+ def magics_class(cls: type[Any]) -> type[Any]: # type: ignore[no-redef,misc]
72
+ """Dummy decorator when IPython not available."""
73
+ return cls
74
+
75
+ def line_magic(func): # type: ignore[no-untyped-def]
76
+ """Dummy decorator."""
77
+ return func
78
+
79
+ def cell_magic(func): # type: ignore[no-untyped-def]
80
+ """Dummy decorator."""
81
+ return func
82
+
83
+
84
+ @magics_class
85
+ class OscuraMagics(Magics): # type: ignore[misc]
86
+ """IPython magics for Oscura analysis.
87
+
88
+ Provides convenient shortcuts for loading traces, running measurements,
89
+ and displaying results in Jupyter notebooks.
90
+ """
91
+
92
+ @line_magic # type: ignore[misc, untyped-decorator]
93
+ def oscura(self, line: str) -> Any:
94
+ """Oscura line magic for quick operations.
95
+
96
+ Usage:
97
+ %oscura load <filename> - Load a trace file
98
+ %oscura measure [names...] - Run measurements
99
+ %oscura info - Show current trace info
100
+ %oscura formats - List supported formats
101
+ %oscura help - Show help
102
+
103
+ Args:
104
+ line: Magic command arguments
105
+
106
+ Returns:
107
+ Command result or None
108
+ """
109
+ import oscura as osc
110
+
111
+ parts = line.strip().split()
112
+ if not parts:
113
+ return self._show_help()
114
+
115
+ cmd = parts[0].lower()
116
+
117
+ if cmd == "load":
118
+ if len(parts) < 2:
119
+ print("Usage: %oscura load <filename>")
120
+ return None
121
+ filename = " ".join(parts[1:])
122
+ return self._load_trace(filename)
123
+
124
+ elif cmd == "measure":
125
+ measurements = parts[1:] if len(parts) > 1 else None
126
+ return self._run_measurements(measurements)
127
+
128
+ elif cmd == "info":
129
+ return self._show_trace_info()
130
+
131
+ elif cmd == "formats":
132
+ formats = osc.get_supported_formats()
133
+ print("Supported formats:")
134
+ for fmt in formats:
135
+ print(f" - {fmt}")
136
+ return formats
137
+
138
+ elif cmd == "help":
139
+ return self._show_help()
140
+
141
+ else:
142
+ print(f"Unknown command: {cmd}")
143
+ return self._show_help()
144
+
145
+ def _load_trace(self, filename: str) -> Any:
146
+ """Load a trace file and store as current."""
147
+ import oscura as osc
148
+
149
+ try:
150
+ trace = osc.load(filename)
151
+ set_current_trace(trace, filename)
152
+
153
+ # Display summary
154
+ info = {
155
+ "file": filename,
156
+ "type": type(trace).__name__,
157
+ "samples": len(trace.data) if hasattr(trace, "data") else "N/A",
158
+ "sample_rate": f"{trace.metadata.sample_rate / 1e9:.3f} GSa/s"
159
+ if hasattr(trace, "metadata")
160
+ else "N/A",
161
+ }
162
+
163
+ print(f"Loaded: {info['type']} with {info['samples']} samples @ {info['sample_rate']}")
164
+ return trace
165
+
166
+ except Exception as e:
167
+ print(f"Error loading {filename}: {e}")
168
+ return None
169
+
170
+ def _run_measurements(self, measurement_names: list[str] | None) -> dict[str, Any]:
171
+ """Run measurements on current trace."""
172
+ import oscura as osc
173
+
174
+ trace = get_current_trace()
175
+ if trace is None:
176
+ print("No trace loaded. Use: %oscura load <filename>")
177
+ return {}
178
+
179
+ if measurement_names:
180
+ # Run specific measurements
181
+ results = {}
182
+ for name in measurement_names:
183
+ if hasattr(osc, name):
184
+ try:
185
+ func = getattr(osc, name)
186
+ results[name] = func(trace)
187
+ except Exception as e:
188
+ results[name] = f"Error: {e}"
189
+ else:
190
+ results[name] = "Unknown measurement"
191
+ else:
192
+ # Run all measurements
193
+ try:
194
+ results = osc.measure(trace)
195
+ except Exception as e:
196
+ print(f"Error running measurements: {e}")
197
+ return {}
198
+
199
+ # Display results
200
+ self._display_measurements(results)
201
+ return results
202
+
203
+ def _display_measurements(self, results: dict[str, Any]) -> None:
204
+ """Display measurement results with formatting."""
205
+ if IPYTHON_AVAILABLE:
206
+ from oscura.jupyter.display import display_measurements
207
+
208
+ display_measurements(results)
209
+ else:
210
+ for name, value in results.items():
211
+ if isinstance(value, float):
212
+ print(f"{name}: {value:.6g}")
213
+ else:
214
+ print(f"{name}: {value}")
215
+
216
+ def _show_trace_info(self) -> dict[str, Any] | None:
217
+ """Show information about current trace."""
218
+ trace = get_current_trace()
219
+ if trace is None:
220
+ print("No trace loaded. Use: %oscura load <filename>")
221
+ return None
222
+
223
+ info = {
224
+ "file": _current_file,
225
+ "type": type(trace).__name__,
226
+ }
227
+
228
+ if hasattr(trace, "data"):
229
+ info["samples"] = len(trace.data) # type: ignore[assignment]
230
+
231
+ if hasattr(trace, "metadata"):
232
+ meta = trace.metadata
233
+ if hasattr(meta, "sample_rate"):
234
+ info["sample_rate"] = meta.sample_rate
235
+ if hasattr(meta, "channel_name"):
236
+ info["channel"] = meta.channel_name
237
+
238
+ for key, value in info.items():
239
+ print(f"{key}: {value}")
240
+
241
+ return info
242
+
243
+ def _show_help(self) -> None:
244
+ """Show magic command help."""
245
+ help_text = """
246
+ Oscura Magic Commands
247
+ =======================
248
+
249
+ %oscura load <filename> Load a trace file
250
+ %oscura measure [names...] Run measurements on current trace
251
+ %oscura info Show current trace info
252
+ %oscura formats List supported file formats
253
+ %oscura help Show this help
254
+
255
+ %%analyze Multi-line analysis cell magic
256
+
257
+ Available measurements: rise_time, fall_time, frequency, period,
258
+ amplitude, rms, overshoot, undershoot, thd, snr, sinad
259
+
260
+ Example:
261
+ %oscura load capture.wfm
262
+ %oscura measure rise_time fall_time
263
+ """
264
+ print(help_text)
265
+
266
+ @cell_magic # type: ignore[misc, untyped-decorator]
267
+ def analyze(self, line: str, cell: str) -> Any:
268
+ """Cell magic for multi-line analysis.
269
+
270
+ Args:
271
+ line: Magic command line arguments (unused).
272
+ cell: Multi-line cell content to execute.
273
+
274
+ Returns:
275
+ Result from cell execution (if 'result' variable defined).
276
+
277
+ Usage:
278
+ %%analyze
279
+ trace = load("capture.wfm")
280
+ result = measure(trace)
281
+ print(f"Rise time: {result['rise_time']}")
282
+
283
+ All oscura functions are auto-imported in the cell namespace.
284
+ """
285
+ import oscura as osc
286
+
287
+ # Build execution namespace with oscura imports
288
+ namespace = {
289
+ "osc": osc,
290
+ "load": osc.load,
291
+ "measure": osc.measure,
292
+ "fft": osc.fft,
293
+ "psd": osc.psd,
294
+ "thd": osc.thd,
295
+ "snr": osc.snr,
296
+ "rise_time": osc.rise_time,
297
+ "fall_time": osc.fall_time,
298
+ "frequency": osc.frequency,
299
+ "amplitude": osc.amplitude,
300
+ "low_pass": osc.low_pass,
301
+ "high_pass": osc.high_pass,
302
+ }
303
+
304
+ # Add current trace if available
305
+ trace = get_current_trace()
306
+ if trace is not None:
307
+ namespace["trace"] = trace
308
+
309
+ # Execute cell
310
+ exec(cell, namespace)
311
+
312
+ # Return any result variable if defined
313
+ return namespace.get("result")
314
+
315
+
316
+ def load_ipython_extension(ipython: InteractiveShell) -> None:
317
+ """Load Oscura IPython extension.
318
+
319
+ Called when user runs: %load_ext oscura
320
+
321
+ Args:
322
+ ipython: The IPython shell instance
323
+ """
324
+ ipython.register_magics(OscuraMagics)
325
+ print("Oscura magics loaded. Type '%oscura help' for usage.")
326
+
327
+
328
+ def unload_ipython_extension(ipython: InteractiveShell) -> None:
329
+ """Unload Oscura IPython extension.
330
+
331
+ Args:
332
+ ipython: The IPython shell instance
333
+ """
334
+ # IPython handles magic cleanup automatically