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,372 @@
1
+ """Safe Operating Area (SOA) analysis for Oscura.
2
+
3
+ Provides SOA checking and visualization for power semiconductor devices.
4
+
5
+
6
+ Example:
7
+ >>> from oscura.analyzers.power.soa import soa_analysis, SOALimit
8
+ >>> limits = [
9
+ ... SOALimit(v_max=100, i_max=50, pulse_width=1e-6),
10
+ ... SOALimit(v_max=80, i_max=100, pulse_width=10e-6),
11
+ ... ]
12
+ >>> result = soa_analysis(v_trace, i_trace, limits)
13
+ >>> print(f"SOA violations: {len(result['violations'])}")
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import dataclass
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ import numpy as np
22
+
23
+ if TYPE_CHECKING:
24
+ from matplotlib.figure import Figure
25
+
26
+ from oscura.core.types import WaveformTrace
27
+
28
+
29
+ @dataclass
30
+ class SOALimit:
31
+ """Defines a point on the SOA boundary.
32
+
33
+ The SOA is typically defined by a piecewise linear boundary in
34
+ log-log V-I space, with different limits for different pulse widths.
35
+
36
+ Attributes:
37
+ v_max: Maximum voltage at this limit point (Volts).
38
+ i_max: Maximum current at this limit point (Amps).
39
+ pulse_width: Pulse duration for this limit (seconds).
40
+ Use np.inf for DC limit.
41
+ name: Optional name for this limit point.
42
+ """
43
+
44
+ v_max: float
45
+ i_max: float
46
+ pulse_width: float = np.inf
47
+ name: str = ""
48
+
49
+
50
+ @dataclass
51
+ class SOAViolation:
52
+ """Information about an SOA violation.
53
+
54
+ Attributes:
55
+ timestamp: Time of violation (seconds).
56
+ sample_index: Sample index of violation.
57
+ voltage: Voltage at violation point.
58
+ current: Current at violation point.
59
+ limit: The SOA limit that was violated.
60
+ margin: How far inside (negative) or outside (positive) the limit.
61
+ """
62
+
63
+ timestamp: float
64
+ sample_index: int
65
+ voltage: float
66
+ current: float
67
+ limit: SOALimit
68
+ margin: float
69
+
70
+
71
+ def soa_analysis(
72
+ voltage: WaveformTrace,
73
+ current: WaveformTrace,
74
+ limits: list[SOALimit],
75
+ *,
76
+ pulse_width: float | None = None,
77
+ ) -> dict[str, Any]:
78
+ """Analyze voltage-current trajectory against SOA limits.
79
+
80
+ Args:
81
+ voltage: Voltage waveform trace.
82
+ current: Current waveform trace.
83
+ limits: List of SOA limit points.
84
+ pulse_width: Pulse width to use for limit selection.
85
+ If None, uses DC limits.
86
+
87
+ Returns:
88
+ Dictionary with:
89
+ - passed: True if no violations
90
+ - violations: List of SOAViolation objects
91
+ - v_trajectory: Voltage values
92
+ - i_trajectory: Current values
93
+ - min_margin: Minimum margin to SOA boundary (negative = inside)
94
+ - applicable_limits: Limits used for this pulse width
95
+
96
+ Example:
97
+ >>> result = soa_analysis(v_ds, i_d, soa_limits)
98
+ >>> if not result['passed']:
99
+ ... print(f"SOA violated at {result['violations'][0].timestamp}s")
100
+ """
101
+ v_data = voltage.data
102
+ i_data = current.data
103
+
104
+ # Ensure same length
105
+ min_len = min(len(v_data), len(i_data))
106
+ v_data = v_data[:min_len]
107
+ i_data = i_data[:min_len]
108
+ sample_period = voltage.metadata.time_base
109
+
110
+ # Select applicable limits based on pulse width
111
+ if pulse_width is None:
112
+ pulse_width = np.inf
113
+
114
+ applicable_limits = [l for l in limits if l.pulse_width >= pulse_width] # noqa: E741
115
+ if not applicable_limits:
116
+ applicable_limits = limits # Use all if none match
117
+
118
+ # Build SOA boundary (interpolate between limit points)
119
+ # Sort by voltage
120
+ sorted_limits = sorted(applicable_limits, key=lambda l: l.v_max) # noqa: E741
121
+
122
+ violations: list[SOAViolation] = []
123
+ margins: list[float] = []
124
+
125
+ for i in range(len(v_data)):
126
+ v = abs(v_data[i])
127
+ current_i = abs(i_data[i])
128
+
129
+ # Find applicable limit (linear interpolation in log-log space)
130
+ i_limit = _interpolate_soa_limit(v, sorted_limits)
131
+
132
+ margin = i_limit - current_i
133
+ margins.append(margin)
134
+
135
+ if current_i > i_limit:
136
+ # Find which specific limit was violated
137
+ for limit in sorted_limits:
138
+ if v <= limit.v_max and current_i > limit.i_max:
139
+ violations.append(
140
+ SOAViolation(
141
+ timestamp=i * sample_period,
142
+ sample_index=i,
143
+ voltage=float(v_data[i]),
144
+ current=float(i_data[i]),
145
+ limit=limit,
146
+ margin=-margin,
147
+ )
148
+ )
149
+ break
150
+
151
+ return {
152
+ "passed": len(violations) == 0,
153
+ "violations": violations,
154
+ "v_trajectory": v_data,
155
+ "i_trajectory": i_data,
156
+ "min_margin": float(np.min(margins)) if margins else 0.0,
157
+ "applicable_limits": applicable_limits,
158
+ }
159
+
160
+
161
+ def _interpolate_soa_limit(voltage: float, limits: list[SOALimit]) -> float:
162
+ """Interpolate SOA current limit at given voltage.
163
+
164
+ Uses log-log interpolation between limit points.
165
+
166
+ Args:
167
+ voltage: Voltage at which to interpolate current limit
168
+ limits: List of SOALimit points defining the boundary
169
+
170
+ Returns:
171
+ Interpolated current limit in Amps
172
+ """
173
+ if len(limits) == 0:
174
+ return np.inf # type: ignore[no-any-return]
175
+
176
+ if len(limits) == 1:
177
+ if voltage <= limits[0].v_max:
178
+ return limits[0].i_max
179
+ return 0.0
180
+
181
+ # Find bracketing points
182
+ for i in range(len(limits) - 1):
183
+ if limits[i].v_max <= voltage <= limits[i + 1].v_max:
184
+ # Log-log interpolation
185
+ v1, v2 = limits[i].v_max, limits[i + 1].v_max
186
+ i1, i2 = limits[i].i_max, limits[i + 1].i_max
187
+
188
+ if v1 <= 0 or v2 <= 0 or i1 <= 0 or i2 <= 0:
189
+ # Linear interpolation fallback
190
+ t = (voltage - v1) / (v2 - v1)
191
+ return i1 + t * (i2 - i1)
192
+
193
+ # Log-log
194
+ log_v = np.log10(voltage)
195
+ log_v1, log_v2 = np.log10(v1), np.log10(v2)
196
+ log_i1, log_i2 = np.log10(i1), np.log10(i2)
197
+
198
+ t = (log_v - log_v1) / (log_v2 - log_v1)
199
+ log_i = log_i1 + t * (log_i2 - log_i1)
200
+ return 10**log_i # type: ignore[no-any-return]
201
+
202
+ # Beyond limits
203
+ if voltage < limits[0].v_max:
204
+ return limits[0].i_max
205
+ return 0.0
206
+
207
+
208
+ def check_soa_violations(
209
+ voltage: WaveformTrace,
210
+ current: WaveformTrace,
211
+ limits: list[SOALimit],
212
+ ) -> list[SOAViolation]:
213
+ """Check for SOA violations and return list of violations.
214
+
215
+ Convenience function that just returns violations.
216
+
217
+ Args:
218
+ voltage: Voltage waveform.
219
+ current: Current waveform.
220
+ limits: SOA limits.
221
+
222
+ Returns:
223
+ List of SOA violations (empty if all within limits).
224
+ """
225
+ result = soa_analysis(voltage, current, limits)
226
+ return result["violations"] # type: ignore[no-any-return]
227
+
228
+
229
+ def plot_soa(
230
+ voltage: WaveformTrace,
231
+ current: WaveformTrace,
232
+ limits: list[SOALimit],
233
+ *,
234
+ figsize: tuple[float, float] = (10, 8),
235
+ title: str | None = None,
236
+ show_violations: bool = True,
237
+ ) -> Figure:
238
+ """Plot SOA diagram with trajectory and limits.
239
+
240
+ Args:
241
+ voltage: Voltage waveform.
242
+ current: Current waveform.
243
+ limits: SOA limits to plot.
244
+ figsize: Figure size in inches.
245
+ title: Plot title.
246
+ show_violations: If True, highlight violations.
247
+
248
+ Returns:
249
+ Matplotlib Figure object.
250
+
251
+ Example:
252
+ >>> fig = plot_soa(v_ds, i_d, soa_limits)
253
+ >>> plt.show()
254
+ """
255
+ import matplotlib.pyplot as plt
256
+
257
+ result = soa_analysis(voltage, current, limits)
258
+
259
+ fig, ax = plt.subplots(figsize=figsize)
260
+
261
+ # Plot SOA boundary
262
+ sorted_limits = sorted(limits, key=lambda l: l.v_max) # noqa: E741
263
+ v_boundary = [l.v_max for l in sorted_limits] # noqa: E741
264
+ i_boundary = [l.i_max for l in sorted_limits] # noqa: E741
265
+
266
+ # Add corner points for closed boundary
267
+ v_boundary = [0, *v_boundary, v_boundary[-1], 0]
268
+ i_boundary = [i_boundary[0], *i_boundary, 0, 0]
269
+
270
+ ax.fill(v_boundary, i_boundary, alpha=0.2, color="green", label="Safe Operating Area")
271
+ ax.plot(v_boundary, i_boundary, "g-", linewidth=2)
272
+
273
+ # Plot trajectory
274
+ v_traj = np.abs(result["v_trajectory"])
275
+ i_traj = np.abs(result["i_trajectory"])
276
+ ax.plot(v_traj, i_traj, "b-", linewidth=1, alpha=0.7, label="Operating trajectory")
277
+
278
+ # Highlight violations
279
+ if show_violations and result["violations"]:
280
+ v_viol = [v.voltage for v in result["violations"]]
281
+ i_viol = [v.current for v in result["violations"]]
282
+ ax.scatter(
283
+ np.abs(v_viol),
284
+ np.abs(i_viol),
285
+ c="red",
286
+ s=50,
287
+ marker="x",
288
+ label=f"Violations ({len(result['violations'])})",
289
+ )
290
+
291
+ ax.set_xlabel("Voltage (V)")
292
+ ax.set_ylabel("Current (A)")
293
+ ax.set_xlim(0, None)
294
+ ax.set_ylim(0, None)
295
+ ax.grid(True, alpha=0.3)
296
+ ax.legend()
297
+
298
+ if title:
299
+ ax.set_title(title)
300
+ else:
301
+ status = "PASS" if result["passed"] else "FAIL"
302
+ ax.set_title(f"Safe Operating Area Analysis - {status}")
303
+
304
+ plt.tight_layout()
305
+ return fig
306
+
307
+
308
+ def create_mosfet_soa(
309
+ v_ds_max: float,
310
+ i_d_max: float,
311
+ p_d_max: float,
312
+ *,
313
+ pulse_limits: dict[float, float] | None = None,
314
+ ) -> list[SOALimit]:
315
+ """Create SOA limits for a MOSFET.
316
+
317
+ Generates typical SOA boundary from datasheet parameters.
318
+
319
+ Args:
320
+ v_ds_max: Maximum drain-source voltage.
321
+ i_d_max: Maximum continuous drain current.
322
+ p_d_max: Maximum power dissipation.
323
+ pulse_limits: Optional dict of {pulse_width: i_max} for pulsed limits.
324
+
325
+ Returns:
326
+ List of SOALimit objects defining the boundary.
327
+
328
+ Example:
329
+ >>> limits = create_mosfet_soa(v_ds_max=100, i_d_max=50, p_d_max=150)
330
+ """
331
+ limits = []
332
+
333
+ # Current limit (horizontal line at I_max)
334
+ limits.append(SOALimit(v_max=1.0, i_max=i_d_max, name="I_max"))
335
+
336
+ # Power limit (hyperbola P = V * I)
337
+ # Find intersection with I_max line
338
+ v_at_imax = p_d_max / i_d_max
339
+ if v_at_imax < v_ds_max:
340
+ limits.append(SOALimit(v_max=v_at_imax, i_max=i_d_max, name="P_max_start"))
341
+
342
+ # Add points along power hyperbola
343
+ for v in np.geomspace(v_at_imax, v_ds_max * 0.9, 5)[1:]:
344
+ i = p_d_max / v
345
+ limits.append(SOALimit(v_max=v, i_max=i, name="P_max"))
346
+
347
+ # Voltage limit
348
+ limits.append(SOALimit(v_max=v_ds_max, i_max=0.1, name="V_max"))
349
+
350
+ # Add pulsed limits if provided
351
+ if pulse_limits:
352
+ for pw, i_max in pulse_limits.items():
353
+ limits.append(
354
+ SOALimit(
355
+ v_max=v_ds_max,
356
+ i_max=i_max,
357
+ pulse_width=pw,
358
+ name=f"Pulse_{pw * 1e6:.0f}us",
359
+ )
360
+ )
361
+
362
+ return limits
363
+
364
+
365
+ __all__ = [
366
+ "SOALimit",
367
+ "SOAViolation",
368
+ "check_soa_violations",
369
+ "create_mosfet_soa",
370
+ "plot_soa",
371
+ "soa_analysis",
372
+ ]