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,397 @@
1
+ """Trace comparison functions for Oscura.
2
+
3
+ This module provides functions for comparing waveform traces including
4
+ difference calculation, correlation, and similarity scoring.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.comparison import compare_traces, similarity_score
9
+ >>> result = compare_traces(trace1, trace2)
10
+ >>> score = similarity_score(trace1, trace2)
11
+
12
+ References:
13
+ IEEE 181-2011: Standard for Transitional Waveform Definitions
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import warnings
19
+ from dataclasses import dataclass
20
+ from typing import TYPE_CHECKING, Literal
21
+
22
+ import numpy as np
23
+ from scipy import signal as sp_signal
24
+ from scipy import stats
25
+
26
+ from oscura.core.types import TraceMetadata, WaveformTrace
27
+
28
+ if TYPE_CHECKING:
29
+ from numpy.typing import NDArray
30
+
31
+
32
+ @dataclass
33
+ class ComparisonResult:
34
+ """Result of a trace comparison operation.
35
+
36
+ Attributes:
37
+ match: True if traces are considered matching.
38
+ similarity: Similarity score (0.0 to 1.0).
39
+ max_difference: Maximum absolute difference.
40
+ rms_difference: RMS of the difference.
41
+ correlation: Correlation coefficient.
42
+ difference_trace: Difference waveform (optional).
43
+ violations: Indices where difference exceeds threshold.
44
+ statistics: Additional comparison statistics.
45
+ """
46
+
47
+ match: bool
48
+ similarity: float
49
+ max_difference: float
50
+ rms_difference: float
51
+ correlation: float
52
+ difference_trace: WaveformTrace | None = None
53
+ violations: NDArray[np.int64] | None = None
54
+ statistics: dict | None = None # type: ignore[type-arg]
55
+
56
+
57
+ def difference(
58
+ trace1: WaveformTrace,
59
+ trace2: WaveformTrace,
60
+ *,
61
+ normalize: bool = False,
62
+ channel_name: str | None = None,
63
+ ) -> WaveformTrace:
64
+ """Compute difference between two traces.
65
+
66
+ Calculates the element-wise difference (trace1 - trace2). Traces
67
+ are aligned to the shorter length.
68
+
69
+ Args:
70
+ trace1: First trace.
71
+ trace2: Second trace.
72
+ normalize: Normalize difference to percentage of reference range.
73
+ channel_name: Name for the result trace.
74
+
75
+ Returns:
76
+ WaveformTrace containing the difference.
77
+
78
+ Raises:
79
+ ValueError: If input traces contain NaN or Inf values.
80
+
81
+ Example:
82
+ >>> diff = difference(measured, reference)
83
+ >>> max_error = np.max(np.abs(diff.data))
84
+ """
85
+ # Get data
86
+ data1 = trace1.data.astype(np.float64)
87
+ data2 = trace2.data.astype(np.float64)
88
+
89
+ # Check for NaN/Inf values
90
+ if np.any(~np.isfinite(data1)) or np.any(~np.isfinite(data2)):
91
+ raise ValueError("Input traces contain NaN or Inf values")
92
+
93
+ # Align lengths
94
+ min_len = min(len(data1), len(data2))
95
+ data1 = data1[:min_len]
96
+ data2 = data2[:min_len]
97
+
98
+ # Compute difference
99
+ diff = data1 - data2
100
+
101
+ if normalize:
102
+ # Normalize to percentage of reference range
103
+ ref_range = np.ptp(data2)
104
+ if ref_range > 0:
105
+ diff = (diff / ref_range) * 100.0
106
+
107
+ new_metadata = TraceMetadata(
108
+ sample_rate=trace1.metadata.sample_rate,
109
+ vertical_scale=None,
110
+ vertical_offset=None,
111
+ acquisition_time=trace1.metadata.acquisition_time,
112
+ trigger_info=trace1.metadata.trigger_info,
113
+ source_file=trace1.metadata.source_file,
114
+ channel_name=channel_name or "difference",
115
+ )
116
+
117
+ return WaveformTrace(data=diff, metadata=new_metadata)
118
+
119
+
120
+ def correlation(
121
+ trace1: WaveformTrace,
122
+ trace2: WaveformTrace,
123
+ *,
124
+ mode: Literal["full", "same", "valid"] = "same",
125
+ normalize: bool = True,
126
+ ) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
127
+ """Compute cross-correlation between two traces.
128
+
129
+ Calculates the cross-correlation of two waveforms, useful for
130
+ finding time delays and pattern matching.
131
+
132
+ Args:
133
+ trace1: First trace.
134
+ trace2: Second trace.
135
+ mode: Correlation mode:
136
+ - "full": Full correlation (length N+M-1)
137
+ - "same": Same length as longer input
138
+ - "valid": Only overlapping region
139
+ normalize: Normalize to correlation coefficient (-1 to 1).
140
+
141
+ Returns:
142
+ Tuple of (lags, correlation_values).
143
+
144
+ Example:
145
+ >>> lags, corr = correlation(trace1, trace2)
146
+ >>> delay = lags[np.argmax(corr)]
147
+ """
148
+ data1 = trace1.data.astype(np.float64)
149
+ data2 = trace2.data.astype(np.float64)
150
+
151
+ if normalize:
152
+ # Normalize inputs
153
+ data1 = (data1 - np.mean(data1)) / (np.std(data1) + 1e-10)
154
+ data2 = (data2 - np.mean(data2)) / (np.std(data2) + 1e-10)
155
+
156
+ # Compute cross-correlation
157
+ corr = sp_signal.correlate(data1, data2, mode=mode)
158
+
159
+ if normalize:
160
+ # Normalize by length for correlation coefficient
161
+ corr = corr / len(data1)
162
+
163
+ # Compute lag axis in samples
164
+ if mode == "full":
165
+ lags = np.arange(-(len(data2) - 1), len(data1))
166
+ elif mode == "same":
167
+ lags = np.arange(-len(data1) // 2, len(data1) - len(data1) // 2)
168
+ else: # valid
169
+ lags = np.arange(0, len(data1) - len(data2) + 1)
170
+
171
+ return lags.astype(np.float64), corr
172
+
173
+
174
+ def similarity_score(
175
+ trace1: WaveformTrace,
176
+ trace2: WaveformTrace,
177
+ *,
178
+ method: Literal["correlation", "rms", "mse", "cosine"] = "correlation",
179
+ normalize_amplitude: bool = True,
180
+ normalize_offset: bool = True,
181
+ ) -> float:
182
+ """Compute similarity score between two traces.
183
+
184
+ Returns a score from 0.0 (completely different) to 1.0 (identical).
185
+
186
+ Args:
187
+ trace1: First trace.
188
+ trace2: Second trace.
189
+ method: Similarity metric:
190
+ - "correlation": Pearson correlation coefficient (default)
191
+ - "rms": 1 - normalized RMS difference
192
+ - "mse": 1 - normalized mean squared error
193
+ - "cosine": Cosine similarity
194
+ normalize_amplitude: Normalize amplitude before comparison.
195
+ normalize_offset: Remove DC offset before comparison.
196
+
197
+ Returns:
198
+ Similarity score (0.0 to 1.0).
199
+
200
+ Raises:
201
+ ValueError: If input traces contain NaN or Inf values.
202
+
203
+ Example:
204
+ >>> score = similarity_score(measured, reference)
205
+ >>> if score > 0.95:
206
+ ... print("Traces match")
207
+ """
208
+ # Get data
209
+ data1 = trace1.data.astype(np.float64).copy()
210
+ data2 = trace2.data.astype(np.float64).copy()
211
+
212
+ # Check for NaN/Inf values
213
+ if np.any(~np.isfinite(data1)) or np.any(~np.isfinite(data2)):
214
+ raise ValueError("Input traces contain NaN or Inf values")
215
+
216
+ # Align lengths
217
+ min_len = min(len(data1), len(data2))
218
+ data1 = data1[:min_len]
219
+ data2 = data2[:min_len]
220
+
221
+ # Normalize offset (remove DC)
222
+ if normalize_offset:
223
+ data1 = data1 - np.mean(data1)
224
+ data2 = data2 - np.mean(data2)
225
+
226
+ # Normalize amplitude
227
+ if normalize_amplitude:
228
+ std1 = np.std(data1)
229
+ std2 = np.std(data2)
230
+ if std1 > 0:
231
+ data1 = data1 / std1
232
+ if std2 > 0:
233
+ data2 = data2 / std2
234
+
235
+ if method == "correlation":
236
+ # Pearson correlation coefficient
237
+ # Handle constant inputs gracefully
238
+ with warnings.catch_warnings():
239
+ warnings.filterwarnings("ignore", category=stats.ConstantInputWarning)
240
+ try:
241
+ r, _ = stats.pearsonr(data1, data2)
242
+ # Handle NaN result (constant traces after normalization)
243
+ if np.isnan(r):
244
+ # If both traces are constant and identical, perfect match
245
+ if np.allclose(data1, data2, equal_nan=False):
246
+ r = 1.0
247
+ else:
248
+ r = 0.0
249
+ except Exception:
250
+ r = 0.0
251
+ # Map from [-1, 1] to [0, 1]
252
+ return float((r + 1) / 2)
253
+
254
+ elif method == "rms":
255
+ # RMS-based similarity
256
+ rms_diff = np.sqrt(np.mean((data1 - data2) ** 2))
257
+ rms_ref = np.sqrt(np.mean(data2**2)) + 1e-10
258
+ return float(max(0, 1 - rms_diff / rms_ref))
259
+
260
+ elif method == "mse":
261
+ # MSE-based similarity
262
+ mse = np.mean((data1 - data2) ** 2)
263
+ var_ref = np.var(data2) + 1e-10
264
+ return float(max(0, 1 - mse / var_ref))
265
+
266
+ elif method == "cosine":
267
+ # Cosine similarity
268
+ dot = np.dot(data1, data2)
269
+ norm1 = np.linalg.norm(data1) + 1e-10
270
+ norm2 = np.linalg.norm(data2) + 1e-10
271
+ cosine = dot / (norm1 * norm2)
272
+ # Map from [-1, 1] to [0, 1]
273
+ return float((cosine + 1) / 2)
274
+
275
+ else:
276
+ raise ValueError(f"Unknown similarity method: {method}")
277
+
278
+
279
+ def compare_traces(
280
+ trace1: WaveformTrace,
281
+ trace2: WaveformTrace,
282
+ *,
283
+ tolerance: float | None = None,
284
+ tolerance_pct: float | None = None,
285
+ method: Literal["absolute", "relative", "statistical"] = "absolute",
286
+ include_difference: bool = True,
287
+ ) -> ComparisonResult:
288
+ """Compare two traces and determine if they match.
289
+
290
+ Comprehensive comparison of two waveforms including difference
291
+ analysis, correlation, and match determination.
292
+
293
+ Args:
294
+ trace1: First trace (typically measured).
295
+ trace2: Second trace (typically reference).
296
+ tolerance: Absolute tolerance for matching.
297
+ tolerance_pct: Percentage tolerance (0-100) relative to reference range.
298
+ method: Comparison method:
299
+ - "absolute": Compare absolute values
300
+ - "relative": Compare relative to reference
301
+ - "statistical": Use statistical tests
302
+ include_difference: Include difference trace in result.
303
+
304
+ Returns:
305
+ ComparisonResult with match status and statistics.
306
+
307
+ Raises:
308
+ ValueError: If method is unknown.
309
+
310
+ Example:
311
+ >>> result = compare_traces(measured, golden, tolerance=0.01)
312
+ >>> if result.match:
313
+ ... print(f"Match! Similarity: {result.similarity:.1%}")
314
+ """
315
+ # Get data
316
+ data1 = trace1.data.astype(np.float64)
317
+ data2 = trace2.data.astype(np.float64)
318
+
319
+ # Align lengths
320
+ min_len = min(len(data1), len(data2))
321
+ data1 = data1[:min_len]
322
+ data2 = data2[:min_len]
323
+
324
+ # Compute difference
325
+ diff = data1 - data2
326
+
327
+ # Compute statistics
328
+ max_diff = float(np.max(np.abs(diff)))
329
+ rms_diff = float(np.sqrt(np.mean(diff**2)))
330
+
331
+ # Compute correlation
332
+ if len(data1) > 1:
333
+ # Handle constant inputs (e.g., DC signals) gracefully
334
+ with warnings.catch_warnings():
335
+ warnings.filterwarnings("ignore", category=stats.ConstantInputWarning)
336
+ try:
337
+ corr, _ = stats.pearsonr(data1, data2)
338
+ except Exception:
339
+ # Fallback for any correlation computation issues
340
+ corr = 0.0
341
+ else:
342
+ corr = 1.0 if data1[0] == data2[0] else 0.0
343
+
344
+ # Compute similarity score
345
+ sim_score = similarity_score(trace1, trace2)
346
+
347
+ # Determine tolerance
348
+ if tolerance is None and tolerance_pct is not None:
349
+ ref_range = float(np.ptp(data2))
350
+ tolerance = ref_range * tolerance_pct / 100.0
351
+ elif tolerance is None:
352
+ # Default: 1% of reference range
353
+ ref_range = float(np.ptp(data2))
354
+ tolerance = ref_range * 0.01
355
+
356
+ # Find violations
357
+ violations = np.where(np.abs(diff) > tolerance)[0]
358
+
359
+ # Determine match
360
+ if method == "absolute":
361
+ match = max_diff <= tolerance
362
+ elif method == "relative":
363
+ ref_range = float(np.ptp(data2)) + 1e-10
364
+ relative_max = max_diff / ref_range
365
+ match = relative_max <= (tolerance_pct or 1.0) / 100.0
366
+ elif method == "statistical":
367
+ # Use t-test for statistical matching
368
+ _, p_value = stats.ttest_rel(data1, data2)
369
+ match = p_value > 0.05 # No significant difference
370
+ else:
371
+ raise ValueError(f"Unknown method: {method}")
372
+
373
+ # Create difference trace if requested
374
+ diff_trace = None
375
+ if include_difference:
376
+ diff_trace = difference(trace1, trace2, channel_name="comparison_diff")
377
+
378
+ # Compute additional statistics
379
+ statistics = {
380
+ "mean_difference": float(np.mean(diff)),
381
+ "std_difference": float(np.std(diff)),
382
+ "median_difference": float(np.median(diff)),
383
+ "num_violations": len(violations),
384
+ "violation_rate": len(violations) / min_len if min_len > 0 else 0,
385
+ "p_value": float(stats.ttest_rel(data1, data2)[1]) if len(data1) > 1 else 1.0,
386
+ }
387
+
388
+ return ComparisonResult(
389
+ match=match,
390
+ similarity=sim_score,
391
+ max_difference=max_diff,
392
+ rms_difference=rms_diff,
393
+ correlation=float(corr),
394
+ difference_trace=diff_trace,
395
+ violations=violations if len(violations) > 0 else None,
396
+ statistics=statistics,
397
+ )