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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,555 @@
1
+ """Eye diagram metrics and measurements.
2
+
3
+ This module provides measurements on eye diagrams including height,
4
+ width, Q-factor, and crossing percentage.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.analyzers.eye.metrics import eye_height, eye_width, q_factor
9
+ >>> height = eye_height(eye_diagram)
10
+ >>> width = eye_width(eye_diagram)
11
+ >>> q = q_factor(eye_diagram)
12
+
13
+ References:
14
+ IEEE 802.3: Ethernet Physical Layer Specifications
15
+ OIF CEI: Common Electrical I/O
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from dataclasses import dataclass
21
+ from typing import TYPE_CHECKING
22
+
23
+ import numpy as np
24
+ from scipy import special
25
+
26
+ if TYPE_CHECKING:
27
+ from numpy.typing import NDArray
28
+
29
+ from oscura.analyzers.eye.diagram import EyeDiagram
30
+
31
+
32
+ @dataclass
33
+ class EyeMetrics:
34
+ """Complete eye diagram measurement results.
35
+
36
+ Attributes:
37
+ height: Eye height in volts.
38
+ height_at_ber: Eye height at specified BER.
39
+ width: Eye width in UI.
40
+ width_at_ber: Eye width at specified BER.
41
+ q_factor: Signal quality factor.
42
+ crossing_percent: Crossing percentage (ideal = 50%).
43
+ mean_high: Mean logic high level.
44
+ mean_low: Mean logic low level.
45
+ sigma_high: Standard deviation of high level.
46
+ sigma_low: Standard deviation of low level.
47
+ snr: Signal-to-noise ratio in dB.
48
+ ber_estimate: Estimated BER from Q-factor.
49
+ """
50
+
51
+ height: float
52
+ height_at_ber: float | None
53
+ width: float
54
+ width_at_ber: float | None
55
+ q_factor: float
56
+ crossing_percent: float
57
+ mean_high: float
58
+ mean_low: float
59
+ sigma_high: float
60
+ sigma_low: float
61
+ snr: float
62
+ ber_estimate: float
63
+
64
+
65
+ def eye_height(
66
+ eye: EyeDiagram,
67
+ *,
68
+ position: float = 0.5,
69
+ ber: float | None = None,
70
+ ) -> float:
71
+ """Measure vertical eye opening (eye height).
72
+
73
+ Measures the vertical distance between logic levels at the
74
+ specified horizontal position within the unit interval.
75
+
76
+ Args:
77
+ eye: Eye diagram data.
78
+ position: Horizontal position in UI (0.0 to 1.0, default 0.5 = center).
79
+ ber: If specified, calculate height at this BER using Gaussian extrapolation.
80
+
81
+ Returns:
82
+ Eye height in volts (or input units).
83
+
84
+ Example:
85
+ >>> height = eye_height(eye)
86
+ >>> print(f"Eye height: {height * 1e3:.2f} mV")
87
+
88
+ References:
89
+ IEEE 802.3 Clause 68: 10GBASE-T PHY
90
+ """
91
+ # Get samples at specified position
92
+ samples_per_ui = eye.samples_per_ui
93
+ position_idx = int(position * samples_per_ui) % len(eye.time_axis)
94
+
95
+ # Use global threshold to separate high from low logic levels
96
+ all_data = eye.data.flatten()
97
+ low_level = np.percentile(all_data, 10)
98
+ high_level = np.percentile(all_data, 90)
99
+ threshold = (low_level + high_level) / 2
100
+
101
+ # Extract voltage values at this position from all traces
102
+ voltages = eye.data[:, position_idx]
103
+ high_voltages = voltages[voltages > threshold]
104
+ low_voltages = voltages[voltages <= threshold]
105
+
106
+ # If no eye opening at this position, search for a better position
107
+ if len(high_voltages) == 0 or len(low_voltages) == 0:
108
+ # Search all positions for one with both high and low samples
109
+ for idx in range(len(eye.time_axis)):
110
+ v = eye.data[:, idx]
111
+ h_v = v[v > threshold]
112
+ l_v = v[v <= threshold]
113
+ if len(h_v) > 0 and len(l_v) > 0:
114
+ # Found a position with eye opening
115
+ high_voltages = h_v
116
+ low_voltages = l_v
117
+ break
118
+ else:
119
+ # No position found with eye opening
120
+ return np.nan # type: ignore[no-any-return]
121
+
122
+ if ber is None:
123
+ # Simple min-max eye height
124
+ min_high = np.min(high_voltages)
125
+ max_low = np.max(low_voltages)
126
+ return max(0.0, min_high - max_low) # type: ignore[no-any-return]
127
+
128
+ else:
129
+ # BER-extrapolated eye height
130
+ mu_high = np.mean(high_voltages)
131
+ mu_low = np.mean(low_voltages)
132
+ sigma_high = np.std(high_voltages)
133
+ sigma_low = np.std(low_voltages)
134
+
135
+ if sigma_high <= 0 or sigma_low <= 0:
136
+ return mu_high - mu_low # type: ignore[no-any-return]
137
+
138
+ # Q-factor for BER
139
+ q = np.sqrt(2) * special.erfcinv(2 * ber)
140
+
141
+ # Eye height at BER = (mu_high - q*sigma_high) - (mu_low + q*sigma_low)
142
+ height = (mu_high - q * sigma_high) - (mu_low + q * sigma_low)
143
+
144
+ return max(0.0, height) # type: ignore[no-any-return]
145
+
146
+
147
+ def eye_width(
148
+ eye: EyeDiagram,
149
+ *,
150
+ level: float = 0.5,
151
+ ber: float | None = None,
152
+ ) -> float:
153
+ """Measure horizontal eye opening (eye width).
154
+
155
+ Measures the horizontal opening at the decision threshold level.
156
+
157
+ Args:
158
+ eye: Eye diagram data.
159
+ level: Vertical level as fraction (0.0 = low, 1.0 = high, default 0.5).
160
+ ber: If specified, calculate width at this BER.
161
+
162
+ Returns:
163
+ Eye width in UI (0.0 to 1.0).
164
+
165
+ Example:
166
+ >>> width = eye_width(eye)
167
+ >>> print(f"Eye width: {width:.3f} UI")
168
+
169
+ References:
170
+ IEEE 802.3 Clause 68
171
+ """
172
+ data = eye.data
173
+
174
+ # Calculate global threshold to separate logic levels
175
+ all_data = data.flatten()
176
+ low_level = np.percentile(all_data, 10)
177
+ high_level = np.percentile(all_data, 90)
178
+ global_threshold = (low_level + high_level) / 2
179
+
180
+ # For a 2-UI eye, we need to find the eye opening across all time positions
181
+ # We look for the widest region where all traces are separated
182
+ samples_per_ui = eye.samples_per_ui
183
+
184
+ # Calculate separation at each time point
185
+ separations = []
186
+ time_indices = []
187
+
188
+ for i in range(len(eye.time_axis)):
189
+ voltages = data[:, i]
190
+ high_v = voltages[voltages > global_threshold]
191
+ low_v = voltages[voltages <= global_threshold]
192
+
193
+ if len(high_v) > 0 and len(low_v) > 0:
194
+ # Measure separation between distributions
195
+ separation = np.min(high_v) - np.max(low_v)
196
+ if separation > 0:
197
+ separations.append(separation)
198
+ time_indices.append(i)
199
+
200
+ if len(separations) == 0:
201
+ return np.nan # type: ignore[no-any-return]
202
+
203
+ # Find contiguous region with good separation
204
+ if len(time_indices) < 2:
205
+ return float(len(time_indices)) / samples_per_ui
206
+
207
+ # Find the widest contiguous region
208
+ diffs = np.diff(time_indices)
209
+ gaps = np.where(diffs > 1)[0]
210
+
211
+ if len(gaps) == 0:
212
+ # All contiguous
213
+ width_samples = len(time_indices)
214
+ else:
215
+ # Find longest contiguous segment
216
+ segments = []
217
+ start = 0
218
+ for gap in gaps:
219
+ segments.append(gap + 1 - start)
220
+ start = gap + 1
221
+ segments.append(len(time_indices) - start)
222
+ width_samples = max(segments)
223
+
224
+ # Width in UI (can be > 1.0 for 2-UI eyes)
225
+ width_ui = width_samples / samples_per_ui
226
+ # Clamp to 1.0 for single UI measurement
227
+ width_ui = min(1.0, width_ui)
228
+
229
+ # Apply BER margin if requested
230
+ if ber is not None and width_ui > 0:
231
+ q = np.sqrt(2) * special.erfcinv(2 * ber)
232
+ # Reduce width by jitter margin (rough approximation)
233
+ jitter_reduction = 0.1 * q / 7.0 # Scale by Q/7 (Q=7 is ~1e-12 BER)
234
+ width_ui = max(0.0, width_ui - jitter_reduction)
235
+
236
+ return max(0.0, min(1.0, width_ui))
237
+
238
+
239
+ def q_factor(eye: EyeDiagram, *, position: float = 0.5) -> float:
240
+ """Calculate Q-factor from eye diagram.
241
+
242
+ Q-factor measures signal quality:
243
+ Q = (mu_high - mu_low) / (sigma_high + sigma_low)
244
+
245
+ Higher Q indicates cleaner eye with better BER margin.
246
+
247
+ Args:
248
+ eye: Eye diagram data.
249
+ position: Horizontal position in UI for measurement.
250
+
251
+ Returns:
252
+ Q-factor value.
253
+
254
+ Example:
255
+ >>> q = q_factor(eye)
256
+ >>> print(f"Q-factor: {q:.2f}")
257
+
258
+ References:
259
+ IEEE 802.3 Clause 52
260
+ """
261
+ samples_per_ui = eye.samples_per_ui
262
+ position_idx = int(position * samples_per_ui) % len(eye.time_axis)
263
+
264
+ # Use global threshold to separate high from low logic levels
265
+ all_data = eye.data.flatten()
266
+ low_level = np.percentile(all_data, 10)
267
+ high_level = np.percentile(all_data, 90)
268
+ threshold = (low_level + high_level) / 2
269
+
270
+ voltages = eye.data[:, position_idx]
271
+ high_voltages = voltages[voltages > threshold]
272
+ low_voltages = voltages[voltages <= threshold]
273
+
274
+ # If no eye opening at this position, search for a better position
275
+ if len(high_voltages) < 2 or len(low_voltages) < 2:
276
+ # Search all positions for one with both high and low samples
277
+ for idx in range(len(eye.time_axis)):
278
+ v = eye.data[:, idx]
279
+ h_v = v[v > threshold]
280
+ l_v = v[v <= threshold]
281
+ if len(h_v) >= 2 and len(l_v) >= 2:
282
+ # Found a position with eye opening
283
+ high_voltages = h_v
284
+ low_voltages = l_v
285
+ break
286
+ else:
287
+ # No position found with eye opening
288
+ return np.nan # type: ignore[no-any-return]
289
+
290
+ mu_high = np.mean(high_voltages)
291
+ mu_low = np.mean(low_voltages)
292
+ sigma_high = np.std(high_voltages)
293
+ sigma_low = np.std(low_voltages)
294
+
295
+ denominator = sigma_high + sigma_low
296
+
297
+ if denominator <= 0:
298
+ return np.inf if mu_high > mu_low else np.nan # type: ignore[no-any-return]
299
+
300
+ q = (mu_high - mu_low) / denominator
301
+
302
+ return q # type: ignore[no-any-return]
303
+
304
+
305
+ def crossing_percentage(eye: EyeDiagram) -> float:
306
+ """Measure eye crossing percentage.
307
+
308
+ The crossing percentage indicates where the eye crosses
309
+ vertically. Ideal is 50% (equal rise/fall times).
310
+ Deviation indicates duty cycle distortion.
311
+
312
+ Args:
313
+ eye: Eye diagram data.
314
+
315
+ Returns:
316
+ Crossing percentage (0.0 to 100.0).
317
+
318
+ Example:
319
+ >>> xing = crossing_percentage(eye)
320
+ >>> print(f"Crossing: {xing:.1f}%")
321
+
322
+ References:
323
+ OIF CEI 3.0 Section 5.3
324
+ """
325
+ data = eye.data
326
+ samples_per_ui = eye.samples_per_ui
327
+
328
+ # Find voltage range
329
+ all_low = np.percentile(data, 5)
330
+ all_high = np.percentile(data, 95)
331
+ amplitude = all_high - all_low
332
+
333
+ if amplitude <= 0:
334
+ return np.nan # type: ignore[no-any-return]
335
+
336
+ # Find crossing points (where traces cross the center time)
337
+ # Look at the rising and falling edges
338
+ center_idx = samples_per_ui // 2
339
+
340
+ # Extract crossing voltages (at or near 0.5 UI and 1.5 UI)
341
+ crossing_voltages = []
342
+
343
+ for trace in data:
344
+ # Find zero-crossings in derivative (transitions)
345
+ diff = np.diff(trace)
346
+
347
+ # Find rising crossings
348
+ rising_mask = (diff[:-1] > 0) & (diff[1:] > 0)
349
+ rising_idx = np.where(rising_mask)[0]
350
+
351
+ for idx in rising_idx:
352
+ if abs(idx - center_idx) < samples_per_ui // 4:
353
+ crossing_voltages.append(trace[idx])
354
+
355
+ # Find falling crossings
356
+ falling_mask = (diff[:-1] < 0) & (diff[1:] < 0)
357
+ falling_idx = np.where(falling_mask)[0]
358
+
359
+ for idx in falling_idx:
360
+ if abs(idx - center_idx) < samples_per_ui // 4:
361
+ crossing_voltages.append(trace[idx])
362
+
363
+ if len(crossing_voltages) < 2:
364
+ # Fall back to simple median crossing level
365
+ np.percentile(data, 50)
366
+ return 50.0
367
+
368
+ crossing_voltage = np.mean(crossing_voltages)
369
+
370
+ # Calculate crossing percentage
371
+ crossing_percent = (crossing_voltage - all_low) / amplitude * 100
372
+
373
+ return crossing_percent # type: ignore[no-any-return]
374
+
375
+
376
+ def eye_contour(
377
+ eye: EyeDiagram,
378
+ ber_levels: list[float] | None = None,
379
+ ) -> dict[float, tuple[NDArray[np.float64], NDArray[np.float64]]]:
380
+ """Generate eye contour polygons at various BER levels.
381
+
382
+ Creates nested contours showing the eye opening at different
383
+ BER levels, useful for margin analysis.
384
+
385
+ Args:
386
+ eye: Eye diagram data.
387
+ ber_levels: List of BER levels (default: [1e-3, 1e-6, 1e-9, 1e-12]).
388
+
389
+ Returns:
390
+ Dictionary mapping BER to (time_ui, voltage) contour arrays.
391
+
392
+ Example:
393
+ >>> contours = eye_contour(eye)
394
+ >>> for ber, (t, v) in contours.items():
395
+ ... print(f"BER {ber:.0e}: {len(t)} points")
396
+
397
+ References:
398
+ OIF CEI: Eye Contour Methodology
399
+ """
400
+ if ber_levels is None:
401
+ ber_levels = [1e-3, 1e-6, 1e-9, 1e-12]
402
+
403
+ contours: dict[float, tuple[NDArray[np.float64], NDArray[np.float64]]] = {}
404
+
405
+ # Use global threshold to separate high from low logic levels
406
+ # Use mean of 10th and 90th percentiles to handle skewed distributions
407
+ all_data = eye.data.flatten()
408
+ low_level = np.percentile(all_data, 10)
409
+ high_level = np.percentile(all_data, 90)
410
+ global_threshold = (low_level + high_level) / 2
411
+
412
+ for ber in ber_levels:
413
+ # Q-factor for this BER
414
+ q = np.sqrt(2) * special.erfcinv(2 * ber)
415
+
416
+ upper_times = []
417
+ upper_voltages = []
418
+ lower_times = []
419
+ lower_voltages = []
420
+
421
+ # Calculate eye opening at each time position across all UIs
422
+ for i in range(len(eye.time_axis)):
423
+ t_ui = eye.time_axis[i]
424
+ voltages = eye.data[:, i]
425
+
426
+ # Use global threshold
427
+ high_v = voltages[voltages > global_threshold]
428
+ low_v = voltages[voltages <= global_threshold]
429
+
430
+ # Need reasonable number of both high and low samples
431
+ if len(high_v) < 2 or len(low_v) < 2:
432
+ continue
433
+
434
+ # Skip if distribution is too skewed (likely transition region)
435
+ total = len(high_v) + len(low_v)
436
+ if len(high_v) < total * 0.2 or len(low_v) < total * 0.2:
437
+ continue
438
+
439
+ mu_high = np.mean(high_v)
440
+ sigma_high = np.std(high_v)
441
+ mu_low = np.mean(low_v)
442
+ sigma_low = np.std(low_v)
443
+
444
+ # Upper contour: mu_high - q * sigma_high
445
+ upper = mu_high - q * sigma_high
446
+
447
+ # Lower contour: mu_low + q * sigma_low
448
+ lower = mu_low + q * sigma_low
449
+
450
+ if upper > lower:
451
+ upper_times.append(t_ui)
452
+ upper_voltages.append(upper)
453
+ lower_times.append(t_ui)
454
+ lower_voltages.append(lower)
455
+
456
+ if len(upper_times) > 0:
457
+ # Create closed contour: upper trace forward, lower trace backward
458
+ contour_times = np.concatenate([np.array(upper_times), np.array(lower_times[::-1])])
459
+ contour_voltages = np.concatenate(
460
+ [np.array(upper_voltages), np.array(lower_voltages[::-1])]
461
+ )
462
+
463
+ contours[ber] = (contour_times, contour_voltages)
464
+
465
+ return contours
466
+
467
+
468
+ def measure_eye(
469
+ eye: EyeDiagram,
470
+ *,
471
+ ber: float = 1e-12,
472
+ ) -> EyeMetrics:
473
+ """Compute comprehensive eye diagram measurements.
474
+
475
+ Args:
476
+ eye: Eye diagram data.
477
+ ber: BER level for extrapolated measurements.
478
+
479
+ Returns:
480
+ EyeMetrics with all measurements.
481
+
482
+ Example:
483
+ >>> metrics = measure_eye(eye)
484
+ >>> print(f"Height: {metrics.height * 1e3:.2f} mV")
485
+ >>> print(f"Width: {metrics.width:.3f} UI")
486
+ >>> print(f"Q-factor: {metrics.q_factor:.2f}")
487
+ """
488
+ # Get samples at center
489
+ samples_per_ui = eye.samples_per_ui
490
+ center_idx = samples_per_ui // 2
491
+ center_voltages = eye.data[:, center_idx]
492
+
493
+ # Use global threshold to separate logic levels
494
+ all_data = eye.data.flatten()
495
+ low_level = np.percentile(all_data, 10)
496
+ high_level = np.percentile(all_data, 90)
497
+ threshold = (low_level + high_level) / 2
498
+
499
+ high_v = center_voltages[center_voltages > threshold]
500
+ low_v = center_voltages[center_voltages <= threshold]
501
+
502
+ if len(high_v) < 2:
503
+ high_v = center_voltages[center_voltages >= np.percentile(center_voltages, 75)]
504
+ if len(low_v) < 2:
505
+ low_v = center_voltages[center_voltages <= np.percentile(center_voltages, 25)]
506
+
507
+ mean_high = float(np.mean(high_v)) if len(high_v) > 0 else np.nan
508
+ mean_low = float(np.mean(low_v)) if len(low_v) > 0 else np.nan
509
+ sigma_high = float(np.std(high_v)) if len(high_v) > 0 else np.nan
510
+ sigma_low = float(np.std(low_v)) if len(low_v) > 0 else np.nan
511
+
512
+ # Calculate metrics
513
+ height = eye_height(eye)
514
+ height_at_ber = eye_height(eye, ber=ber)
515
+ width = eye_width(eye)
516
+ width_at_ber = eye_width(eye, ber=ber)
517
+ q = q_factor(eye)
518
+ xing = crossing_percentage(eye)
519
+
520
+ # SNR
521
+ amplitude = mean_high - mean_low
522
+ noise_rms = np.sqrt((sigma_high**2 + sigma_low**2) / 2)
523
+ if noise_rms > 0 and amplitude > 0:
524
+ snr = 20 * np.log10(amplitude / noise_rms)
525
+ else:
526
+ snr = np.inf if amplitude > 0 else np.nan
527
+
528
+ # BER estimate from Q-factor
529
+ ber_estimate = 0.5 * special.erfc(q / np.sqrt(2)) if q > 0 and np.isfinite(q) else 0.5
530
+
531
+ return EyeMetrics(
532
+ height=height,
533
+ height_at_ber=height_at_ber,
534
+ width=width,
535
+ width_at_ber=width_at_ber,
536
+ q_factor=q,
537
+ crossing_percent=xing,
538
+ mean_high=mean_high,
539
+ mean_low=mean_low,
540
+ sigma_high=sigma_high,
541
+ sigma_low=sigma_low,
542
+ snr=snr,
543
+ ber_estimate=ber_estimate,
544
+ )
545
+
546
+
547
+ __all__ = [
548
+ "EyeMetrics",
549
+ "crossing_percentage",
550
+ "eye_contour",
551
+ "eye_height",
552
+ "eye_width",
553
+ "measure_eye",
554
+ "q_factor",
555
+ ]
@@ -0,0 +1,83 @@
1
+ """Jitter analysis module for advanced timing characterization.
2
+
3
+ This module provides IEEE 2414-2020 compliant jitter analysis including
4
+ decomposition into random and deterministic components, bathtub curves,
5
+ and jitter spectrum analysis.
6
+
7
+
8
+ Example:
9
+ >>> from oscura.analyzers.jitter import extract_rj, tj_at_ber, bathtub_curve
10
+ >>> rj = extract_rj(tie_data)
11
+ >>> tj = tj_at_ber(rj_rms=rj.rj_rms, dj_pp=dj.dj_pp, ber=1e-12)
12
+ >>> positions, ber_values = bathtub_curve(tie_data, unit_interval=1e-9)
13
+
14
+ References:
15
+ IEEE 2414-2020: Standard for Jitter and Phase Noise
16
+ JEDEC JESD65C: Definition of Skew Specifications for Standard Logic Devices
17
+ """
18
+
19
+ from oscura.analyzers.jitter.ber import (
20
+ BathtubCurveResult,
21
+ bathtub_curve,
22
+ ber_from_q_factor,
23
+ eye_opening_at_ber,
24
+ q_factor_from_ber,
25
+ tj_at_ber,
26
+ )
27
+ from oscura.analyzers.jitter.decomposition import (
28
+ DataDependentJitterResult,
29
+ DeterministicJitterResult,
30
+ JitterDecomposition,
31
+ PeriodicJitterResult,
32
+ RandomJitterResult,
33
+ decompose_jitter,
34
+ extract_ddj,
35
+ extract_dj,
36
+ extract_pj,
37
+ extract_rj,
38
+ )
39
+ from oscura.analyzers.jitter.measurements import (
40
+ CycleJitterResult,
41
+ DutyCycleDistortionResult,
42
+ cycle_to_cycle_jitter,
43
+ measure_dcd,
44
+ period_jitter,
45
+ tie_from_edges,
46
+ )
47
+ from oscura.analyzers.jitter.spectrum import (
48
+ JitterSpectrumResult,
49
+ identify_periodic_components,
50
+ jitter_spectrum,
51
+ )
52
+
53
+ __all__ = [
54
+ # BER
55
+ "BathtubCurveResult",
56
+ # Measurements
57
+ "CycleJitterResult",
58
+ "DataDependentJitterResult",
59
+ "DeterministicJitterResult",
60
+ "DutyCycleDistortionResult",
61
+ # Decomposition
62
+ "JitterDecomposition",
63
+ # Spectrum
64
+ "JitterSpectrumResult",
65
+ "PeriodicJitterResult",
66
+ "RandomJitterResult",
67
+ "bathtub_curve",
68
+ "ber_from_q_factor",
69
+ "cycle_to_cycle_jitter",
70
+ "decompose_jitter",
71
+ "extract_ddj",
72
+ "extract_dj",
73
+ "extract_pj",
74
+ "extract_rj",
75
+ "eye_opening_at_ber",
76
+ "identify_periodic_components",
77
+ "jitter_spectrum",
78
+ "measure_dcd",
79
+ "period_jitter",
80
+ "q_factor_from_ber",
81
+ "tie_from_edges",
82
+ "tj_at_ber",
83
+ ]