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,453 @@
1
+ """Window and zone triggering for TraceKit.
2
+
3
+ Provides window triggering (signal inside/outside voltage window) and
4
+ zone triggering (signal enters/exits defined zones) for limit testing.
5
+
6
+ Example:
7
+ >>> from oscura.triggering.window import WindowTrigger, find_window_violations
8
+ >>> # Trigger when signal exits 0-3.3V window
9
+ >>> trigger = WindowTrigger(low_threshold=0, high_threshold=3.3, trigger_on="exit")
10
+ >>> violations = trigger.find_events(trace)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass
16
+ from typing import TYPE_CHECKING, Literal
17
+
18
+ import numpy as np
19
+
20
+ from oscura.core.exceptions import AnalysisError
21
+ from oscura.triggering.base import (
22
+ Trigger,
23
+ TriggerEvent,
24
+ TriggerType,
25
+ )
26
+
27
+ if TYPE_CHECKING:
28
+ from oscura.core.types import WaveformTrace
29
+
30
+
31
+ @dataclass
32
+ class Zone:
33
+ """Defines a voltage/time zone for triggering.
34
+
35
+ Attributes:
36
+ low: Lower voltage boundary.
37
+ high: Upper voltage boundary.
38
+ start_time: Start time boundary (None for no limit).
39
+ end_time: End time boundary (None for no limit).
40
+ name: Optional zone name for identification.
41
+ """
42
+
43
+ low: float
44
+ high: float
45
+ start_time: float | None = None
46
+ end_time: float | None = None
47
+ name: str = ""
48
+
49
+
50
+ class WindowTrigger(Trigger):
51
+ """Window trigger for detecting voltage limit violations.
52
+
53
+ Triggers when the signal enters or exits a voltage window defined
54
+ by low and high threshold levels.
55
+
56
+ Attributes:
57
+ low_threshold: Lower window boundary.
58
+ high_threshold: Upper window boundary.
59
+ trigger_on: When to trigger - "entry", "exit", or "both".
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ low_threshold: float,
65
+ high_threshold: float,
66
+ trigger_on: Literal["entry", "exit", "both"] = "exit",
67
+ ) -> None:
68
+ """Initialize window trigger.
69
+
70
+ Args:
71
+ low_threshold: Lower window boundary.
72
+ high_threshold: Upper window boundary.
73
+ trigger_on: "entry" triggers when entering window,
74
+ "exit" triggers when leaving window,
75
+ "both" triggers on either event.
76
+
77
+ Raises:
78
+ AnalysisError: If low_threshold is not less than high_threshold.
79
+ """
80
+ if low_threshold >= high_threshold:
81
+ raise AnalysisError("low_threshold must be less than high_threshold")
82
+
83
+ self.low_threshold = low_threshold
84
+ self.high_threshold = high_threshold
85
+ self.trigger_on = trigger_on
86
+
87
+ def find_events(
88
+ self,
89
+ trace: WaveformTrace, # type: ignore[override]
90
+ ) -> list[TriggerEvent]:
91
+ """Find all window entry/exit events.
92
+
93
+ Args:
94
+ trace: Input waveform trace.
95
+
96
+ Returns:
97
+ List of trigger events for window crossings.
98
+ """
99
+ data = trace.data
100
+ sample_period = trace.metadata.time_base
101
+ events: list[TriggerEvent] = []
102
+
103
+ # Determine if each sample is inside the window
104
+ inside = (data >= self.low_threshold) & (data <= self.high_threshold)
105
+
106
+ # Find transitions
107
+ for i in range(1, len(inside)):
108
+ if inside[i] and not inside[i - 1]:
109
+ # Entry event
110
+ if self.trigger_on in ("entry", "both"):
111
+ events.append(
112
+ TriggerEvent(
113
+ timestamp=i * sample_period,
114
+ sample_index=i,
115
+ event_type=TriggerType.WINDOW_ENTRY,
116
+ level=float(data[i]),
117
+ data={
118
+ "window": (self.low_threshold, self.high_threshold),
119
+ "direction": "entering",
120
+ },
121
+ )
122
+ )
123
+
124
+ elif not inside[i] and inside[i - 1]:
125
+ # Exit event
126
+ if self.trigger_on in ("exit", "both"):
127
+ # Determine which boundary was crossed
128
+ boundary = "high" if data[i] > self.high_threshold else "low"
129
+ events.append(
130
+ TriggerEvent(
131
+ timestamp=i * sample_period,
132
+ sample_index=i,
133
+ event_type=TriggerType.WINDOW_EXIT,
134
+ level=float(data[i]),
135
+ data={
136
+ "window": (self.low_threshold, self.high_threshold),
137
+ "direction": "exiting",
138
+ "boundary": boundary,
139
+ },
140
+ )
141
+ )
142
+
143
+ return events
144
+
145
+
146
+ class ZoneTrigger(Trigger):
147
+ """Zone trigger for multiple defined voltage/time zones.
148
+
149
+ Triggers when signal enters any of the defined zones. Useful for
150
+ mask testing and compliance checking.
151
+
152
+ Attributes:
153
+ zones: List of Zone definitions.
154
+ trigger_on: When to trigger - "entry", "exit", or "violation".
155
+ """
156
+
157
+ def __init__(
158
+ self,
159
+ zones: list[Zone],
160
+ trigger_on: Literal["entry", "exit", "violation"] = "violation",
161
+ ) -> None:
162
+ """Initialize zone trigger.
163
+
164
+ Args:
165
+ zones: List of zones to monitor.
166
+ trigger_on: "entry" for entering zones, "exit" for leaving,
167
+ "violation" is alias for "entry" (common use case).
168
+ """
169
+ self.zones = zones
170
+ self.trigger_on = trigger_on
171
+
172
+ def find_events(
173
+ self,
174
+ trace: WaveformTrace, # type: ignore[override]
175
+ ) -> list[TriggerEvent]:
176
+ """Find all zone-related events.
177
+
178
+ Args:
179
+ trace: Input waveform trace.
180
+
181
+ Returns:
182
+ List of trigger events.
183
+ """
184
+ data = trace.data
185
+ sample_period = trace.metadata.time_base
186
+ time_vector = np.arange(len(data)) * sample_period
187
+ events: list[TriggerEvent] = []
188
+
189
+ for zone in self.zones:
190
+ # Check time limits
191
+ if zone.start_time is not None:
192
+ time_mask = time_vector >= zone.start_time
193
+ else:
194
+ time_mask = np.ones(len(data), dtype=bool)
195
+
196
+ if zone.end_time is not None:
197
+ time_mask &= time_vector <= zone.end_time
198
+
199
+ # Check voltage limits
200
+ in_zone = (data >= zone.low) & (data <= zone.high) & time_mask
201
+
202
+ # Find transitions
203
+ for i in range(1, len(in_zone)):
204
+ if in_zone[i] and not in_zone[i - 1]:
205
+ # Entry event
206
+ if self.trigger_on in ("entry", "violation"):
207
+ events.append(
208
+ TriggerEvent(
209
+ timestamp=i * sample_period,
210
+ sample_index=i,
211
+ event_type=TriggerType.ZONE_VIOLATION,
212
+ level=float(data[i]),
213
+ data={
214
+ "zone_name": zone.name,
215
+ "zone_bounds": (zone.low, zone.high),
216
+ "direction": "entering",
217
+ },
218
+ )
219
+ )
220
+
221
+ elif not in_zone[i] and in_zone[i - 1]:
222
+ # Exit event
223
+ if self.trigger_on == "exit":
224
+ events.append(
225
+ TriggerEvent(
226
+ timestamp=i * sample_period,
227
+ sample_index=i,
228
+ event_type=TriggerType.ZONE_VIOLATION,
229
+ level=float(data[i]),
230
+ data={
231
+ "zone_name": zone.name,
232
+ "zone_bounds": (zone.low, zone.high),
233
+ "direction": "exiting",
234
+ },
235
+ )
236
+ )
237
+
238
+ # Sort by timestamp
239
+ events.sort(key=lambda e: e.timestamp)
240
+ return events
241
+
242
+
243
+ def find_window_violations(
244
+ trace: WaveformTrace,
245
+ low: float,
246
+ high: float,
247
+ ) -> list[TriggerEvent]:
248
+ """Find all window violations (signal outside limits).
249
+
250
+ Args:
251
+ trace: Input waveform trace.
252
+ low: Lower limit.
253
+ high: Upper limit.
254
+
255
+ Returns:
256
+ List of trigger events for each exit from the window.
257
+
258
+ Example:
259
+ >>> # Check if signal stays within 0-3.3V
260
+ >>> violations = find_window_violations(trace, low=0, high=3.3)
261
+ >>> if violations:
262
+ ... print(f"Signal violated limits {len(violations)} times")
263
+ """
264
+ trigger = WindowTrigger(
265
+ low_threshold=low,
266
+ high_threshold=high,
267
+ trigger_on="exit",
268
+ )
269
+ return trigger.find_events(trace)
270
+
271
+
272
+ def find_zone_events(
273
+ trace: WaveformTrace,
274
+ zones: list[tuple[float, float] | Zone],
275
+ ) -> list[TriggerEvent]:
276
+ """Find events where signal enters defined zones.
277
+
278
+ Args:
279
+ trace: Input waveform trace.
280
+ zones: List of zones as (low, high) tuples or Zone objects.
281
+
282
+ Returns:
283
+ List of trigger events.
284
+
285
+ Example:
286
+ >>> # Define forbidden zones
287
+ >>> zones = [
288
+ ... (0.8, 1.2), # Metastable region around 1V
289
+ ... (3.5, 5.0), # Overvoltage region
290
+ ... ]
291
+ >>> events = find_zone_events(trace, zones)
292
+ """
293
+ zone_objs: list[Zone] = []
294
+ for i, z in enumerate(zones):
295
+ if isinstance(z, Zone):
296
+ zone_objs.append(z)
297
+ else:
298
+ zone_objs.append(Zone(low=z[0], high=z[1], name=f"zone_{i}"))
299
+
300
+ trigger = ZoneTrigger(zones=zone_objs, trigger_on="violation")
301
+ return trigger.find_events(trace)
302
+
303
+
304
+ def check_limits(
305
+ trace: WaveformTrace,
306
+ low: float,
307
+ high: float,
308
+ ) -> dict: # type: ignore[type-arg]
309
+ """Check if trace stays within voltage limits.
310
+
311
+ Args:
312
+ trace: Input waveform trace.
313
+ low: Lower limit.
314
+ high: Upper limit.
315
+
316
+ Returns:
317
+ Dictionary with:
318
+ - passed: True if no violations
319
+ - violations: List of violation events
320
+ - min_value: Minimum value in trace
321
+ - max_value: Maximum value in trace
322
+ - time_in_spec: Percentage of time within limits
323
+ - time_out_of_spec: Percentage of time outside limits
324
+
325
+ Example:
326
+ >>> result = check_limits(trace, low=0, high=3.3)
327
+ >>> if result['passed']:
328
+ ... print("Signal within limits")
329
+ >>> else:
330
+ ... print(f"{result['time_out_of_spec']:.1f}% of time out of spec")
331
+ """
332
+ violations = find_window_violations(trace, low, high)
333
+
334
+ data = trace.data
335
+ min_val = float(np.min(data))
336
+ max_val = float(np.max(data))
337
+
338
+ # Calculate time in/out of spec
339
+ in_spec = (data >= low) & (data <= high)
340
+ pct_in_spec = np.sum(in_spec) / len(data) * 100
341
+ pct_out_spec = 100 - pct_in_spec
342
+
343
+ return {
344
+ "passed": len(violations) == 0 and min_val >= low and max_val <= high,
345
+ "violations": violations,
346
+ "min_value": min_val,
347
+ "max_value": max_val,
348
+ "time_in_spec": pct_in_spec,
349
+ "time_out_of_spec": pct_out_spec,
350
+ }
351
+
352
+
353
+ class MaskTrigger(Trigger):
354
+ """Mask trigger for eye diagram and waveform mask testing.
355
+
356
+ Tests waveform against a defined mask (polygonal region).
357
+ Triggers on any mask violation.
358
+ """
359
+
360
+ def __init__(
361
+ self,
362
+ mask_points: list[tuple[float, float]],
363
+ mode: Literal["inside", "outside"] = "inside",
364
+ ) -> None:
365
+ """Initialize mask trigger.
366
+
367
+ Args:
368
+ mask_points: List of (time, voltage) points defining mask polygon.
369
+ mode: "inside" triggers when signal is inside mask,
370
+ "outside" triggers when signal is outside mask.
371
+
372
+ Raises:
373
+ AnalysisError: If mask has fewer than 3 points.
374
+ """
375
+ if len(mask_points) < 3:
376
+ raise AnalysisError("Mask must have at least 3 points")
377
+
378
+ self.mask_points = mask_points
379
+ self.mode = mode
380
+
381
+ def find_events(
382
+ self,
383
+ trace: WaveformTrace, # type: ignore[override]
384
+ ) -> list[TriggerEvent]:
385
+ """Find mask violations.
386
+
387
+ Args:
388
+ trace: Input waveform trace.
389
+
390
+ Returns:
391
+ List of trigger events for mask violations.
392
+ """
393
+ from matplotlib.path import Path
394
+
395
+ # Create polygon path
396
+ mask_path = Path(self.mask_points)
397
+
398
+ data = trace.data
399
+ sample_period = trace.metadata.time_base
400
+ time_vector = np.arange(len(data)) * sample_period
401
+
402
+ # Create points array for containment test
403
+ points = np.column_stack([time_vector, data])
404
+
405
+ # Check which points are inside the mask
406
+ inside = mask_path.contains_points(points)
407
+
408
+ events: list[TriggerEvent] = []
409
+
410
+ # Find violations based on mode
411
+ if self.mode == "inside":
412
+ # Trigger when inside mask (mask defines forbidden region)
413
+ violation_indices = np.where(inside)[0]
414
+ else:
415
+ # Trigger when outside mask (mask defines required region)
416
+ violation_indices = np.where(~inside)[0]
417
+
418
+ # Group consecutive violations into events
419
+ if len(violation_indices) > 0:
420
+ # Find starts of violation regions
421
+ starts = [violation_indices[0]]
422
+ for i in range(1, len(violation_indices)):
423
+ if violation_indices[i] != violation_indices[i - 1] + 1:
424
+ starts.append(violation_indices[i])
425
+
426
+ for start_idx in starts:
427
+ events.append(
428
+ TriggerEvent(
429
+ timestamp=start_idx * sample_period,
430
+ sample_index=int(start_idx),
431
+ event_type=TriggerType.ZONE_VIOLATION,
432
+ level=float(data[start_idx]),
433
+ data={
434
+ "mask_mode": self.mode,
435
+ "violation_type": "inside_forbidden"
436
+ if self.mode == "inside"
437
+ else "outside_required",
438
+ },
439
+ )
440
+ )
441
+
442
+ return events
443
+
444
+
445
+ __all__ = [
446
+ "MaskTrigger",
447
+ "WindowTrigger",
448
+ "Zone",
449
+ "ZoneTrigger",
450
+ "check_limits",
451
+ "find_window_violations",
452
+ "find_zone_events",
453
+ ]
oscura/ui/__init__.py ADDED
@@ -0,0 +1,48 @@
1
+ """TraceKit UI module.
2
+
3
+ Provides user interface patterns for progressive disclosure and formatting utilities.
4
+ """
5
+
6
+ from oscura.ui.formatters import (
7
+ Color,
8
+ FormattedText,
9
+ TextAlignment,
10
+ align_text,
11
+ colorize,
12
+ format_code_block,
13
+ format_duration,
14
+ format_key_value_pairs,
15
+ format_list,
16
+ format_percentage,
17
+ format_size,
18
+ format_status,
19
+ format_table,
20
+ format_text,
21
+ truncate,
22
+ )
23
+ from oscura.ui.progressive_display import (
24
+ ProgressiveDisplay,
25
+ ProgressiveOutput,
26
+ Section,
27
+ )
28
+
29
+ __all__ = [
30
+ "Color",
31
+ "FormattedText",
32
+ "ProgressiveDisplay",
33
+ "ProgressiveOutput",
34
+ "Section",
35
+ "TextAlignment",
36
+ "align_text",
37
+ "colorize",
38
+ "format_code_block",
39
+ "format_duration",
40
+ "format_key_value_pairs",
41
+ "format_list",
42
+ "format_percentage",
43
+ "format_size",
44
+ "format_status",
45
+ "format_table",
46
+ "format_text",
47
+ "truncate",
48
+ ]