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
oscura/convenience.py ADDED
@@ -0,0 +1,457 @@
1
+ """High-level convenience functions for common analysis tasks.
2
+
3
+ This module provides one-call solutions for common signal analysis tasks,
4
+ wrapping multiple lower-level functions into easy-to-use high-level APIs.
5
+
6
+ Example:
7
+ >>> import oscura as osc
8
+ >>> trace = osc.load("audio_capture.wfm")
9
+ >>>
10
+ >>> # One-call spectral analysis
11
+ >>> metrics = osc.quick_spectral(trace, fundamental=1000)
12
+ >>> print(f"THD: {metrics.thd_db:.1f} dB, SNR: {metrics.snr_db:.1f} dB")
13
+ >>>
14
+ >>> # Auto-detect and decode protocol
15
+ >>> result = osc.auto_decode(trace)
16
+ >>> print(f"Protocol: {result.protocol}, Frames: {len(result.frames)}")
17
+ >>>
18
+ >>> # Smart filtering
19
+ >>> clean = osc.smart_filter(trace, target="noise")
20
+
21
+ References:
22
+ - Oscura API Design Guidelines
23
+ - IEEE 1241-2010 (ADC Characterization)
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from dataclasses import dataclass
29
+ from typing import TYPE_CHECKING, Any, Literal
30
+
31
+ import numpy as np
32
+
33
+ if TYPE_CHECKING:
34
+ from oscura.core.types import DigitalTrace, WaveformTrace
35
+
36
+
37
+ @dataclass
38
+ class SpectralMetrics:
39
+ """Results from quick_spectral analysis.
40
+
41
+ Attributes:
42
+ thd_db: Total Harmonic Distortion in dB.
43
+ thd_percent: Total Harmonic Distortion as percentage.
44
+ snr_db: Signal-to-Noise Ratio in dB.
45
+ sinad_db: Signal-to-Noise and Distortion in dB.
46
+ enob: Effective Number of Bits.
47
+ sfdr_db: Spurious-Free Dynamic Range in dBc.
48
+ fundamental_freq: Detected fundamental frequency in Hz.
49
+ fundamental_mag_db: Fundamental magnitude in dB.
50
+ noise_floor_db: Estimated noise floor in dB.
51
+ """
52
+
53
+ thd_db: float
54
+ thd_percent: float
55
+ snr_db: float
56
+ sinad_db: float
57
+ enob: float
58
+ sfdr_db: float
59
+ fundamental_freq: float
60
+ fundamental_mag_db: float
61
+ noise_floor_db: float
62
+
63
+
64
+ @dataclass
65
+ class DecodeResult:
66
+ """Results from auto_decode analysis.
67
+
68
+ Attributes:
69
+ protocol: Detected protocol name.
70
+ frames: List of decoded protocol packets.
71
+ confidence: Detection confidence (0-1).
72
+ baud_rate: Detected baud/bit rate (if applicable).
73
+ config: Protocol configuration parameters.
74
+ errors: List of decoding errors.
75
+ statistics: Decoding statistics.
76
+ """
77
+
78
+ protocol: str
79
+ frames: list[Any]
80
+ confidence: float
81
+ baud_rate: float | None
82
+ config: dict[str, Any]
83
+ errors: list[str]
84
+ statistics: dict[str, Any]
85
+
86
+
87
+ def quick_spectral(
88
+ trace: WaveformTrace,
89
+ fundamental: float | None = None,
90
+ n_harmonics: int = 10,
91
+ window: str = "hann",
92
+ ) -> SpectralMetrics:
93
+ """One-call spectral analysis with all common metrics.
94
+
95
+ Computes THD, SNR, SINAD, ENOB, and SFDR in a single call with
96
+ optimized caching for efficiency.
97
+
98
+ Args:
99
+ trace: Input waveform trace.
100
+ fundamental: Expected fundamental frequency in Hz.
101
+ If None, auto-detected from FFT peak.
102
+ n_harmonics: Number of harmonics to consider for THD (default 10).
103
+ window: Window function for FFT (default "hann").
104
+
105
+ Returns:
106
+ SpectralMetrics with all computed values.
107
+
108
+ Example:
109
+ >>> trace = osc.load("audio_1khz.wfm")
110
+ >>> metrics = osc.quick_spectral(trace, fundamental=1000)
111
+ >>> print(f"THD: {metrics.thd_db:.1f} dB")
112
+ >>> print(f"SNR: {metrics.snr_db:.1f} dB")
113
+ >>> print(f"ENOB: {metrics.enob:.1f} bits")
114
+
115
+ References:
116
+ IEEE 1241-2010 Section 4.1 (ADC Characterization)
117
+ """
118
+ from oscura.analyzers.waveform.spectral import (
119
+ enob,
120
+ fft,
121
+ sfdr,
122
+ sinad,
123
+ snr,
124
+ thd,
125
+ )
126
+
127
+ # Compute FFT once
128
+ fft_result = fft(trace, window=window)
129
+ freq = fft_result[0]
130
+ mag_db = fft_result[1]
131
+
132
+ # Find fundamental if not specified
133
+ if fundamental is None:
134
+ # Skip DC bins, find peak
135
+ dc_bins = max(5, len(freq) // 1000)
136
+ peak_idx = dc_bins + int(np.argmax(mag_db[dc_bins : len(mag_db) // 2]))
137
+ fundamental = float(freq[peak_idx])
138
+ fundamental_mag = float(mag_db[peak_idx])
139
+ else:
140
+ # Find closest bin to specified fundamental
141
+ peak_idx = int(np.argmin(np.abs(freq - fundamental)))
142
+ fundamental_mag = float(mag_db[peak_idx])
143
+
144
+ # Estimate noise floor (median of lower half of spectrum, excluding DC and peaks)
145
+ noise_bins = mag_db[10 : len(mag_db) // 2]
146
+ noise_floor = float(np.median(noise_bins))
147
+
148
+ # Compute metrics (these functions don't accept 'fundamental' parameter)
149
+ thd_db_val = thd(trace, n_harmonics=n_harmonics, window=window)
150
+ thd_pct = 100 * 10 ** (thd_db_val / 20) if not np.isnan(thd_db_val) else np.nan
151
+ snr_db_val = snr(trace, n_harmonics=n_harmonics, window=window)
152
+ sinad_db_val = sinad(trace, window=window)
153
+ enob_val = enob(trace, window=window)
154
+ sfdr_db_val = sfdr(trace, window=window)
155
+
156
+ return SpectralMetrics(
157
+ thd_db=thd_db_val,
158
+ thd_percent=thd_pct,
159
+ snr_db=snr_db_val,
160
+ sinad_db=sinad_db_val,
161
+ enob=enob_val,
162
+ sfdr_db=sfdr_db_val,
163
+ fundamental_freq=fundamental,
164
+ fundamental_mag_db=fundamental_mag,
165
+ noise_floor_db=noise_floor,
166
+ )
167
+
168
+
169
+ def auto_decode(
170
+ trace: WaveformTrace | DigitalTrace,
171
+ protocol: str | None = None,
172
+ min_confidence: float = 0.5,
173
+ ) -> DecodeResult:
174
+ """Auto-detect protocol and decode frames in one call.
175
+
176
+ Automatically detects the protocol type (UART, SPI, I2C, CAN, etc.)
177
+ if not specified, then decodes all frames.
178
+
179
+ Args:
180
+ trace: Input trace (waveform or digital).
181
+ protocol: Force specific protocol (None for auto-detect).
182
+ min_confidence: Minimum confidence for auto-detection (0-1).
183
+
184
+ Returns:
185
+ DecodeResult with protocol name, decoded frames, and statistics.
186
+
187
+ Example:
188
+ >>> trace = osc.load("serial_capture.wfm")
189
+ >>> result = osc.auto_decode(trace)
190
+ >>> print(f"Protocol: {result.protocol}")
191
+ >>> print(f"Frames decoded: {len(result.frames)}")
192
+ >>> for frame in result.frames[:5]:
193
+ ... print(f" {frame.data.hex()}")
194
+
195
+ References:
196
+ sigrok Protocol Decoder API
197
+ """
198
+ from oscura.core.types import WaveformTrace
199
+ from oscura.inference.protocol import detect_protocol
200
+
201
+ # Convert to digital if needed
202
+ if isinstance(trace, WaveformTrace):
203
+ from oscura.analyzers.digital.extraction import to_digital
204
+
205
+ digital_trace = to_digital(trace, threshold="auto")
206
+ else:
207
+ digital_trace = trace
208
+
209
+ # Auto-detect protocol if not specified
210
+ if protocol is None or protocol.lower() == "auto":
211
+ # detect_protocol only accepts WaveformTrace, use original trace if it's waveform
212
+ if isinstance(trace, WaveformTrace):
213
+ detection = detect_protocol(
214
+ trace, min_confidence=min_confidence, return_candidates=True
215
+ )
216
+ else:
217
+ # For DigitalTrace, we can't auto-detect protocol, use default UART
218
+ detection = {"protocol": "UART", "config": {}, "confidence": 0.5}
219
+ protocol = detection.get("protocol", "unknown")
220
+ config = detection.get("config", {})
221
+ confidence = detection.get("confidence", 0.0)
222
+ else:
223
+ protocol = protocol.upper()
224
+ confidence = 1.0
225
+ config = _get_default_protocol_config(protocol)
226
+
227
+ # Decode based on protocol
228
+ frames: list[Any] = []
229
+ errors: list[str] = []
230
+
231
+ try:
232
+ if protocol == "UART":
233
+ from oscura.analyzers.protocols.uart import UARTDecoder
234
+
235
+ baud_rate = config.get("baud_rate", 115200)
236
+ decoder = UARTDecoder(
237
+ baudrate=baud_rate,
238
+ data_bits=config.get("data_bits", 8),
239
+ parity=config.get("parity", "none"),
240
+ stop_bits=config.get("stop_bits", 1),
241
+ )
242
+ frames = list(decoder.decode(digital_trace))
243
+
244
+ elif protocol == "SPI":
245
+ from oscura.analyzers.protocols.spi import SPIDecoder
246
+
247
+ spi_decoder = SPIDecoder(
248
+ cpol=config.get("clock_polarity", 0),
249
+ cpha=config.get("clock_phase", 0),
250
+ )
251
+ # Single channel decode - pass trace with channel mapping
252
+ frames = list(
253
+ spi_decoder.decode(digital_trace, clk=digital_trace.data, mosi=digital_trace.data)
254
+ )
255
+
256
+ elif protocol == "I2C":
257
+ from oscura.analyzers.protocols.i2c import I2CDecoder
258
+
259
+ i2c_decoder = I2CDecoder()
260
+ # Single channel - use SDA and create synthetic SCL
261
+ sda = digital_trace.data
262
+ edges = np.where(np.diff(sda.astype(int)) != 0)[0]
263
+ scl = np.ones_like(sda, dtype=bool)
264
+ for i, edge in enumerate(edges):
265
+ if i % 2 == 0 and edge + 10 < len(scl):
266
+ scl[edge : edge + 10] = False
267
+ frames = list(i2c_decoder.decode(digital_trace, scl=scl, sda=sda))
268
+
269
+ elif protocol == "CAN":
270
+ from oscura.analyzers.protocols.can import CANDecoder
271
+
272
+ can_decoder = CANDecoder(
273
+ bitrate=config.get("baud_rate", 500000),
274
+ sample_point=config.get("sample_point", 0.75),
275
+ )
276
+ frames = list(can_decoder.decode(digital_trace))
277
+
278
+ else:
279
+ errors.append(f"Unsupported protocol: {protocol}")
280
+
281
+ except Exception as e:
282
+ errors.append(f"Decoding error: {e!s}")
283
+
284
+ # Calculate statistics
285
+ error_frames = sum(1 for f in frames if hasattr(f, "errors") and f.errors)
286
+ statistics = {
287
+ "total_frames": len(frames),
288
+ "error_frames": error_frames,
289
+ "error_rate": error_frames / len(frames) if frames else 0,
290
+ }
291
+
292
+ return DecodeResult(
293
+ protocol=protocol,
294
+ frames=frames,
295
+ confidence=confidence,
296
+ baud_rate=config.get("baud_rate"),
297
+ config=config,
298
+ errors=errors,
299
+ statistics=statistics,
300
+ )
301
+
302
+
303
+ def smart_filter(
304
+ trace: WaveformTrace,
305
+ target: Literal["noise", "high_freq", "low_freq", "60hz_hum", "50hz_hum", "auto"] = "auto",
306
+ strength: float = 1.0,
307
+ ) -> WaveformTrace:
308
+ """Intelligently filter trace based on target.
309
+
310
+ Automatically selects appropriate filter type and parameters
311
+ based on the specified target or auto-detected noise characteristics.
312
+
313
+ Args:
314
+ trace: Input waveform trace.
315
+ target: What to filter:
316
+ - "noise": General noise reduction
317
+ - "high_freq": Remove high frequency components
318
+ - "low_freq": Remove DC and low frequency drift
319
+ - "60hz_hum": Remove 60 Hz power line interference
320
+ - "50hz_hum": Remove 50 Hz power line interference
321
+ - "auto": Auto-detect and filter dominant noise source
322
+ strength: Filter strength 0-1 (default 1.0 = full strength).
323
+
324
+ Returns:
325
+ Filtered WaveformTrace.
326
+
327
+ Example:
328
+ >>> noisy = osc.load("noisy_capture.wfm")
329
+ >>> clean = osc.smart_filter(noisy, target="noise")
330
+ >>> # Or auto-detect
331
+ >>> clean = osc.smart_filter(noisy, target="auto")
332
+ """
333
+ from oscura.filtering.convenience import (
334
+ high_pass,
335
+ low_pass,
336
+ median_filter,
337
+ notch_filter,
338
+ )
339
+
340
+ sample_rate = trace.metadata.sample_rate
341
+
342
+ if target == "auto":
343
+ target = _detect_noise_type(trace)
344
+
345
+ if target == "noise":
346
+ # Use median filter for general noise reduction
347
+ kernel_size = int(3 + 4 * strength)
348
+ if kernel_size % 2 == 0:
349
+ kernel_size += 1
350
+ return median_filter(trace, kernel_size=kernel_size)
351
+
352
+ elif target == "high_freq":
353
+ # Low-pass filter
354
+ cutoff = sample_rate / 10 * (1 - 0.5 * strength)
355
+ return low_pass(trace, cutoff=cutoff)
356
+
357
+ elif target == "low_freq":
358
+ # High-pass filter
359
+ cutoff = 10 + 90 * strength # 10-100 Hz
360
+ return high_pass(trace, cutoff=cutoff)
361
+
362
+ elif target == "60hz_hum":
363
+ # 60 Hz notch filter with harmonics
364
+ result = trace
365
+ for harmonic in range(1, int(1 + 4 * strength)):
366
+ freq = 60 * harmonic
367
+ if freq < sample_rate / 2:
368
+ result = notch_filter(result, freq=freq, q_factor=30)
369
+ return result
370
+
371
+ elif target == "50hz_hum":
372
+ # 50 Hz notch filter with harmonics
373
+ result = trace
374
+ for harmonic in range(1, int(1 + 4 * strength)):
375
+ freq = 50 * harmonic
376
+ if freq < sample_rate / 2:
377
+ result = notch_filter(result, freq=freq, q_factor=30)
378
+ return result
379
+
380
+ else:
381
+ raise ValueError(f"Unknown filter target: {target}")
382
+
383
+
384
+ def _detect_noise_type(
385
+ trace: WaveformTrace,
386
+ ) -> Literal["noise", "high_freq", "low_freq", "60hz_hum", "50hz_hum"]:
387
+ """Auto-detect dominant noise type in trace.
388
+
389
+ Args:
390
+ trace: Input trace.
391
+
392
+ Returns:
393
+ Detected noise type string.
394
+ """
395
+ from oscura.analyzers.waveform.spectral import fft
396
+
397
+ fft_result = fft(trace, window="hann")
398
+ freq = fft_result[0]
399
+ mag_db = fft_result[1]
400
+
401
+ # Check for 50/60 Hz peaks
402
+ idx_50 = int(np.argmin(np.abs(freq - 50)))
403
+ idx_60 = int(np.argmin(np.abs(freq - 60)))
404
+
405
+ # Get noise floor estimate
406
+ noise_floor = np.median(mag_db[10 : len(mag_db) // 4])
407
+
408
+ # Check for power line hum
409
+ if idx_60 < len(mag_db) and mag_db[idx_60] > noise_floor + 20:
410
+ return "60hz_hum"
411
+ if idx_50 < len(mag_db) and mag_db[idx_50] > noise_floor + 20:
412
+ return "50hz_hum"
413
+
414
+ # Check frequency distribution
415
+ low_power = np.mean(mag_db[1 : len(mag_db) // 10])
416
+ mid_power = np.mean(mag_db[len(mag_db) // 10 : len(mag_db) // 4])
417
+ high_power = np.mean(mag_db[len(mag_db) // 4 : len(mag_db) // 2])
418
+
419
+ if low_power > mid_power + 10:
420
+ return "low_freq"
421
+ if high_power > mid_power + 10:
422
+ return "high_freq"
423
+
424
+ return "noise"
425
+
426
+
427
+ def _get_default_protocol_config(protocol: str) -> dict[str, Any]:
428
+ """Get default configuration for a protocol.
429
+
430
+ Args:
431
+ protocol: Protocol name.
432
+
433
+ Returns:
434
+ Default configuration dictionary.
435
+ """
436
+ configs: dict[str, dict[str, Any]] = {
437
+ "UART": {
438
+ "baud_rate": 115200,
439
+ "data_bits": 8,
440
+ "parity": "none",
441
+ "stop_bits": 1,
442
+ },
443
+ "SPI": {
444
+ "clock_polarity": 0,
445
+ "clock_phase": 0,
446
+ "bit_order": "MSB",
447
+ },
448
+ "I2C": {
449
+ "clock_rate": 100000,
450
+ "address_bits": 7,
451
+ },
452
+ "CAN": {
453
+ "baud_rate": 500000,
454
+ "sample_point": 0.75,
455
+ },
456
+ }
457
+ return configs.get(protocol, {})