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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
oscura/api/fluent.py ADDED
@@ -0,0 +1,571 @@
1
+ """Fluent interface for signal analysis.
2
+
3
+ This module provides a fluent (method chaining) interface for
4
+ expressing signal analysis operations in a readable, intuitive way.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from typing import TYPE_CHECKING, Any, TypeVar
11
+
12
+ import numpy as np
13
+
14
+ if TYPE_CHECKING:
15
+ from collections.abc import Callable
16
+
17
+ from numpy.typing import NDArray
18
+
19
+ T = TypeVar("T")
20
+
21
+ __all__ = [
22
+ "FluentResult",
23
+ "FluentTrace",
24
+ "trace",
25
+ ]
26
+
27
+
28
+ @dataclass
29
+ class FluentResult[T]:
30
+ """Result container with fluent interface.
31
+
32
+ Provides method chaining for result processing.
33
+
34
+ Attributes:
35
+ value: The wrapped value
36
+ metadata: Associated metadata
37
+
38
+ Example:
39
+ >>> result = FluentResult(42.5)
40
+ >>> result.format("The value is {:.2f}").print()
41
+ The value is 42.50
42
+
43
+ References:
44
+ API-019: Fluent Interface
45
+ """
46
+
47
+ value: T
48
+ metadata: dict[str, Any] = field(default_factory=dict)
49
+
50
+ def get(self) -> T:
51
+ """Get the raw value.
52
+
53
+ Returns:
54
+ The wrapped value
55
+ """
56
+ return self.value
57
+
58
+ def map(self, func: Callable[[T], Any]) -> FluentResult: # type: ignore[type-arg]
59
+ """Apply function to value.
60
+
61
+ Args:
62
+ func: Function to apply
63
+
64
+ Returns:
65
+ New FluentResult with mapped value
66
+ """
67
+ return FluentResult(func(self.value), self.metadata.copy())
68
+
69
+ def filter(self, predicate: Callable[[T], bool]) -> FluentResult | None: # type: ignore[type-arg]
70
+ """Filter based on predicate.
71
+
72
+ Args:
73
+ predicate: Filter function
74
+
75
+ Returns:
76
+ Self if predicate passes, None otherwise
77
+ """
78
+ if predicate(self.value):
79
+ return self
80
+ return None
81
+
82
+ def format(self, fmt: str) -> FluentResult[str]:
83
+ """Format value as string.
84
+
85
+ Args:
86
+ fmt: Format string
87
+
88
+ Returns:
89
+ New FluentResult with formatted string
90
+ """
91
+ return FluentResult(fmt.format(self.value), self.metadata.copy())
92
+
93
+ def print(self, prefix: str = "") -> FluentResult[T]:
94
+ """Print value and return self.
95
+
96
+ Args:
97
+ prefix: Optional prefix
98
+
99
+ Returns:
100
+ Self (for chaining)
101
+ """
102
+ print(f"{prefix}{self.value}")
103
+ return self
104
+
105
+ def with_metadata(self, **kwargs: Any) -> FluentResult[T]:
106
+ """Add metadata.
107
+
108
+ Args:
109
+ **kwargs: Metadata key-value pairs
110
+
111
+ Returns:
112
+ Self (for chaining)
113
+ """
114
+ self.metadata.update(kwargs)
115
+ return self
116
+
117
+ def __repr__(self) -> str:
118
+ return f"FluentResult({self.value!r})"
119
+
120
+
121
+ class FluentTrace:
122
+ """Fluent interface wrapper for trace data.
123
+
124
+ Provides method chaining for signal processing operations.
125
+
126
+ Example:
127
+ >>> result = (FluentTrace(data, sample_rate=1e9)
128
+ ... .lowpass(cutoff=1e6)
129
+ ... .normalize()
130
+ ... .fft(nfft=8192)
131
+ ... .magnitude()
132
+ ... .get())
133
+
134
+ References:
135
+ API-019: Fluent Interface
136
+ """
137
+
138
+ def __init__(self, data: NDArray[np.float64], sample_rate: float = 1.0, **metadata: Any):
139
+ """Initialize fluent trace.
140
+
141
+ Args:
142
+ data: Trace data array
143
+ sample_rate: Sample rate in Hz
144
+ **metadata: Additional metadata
145
+ """
146
+ self._data = data
147
+ self._sample_rate = sample_rate
148
+ self._metadata = metadata
149
+ self._history: list[str] = []
150
+
151
+ @property
152
+ def data(self) -> NDArray[np.float64]:
153
+ """Get current data."""
154
+ return self._data
155
+
156
+ @property
157
+ def sample_rate(self) -> float:
158
+ """Get sample rate."""
159
+ return self._sample_rate
160
+
161
+ def get(self) -> NDArray[np.float64]:
162
+ """Get raw data array.
163
+
164
+ Returns:
165
+ Data array
166
+ """
167
+ return self._data
168
+
169
+ def copy(self) -> FluentTrace:
170
+ """Create copy of trace.
171
+
172
+ Returns:
173
+ New FluentTrace with copied data
174
+ """
175
+ return FluentTrace(self._data.copy(), self._sample_rate, **self._metadata.copy())
176
+
177
+ # =========================================================================
178
+ # Filtering Methods
179
+ # =========================================================================
180
+
181
+ def lowpass(self, cutoff: float, order: int = 4) -> FluentTrace:
182
+ """Apply low-pass filter.
183
+
184
+ Args:
185
+ cutoff: Cutoff frequency in Hz
186
+ order: Filter order
187
+
188
+ Returns:
189
+ Self (for chaining)
190
+ """
191
+ from scipy import signal
192
+
193
+ nyq = self._sample_rate / 2
194
+ normalized_cutoff = min(cutoff / nyq, 0.99)
195
+ b, a = signal.butter(order, normalized_cutoff, btype="low")
196
+ self._data = signal.filtfilt(b, a, self._data)
197
+ self._history.append(f"lowpass(cutoff={cutoff})")
198
+ return self
199
+
200
+ def highpass(self, cutoff: float, order: int = 4) -> FluentTrace:
201
+ """Apply high-pass filter.
202
+
203
+ Args:
204
+ cutoff: Cutoff frequency in Hz
205
+ order: Filter order
206
+
207
+ Returns:
208
+ Self (for chaining)
209
+ """
210
+ from scipy import signal
211
+
212
+ nyq = self._sample_rate / 2
213
+ normalized_cutoff = max(cutoff / nyq, 0.01)
214
+ b, a = signal.butter(order, normalized_cutoff, btype="high")
215
+ self._data = signal.filtfilt(b, a, self._data)
216
+ self._history.append(f"highpass(cutoff={cutoff})")
217
+ return self
218
+
219
+ def bandpass(self, low: float, high: float, order: int = 4) -> FluentTrace:
220
+ """Apply band-pass filter.
221
+
222
+ Args:
223
+ low: Low cutoff frequency
224
+ high: High cutoff frequency
225
+ order: Filter order
226
+
227
+ Returns:
228
+ Self (for chaining)
229
+ """
230
+ from scipy import signal
231
+
232
+ nyq = self._sample_rate / 2
233
+ b, a = signal.butter(order, [low / nyq, high / nyq], btype="band")
234
+ self._data = signal.filtfilt(b, a, self._data)
235
+ self._history.append(f"bandpass(low={low}, high={high})")
236
+ return self
237
+
238
+ def notch(self, freq: float, Q: float = 30.0) -> FluentTrace:
239
+ """Apply notch filter.
240
+
241
+ Args:
242
+ freq: Notch frequency
243
+ Q: Quality factor
244
+
245
+ Returns:
246
+ Self (for chaining)
247
+ """
248
+ from scipy import signal
249
+
250
+ nyq = self._sample_rate / 2
251
+ b, a = signal.iirnotch(freq / nyq, Q)
252
+ self._data = signal.filtfilt(b, a, self._data)
253
+ self._history.append(f"notch(freq={freq})")
254
+ return self
255
+
256
+ # =========================================================================
257
+ # Transform Methods
258
+ # =========================================================================
259
+
260
+ def normalize(self, method: str = "minmax") -> FluentTrace:
261
+ """Normalize data.
262
+
263
+ Args:
264
+ method: Normalization method (minmax, zscore, peak)
265
+
266
+ Returns:
267
+ Self (for chaining)
268
+ """
269
+ if method == "minmax":
270
+ data_min = np.min(self._data)
271
+ data_max = np.max(self._data)
272
+ if data_max - data_min > 0:
273
+ self._data = (self._data - data_min) / (data_max - data_min)
274
+ elif method == "zscore":
275
+ std = np.std(self._data)
276
+ if std > 0:
277
+ self._data = (self._data - np.mean(self._data)) / std
278
+ elif method == "peak":
279
+ peak = np.max(np.abs(self._data))
280
+ if peak > 0:
281
+ self._data = self._data / peak
282
+
283
+ self._history.append(f"normalize(method={method})")
284
+ return self
285
+
286
+ def scale(self, factor: float) -> FluentTrace:
287
+ """Scale data by factor.
288
+
289
+ Args:
290
+ factor: Scale factor
291
+
292
+ Returns:
293
+ Self (for chaining)
294
+ """
295
+ self._data = self._data * factor
296
+ self._history.append(f"scale(factor={factor})")
297
+ return self
298
+
299
+ def offset(self, value: float) -> FluentTrace:
300
+ """Add offset to data.
301
+
302
+ Args:
303
+ value: Offset value
304
+
305
+ Returns:
306
+ Self (for chaining)
307
+ """
308
+ self._data = self._data + value
309
+ self._history.append(f"offset(value={value})")
310
+ return self
311
+
312
+ def clip(self, low: float, high: float) -> FluentTrace:
313
+ """Clip data to range.
314
+
315
+ Args:
316
+ low: Low limit
317
+ high: High limit
318
+
319
+ Returns:
320
+ Self (for chaining)
321
+ """
322
+ self._data = np.clip(self._data, low, high)
323
+ self._history.append(f"clip(low={low}, high={high})")
324
+ return self
325
+
326
+ def abs(self) -> FluentTrace:
327
+ """Take absolute value.
328
+
329
+ Returns:
330
+ Self (for chaining)
331
+ """
332
+ self._data = np.abs(self._data)
333
+ self._history.append("abs()")
334
+ return self
335
+
336
+ def diff(self) -> FluentTrace:
337
+ """Differentiate data.
338
+
339
+ Returns:
340
+ Self (for chaining)
341
+ """
342
+ self._data = np.diff(self._data, prepend=self._data[0])
343
+ self._history.append("diff()")
344
+ return self
345
+
346
+ def integrate(self) -> FluentTrace:
347
+ """Integrate data.
348
+
349
+ Returns:
350
+ Self (for chaining)
351
+ """
352
+ dt = 1.0 / self._sample_rate
353
+ self._data = np.cumsum(self._data) * dt
354
+ self._history.append("integrate()")
355
+ return self
356
+
357
+ # =========================================================================
358
+ # Resampling Methods
359
+ # =========================================================================
360
+
361
+ def resample(self, new_length: int) -> FluentTrace:
362
+ """Resample to new length.
363
+
364
+ Args:
365
+ new_length: New number of samples
366
+
367
+ Returns:
368
+ Self (for chaining)
369
+ """
370
+ from scipy import signal
371
+
372
+ self._data = signal.resample(self._data, new_length)
373
+ self._sample_rate = self._sample_rate * new_length / len(self._data)
374
+ self._history.append(f"resample(new_length={new_length})")
375
+ return self
376
+
377
+ def decimate(self, factor: int) -> FluentTrace:
378
+ """Decimate by factor.
379
+
380
+ Args:
381
+ factor: Decimation factor
382
+
383
+ Returns:
384
+ Self (for chaining)
385
+ """
386
+ from scipy import signal
387
+
388
+ self._data = signal.decimate(self._data, factor)
389
+ self._sample_rate = self._sample_rate / factor
390
+ self._history.append(f"decimate(factor={factor})")
391
+ return self
392
+
393
+ def slice(self, start: int = 0, end: int | None = None) -> FluentTrace:
394
+ """Slice data.
395
+
396
+ Args:
397
+ start: Start index
398
+ end: End index (None for end of data)
399
+
400
+ Returns:
401
+ Self (for chaining)
402
+ """
403
+ self._data = self._data[start:end]
404
+ self._history.append(f"slice(start={start}, end={end})")
405
+ return self
406
+
407
+ # =========================================================================
408
+ # Spectral Methods
409
+ # =========================================================================
410
+
411
+ def fft(self, nfft: int | None = None) -> FluentTrace:
412
+ """Compute FFT.
413
+
414
+ Args:
415
+ nfft: FFT size
416
+
417
+ Returns:
418
+ Self (for chaining, data is now complex)
419
+ """
420
+ self._data = np.fft.fft(self._data, n=nfft) # type: ignore[assignment]
421
+ self._history.append(f"fft(nfft={nfft})")
422
+ return self
423
+
424
+ def magnitude(self) -> FluentTrace:
425
+ """Compute magnitude of complex data.
426
+
427
+ Returns:
428
+ Self (for chaining)
429
+ """
430
+ self._data = np.abs(self._data)
431
+ self._history.append("magnitude()")
432
+ return self
433
+
434
+ def phase(self) -> FluentTrace:
435
+ """Compute phase of complex data.
436
+
437
+ Returns:
438
+ Self (for chaining)
439
+ """
440
+ self._data = np.angle(self._data)
441
+ self._history.append("phase()")
442
+ return self
443
+
444
+ def psd(self, nperseg: int = 256) -> FluentResult[tuple]: # type: ignore[type-arg]
445
+ """Compute power spectral density.
446
+
447
+ Args:
448
+ nperseg: Segment size
449
+
450
+ Returns:
451
+ FluentResult with (frequencies, psd) tuple
452
+ """
453
+ from scipy import signal
454
+
455
+ f, psd = signal.welch(self._data, self._sample_rate, nperseg=nperseg)
456
+ return FluentResult((f, psd))
457
+
458
+ # =========================================================================
459
+ # Measurement Methods
460
+ # =========================================================================
461
+
462
+ def mean(self) -> FluentResult[float]:
463
+ """Compute mean.
464
+
465
+ Returns:
466
+ FluentResult with mean value
467
+ """
468
+ return FluentResult(float(np.mean(self._data)))
469
+
470
+ def std(self) -> FluentResult[float]:
471
+ """Compute standard deviation.
472
+
473
+ Returns:
474
+ FluentResult with std value
475
+ """
476
+ return FluentResult(float(np.std(self._data)))
477
+
478
+ def rms(self) -> FluentResult[float]:
479
+ """Compute RMS value.
480
+
481
+ Returns:
482
+ FluentResult with RMS value
483
+ """
484
+ return FluentResult(float(np.sqrt(np.mean(self._data**2))))
485
+
486
+ def peak_to_peak(self) -> FluentResult[float]:
487
+ """Compute peak-to-peak value.
488
+
489
+ Returns:
490
+ FluentResult with peak-to-peak value
491
+ """
492
+ return FluentResult(float(np.ptp(self._data)))
493
+
494
+ def min(self) -> FluentResult[float]:
495
+ """Get minimum value.
496
+
497
+ Returns:
498
+ FluentResult with min value
499
+ """
500
+ return FluentResult(float(np.min(self._data)))
501
+
502
+ def max(self) -> FluentResult[float]:
503
+ """Get maximum value.
504
+
505
+ Returns:
506
+ FluentResult with max value
507
+ """
508
+ return FluentResult(float(np.max(self._data)))
509
+
510
+ # =========================================================================
511
+ # Utility Methods
512
+ # =========================================================================
513
+
514
+ def print_history(self) -> FluentTrace:
515
+ """Print operation history.
516
+
517
+ Returns:
518
+ Self (for chaining)
519
+ """
520
+ print("Operation history:")
521
+ for op in self._history:
522
+ print(f" - {op}")
523
+ return self
524
+
525
+ def with_metadata(self, **kwargs: Any) -> FluentTrace:
526
+ """Add metadata.
527
+
528
+ Args:
529
+ **kwargs: Metadata key-value pairs
530
+
531
+ Returns:
532
+ Self (for chaining)
533
+ """
534
+ self._metadata.update(kwargs)
535
+ return self
536
+
537
+ def __len__(self) -> int:
538
+ return len(self._data)
539
+
540
+ def __repr__(self) -> str:
541
+ return (
542
+ f"FluentTrace(samples={len(self._data)}, "
543
+ f"sample_rate={self._sample_rate}, "
544
+ f"operations={len(self._history)})"
545
+ )
546
+
547
+
548
+ def trace(data: NDArray[np.float64], sample_rate: float = 1.0, **metadata: Any) -> FluentTrace:
549
+ """Create fluent trace wrapper.
550
+
551
+ Factory function for creating FluentTrace instances.
552
+
553
+ Args:
554
+ data: Trace data array
555
+ sample_rate: Sample rate in Hz
556
+ **metadata: Additional metadata
557
+
558
+ Returns:
559
+ FluentTrace instance
560
+
561
+ Example:
562
+ >>> result = (trace(data, sample_rate=1e9)
563
+ ... .lowpass(cutoff=1e6)
564
+ ... .normalize()
565
+ ... .mean()
566
+ ... .get())
567
+
568
+ References:
569
+ API-019: Fluent Interface
570
+ """
571
+ return FluentTrace(data, sample_rate, **metadata)