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,523 @@
1
+ """GPU acceleration backend with automatic numpy fallback.
2
+
3
+ This module provides optional GPU acceleration using CuPy with seamless
4
+ fallback to NumPy when CuPy is unavailable or GPU processing is disabled.
5
+
6
+ The GPU backend is lazy-initialized and memory-safe, automatically transferring
7
+ data to/from GPU as needed. GPU usage can be controlled via the environment
8
+ variable OSCURA_USE_GPU (0 to disable, 1 to enable).
9
+
10
+
11
+ Example:
12
+ >>> from oscura.core.gpu_backend import gpu
13
+ >>> # Automatically uses GPU if available, numpy otherwise
14
+ >>> freqs = gpu.fft(signal_data)
15
+ >>>
16
+ >>> # Force CPU-only operation
17
+ >>> from oscura.core.gpu_backend import GPUBackend
18
+ >>> cpu_only = GPUBackend(force_cpu=True)
19
+ >>> freqs = cpu_only.fft(signal_data)
20
+
21
+ Configuration:
22
+ Set OSCURA_USE_GPU environment variable to control GPU usage:
23
+ - OSCURA_USE_GPU=0: Force CPU-only operation
24
+ - OSCURA_USE_GPU=1: Enable GPU if available (default)
25
+
26
+ References:
27
+ - CuPy documentation: https://docs.cupy.dev/
28
+ - NumPy FFT module: https://numpy.org/doc/stable/reference/routines.fft.html
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import os
34
+ import warnings
35
+ from typing import TYPE_CHECKING, Any, Literal
36
+
37
+ import numpy as np
38
+
39
+ if TYPE_CHECKING:
40
+ from numpy.typing import NDArray
41
+
42
+
43
+ class GPUBackend:
44
+ """Optional GPU acceleration with transparent numpy fallback.
45
+
46
+ This class provides GPU-accelerated versions of common array operations
47
+ with automatic fallback to NumPy when CuPy is unavailable or GPU is disabled.
48
+
49
+ GPU availability is checked lazily on first use, and data is automatically
50
+ transferred between CPU and GPU as needed for transparent operation.
51
+
52
+ Args:
53
+ force_cpu: If True, always use CPU (NumPy) even if GPU is available.
54
+ Useful for testing or when GPU memory is limited.
55
+
56
+ Attributes:
57
+ gpu_available: True if CuPy is available and GPU is enabled.
58
+ using_gpu: True if currently using GPU backend (may differ from
59
+ gpu_available if lazy initialization hasn't occurred yet).
60
+
61
+ Example:
62
+ >>> backend = GPUBackend()
63
+ >>> if backend.gpu_available:
64
+ ... print("Using GPU acceleration")
65
+ >>> else:
66
+ ... print("Using CPU (NumPy) fallback")
67
+ >>>
68
+ >>> # All operations work identically regardless of backend
69
+ >>> result = backend.fft(data)
70
+
71
+ References:
72
+ PERF-001 through PERF-004: GPU acceleration requirements
73
+ """
74
+
75
+ def __init__(self, force_cpu: bool = False) -> None:
76
+ """Initialize GPU backend with optional CPU-only mode.
77
+
78
+ Args:
79
+ force_cpu: If True, never use GPU even if available.
80
+ """
81
+ self._force_cpu = force_cpu
82
+ self._gpu_available: bool | None = None
83
+ self._cp: Any = None # CuPy module if available
84
+ self._initialized = False
85
+
86
+ def _check_gpu(self) -> bool:
87
+ """Check if GPU/CuPy is available and should be used.
88
+
89
+ This is called lazily on first operation to avoid import overhead
90
+ when GPU is not needed.
91
+
92
+ Returns:
93
+ True if GPU should be used, False to fall back to NumPy.
94
+ """
95
+ if self._initialized:
96
+ return self._gpu_available or False
97
+
98
+ self._initialized = True
99
+
100
+ # Check environment variable override
101
+ use_gpu_env = os.environ.get("OSCURA_USE_GPU", "1")
102
+ if use_gpu_env == "0" or self._force_cpu:
103
+ self._gpu_available = False
104
+ return False
105
+
106
+ # Try to import CuPy
107
+ try:
108
+ import cupy as cp # type: ignore[import-not-found]
109
+
110
+ # Verify GPU is actually accessible
111
+ try:
112
+ # Try a simple operation to verify GPU works
113
+ _ = cp.array([1.0])
114
+ self._cp = cp
115
+ self._gpu_available = True
116
+ return True
117
+ except Exception as e:
118
+ warnings.warn(
119
+ f"CuPy is installed but GPU is not accessible: {e}. Falling back to NumPy.",
120
+ RuntimeWarning,
121
+ stacklevel=2,
122
+ )
123
+ self._gpu_available = False
124
+ return False
125
+ except ImportError:
126
+ # CuPy not installed - silent fallback
127
+ self._gpu_available = False
128
+ return False
129
+
130
+ @property
131
+ def gpu_available(self) -> bool:
132
+ """Check if GPU acceleration is available.
133
+
134
+ Returns:
135
+ True if CuPy is available and GPU can be used.
136
+ """
137
+ if not self._initialized:
138
+ self._check_gpu()
139
+ return self._gpu_available or False
140
+
141
+ @property
142
+ def using_gpu(self) -> bool:
143
+ """Alias for gpu_available for backwards compatibility.
144
+
145
+ Returns:
146
+ True if currently using GPU backend.
147
+ """
148
+ return self.gpu_available
149
+
150
+ def _to_cpu(self, array: Any) -> NDArray[Any]:
151
+ """Transfer array from GPU to CPU if needed.
152
+
153
+ Args:
154
+ array: Array that may be on GPU or CPU.
155
+
156
+ Returns:
157
+ NumPy array on CPU.
158
+ """
159
+ if self.gpu_available and self._cp is not None:
160
+ if isinstance(array, self._cp.ndarray):
161
+ return self._cp.asnumpy(array) # type: ignore[no-any-return]
162
+ return np.asarray(array)
163
+
164
+ def _to_gpu(self, array: NDArray[Any]) -> Any:
165
+ """Transfer array from CPU to GPU if GPU is enabled.
166
+
167
+ Args:
168
+ array: NumPy array on CPU.
169
+
170
+ Returns:
171
+ CuPy array on GPU if GPU is available, otherwise NumPy array.
172
+ """
173
+ if self.gpu_available and self._cp is not None:
174
+ return self._cp.asarray(array)
175
+ return array
176
+
177
+ def fft(
178
+ self,
179
+ data: NDArray[np.complex128] | NDArray[np.float64],
180
+ n: int | None = None,
181
+ axis: int = -1,
182
+ norm: Literal["backward", "ortho", "forward"] | None = None,
183
+ ) -> NDArray[np.complex128]:
184
+ """GPU-accelerated FFT with automatic fallback to NumPy.
185
+
186
+ Computes the one-dimensional discrete Fourier Transform using GPU
187
+ if available, otherwise falls back to NumPy.
188
+
189
+ Args:
190
+ data: Input array (can be real or complex).
191
+ n: Length of the transformed axis. If None, uses data.shape[axis].
192
+ axis: Axis over which to compute the FFT.
193
+ norm: Normalization mode ("backward", "ortho", or "forward").
194
+
195
+ Returns:
196
+ Complex-valued FFT of the input array (always NumPy array on CPU).
197
+
198
+ Example:
199
+ >>> signal = np.random.randn(1000)
200
+ >>> spectrum = gpu.fft(signal)
201
+ >>> # Result is always NumPy array, regardless of backend
202
+
203
+ References:
204
+ SPE-001: Standard FFT Computation
205
+ PERF-001: GPU-accelerated FFT
206
+ """
207
+ if self._check_gpu() and self._cp is not None:
208
+ # GPU path
209
+ gpu_data = self._to_gpu(data)
210
+ result = self._cp.fft.fft(gpu_data, n=n, axis=axis, norm=norm)
211
+ return self._to_cpu(result)
212
+ else:
213
+ # CPU fallback
214
+ return np.fft.fft(data, n=n, axis=axis, norm=norm)
215
+
216
+ def ifft(
217
+ self,
218
+ data: NDArray[np.complex128],
219
+ n: int | None = None,
220
+ axis: int = -1,
221
+ norm: Literal["backward", "ortho", "forward"] | None = None,
222
+ ) -> NDArray[np.complex128]:
223
+ """GPU-accelerated inverse FFT with automatic fallback.
224
+
225
+ Computes the one-dimensional inverse discrete Fourier Transform.
226
+
227
+ Args:
228
+ data: Input complex array.
229
+ n: Length of the transformed axis. If None, uses data.shape[axis].
230
+ axis: Axis over which to compute the IFFT.
231
+ norm: Normalization mode ("backward", "ortho", or "forward").
232
+
233
+ Returns:
234
+ Complex-valued IFFT of the input array (always NumPy array on CPU).
235
+
236
+ Example:
237
+ >>> spectrum = np.fft.fft(signal)
238
+ >>> recovered = gpu.ifft(spectrum)
239
+
240
+ References:
241
+ SPE-001: Standard FFT Computation
242
+ PERF-001: GPU-accelerated FFT
243
+ """
244
+ if self._check_gpu() and self._cp is not None:
245
+ # GPU path
246
+ gpu_data = self._to_gpu(data)
247
+ result = self._cp.fft.ifft(gpu_data, n=n, axis=axis, norm=norm)
248
+ return self._to_cpu(result)
249
+ else:
250
+ # CPU fallback
251
+ return np.fft.ifft(data, n=n, axis=axis, norm=norm)
252
+
253
+ def rfft(
254
+ self,
255
+ data: NDArray[np.float64],
256
+ n: int | None = None,
257
+ axis: int = -1,
258
+ norm: Literal["backward", "ortho", "forward"] | None = None,
259
+ ) -> NDArray[np.complex128]:
260
+ """GPU-accelerated real FFT with automatic fallback.
261
+
262
+ Computes the one-dimensional FFT of real-valued input, returning
263
+ only the positive frequency components (memory efficient).
264
+
265
+ Args:
266
+ data: Input real-valued array.
267
+ n: Length of the transformed axis. If None, uses data.shape[axis].
268
+ axis: Axis over which to compute the FFT.
269
+ norm: Normalization mode ("backward", "ortho", or "forward").
270
+
271
+ Returns:
272
+ Complex-valued FFT (positive frequencies only) on CPU.
273
+
274
+ Example:
275
+ >>> signal = np.random.randn(1000)
276
+ >>> spectrum = gpu.rfft(signal)
277
+ >>> # Result has length n//2 + 1
278
+
279
+ References:
280
+ SPE-001: Standard FFT Computation
281
+ PERF-001: GPU-accelerated FFT
282
+ """
283
+ if self._check_gpu() and self._cp is not None:
284
+ # GPU path
285
+ gpu_data = self._to_gpu(data)
286
+ result = self._cp.fft.rfft(gpu_data, n=n, axis=axis, norm=norm)
287
+ return self._to_cpu(result)
288
+ else:
289
+ # CPU fallback
290
+ return np.fft.rfft(data, n=n, axis=axis, norm=norm)
291
+
292
+ def irfft(
293
+ self,
294
+ data: NDArray[np.complex128],
295
+ n: int | None = None,
296
+ axis: int = -1,
297
+ norm: Literal["backward", "ortho", "forward"] | None = None,
298
+ ) -> NDArray[np.float64]:
299
+ """GPU-accelerated inverse real FFT with automatic fallback.
300
+
301
+ Computes the inverse FFT of rfft, returning real-valued output.
302
+
303
+ Args:
304
+ data: Input complex array (from rfft).
305
+ n: Length of output. If None, uses (data.shape[axis] - 1) * 2.
306
+ axis: Axis over which to compute the IFFT.
307
+ norm: Normalization mode ("backward", "ortho", or "forward").
308
+
309
+ Returns:
310
+ Real-valued IFFT on CPU.
311
+
312
+ Example:
313
+ >>> spectrum = gpu.rfft(signal)
314
+ >>> recovered = gpu.irfft(spectrum)
315
+
316
+ References:
317
+ SPE-001: Standard FFT Computation
318
+ PERF-001: GPU-accelerated FFT
319
+ """
320
+ if self._check_gpu() and self._cp is not None:
321
+ # GPU path
322
+ gpu_data = self._to_gpu(data)
323
+ result = self._cp.fft.irfft(gpu_data, n=n, axis=axis, norm=norm)
324
+ return self._to_cpu(result)
325
+ else:
326
+ # CPU fallback
327
+ return np.fft.irfft(data, n=n, axis=axis, norm=norm)
328
+
329
+ def convolve(
330
+ self,
331
+ data: NDArray[np.float64],
332
+ kernel: NDArray[np.float64],
333
+ mode: Literal["full", "valid", "same"] = "full",
334
+ ) -> NDArray[np.float64]:
335
+ """GPU-accelerated convolution with automatic fallback.
336
+
337
+ Computes the discrete linear convolution of data with kernel.
338
+ Uses FFT-based convolution for efficiency on large arrays.
339
+
340
+ Args:
341
+ data: Input signal array.
342
+ kernel: Convolution kernel (filter coefficients).
343
+ mode: Convolution mode:
344
+ - "full": Full convolution (length N + M - 1)
345
+ - "valid": Only where data and kernel fully overlap
346
+ - "same": Same length as data (centered)
347
+
348
+ Returns:
349
+ Convolved array on CPU.
350
+
351
+ Example:
352
+ >>> signal = np.random.randn(1000)
353
+ >>> kernel = np.array([0.25, 0.5, 0.25]) # Simple smoothing
354
+ >>> smoothed = gpu.convolve(signal, kernel, mode="same")
355
+
356
+ References:
357
+ PERF-002: GPU-accelerated convolution
358
+ """
359
+ if self._check_gpu() and self._cp is not None:
360
+ # GPU path
361
+ gpu_data = self._to_gpu(data)
362
+ gpu_kernel = self._to_gpu(kernel)
363
+ result = self._cp.convolve(gpu_data, gpu_kernel, mode=mode)
364
+ return self._to_cpu(result)
365
+ else:
366
+ # CPU fallback
367
+ return np.convolve(data, kernel, mode=mode)
368
+
369
+ def correlate(
370
+ self,
371
+ a: NDArray[np.float64],
372
+ v: NDArray[np.float64],
373
+ mode: Literal["full", "valid", "same"] = "full",
374
+ ) -> NDArray[np.float64]:
375
+ """GPU-accelerated correlation with automatic fallback.
376
+
377
+ Computes the cross-correlation of two 1-dimensional sequences.
378
+
379
+ Args:
380
+ a: First input sequence.
381
+ v: Second input sequence.
382
+ mode: Correlation mode ("full", "valid", or "same").
383
+
384
+ Returns:
385
+ Cross-correlation on CPU.
386
+
387
+ Example:
388
+ >>> signal = np.random.randn(1000)
389
+ >>> template = signal[100:200]
390
+ >>> corr = gpu.correlate(signal, template, mode="valid")
391
+ >>> # Find best match location
392
+ >>> match_idx = np.argmax(corr)
393
+
394
+ References:
395
+ PERF-003: GPU-accelerated pattern matching
396
+ """
397
+ if self._check_gpu() and self._cp is not None:
398
+ # GPU path
399
+ gpu_a = self._to_gpu(a)
400
+ gpu_v = self._to_gpu(v)
401
+ result = self._cp.correlate(gpu_a, gpu_v, mode=mode)
402
+ return self._to_cpu(result)
403
+ else:
404
+ # CPU fallback
405
+ return np.correlate(a, v, mode=mode)
406
+
407
+ def histogram(
408
+ self,
409
+ data: NDArray[np.float64],
410
+ bins: int | NDArray[np.float64] = 10,
411
+ range: tuple[float, float] | None = None,
412
+ density: bool = False,
413
+ ) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
414
+ """GPU-accelerated histogram with automatic fallback.
415
+
416
+ Computes the histogram of a dataset, useful for statistical analysis
417
+ and signal quality metrics.
418
+
419
+ Args:
420
+ data: Input data array.
421
+ bins: Number of bins or array of bin edges.
422
+ range: Lower and upper range of bins. If None, uses (data.min(), data.max()).
423
+ density: If True, return probability density instead of counts.
424
+
425
+ Returns:
426
+ Tuple of (counts, bin_edges) both on CPU.
427
+
428
+ Example:
429
+ >>> signal = np.random.randn(10000)
430
+ >>> counts, edges = gpu.histogram(signal, bins=100)
431
+ >>> # Plot histogram
432
+ >>> plt.bar(edges[:-1], counts, width=np.diff(edges))
433
+
434
+ References:
435
+ PERF-004: GPU-accelerated histogram computation
436
+ """
437
+ if self._check_gpu() and self._cp is not None:
438
+ # GPU path
439
+ gpu_data = self._to_gpu(data)
440
+ # Transfer bins to GPU if it's an array (not just int)
441
+ gpu_bins = self._to_gpu(bins) if isinstance(bins, np.ndarray) else bins
442
+ counts, edges = self._cp.histogram(
443
+ gpu_data, bins=gpu_bins, range=range, density=density
444
+ )
445
+ return self._to_cpu(counts), self._to_cpu(edges)
446
+ else:
447
+ # CPU fallback
448
+ return np.histogram(data, bins=bins, range=range, density=density) # type: ignore[no-any-return]
449
+
450
+ def dot(
451
+ self,
452
+ a: NDArray[np.float64],
453
+ b: NDArray[np.float64],
454
+ ) -> NDArray[np.float64] | np.float64:
455
+ """GPU-accelerated dot product with automatic fallback.
456
+
457
+ Computes the dot product of two arrays, useful for correlation
458
+ and pattern matching operations.
459
+
460
+ Args:
461
+ a: First array.
462
+ b: Second array.
463
+
464
+ Returns:
465
+ Dot product on CPU (scalar or array depending on input dimensions).
466
+
467
+ Example:
468
+ >>> a = np.random.randn(1000)
469
+ >>> b = np.random.randn(1000)
470
+ >>> similarity = gpu.dot(a, b)
471
+
472
+ References:
473
+ PERF-003: GPU-accelerated matrix operations
474
+ """
475
+ if self._check_gpu() and self._cp is not None:
476
+ # GPU path
477
+ gpu_a = self._to_gpu(a)
478
+ gpu_b = self._to_gpu(b)
479
+ result = self._cp.dot(gpu_a, gpu_b)
480
+ return self._to_cpu(result) # type: ignore[return-value]
481
+ else:
482
+ # CPU fallback
483
+ return np.dot(a, b) # type: ignore[return-value, no-any-return]
484
+
485
+ def matmul(
486
+ self,
487
+ a: NDArray[np.float64],
488
+ b: NDArray[np.float64],
489
+ ) -> NDArray[np.float64]:
490
+ """GPU-accelerated matrix multiplication with automatic fallback.
491
+
492
+ Computes the matrix product of two arrays.
493
+
494
+ Args:
495
+ a: First matrix.
496
+ b: Second matrix.
497
+
498
+ Returns:
499
+ Matrix product on CPU.
500
+
501
+ Example:
502
+ >>> A = np.random.randn(100, 50)
503
+ >>> B = np.random.randn(50, 100)
504
+ >>> C = gpu.matmul(A, B)
505
+
506
+ References:
507
+ PERF-003: GPU-accelerated matrix operations
508
+ """
509
+ if self._check_gpu() and self._cp is not None:
510
+ # GPU path
511
+ gpu_a = self._to_gpu(a)
512
+ gpu_b = self._to_gpu(b)
513
+ result = self._cp.matmul(gpu_a, gpu_b)
514
+ return self._to_cpu(result) # type: ignore[return-value]
515
+ else:
516
+ # CPU fallback
517
+ return np.matmul(a, b) # type: ignore[return-value, no-any-return]
518
+
519
+
520
+ # Module-level singleton for convenient access
521
+ gpu = GPUBackend()
522
+
523
+ __all__ = ["GPUBackend", "gpu"]