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,481 @@
1
+ """Visualization utilities for trace comparison.
2
+
3
+ This module provides visualization functions for comparing traces including
4
+ overlay plots, difference plots, and comparison heat maps.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.comparison.visualization import (
9
+ ... plot_overlay,
10
+ ... plot_difference,
11
+ ... plot_comparison_heatmap
12
+ ... )
13
+ >>> fig = plot_overlay(trace1, trace2)
14
+ >>> fig = plot_difference(trace1, trace2)
15
+
16
+ References:
17
+ - Tufte, E. R. (2001). The Visual Display of Quantitative Information
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from typing import TYPE_CHECKING, Any
23
+
24
+ import matplotlib.pyplot as plt
25
+ import numpy as np
26
+ from matplotlib.gridspec import GridSpec
27
+
28
+ if TYPE_CHECKING:
29
+ from matplotlib.figure import Figure
30
+
31
+ from oscura.comparison.compare import ComparisonResult
32
+ from oscura.core.types import WaveformTrace
33
+
34
+
35
+ def plot_overlay(
36
+ trace1: WaveformTrace,
37
+ trace2: WaveformTrace,
38
+ *,
39
+ labels: tuple[str, str] = ("Trace 1", "Trace 2"),
40
+ title: str = "Trace Comparison - Overlay",
41
+ highlight_differences: bool = True,
42
+ difference_threshold: float | None = None,
43
+ figsize: tuple[float, float] = (10, 6),
44
+ **kwargs: Any,
45
+ ) -> Figure:
46
+ """Create overlay plot showing both traces.
47
+
48
+ : Overlay plot with difference highlighting.
49
+
50
+ Args:
51
+ trace1: First trace
52
+ trace2: Second trace
53
+ labels: Labels for the two traces
54
+ title: Plot title
55
+ highlight_differences: Highlight regions where traces differ
56
+ difference_threshold: Threshold for highlighting (default: auto)
57
+ figsize: Figure size (width, height)
58
+ **kwargs: Additional arguments passed to plot()
59
+
60
+ Returns:
61
+ Matplotlib Figure object
62
+
63
+ Example:
64
+ >>> from oscura.comparison.visualization import plot_overlay
65
+ >>> fig = plot_overlay(measured, reference,
66
+ ... labels=("Measured", "Reference"))
67
+ >>> plt.show()
68
+
69
+ References:
70
+ CMP-003: Overlay plot with difference highlighting
71
+ """
72
+ fig, ax = plt.subplots(figsize=figsize)
73
+
74
+ # Get data
75
+ data1 = trace1.data.astype(np.float64)
76
+ data2 = trace2.data.astype(np.float64)
77
+
78
+ # Align lengths
79
+ min_len = min(len(data1), len(data2))
80
+ data1 = data1[:min_len]
81
+ data2 = data2[:min_len]
82
+
83
+ # Create time axis
84
+ if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
85
+ sample_rate = trace1.metadata.sample_rate
86
+ time = np.arange(min_len) / sample_rate
87
+ xlabel = "Time (s)"
88
+ else:
89
+ time = np.arange(min_len, dtype=np.float64)
90
+ xlabel = "Sample"
91
+
92
+ # Plot traces
93
+ ax.plot(time, data1, label=labels[0], alpha=0.7, linewidth=1.5, **kwargs)
94
+ ax.plot(time, data2, label=labels[1], alpha=0.7, linewidth=1.5, **kwargs)
95
+
96
+ # Highlight differences
97
+ if highlight_differences:
98
+ diff = np.abs(data1 - data2)
99
+ if difference_threshold is None:
100
+ # Auto threshold: mean + 2*std of difference
101
+ difference_threshold = float(np.mean(diff) + 2 * np.std(diff))
102
+
103
+ # Find regions with significant difference
104
+ diff_mask = diff > difference_threshold
105
+ if np.any(diff_mask):
106
+ # Highlight regions with vertical spans
107
+ in_region = False
108
+ start_idx = 0
109
+ for i in range(len(diff_mask)):
110
+ if diff_mask[i] and not in_region:
111
+ start_idx = i
112
+ in_region = True
113
+ elif not diff_mask[i] and in_region:
114
+ ax.axvspan(
115
+ time[start_idx],
116
+ time[i - 1],
117
+ alpha=0.2,
118
+ color="red",
119
+ label="Difference" if start_idx == 0 else "",
120
+ )
121
+ in_region = False
122
+ # Handle last region
123
+ if in_region:
124
+ ax.axvspan(time[start_idx], time[-1], alpha=0.2, color="red")
125
+
126
+ ax.set_xlabel(xlabel)
127
+ ax.set_ylabel("Amplitude")
128
+ ax.set_title(title)
129
+ ax.legend()
130
+ ax.grid(True, alpha=0.3)
131
+ plt.tight_layout()
132
+
133
+ return fig
134
+
135
+
136
+ def plot_difference(
137
+ trace1: WaveformTrace,
138
+ trace2: WaveformTrace,
139
+ *,
140
+ title: str = "Trace Comparison - Difference",
141
+ normalize: bool = False,
142
+ show_statistics: bool = True,
143
+ figsize: tuple[float, float] = (10, 6),
144
+ **kwargs: Any,
145
+ ) -> Figure:
146
+ """Create difference plot (trace1 - trace2).
147
+
148
+ : Difference trace visualization.
149
+
150
+ Args:
151
+ trace1: First trace
152
+ trace2: Second trace
153
+ title: Plot title
154
+ normalize: Normalize difference to percentage
155
+ show_statistics: Show statistics text box
156
+ figsize: Figure size
157
+ **kwargs: Additional arguments passed to plot()
158
+
159
+ Returns:
160
+ Matplotlib Figure object
161
+
162
+ Example:
163
+ >>> from oscura.comparison.visualization import plot_difference
164
+ >>> fig = plot_difference(measured, reference, normalize=True)
165
+ >>> plt.show()
166
+
167
+ References:
168
+ CMP-003: Comparison Visualization
169
+ """
170
+ fig, ax = plt.subplots(figsize=figsize)
171
+
172
+ # Get data
173
+ data1 = trace1.data.astype(np.float64)
174
+ data2 = trace2.data.astype(np.float64)
175
+
176
+ # Align lengths
177
+ min_len = min(len(data1), len(data2))
178
+ data1 = data1[:min_len]
179
+ data2 = data2[:min_len]
180
+
181
+ # Compute difference
182
+ diff = data1 - data2
183
+
184
+ if normalize:
185
+ # Normalize to percentage of reference range
186
+ ref_range = np.ptp(data2)
187
+ if ref_range > 0:
188
+ diff = (diff / ref_range) * 100.0
189
+ ylabel = "Difference (%)"
190
+ else:
191
+ ylabel = "Difference"
192
+
193
+ # Create time axis
194
+ if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
195
+ sample_rate = trace1.metadata.sample_rate
196
+ time = np.arange(min_len) / sample_rate
197
+ xlabel = "Time (s)"
198
+ else:
199
+ time = np.arange(min_len, dtype=np.float64)
200
+ xlabel = "Sample"
201
+
202
+ # Plot difference
203
+ ax.plot(time, diff, label="Difference", **kwargs)
204
+ ax.axhline(y=0, color="k", linestyle="--", alpha=0.5, linewidth=1)
205
+
206
+ # Add statistics text box
207
+ if show_statistics:
208
+ max_diff = float(np.max(np.abs(diff)))
209
+ rms_diff = float(np.sqrt(np.mean(diff**2)))
210
+ mean_diff = float(np.mean(diff))
211
+ std_diff = float(np.std(diff))
212
+
213
+ stats_text = (
214
+ f"Max: {max_diff:.3f}\nRMS: {rms_diff:.3f}\nMean: {mean_diff:.3f}\nStd: {std_diff:.3f}"
215
+ )
216
+
217
+ ax.text(
218
+ 0.02,
219
+ 0.98,
220
+ stats_text,
221
+ transform=ax.transAxes,
222
+ verticalalignment="top",
223
+ bbox={"boxstyle": "round", "facecolor": "wheat", "alpha": 0.8},
224
+ fontsize=9,
225
+ family="monospace",
226
+ )
227
+
228
+ ax.set_xlabel(xlabel)
229
+ ax.set_ylabel(ylabel)
230
+ ax.set_title(title)
231
+ ax.grid(True, alpha=0.3)
232
+ plt.tight_layout()
233
+
234
+ return fig
235
+
236
+
237
+ def plot_comparison_heatmap(
238
+ trace1: WaveformTrace,
239
+ trace2: WaveformTrace,
240
+ *,
241
+ title: str = "Trace Comparison - Difference Heatmap",
242
+ window_size: int = 100,
243
+ figsize: tuple[float, float] = (10, 8),
244
+ **kwargs: Any,
245
+ ) -> Figure:
246
+ """Create difference heatmap showing where changes occur.
247
+
248
+ : Difference heat map showing where changes occur.
249
+
250
+ Args:
251
+ trace1: First trace
252
+ trace2: Second trace
253
+ title: Plot title
254
+ window_size: Window size for heatmap bins
255
+ figsize: Figure size
256
+ **kwargs: Additional arguments passed to imshow()
257
+
258
+ Returns:
259
+ Matplotlib Figure object
260
+
261
+ Example:
262
+ >>> from oscura.comparison.visualization import plot_comparison_heatmap
263
+ >>> fig = plot_comparison_heatmap(trace1, trace2, window_size=50)
264
+ >>> plt.show()
265
+
266
+ References:
267
+ CMP-003: Difference heat map showing where changes occur
268
+ """
269
+ fig = plt.figure(figsize=figsize)
270
+ gs = GridSpec(2, 1, height_ratios=[3, 1], hspace=0.3)
271
+ ax_heat = fig.add_subplot(gs[0])
272
+ ax_trace = fig.add_subplot(gs[1], sharex=ax_heat)
273
+
274
+ # Get data
275
+ data1 = trace1.data.astype(np.float64)
276
+ data2 = trace2.data.astype(np.float64)
277
+
278
+ # Align lengths
279
+ min_len = min(len(data1), len(data2))
280
+ data1 = data1[:min_len]
281
+ data2 = data2[:min_len]
282
+
283
+ # Compute difference
284
+ diff = np.abs(data1 - data2)
285
+
286
+ # Create windowed heatmap
287
+ n_windows = min_len // window_size
288
+ if n_windows == 0:
289
+ n_windows = 1
290
+ window_size = min_len
291
+
292
+ heatmap_data = np.zeros((10, n_windows))
293
+ for i in range(n_windows):
294
+ start = i * window_size
295
+ end = min(start + window_size, min_len)
296
+ window_diff = diff[start:end]
297
+
298
+ # Bin into 10 levels based on amplitude
299
+ window_data1 = data1[start:end]
300
+ window_data2 = data2[start:end]
301
+ y_min = min(np.min(window_data1), np.min(window_data2))
302
+ y_max = max(np.max(window_data1), np.max(window_data2))
303
+
304
+ if y_max - y_min > 0:
305
+ bins = np.linspace(y_min, y_max, 11)
306
+ for sample_idx in range(len(window_diff)):
307
+ y_val = window_data1[sample_idx] # window_data1 is already sliced
308
+ bin_idx = np.digitize(y_val, bins) - 1
309
+ bin_idx = max(0, min(9, bin_idx))
310
+ heatmap_data[bin_idx, i] += window_diff[sample_idx]
311
+
312
+ # Normalize heatmap
313
+ heatmap_data = heatmap_data / window_size
314
+
315
+ # Plot heatmap
316
+ im = ax_heat.imshow(
317
+ heatmap_data,
318
+ aspect="auto",
319
+ cmap="hot",
320
+ origin="lower",
321
+ interpolation="nearest",
322
+ **kwargs,
323
+ )
324
+ plt.colorbar(im, ax=ax_heat, label="Average Difference")
325
+
326
+ ax_heat.set_ylabel("Amplitude Bin")
327
+ ax_heat.set_title(title)
328
+
329
+ # Plot difference trace below
330
+ if hasattr(trace1, "metadata") and trace1.metadata.sample_rate is not None:
331
+ sample_rate = trace1.metadata.sample_rate
332
+ time = np.arange(min_len) / sample_rate
333
+ xlabel = "Time (s)"
334
+ else:
335
+ time = np.arange(min_len, dtype=np.float64)
336
+ xlabel = "Sample"
337
+
338
+ ax_trace.plot(time, diff, linewidth=0.5)
339
+ ax_trace.set_xlabel(xlabel)
340
+ ax_trace.set_ylabel("Difference")
341
+ ax_trace.grid(True, alpha=0.3)
342
+
343
+ plt.tight_layout()
344
+ return fig
345
+
346
+
347
+ def plot_comparison_summary(
348
+ result: ComparisonResult,
349
+ *,
350
+ title: str = "Trace Comparison Summary",
351
+ figsize: tuple[float, float] = (12, 8),
352
+ ) -> Figure:
353
+ """Create comprehensive comparison summary figure.
354
+
355
+ : Summary table of key differences.
356
+
357
+ Args:
358
+ result: ComparisonResult from compare_traces()
359
+ title: Plot title
360
+ figsize: Figure size
361
+
362
+ Returns:
363
+ Matplotlib Figure object
364
+
365
+ Example:
366
+ >>> from oscura.comparison import compare_traces
367
+ >>> from oscura.comparison.visualization import plot_comparison_summary
368
+ >>> result = compare_traces(trace1, trace2)
369
+ >>> fig = plot_comparison_summary(result)
370
+ >>> plt.show()
371
+
372
+ References:
373
+ CMP-003: Summary table of key differences
374
+ """
375
+ fig = plt.figure(figsize=figsize)
376
+ gs = GridSpec(3, 2, hspace=0.4, wspace=0.3)
377
+
378
+ # Statistics table
379
+ ax_stats = fig.add_subplot(gs[0, :])
380
+ ax_stats.axis("off")
381
+
382
+ stats_data = [
383
+ ["Match Status", "PASS ✓" if result.match else "FAIL ✗"],
384
+ ["Similarity Score", f"{result.similarity:.4f}"],
385
+ ["Correlation", f"{result.correlation:.4f}"],
386
+ ["Max Difference", f"{result.max_difference:.6f}"],
387
+ ["RMS Difference", f"{result.rms_difference:.6f}"],
388
+ ]
389
+
390
+ if result.statistics:
391
+ stats_data.extend(
392
+ [
393
+ ["Mean Difference", f"{result.statistics['mean_difference']:.6f}"],
394
+ ["Violations", f"{result.statistics['num_violations']}"],
395
+ ["Violation Rate", f"{result.statistics['violation_rate'] * 100:.2f}%"],
396
+ ]
397
+ )
398
+
399
+ table = ax_stats.table(
400
+ cellText=stats_data,
401
+ colLabels=["Metric", "Value"],
402
+ cellLoc="left",
403
+ loc="center",
404
+ bbox=[0, 0, 1, 1], # type: ignore[arg-type]
405
+ )
406
+ table.auto_set_font_size(False)
407
+ table.set_fontsize(10)
408
+ table.scale(1, 2)
409
+
410
+ # Color code match status
411
+ if result.match:
412
+ table[(1, 1)].set_facecolor("#90EE90") # Light green
413
+ else:
414
+ table[(1, 1)].set_facecolor("#FFB6C1") # Light red
415
+
416
+ ax_stats.set_title(title, fontsize=14, fontweight="bold", pad=20)
417
+
418
+ # Overlay plot
419
+ if result.difference_trace is not None:
420
+ # Plot difference trace
421
+ ax_overlay = fig.add_subplot(gs[1, :])
422
+ n_samples = len(result.difference_trace.data)
423
+ time = np.arange(n_samples)
424
+ ax_overlay.plot(time, result.difference_trace.data, label="Difference")
425
+ ax_overlay.axhline(y=0, color="k", linestyle="--", alpha=0.5)
426
+ ax_overlay.set_xlabel("Sample")
427
+ ax_overlay.set_ylabel("Difference")
428
+ ax_overlay.set_title("Difference Trace")
429
+ ax_overlay.legend()
430
+ ax_overlay.grid(True, alpha=0.3)
431
+
432
+ # Histogram of differences
433
+ if result.difference_trace is not None:
434
+ ax_hist = fig.add_subplot(gs[2, 0])
435
+ diff_data = result.difference_trace.data
436
+ ax_hist.hist(diff_data, bins=50, edgecolor="black", alpha=0.7)
437
+ ax_hist.axvline(x=0, color="r", linestyle="--", linewidth=2, label="Zero difference")
438
+ ax_hist.set_xlabel("Difference")
439
+ ax_hist.set_ylabel("Count")
440
+ ax_hist.set_title("Difference Distribution")
441
+ ax_hist.legend()
442
+ ax_hist.grid(True, alpha=0.3)
443
+
444
+ # Violation locations
445
+ ax_viol = fig.add_subplot(gs[2, 1])
446
+ if result.violations is not None and len(result.violations) > 0:
447
+ ax_viol.scatter(
448
+ result.violations,
449
+ np.ones_like(result.violations),
450
+ marker="|",
451
+ s=100,
452
+ color="red",
453
+ alpha=0.5,
454
+ )
455
+ ax_viol.set_xlim(0, len(result.difference_trace.data) if result.difference_trace else 1000)
456
+ ax_viol.set_ylim(0.5, 1.5)
457
+ ax_viol.set_xlabel("Sample Index")
458
+ ax_viol.set_title(f"Violation Locations ({len(result.violations)} total)")
459
+ ax_viol.set_yticks([])
460
+ else:
461
+ ax_viol.text(
462
+ 0.5,
463
+ 0.5,
464
+ "No Violations",
465
+ ha="center",
466
+ va="center",
467
+ fontsize=14,
468
+ color="green",
469
+ )
470
+ ax_viol.axis("off")
471
+
472
+ plt.tight_layout()
473
+ return fig
474
+
475
+
476
+ __all__ = [
477
+ "plot_comparison_heatmap",
478
+ "plot_comparison_summary",
479
+ "plot_difference",
480
+ "plot_overlay",
481
+ ]
@@ -0,0 +1,70 @@
1
+ """EMC/EMI compliance testing module.
2
+
3
+ This module provides regulatory compliance testing capabilities including
4
+ limit masks, compliance testing, and report generation for FCC, CE/CISPR,
5
+ and MIL-STD standards.
6
+
7
+
8
+ Example:
9
+ >>> import oscura as osc
10
+ >>> from oscura.compliance import load_limit_mask, check_compliance, generate_compliance_report
11
+ >>>
12
+ >>> trace = osc.load('emissions.wfm')
13
+ >>> mask = load_limit_mask('FCC_Part15_ClassB')
14
+ >>> result = check_compliance(trace, mask)
15
+ >>> generate_compliance_report(result, 'compliance_report.html')
16
+ """
17
+
18
+ from oscura.compliance.advanced import (
19
+ ComplianceTestConfig,
20
+ ComplianceTestRunner,
21
+ ComplianceTestSuite,
22
+ InterpolationMethod,
23
+ LimitInterpolator,
24
+ QPDetectorBand,
25
+ QPDetectorParams,
26
+ QuasiPeakDetector,
27
+ interpolate_limit,
28
+ )
29
+ from oscura.compliance.masks import (
30
+ AVAILABLE_MASKS,
31
+ LimitMask,
32
+ create_custom_mask,
33
+ load_limit_mask,
34
+ )
35
+ from oscura.compliance.reporting import (
36
+ ComplianceReportFormat,
37
+ generate_compliance_report,
38
+ )
39
+ from oscura.compliance.testing import (
40
+ ComplianceResult,
41
+ ComplianceViolation,
42
+ DetectorType,
43
+ check_compliance,
44
+ )
45
+
46
+ __all__ = [
47
+ # Masks (EMC-001)
48
+ "AVAILABLE_MASKS",
49
+ "ComplianceReportFormat",
50
+ "ComplianceResult",
51
+ # Advanced Compliance (COMP-005, 006, 007)
52
+ "ComplianceTestConfig",
53
+ "ComplianceTestRunner",
54
+ "ComplianceTestSuite",
55
+ "ComplianceViolation",
56
+ "DetectorType",
57
+ "InterpolationMethod",
58
+ "LimitInterpolator",
59
+ "LimitMask",
60
+ "QPDetectorBand",
61
+ "QPDetectorParams",
62
+ "QuasiPeakDetector",
63
+ # Testing (EMC-002)
64
+ "check_compliance",
65
+ "create_custom_mask",
66
+ # Reporting (EMC-003)
67
+ "generate_compliance_report",
68
+ "interpolate_limit",
69
+ "load_limit_mask",
70
+ ]