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,391 @@
1
+ """Limit testing for TraceKit.
2
+
3
+ This module provides specification limit testing including upper/lower
4
+ bounds, pass/fail determination, and margin analysis.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.comparison import check_limits, margin_analysis
9
+ >>> result = check_limits(trace, upper=1.5, lower=-0.5)
10
+ >>> margins = margin_analysis(trace, limits)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass
16
+ from typing import TYPE_CHECKING, Any, Literal
17
+
18
+ import numpy as np
19
+
20
+ from oscura.core.exceptions import AnalysisError
21
+ from oscura.core.types import WaveformTrace
22
+
23
+ if TYPE_CHECKING:
24
+ from numpy.typing import NDArray
25
+
26
+
27
+ @dataclass
28
+ class LimitSpec:
29
+ """Specification limit definition.
30
+
31
+ Defines upper and lower limits for a measurement with optional
32
+ guardbands and absolute/relative modes.
33
+
34
+ Attributes:
35
+ upper: Upper limit value.
36
+ lower: Lower limit value.
37
+ upper_guardband: Guardband below upper limit (margin).
38
+ lower_guardband: Guardband above lower limit (margin).
39
+ name: Name of the specification.
40
+ unit: Unit of measurement.
41
+ mode: Limit mode ("absolute" or "relative").
42
+ """
43
+
44
+ upper: float | None = None
45
+ lower: float | None = None
46
+ upper_guardband: float = 0.0
47
+ lower_guardband: float = 0.0
48
+ name: str = "spec"
49
+ unit: str = ""
50
+ mode: Literal["absolute", "relative"] = "absolute"
51
+
52
+ def __post_init__(self) -> None:
53
+ """Validate limit specification."""
54
+ if self.upper is None and self.lower is None:
55
+ raise ValueError("At least one of upper or lower limit must be specified")
56
+ if self.upper is not None and self.lower is not None and self.upper < self.lower:
57
+ raise ValueError(f"Upper limit ({self.upper}) must be >= lower limit ({self.lower})")
58
+
59
+
60
+ @dataclass
61
+ class LimitTestResult:
62
+ """Result of a limit test.
63
+
64
+ Attributes:
65
+ passed: True if all samples are within limits.
66
+ num_violations: Number of samples violating limits.
67
+ violation_rate: Fraction of samples violating limits.
68
+ upper_violations: Indices of samples exceeding upper limit.
69
+ lower_violations: Indices of samples below lower limit.
70
+ max_value: Maximum value in data.
71
+ min_value: Minimum value in data.
72
+ upper_margin: Margin to upper limit (positive = within, negative = exceeded).
73
+ lower_margin: Margin to lower limit (positive = within, negative = exceeded).
74
+ margin_percentage: Smallest margin as percentage of limit range.
75
+ within_guardband: True if within guardband but outside tight limits.
76
+ """
77
+
78
+ passed: bool
79
+ num_violations: int
80
+ violation_rate: float
81
+ upper_violations: NDArray[np.int64] | None = None
82
+ lower_violations: NDArray[np.int64] | None = None
83
+ max_value: float = 0.0
84
+ min_value: float = 0.0
85
+ upper_margin: float | None = None
86
+ lower_margin: float | None = None
87
+ margin_percentage: float | None = None
88
+ within_guardband: bool = False
89
+
90
+
91
+ def create_limit_spec(
92
+ *,
93
+ upper: float | None = None,
94
+ lower: float | None = None,
95
+ center: float | None = None,
96
+ tolerance: float | None = None,
97
+ tolerance_pct: float | None = None,
98
+ guardband_pct: float = 0.0,
99
+ name: str = "spec",
100
+ unit: str = "",
101
+ ) -> LimitSpec:
102
+ """Create a limit specification.
103
+
104
+ Creates a LimitSpec from various input formats including
105
+ center +/- tolerance notation.
106
+
107
+ Args:
108
+ upper: Upper limit value.
109
+ lower: Lower limit value.
110
+ center: Center value (used with tolerance).
111
+ tolerance: Absolute tolerance (+/- from center).
112
+ tolerance_pct: Percentage tolerance (+/- % of center).
113
+ guardband_pct: Guardband as percentage of limit range.
114
+ name: Specification name.
115
+ unit: Unit of measurement.
116
+
117
+ Returns:
118
+ LimitSpec instance.
119
+
120
+ Raises:
121
+ ValueError: If center requires tolerance or tolerance_pct, or if no limits specified.
122
+
123
+ Example:
124
+ >>> spec = create_limit_spec(center=1.0, tolerance_pct=5) # 1.0 +/- 5%
125
+ >>> spec = create_limit_spec(upper=1.5, lower=0.5, guardband_pct=10)
126
+ """
127
+ if center is not None:
128
+ if tolerance is not None:
129
+ upper = center + tolerance
130
+ lower = center - tolerance
131
+ elif tolerance_pct is not None:
132
+ abs_tol = abs(center) * tolerance_pct / 100.0
133
+ upper = center + abs_tol
134
+ lower = center - abs_tol
135
+ else:
136
+ raise ValueError("center requires tolerance or tolerance_pct")
137
+
138
+ if upper is None and lower is None:
139
+ raise ValueError("Must specify limits (upper/lower or center+tolerance)")
140
+
141
+ # Calculate guardbands
142
+ upper_gb = 0.0
143
+ lower_gb = 0.0
144
+ if guardband_pct > 0 and upper is not None and lower is not None:
145
+ range_val = upper - lower
146
+ guardband = range_val * guardband_pct / 100.0
147
+ upper_gb = guardband
148
+ lower_gb = guardband
149
+
150
+ return LimitSpec(
151
+ upper=upper,
152
+ lower=lower,
153
+ upper_guardband=upper_gb,
154
+ lower_guardband=lower_gb,
155
+ name=name,
156
+ unit=unit,
157
+ )
158
+
159
+
160
+ def check_limits(
161
+ trace: WaveformTrace | NDArray[np.floating[Any]],
162
+ limits: LimitSpec | None = None,
163
+ *,
164
+ upper: float | None = None,
165
+ lower: float | None = None,
166
+ reference: float | None = None,
167
+ ) -> LimitTestResult:
168
+ """Check if trace data is within specification limits.
169
+
170
+ Tests all samples against upper and lower limits and returns
171
+ detailed violation information.
172
+
173
+ Args:
174
+ trace: Input trace or data array.
175
+ limits: LimitSpec defining the limits.
176
+ upper: Upper limit (alternative to LimitSpec).
177
+ lower: Lower limit (alternative to LimitSpec).
178
+ reference: Reference value for relative limits.
179
+
180
+ Returns:
181
+ LimitTestResult with pass/fail status and violation details.
182
+
183
+ Raises:
184
+ ValueError: If no limits or bounds specified.
185
+
186
+ Example:
187
+ >>> result = check_limits(trace, upper=1.5, lower=-0.5)
188
+ >>> if not result.passed:
189
+ ... print(f"{result.num_violations} violations found")
190
+ """
191
+ # Get data
192
+ if isinstance(trace, WaveformTrace):
193
+ data = trace.data.astype(np.float64)
194
+ else:
195
+ data = np.asarray(trace, dtype=np.float64)
196
+
197
+ # Create or use limits
198
+ if limits is None:
199
+ if upper is None and lower is None:
200
+ raise ValueError("Must specify limits or upper/lower bounds")
201
+ limits = LimitSpec(upper=upper, lower=lower)
202
+
203
+ # Handle relative limits
204
+ actual_upper = limits.upper
205
+ actual_lower = limits.lower
206
+ if limits.mode == "relative" and reference is not None:
207
+ if actual_upper is not None:
208
+ actual_upper = reference + actual_upper
209
+ if actual_lower is not None:
210
+ actual_lower = reference + actual_lower
211
+
212
+ # Find violations
213
+ upper_viol = np.array([], dtype=np.int64)
214
+ lower_viol = np.array([], dtype=np.int64)
215
+
216
+ if actual_upper is not None:
217
+ upper_viol = np.where(data > actual_upper)[0]
218
+ if actual_lower is not None:
219
+ lower_viol = np.where(data < actual_lower)[0]
220
+
221
+ # Combine violations
222
+ all_violations = np.union1d(upper_viol, lower_viol)
223
+ num_violations = len(all_violations)
224
+ violation_rate = num_violations / len(data) if len(data) > 0 else 0.0
225
+
226
+ # Compute statistics
227
+ max_val = float(np.max(data))
228
+ min_val = float(np.min(data))
229
+
230
+ # Compute margins
231
+ upper_margin = None
232
+ lower_margin = None
233
+ if actual_upper is not None:
234
+ upper_margin = float(actual_upper - max_val)
235
+ if actual_lower is not None:
236
+ lower_margin = float(min_val - actual_lower)
237
+
238
+ # Compute margin percentage
239
+ margin_pct = None
240
+ if actual_upper is not None and actual_lower is not None:
241
+ limit_range = actual_upper - actual_lower
242
+ if limit_range > 0:
243
+ min_margin = min(
244
+ upper_margin if upper_margin is not None else float("inf"),
245
+ lower_margin if lower_margin is not None else float("inf"),
246
+ )
247
+ margin_pct = (min_margin / limit_range) * 100.0
248
+
249
+ # Check guardband
250
+ within_guardband = False
251
+ if num_violations == 0:
252
+ # Check if within guardband
253
+ if limits.upper_guardband > 0 and upper_margin is not None:
254
+ if upper_margin < limits.upper_guardband:
255
+ within_guardband = True
256
+ if limits.lower_guardband > 0 and lower_margin is not None:
257
+ if lower_margin < limits.lower_guardband:
258
+ within_guardband = True
259
+
260
+ return LimitTestResult(
261
+ passed=num_violations == 0,
262
+ num_violations=num_violations,
263
+ violation_rate=violation_rate,
264
+ upper_violations=upper_viol if len(upper_viol) > 0 else None,
265
+ lower_violations=lower_viol if len(lower_viol) > 0 else None,
266
+ max_value=max_val,
267
+ min_value=min_val,
268
+ upper_margin=upper_margin,
269
+ lower_margin=lower_margin,
270
+ margin_percentage=margin_pct,
271
+ within_guardband=within_guardband,
272
+ )
273
+
274
+
275
+ @dataclass
276
+ class MarginAnalysis:
277
+ """Margin analysis result.
278
+
279
+ Attributes:
280
+ upper_margin: Margin to upper limit.
281
+ lower_margin: Margin to lower limit.
282
+ min_margin: Smallest margin (most critical).
283
+ margin_percentage: Margin as percentage of limit range.
284
+ critical_limit: Which limit has the smallest margin.
285
+ warning: True if margin is below warning threshold.
286
+ margin_status: "pass", "warning", or "fail".
287
+ """
288
+
289
+ upper_margin: float | None
290
+ lower_margin: float | None
291
+ min_margin: float
292
+ margin_percentage: float
293
+ critical_limit: Literal["upper", "lower", "both", "none"]
294
+ warning: bool
295
+ margin_status: Literal["pass", "warning", "fail"]
296
+
297
+
298
+ def margin_analysis(
299
+ trace: WaveformTrace | NDArray[np.floating[Any]],
300
+ limits: LimitSpec,
301
+ *,
302
+ warning_threshold_pct: float = 20.0,
303
+ ) -> MarginAnalysis:
304
+ """Analyze margins to specification limits.
305
+
306
+ Calculates how much margin exists between the data and the
307
+ specification limits.
308
+
309
+ Args:
310
+ trace: Input trace or data array.
311
+ limits: LimitSpec defining the limits.
312
+ warning_threshold_pct: Threshold for margin warning (percent).
313
+
314
+ Returns:
315
+ MarginAnalysis with margin details.
316
+
317
+ Raises:
318
+ AnalysisError: If no limits defined for margin analysis.
319
+
320
+ Example:
321
+ >>> margins = margin_analysis(trace, limits)
322
+ >>> print(f"Margin: {margins.margin_percentage:.1f}%")
323
+ """
324
+ # Get data
325
+ if isinstance(trace, WaveformTrace):
326
+ data = trace.data.astype(np.float64)
327
+ else:
328
+ data = np.asarray(trace, dtype=np.float64)
329
+
330
+ max_val = float(np.max(data))
331
+ min_val = float(np.min(data))
332
+
333
+ # Compute margins
334
+ upper_margin = None
335
+ lower_margin = None
336
+
337
+ if limits.upper is not None:
338
+ upper_margin = limits.upper - max_val
339
+ if limits.lower is not None:
340
+ lower_margin = min_val - limits.lower
341
+
342
+ # Determine minimum margin and critical limit
343
+ margins = []
344
+ if upper_margin is not None:
345
+ margins.append(("upper", upper_margin))
346
+ if lower_margin is not None:
347
+ margins.append(("lower", lower_margin))
348
+
349
+ if not margins:
350
+ raise AnalysisError("No limits defined for margin analysis")
351
+
352
+ # Find minimum margin
353
+ min_margin_tuple = min(margins, key=lambda x: x[1])
354
+ min_margin = min_margin_tuple[1]
355
+
356
+ # Determine critical limit
357
+ if len(margins) == 2 and abs(margins[0][1] - margins[1][1]) < 1e-10:
358
+ critical_limit: Literal["upper", "lower", "both", "none"] = "both"
359
+ else:
360
+ critical_limit = min_margin_tuple[0] # type: ignore[assignment]
361
+
362
+ # Compute margin percentage
363
+ margin_pct = 0.0
364
+ if limits.upper is not None and limits.lower is not None:
365
+ limit_range = limits.upper - limits.lower
366
+ if limit_range > 0:
367
+ margin_pct = (min_margin / limit_range) * 100.0
368
+ elif limits.upper is not None and upper_margin is not None:
369
+ margin_pct = (upper_margin / abs(limits.upper)) * 100.0 if limits.upper != 0 else 0
370
+ elif limits.lower is not None and lower_margin is not None:
371
+ margin_pct = (lower_margin / abs(limits.lower)) * 100.0 if limits.lower != 0 else 0
372
+
373
+ # Determine status
374
+ warning = False
375
+ if min_margin < 0:
376
+ margin_status: Literal["pass", "warning", "fail"] = "fail"
377
+ elif margin_pct < warning_threshold_pct:
378
+ margin_status = "warning"
379
+ warning = True
380
+ else:
381
+ margin_status = "pass"
382
+
383
+ return MarginAnalysis(
384
+ upper_margin=upper_margin,
385
+ lower_margin=lower_margin,
386
+ min_margin=min_margin,
387
+ margin_percentage=margin_pct,
388
+ critical_limit=critical_limit,
389
+ warning=warning,
390
+ margin_status=margin_status,
391
+ )