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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,303 @@
1
+ """CSV export functionality.
2
+
3
+ This module provides trace and measurement export to CSV format.
4
+
5
+
6
+ Example:
7
+ >>> from oscura.exporters.csv import export_csv
8
+ >>> export_csv(trace, "output.csv")
9
+ >>> export_csv(measurements, "results.csv")
10
+
11
+ References:
12
+ RFC 4180 (CSV format)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import csv
18
+ from pathlib import Path
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ import numpy as np
22
+
23
+ from oscura.core.types import DigitalTrace, WaveformTrace
24
+
25
+ if TYPE_CHECKING:
26
+ from numpy.typing import NDArray
27
+
28
+
29
+ def export_csv(
30
+ data: WaveformTrace | DigitalTrace | dict[str, Any] | NDArray[Any],
31
+ path: str | Path,
32
+ *,
33
+ include_time: bool = True,
34
+ time_unit: str = "s",
35
+ precision: int = 9,
36
+ delimiter: str = ",",
37
+ header: bool = True,
38
+ ) -> None:
39
+ """Export data to CSV format.
40
+
41
+ Args:
42
+ data: Data to export. Can be:
43
+ - WaveformTrace or DigitalTrace (with metadata as comments)
44
+ - Dictionary of measurements
45
+ - NumPy array
46
+ path: Output file path.
47
+ include_time: Include time column for traces.
48
+ time_unit: Time unit ("s", "ms", "us", "ns").
49
+ precision: Decimal precision for floating point values.
50
+ delimiter: Column delimiter.
51
+ header: Include header row and metadata comments.
52
+
53
+ Raises:
54
+ TypeError: If data type is not supported.
55
+
56
+ Example:
57
+ >>> export_csv(trace, "waveform.csv")
58
+ >>> export_csv(trace, "data.csv", precision=6, delimiter="\t")
59
+ >>> export_csv(measurements, "results.csv")
60
+
61
+ Note:
62
+ When exporting traces, metadata is included as comment lines
63
+ starting with '#' when header=True.
64
+
65
+ References:
66
+ EXP-001
67
+ """
68
+ path = Path(path)
69
+
70
+ if isinstance(data, WaveformTrace | DigitalTrace):
71
+ _export_trace(data, path, include_time, time_unit, precision, delimiter, header)
72
+ elif isinstance(data, dict):
73
+ _export_dict(data, path, precision, delimiter, header)
74
+ elif isinstance(data, np.ndarray):
75
+ _export_array(data, path, precision, delimiter, header)
76
+ else:
77
+ raise TypeError(f"Unsupported data type: {type(data)}")
78
+
79
+
80
+ def _export_trace(
81
+ trace: WaveformTrace | DigitalTrace,
82
+ path: Path,
83
+ include_time: bool,
84
+ time_unit: str,
85
+ precision: int,
86
+ delimiter: str,
87
+ header: bool,
88
+ ) -> None:
89
+ """Export trace to CSV.
90
+
91
+ Args:
92
+ trace: Trace to export.
93
+ path: Output file path.
94
+ include_time: Include time column.
95
+ time_unit: Time unit for column.
96
+ precision: Decimal precision.
97
+ delimiter: Column delimiter.
98
+ header: Include header row.
99
+ """
100
+ time_multipliers = {"s": 1.0, "ms": 1e3, "us": 1e6, "ns": 1e9}
101
+ multiplier = time_multipliers.get(time_unit, 1.0)
102
+
103
+ with open(path, "w", newline="") as f:
104
+ writer = csv.writer(f, delimiter=delimiter)
105
+
106
+ # Write metadata as comments if header is enabled
107
+ if header:
108
+ # Metadata comments
109
+ meta = trace.metadata
110
+ f.write("# TraceKit CSV Export\n")
111
+ f.write(f"# Sample Rate: {meta.sample_rate} Hz\n")
112
+ f.write(f"# Time Base: {meta.time_base} s\n")
113
+ f.write(f"# Samples: {len(trace.data)}\n")
114
+ f.write(f"# Duration: {trace.duration} s\n")
115
+
116
+ if meta.vertical_scale is not None:
117
+ f.write(f"# Vertical Scale: {meta.vertical_scale} V/div\n")
118
+ if meta.vertical_offset is not None:
119
+ f.write(f"# Vertical Offset: {meta.vertical_offset} V\n")
120
+ if meta.acquisition_time is not None:
121
+ f.write(f"# Acquisition Time: {meta.acquisition_time.isoformat()}\n")
122
+ if meta.source_file is not None:
123
+ f.write(f"# Source File: {meta.source_file}\n")
124
+ if meta.channel_name is not None:
125
+ f.write(f"# Channel: {meta.channel_name}\n")
126
+
127
+ f.write("#\n")
128
+
129
+ # Column headers
130
+ if include_time:
131
+ if isinstance(trace, WaveformTrace):
132
+ writer.writerow([f"Time ({time_unit})", "Voltage"])
133
+ else:
134
+ writer.writerow([f"Time ({time_unit})", "Digital"])
135
+ elif isinstance(trace, WaveformTrace):
136
+ writer.writerow(["Voltage"])
137
+ else:
138
+ writer.writerow(["Digital"])
139
+
140
+ # Data
141
+ n_samples = len(trace.data)
142
+ time_base = trace.metadata.time_base
143
+
144
+ for i in range(n_samples):
145
+ if include_time:
146
+ time_val = i * time_base * multiplier
147
+ if isinstance(trace, WaveformTrace):
148
+ writer.writerow([f"{time_val:.{precision}g}", f"{trace.data[i]:.{precision}g}"])
149
+ else:
150
+ writer.writerow([f"{time_val:.{precision}g}", int(trace.data[i])])
151
+ elif isinstance(trace, WaveformTrace):
152
+ writer.writerow([f"{trace.data[i]:.{precision}g}"])
153
+ else:
154
+ writer.writerow([int(trace.data[i])])
155
+
156
+
157
+ def _export_dict(
158
+ data: dict[str, Any],
159
+ path: Path,
160
+ precision: int,
161
+ delimiter: str,
162
+ header: bool,
163
+ ) -> None:
164
+ """Export dictionary to CSV.
165
+
166
+ Args:
167
+ data: Dictionary to export.
168
+ path: Output file path.
169
+ precision: Decimal precision.
170
+ delimiter: Column delimiter.
171
+ header: Include header row.
172
+ """
173
+ with open(path, "w", newline="") as f:
174
+ writer = csv.writer(f, delimiter=delimiter)
175
+
176
+ if header:
177
+ writer.writerow(["Parameter", "Value", "Unit"])
178
+
179
+ for key, value in data.items():
180
+ if isinstance(value, dict):
181
+ # Nested dict with value/unit
182
+ val = value.get("value", value)
183
+ unit = value.get("unit", "")
184
+ if isinstance(val, float):
185
+ writer.writerow([key, f"{val:.{precision}g}", unit])
186
+ else:
187
+ writer.writerow([key, val, unit])
188
+ elif isinstance(value, float):
189
+ writer.writerow([key, f"{value:.{precision}g}", ""])
190
+ else:
191
+ writer.writerow([key, value, ""])
192
+
193
+
194
+ def _export_array(
195
+ data: NDArray[Any],
196
+ path: Path,
197
+ precision: int,
198
+ delimiter: str,
199
+ header: bool,
200
+ ) -> None:
201
+ """Export numpy array to CSV.
202
+
203
+ Args:
204
+ data: NumPy array to export.
205
+ path: Output file path.
206
+ precision: Decimal precision.
207
+ delimiter: Column delimiter.
208
+ header: Include header row.
209
+ """
210
+ # Handle different array dimensions
211
+ if data.ndim == 1:
212
+ data = data.reshape(-1, 1)
213
+
214
+ with open(path, "w", newline="") as f:
215
+ writer = csv.writer(f, delimiter=delimiter)
216
+
217
+ if header:
218
+ cols = [f"Column_{i}" for i in range(data.shape[1])]
219
+ writer.writerow(cols)
220
+
221
+ for row in data:
222
+ formatted = []
223
+ for val in row:
224
+ if isinstance(val, float | np.floating):
225
+ formatted.append(f"{val:.{precision}g}")
226
+ else:
227
+ formatted.append(str(val)) # type: ignore[unreachable]
228
+ writer.writerow(formatted)
229
+
230
+
231
+ def export_multi_trace_csv(
232
+ traces: list[WaveformTrace | DigitalTrace],
233
+ path: str | Path,
234
+ *,
235
+ names: list[str] | None = None,
236
+ include_time: bool = True,
237
+ time_unit: str = "s",
238
+ precision: int = 9,
239
+ ) -> None:
240
+ """Export multiple traces to single CSV file.
241
+
242
+ Args:
243
+ traces: List of traces to export.
244
+ path: Output file path.
245
+ names: Column names for each trace.
246
+ include_time: Include time column.
247
+ time_unit: Time unit.
248
+ precision: Decimal precision.
249
+
250
+ Example:
251
+ >>> export_multi_trace_csv([ch1, ch2, ch3], "channels.csv",
252
+ ... names=["CH1", "CH2", "CH3"])
253
+ """
254
+ if len(traces) == 0:
255
+ return
256
+
257
+ path = Path(path)
258
+
259
+ if names is None:
260
+ names = [f"Trace_{i}" for i in range(len(traces))]
261
+
262
+ # Use first trace for timing
263
+ ref_trace = traces[0]
264
+ n_samples = len(ref_trace.data)
265
+ time_base = ref_trace.metadata.time_base
266
+
267
+ time_multipliers = {"s": 1.0, "ms": 1e3, "us": 1e6, "ns": 1e9}
268
+ multiplier = time_multipliers.get(time_unit, 1.0)
269
+
270
+ with open(path, "w", newline="") as f:
271
+ writer = csv.writer(f)
272
+
273
+ # Header
274
+ header_row = []
275
+ if include_time:
276
+ header_row.append(f"Time ({time_unit})")
277
+ header_row.extend(names)
278
+ writer.writerow(header_row)
279
+
280
+ # Data
281
+ for i in range(n_samples):
282
+ row = []
283
+
284
+ if include_time:
285
+ time_val = i * time_base * multiplier
286
+ row.append(f"{time_val:.{precision}g}")
287
+
288
+ for trace in traces:
289
+ if i < len(trace.data):
290
+ if isinstance(trace, WaveformTrace):
291
+ row.append(f"{trace.data[i]:.{precision}g}")
292
+ else:
293
+ row.append(str(int(trace.data[i])))
294
+ else:
295
+ row.append("")
296
+
297
+ writer.writerow(row)
298
+
299
+
300
+ __all__ = [
301
+ "export_csv",
302
+ "export_multi_trace_csv",
303
+ ]
@@ -0,0 +1,44 @@
1
+ """Exporters namespace module.
2
+
3
+ This module provides a namespace for export functions to support:
4
+ from oscura.exporters import exporters
5
+ exporters.csv(trace, "output.csv")
6
+
7
+ Re-exports main export functions with short names.
8
+ """
9
+
10
+ from oscura.exporters.csv import (
11
+ export_csv as csv,
12
+ )
13
+ from oscura.exporters.hdf5 import (
14
+ export_hdf5 as hdf5,
15
+ )
16
+ from oscura.exporters.html_export import (
17
+ export_html as html,
18
+ )
19
+ from oscura.exporters.json_export import (
20
+ export_json as json,
21
+ )
22
+ from oscura.exporters.markdown_export import (
23
+ export_markdown as markdown,
24
+ )
25
+ from oscura.exporters.matlab_export import (
26
+ export_mat as mat,
27
+ )
28
+ from oscura.exporters.npz_export import (
29
+ export_npz as npz,
30
+ )
31
+ from oscura.exporters.spice_export import (
32
+ export_pwl as pwl,
33
+ )
34
+
35
+ __all__ = [
36
+ "csv",
37
+ "hdf5",
38
+ "html",
39
+ "json",
40
+ "markdown",
41
+ "mat",
42
+ "npz",
43
+ "pwl",
44
+ ]
@@ -0,0 +1,219 @@
1
+ """HDF5 export functionality.
2
+
3
+ This module provides trace export to HDF5 format with metadata attributes.
4
+
5
+
6
+ Example:
7
+ >>> from oscura.exporters.hdf5 import export_hdf5
8
+ >>> export_hdf5(trace, "output.h5")
9
+
10
+ References:
11
+ HDF5 specification (https://www.hdfgroup.org/)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from datetime import datetime
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ import numpy as np
21
+
22
+ try:
23
+ import h5py
24
+
25
+ HAS_H5PY = True
26
+ except ImportError:
27
+ HAS_H5PY = False
28
+
29
+ from oscura.core.types import DigitalTrace, WaveformTrace
30
+
31
+
32
+ def export_hdf5(
33
+ data: WaveformTrace | DigitalTrace | dict[str, WaveformTrace | DigitalTrace],
34
+ path: str | Path,
35
+ *,
36
+ compression: str | None = "gzip",
37
+ compression_opts: int = 4,
38
+ include_metadata: bool = True,
39
+ ) -> None:
40
+ """Export data to HDF5 format.
41
+
42
+ Args:
43
+ data: Data to export. Can be:
44
+ - Single WaveformTrace or DigitalTrace
45
+ - Dictionary mapping names to traces
46
+ path: Output file path.
47
+ compression: Compression algorithm ("gzip", "lzf", None).
48
+ compression_opts: Compression level (1-9 for gzip).
49
+ include_metadata: Include trace metadata as attributes.
50
+
51
+ Raises:
52
+ ImportError: If h5py is not installed.
53
+
54
+ Example:
55
+ >>> export_hdf5(trace, "waveform.h5")
56
+ >>> export_hdf5({"ch1": ch1, "ch2": ch2}, "channels.h5")
57
+ """
58
+ if not HAS_H5PY:
59
+ raise ImportError("h5py is required for HDF5 export. Install with: pip install h5py")
60
+
61
+ path = Path(path)
62
+
63
+ if isinstance(data, WaveformTrace | DigitalTrace):
64
+ data = {"trace": data}
65
+
66
+ with h5py.File(path, "w") as f:
67
+ # Add file-level metadata
68
+ f.attrs["created"] = datetime.now().isoformat()
69
+ f.attrs["oscura_version"] = "1.0"
70
+ f.attrs["format"] = "oscura_hdf5"
71
+
72
+ for name, trace in data.items():
73
+ _write_trace_dataset(
74
+ f,
75
+ name,
76
+ trace,
77
+ compression,
78
+ compression_opts,
79
+ include_metadata,
80
+ )
81
+
82
+
83
+ def _write_trace_dataset(
84
+ f: h5py.File,
85
+ name: str,
86
+ trace: WaveformTrace | DigitalTrace,
87
+ compression: str | None,
88
+ compression_opts: int,
89
+ include_metadata: bool,
90
+ ) -> None:
91
+ """Write trace to HDF5 dataset.
92
+
93
+ Args:
94
+ f: HDF5 file object.
95
+ name: Dataset name.
96
+ trace: Trace to write.
97
+ compression: Compression algorithm.
98
+ compression_opts: Compression level.
99
+ include_metadata: Include metadata as attributes.
100
+ """
101
+ # Create dataset
102
+ dtype = np.float64 if isinstance(trace, WaveformTrace) else np.bool_
103
+
104
+ kwargs = {}
105
+ if compression:
106
+ kwargs["compression"] = compression
107
+ if compression == "gzip":
108
+ kwargs["compression_opts"] = compression_opts # type: ignore[assignment]
109
+
110
+ ds = f.create_dataset(name, data=trace.data.astype(dtype), **kwargs)
111
+
112
+ # Add metadata attributes
113
+ if include_metadata:
114
+ meta = trace.metadata
115
+
116
+ ds.attrs["sample_rate"] = meta.sample_rate
117
+ ds.attrs["time_base"] = meta.time_base
118
+
119
+ if meta.vertical_scale is not None:
120
+ ds.attrs["vertical_scale"] = meta.vertical_scale
121
+
122
+ if meta.vertical_offset is not None:
123
+ ds.attrs["vertical_offset"] = meta.vertical_offset
124
+
125
+ if meta.acquisition_time is not None:
126
+ ds.attrs["acquisition_time"] = meta.acquisition_time.isoformat()
127
+
128
+ if meta.source_file is not None:
129
+ ds.attrs["source_file"] = str(meta.source_file)
130
+
131
+ if meta.channel_name is not None:
132
+ ds.attrs["channel_name"] = meta.channel_name
133
+
134
+ if meta.trigger_info:
135
+ for key, value in meta.trigger_info.items():
136
+ ds.attrs[f"trigger_{key}"] = value
137
+
138
+ # Type indicator
139
+ ds.attrs["trace_type"] = "waveform" if isinstance(trace, WaveformTrace) else "digital"
140
+
141
+
142
+ def export_measurement_results(
143
+ results: dict[str, Any],
144
+ path: str | Path,
145
+ *,
146
+ group_name: str = "measurements",
147
+ ) -> None:
148
+ """Export measurement results to HDF5.
149
+
150
+ Args:
151
+ results: Dictionary of measurement results.
152
+ path: Output file path.
153
+ group_name: HDF5 group name for results.
154
+
155
+ Raises:
156
+ ImportError: If h5py is not installed.
157
+
158
+ Example:
159
+ >>> results = measure(trace)
160
+ >>> export_measurement_results(results, "measurements.h5")
161
+ """
162
+ if not HAS_H5PY:
163
+ raise ImportError("h5py is required for HDF5 export")
164
+
165
+ path = Path(path)
166
+
167
+ with h5py.File(path, "a") as f:
168
+ grp = f.require_group(group_name)
169
+
170
+ for name, value in results.items():
171
+ if isinstance(value, dict):
172
+ # Nested dict (value/unit pairs)
173
+ sub_grp = grp.require_group(name)
174
+ for k, v in value.items():
175
+ if isinstance(v, np.ndarray):
176
+ sub_grp.create_dataset(k, data=v)
177
+ else:
178
+ sub_grp.attrs[k] = v
179
+ elif isinstance(value, np.ndarray):
180
+ grp.create_dataset(name, data=value)
181
+ else:
182
+ grp.attrs[name] = value
183
+
184
+
185
+ def append_trace(
186
+ path: str | Path,
187
+ name: str,
188
+ trace: WaveformTrace | DigitalTrace,
189
+ *,
190
+ compression: str | None = "gzip",
191
+ ) -> None:
192
+ """Append trace to existing HDF5 file.
193
+
194
+ Args:
195
+ path: HDF5 file path.
196
+ name: Dataset name for new trace.
197
+ trace: Trace to append.
198
+ compression: Compression algorithm.
199
+
200
+ Raises:
201
+ ImportError: If h5py is not installed.
202
+
203
+ Example:
204
+ >>> append_trace("data.h5", "ch3", channel3_trace)
205
+ """
206
+ if not HAS_H5PY:
207
+ raise ImportError("h5py is required for HDF5 export")
208
+
209
+ path = Path(path)
210
+
211
+ with h5py.File(path, "a") as f:
212
+ _write_trace_dataset(f, name, trace, compression, 4, True)
213
+
214
+
215
+ __all__ = [
216
+ "append_trace",
217
+ "export_hdf5",
218
+ "export_measurement_results",
219
+ ]