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,453 @@
1
+ """Adaptive parameter tuning for analysis functions.
2
+
3
+ Auto-configures analysis parameters based on signal characteristics,
4
+ reducing the need for manual parameter specification.
5
+
6
+
7
+ Example:
8
+ >>> import oscura as osc
9
+ >>> trace = osc.load('signal.wfm')
10
+ >>> tuner = osc.AdaptiveParameterTuner(trace.data, trace.metadata.sample_rate)
11
+ >>> params = tuner.get_spectral_params()
12
+ >>> print(f"NFFT: {params.get('nfft')}")
13
+ >>> print(f"Window: {params.get('window')}")
14
+ >>> print(f"Reasoning: {params.reasoning}")
15
+
16
+ References:
17
+ Harris, F. J. (1978): On the use of windows for harmonic analysis with DFT
18
+ Oppenheim, A. V. & Schafer, R. W. (2010): Discrete-Time Signal Processing
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ from dataclasses import dataclass, field
25
+ from typing import TYPE_CHECKING, Any
26
+
27
+ import numpy as np
28
+
29
+ if TYPE_CHECKING:
30
+ from numpy.typing import NDArray
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ @dataclass
36
+ class TunedParameters:
37
+ """Container for auto-tuned parameters.
38
+
39
+ Attributes:
40
+ parameters: Dictionary of parameter names to values.
41
+ confidence: Confidence in parameter tuning (0.0-1.0).
42
+ reasoning: Dictionary mapping parameter names to reasoning strings.
43
+ """
44
+
45
+ parameters: dict[str, Any] = field(default_factory=dict)
46
+ confidence: float = 0.5
47
+ reasoning: dict[str, str] = field(default_factory=dict)
48
+
49
+ def get(self, key: str, default: Any = None) -> Any:
50
+ """Get parameter value with default.
51
+
52
+ Args:
53
+ key: Parameter name.
54
+ default: Default value if parameter not found.
55
+
56
+ Returns:
57
+ Parameter value or default.
58
+ """
59
+ return self.parameters.get(key, default)
60
+
61
+
62
+ class AdaptiveParameterTuner:
63
+ """Auto-configure analysis parameters based on signal characteristics.
64
+
65
+ This class analyzes signal characteristics and provides intelligent
66
+ parameter suggestions for various analysis domains (spectral, digital,
67
+ timing, jitter, pattern recognition).
68
+
69
+ Attributes:
70
+ data: Input signal data array.
71
+ sample_rate: Sample rate in Hz.
72
+ signal_type: Optional signal type hint (digital, analog, etc.).
73
+
74
+ Example:
75
+ >>> tuner = AdaptiveParameterTuner(signal_data, sample_rate=1e6)
76
+ >>> spectral_params = tuner.get_spectral_params()
77
+ >>> print(spectral_params.parameters)
78
+ {'nfft': 8192, 'window': 'hann', 'overlap': 0.5}
79
+ """
80
+
81
+ def __init__(
82
+ self,
83
+ data: NDArray[np.floating[Any]],
84
+ sample_rate: float = 1.0,
85
+ signal_type: str | None = None,
86
+ ):
87
+ """Initialize tuner with signal data.
88
+
89
+ Args:
90
+ data: Input signal data.
91
+ sample_rate: Sample rate in Hz.
92
+ signal_type: Optional signal type hint (digital, analog, etc.).
93
+ """
94
+ self.data = data
95
+ self.sample_rate = sample_rate
96
+ self.signal_type = signal_type
97
+
98
+ # Pre-compute signal characteristics
99
+ self._characteristics = self._analyze_signal()
100
+
101
+ def _analyze_signal(self) -> dict[str, Any]:
102
+ """Analyze signal characteristics for parameter tuning.
103
+
104
+ Returns:
105
+ Dictionary of signal characteristics including statistics,
106
+ noise estimates, frequency content, and signal type indicators.
107
+ """
108
+ chars: dict[str, Any] = {}
109
+
110
+ try:
111
+ # Basic statistics
112
+ chars["mean"] = float(np.mean(self.data))
113
+ chars["std"] = float(np.std(self.data))
114
+ chars["min"] = float(np.min(self.data))
115
+ chars["max"] = float(np.max(self.data))
116
+ chars["range"] = chars["max"] - chars["min"]
117
+ chars["n_samples"] = len(self.data)
118
+ chars["duration"] = len(self.data) / self.sample_rate
119
+
120
+ # Detect if digital
121
+ unique_values = len(np.unique(np.round(self.data, decimals=2)))
122
+ chars["likely_digital"] = unique_values < 10
123
+
124
+ # Estimate dominant frequency
125
+ chars["dominant_freq"] = self._estimate_dominant_frequency()
126
+
127
+ # Estimate noise floor
128
+ median = np.median(self.data)
129
+ mad = np.median(np.abs(self.data - median)) * 1.4826
130
+ chars["noise_floor"] = float(mad)
131
+
132
+ # SNR estimate
133
+ signal_power = np.var(self.data)
134
+ noise_power = mad**2
135
+ if noise_power > 0:
136
+ chars["snr_db"] = float(10 * np.log10(signal_power / noise_power))
137
+ else:
138
+ chars["snr_db"] = 40.0
139
+
140
+ except Exception as e:
141
+ logger.debug(f"Error analyzing signal: {e}")
142
+
143
+ return chars
144
+
145
+ def _estimate_dominant_frequency(self) -> float | None:
146
+ """Estimate dominant frequency using FFT.
147
+
148
+ Returns:
149
+ Dominant frequency in Hz, or None if not detectable.
150
+ """
151
+ try:
152
+ data_ac = self.data - np.mean(self.data)
153
+ fft_result = np.fft.rfft(data_ac)
154
+ freqs = np.fft.rfftfreq(len(data_ac), d=1.0 / self.sample_rate)
155
+ magnitude = np.abs(fft_result[1:]) # Skip DC
156
+
157
+ if len(magnitude) > 0:
158
+ peak_idx = np.argmax(magnitude)
159
+ return float(freqs[1:][peak_idx])
160
+ except Exception:
161
+ pass
162
+ return None
163
+
164
+ def get_spectral_params(self) -> TunedParameters:
165
+ """Get tuned parameters for spectral analysis.
166
+
167
+ Selects FFT size, window function, and overlap based on signal
168
+ characteristics and quality requirements.
169
+
170
+ Returns:
171
+ TunedParameters with spectral analysis configuration.
172
+
173
+ Example:
174
+ >>> params = tuner.get_spectral_params()
175
+ >>> print(f"NFFT: {params.get('nfft')}")
176
+ >>> print(f"Reasoning: {params.reasoning['nfft']}")
177
+ """
178
+ params = {}
179
+ reasoning = {}
180
+ confidence = 0.8
181
+
182
+ n_samples = self._characteristics.get("n_samples", 1000)
183
+
184
+ # NFFT - power of 2, balancing resolution and computation
185
+ ideal_nfft = min(8192, max(256, 2 ** int(np.ceil(np.log2(n_samples / 4)))))
186
+ params["nfft"] = ideal_nfft
187
+ reasoning["nfft"] = f"Power of 2 for efficiency, ~{n_samples / ideal_nfft:.0f} averages"
188
+
189
+ # Window selection based on signal characteristics
190
+ snr = self._characteristics.get("snr_db", 20)
191
+ if snr < 15:
192
+ params["window"] = "blackman"
193
+ reasoning["window"] = "Low SNR - using Blackman for better noise rejection"
194
+ elif snr < 25:
195
+ params["window"] = "hann"
196
+ reasoning["window"] = "Moderate SNR - using Hann for balance"
197
+ else:
198
+ params["window"] = "hamming"
199
+ reasoning["window"] = "Good SNR - using Hamming for resolution"
200
+
201
+ # Overlap
202
+ params["overlap"] = 0.5
203
+ reasoning["overlap"] = "Standard 50% overlap for smooth averaging"
204
+
205
+ # Frequency range based on dominant frequency
206
+ dom_freq = self._characteristics.get("dominant_freq")
207
+ if dom_freq and dom_freq > 0:
208
+ params["freq_min"] = max(0, dom_freq / 10)
209
+ params["freq_max"] = min(self.sample_rate / 2, dom_freq * 5)
210
+ reasoning["freq_range"] = f"Based on dominant frequency {dom_freq:.1f} Hz"
211
+
212
+ return TunedParameters(parameters=params, confidence=confidence, reasoning=reasoning)
213
+
214
+ def get_digital_params(self) -> TunedParameters:
215
+ """Get tuned parameters for digital signal analysis.
216
+
217
+ Determines threshold levels, edge detection sensitivity, and
218
+ baud rate hints based on signal characteristics.
219
+
220
+ Returns:
221
+ TunedParameters with digital analysis configuration.
222
+
223
+ Example:
224
+ >>> params = tuner.get_digital_params()
225
+ >>> print(f"Threshold: {params.get('threshold')}")
226
+ >>> print(f"Baud rate hint: {params.get('baud_rate_hint')}")
227
+ """
228
+ params = {}
229
+ reasoning = {}
230
+ confidence = 0.7
231
+
232
+ chars = self._characteristics
233
+
234
+ # Threshold based on signal levels
235
+ if chars.get("likely_digital"):
236
+ mid = (chars["min"] + chars["max"]) / 2
237
+ params["threshold"] = mid
238
+ params["threshold_low"] = chars["min"] + 0.3 * chars["range"]
239
+ params["threshold_high"] = chars["max"] - 0.3 * chars["range"]
240
+ reasoning["threshold"] = (
241
+ f"Midpoint of signal range ({chars['min']:.2f} to {chars['max']:.2f})"
242
+ )
243
+ confidence = 0.85
244
+ else:
245
+ params["threshold"] = chars.get("mean", 0)
246
+ reasoning["threshold"] = "Using mean (signal may not be digital)"
247
+ confidence = 0.5
248
+
249
+ # Edge detection sensitivity based on noise
250
+ noise = chars.get("noise_floor", 0.1)
251
+ params["min_edge_separation"] = max(2, int(noise * 10))
252
+ reasoning["min_edge_separation"] = f"Based on noise floor {noise:.3f}"
253
+
254
+ # Baud rate hint from dominant frequency
255
+ dom_freq = chars.get("dominant_freq")
256
+ if dom_freq and dom_freq > 0:
257
+ # Common baud rates
258
+ common_bauds = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]
259
+ closest_baud = min(common_bauds, key=lambda b: abs(b - dom_freq * 2))
260
+ params["baud_rate_hint"] = closest_baud
261
+ reasoning["baud_rate"] = f"Estimated from frequency {dom_freq:.0f} Hz"
262
+
263
+ return TunedParameters(parameters=params, confidence=confidence, reasoning=reasoning)
264
+
265
+ def get_timing_params(self) -> TunedParameters:
266
+ """Get tuned parameters for timing analysis.
267
+
268
+ Configures time resolution, expected period, and edge timing
269
+ thresholds based on sample rate and signal characteristics.
270
+
271
+ Returns:
272
+ TunedParameters with timing analysis configuration.
273
+
274
+ Example:
275
+ >>> params = tuner.get_timing_params()
276
+ >>> print(f"Expected period: {params.get('expected_period')}")
277
+ >>> print(f"Tolerance: {params.get('period_tolerance')}")
278
+ """
279
+ params = {}
280
+ reasoning = {}
281
+ confidence = 0.75
282
+
283
+ chars = self._characteristics
284
+
285
+ # Time resolution based on sample rate
286
+ params["time_resolution"] = 1.0 / self.sample_rate
287
+ reasoning["time_resolution"] = f"Based on sample rate {self.sample_rate:.0f} Hz"
288
+
289
+ # Expected period from dominant frequency
290
+ dom_freq = chars.get("dominant_freq")
291
+ if dom_freq and dom_freq > 0:
292
+ params["expected_period"] = 1.0 / dom_freq
293
+ params["period_tolerance"] = 0.2 / dom_freq # 20% tolerance
294
+ reasoning["period"] = f"From dominant frequency {dom_freq:.1f} Hz"
295
+ confidence = 0.85
296
+
297
+ # Edge timing thresholds
298
+ noise = chars.get("noise_floor", 0.1)
299
+ params["edge_threshold"] = noise * 3 # 3-sigma
300
+ reasoning["edge_threshold"] = f"3x noise floor ({noise:.3f})"
301
+
302
+ return TunedParameters(parameters=params, confidence=confidence, reasoning=reasoning)
303
+
304
+ def get_jitter_params(self) -> TunedParameters:
305
+ """Get tuned parameters for jitter analysis.
306
+
307
+ Determines unit interval, histogram binning, and tolerance
308
+ parameters for jitter measurements.
309
+
310
+ Returns:
311
+ TunedParameters with jitter analysis configuration.
312
+
313
+ Example:
314
+ >>> params = tuner.get_jitter_params()
315
+ >>> print(f"Unit interval: {params.get('unit_interval')}")
316
+ >>> print(f"Histogram bins: {params.get('histogram_bins')}")
317
+ """
318
+ params = {}
319
+ reasoning = {}
320
+ confidence = 0.7
321
+
322
+ chars = self._characteristics
323
+
324
+ # Unit interval from dominant frequency
325
+ dom_freq = chars.get("dominant_freq")
326
+ if dom_freq and dom_freq > 0:
327
+ ui = 1.0 / dom_freq
328
+ params["unit_interval"] = ui
329
+ params["ui_tolerance"] = ui * 0.1
330
+ reasoning["unit_interval"] = f"From dominant frequency {dom_freq:.1f} Hz"
331
+ confidence = 0.85
332
+
333
+ # Histogram bins based on data range and noise
334
+ snr = chars.get("snr_db", 20)
335
+ if snr > 30:
336
+ params["histogram_bins"] = 256
337
+ elif snr > 20:
338
+ params["histogram_bins"] = 128
339
+ else:
340
+ params["histogram_bins"] = 64
341
+ reasoning["histogram_bins"] = f"Based on SNR {snr:.0f} dB"
342
+
343
+ return TunedParameters(parameters=params, confidence=confidence, reasoning=reasoning)
344
+
345
+ def get_pattern_params(self) -> TunedParameters:
346
+ """Get tuned parameters for pattern analysis.
347
+
348
+ Configures minimum pattern length and maximum distance for
349
+ fuzzy matching based on signal characteristics.
350
+
351
+ Returns:
352
+ TunedParameters with pattern analysis configuration.
353
+
354
+ Example:
355
+ >>> params = tuner.get_pattern_params()
356
+ >>> print(f"Min pattern length: {params.get('min_length')}")
357
+ >>> print(f"Max fuzzy distance: {params.get('max_distance')}")
358
+ """
359
+ params = {}
360
+ reasoning = {}
361
+ confidence = 0.7
362
+
363
+ chars = self._characteristics
364
+ n_samples = chars.get("n_samples", 1000)
365
+
366
+ # Min pattern length based on signal characteristics
367
+ dom_freq = chars.get("dominant_freq")
368
+ if dom_freq and dom_freq > 0:
369
+ samples_per_period = self.sample_rate / dom_freq
370
+ params["min_length"] = max(3, int(samples_per_period / 4))
371
+ reasoning["min_length"] = (
372
+ f"Quarter of estimated period ({samples_per_period:.0f} samples)"
373
+ )
374
+ else:
375
+ params["min_length"] = max(3, n_samples // 100)
376
+ reasoning["min_length"] = "1% of signal length"
377
+
378
+ # Max distance for fuzzy matching based on noise
379
+ noise_ratio = chars.get("noise_floor", 0.1) / max(chars.get("range", 1), 0.001)
380
+ params["max_distance"] = max(1, int(noise_ratio * 10))
381
+ reasoning["max_distance"] = f"Based on noise ratio {noise_ratio:.2%}"
382
+
383
+ return TunedParameters(parameters=params, confidence=confidence, reasoning=reasoning)
384
+
385
+ def get_params_for_domain(self, domain: str) -> TunedParameters:
386
+ """Get tuned parameters for a specific analysis domain.
387
+
388
+ Args:
389
+ domain: Analysis domain name (spectral, digital, timing, jitter, pattern).
390
+
391
+ Returns:
392
+ TunedParameters for the specified domain.
393
+
394
+ Example:
395
+ >>> params = tuner.get_params_for_domain("spectral")
396
+ >>> print(params.parameters)
397
+ {'nfft': 8192, 'window': 'hann', 'overlap': 0.5}
398
+ """
399
+ domain_lower = domain.lower()
400
+
401
+ if "spectral" in domain_lower or "fft" in domain_lower:
402
+ return self.get_spectral_params()
403
+ elif "digital" in domain_lower:
404
+ return self.get_digital_params()
405
+ elif "timing" in domain_lower:
406
+ return self.get_timing_params()
407
+ elif "jitter" in domain_lower:
408
+ return self.get_jitter_params()
409
+ elif "pattern" in domain_lower:
410
+ return self.get_pattern_params()
411
+ else:
412
+ # Return basic params for unknown domains
413
+ return TunedParameters(
414
+ parameters={},
415
+ confidence=0.5,
416
+ reasoning={"note": "No domain-specific tuning available"},
417
+ )
418
+
419
+
420
+ def get_adaptive_parameters(
421
+ data: NDArray[np.floating[Any]],
422
+ sample_rate: float,
423
+ domain: str,
424
+ signal_type: str | None = None,
425
+ ) -> TunedParameters:
426
+ """Convenience function to get adaptive parameters.
427
+
428
+ This is a shortcut for creating an AdaptiveParameterTuner and
429
+ getting parameters for a specific domain.
430
+
431
+ Args:
432
+ data: Input signal data.
433
+ sample_rate: Sample rate in Hz.
434
+ domain: Analysis domain (spectral, digital, timing, jitter, pattern).
435
+ signal_type: Optional signal type hint.
436
+
437
+ Returns:
438
+ TunedParameters for the specified domain.
439
+
440
+ Example:
441
+ >>> params = get_adaptive_parameters(signal, 1e6, "spectral")
442
+ >>> print(f"Window: {params.get('window')}")
443
+ >>> print(f"Confidence: {params.confidence}")
444
+ """
445
+ tuner = AdaptiveParameterTuner(data, sample_rate, signal_type)
446
+ return tuner.get_params_for_domain(domain)
447
+
448
+
449
+ __all__ = [
450
+ "AdaptiveParameterTuner",
451
+ "TunedParameters",
452
+ "get_adaptive_parameters",
453
+ ]