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.
- oscura/__init__.py +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.0.dist-info/METADATA +300 -0
- oscura-0.1.0.dist-info/RECORD +463 -0
- oscura-0.1.0.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"""Safe Operating Area (SOA) analysis for TraceKit.
|
|
2
|
+
|
|
3
|
+
Provides SOA checking and visualization for power semiconductor devices.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from oscura.analyzers.power.soa import soa_analysis, SOALimit
|
|
8
|
+
>>> limits = [
|
|
9
|
+
... SOALimit(v_max=100, i_max=50, pulse_width=1e-6),
|
|
10
|
+
... SOALimit(v_max=80, i_max=100, pulse_width=10e-6),
|
|
11
|
+
... ]
|
|
12
|
+
>>> result = soa_analysis(v_trace, i_trace, limits)
|
|
13
|
+
>>> print(f"SOA violations: {len(result['violations'])}")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from typing import TYPE_CHECKING, Any
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from matplotlib.figure import Figure
|
|
25
|
+
|
|
26
|
+
from oscura.core.types import WaveformTrace
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class SOALimit:
|
|
31
|
+
"""Defines a point on the SOA boundary.
|
|
32
|
+
|
|
33
|
+
The SOA is typically defined by a piecewise linear boundary in
|
|
34
|
+
log-log V-I space, with different limits for different pulse widths.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
v_max: Maximum voltage at this limit point (Volts).
|
|
38
|
+
i_max: Maximum current at this limit point (Amps).
|
|
39
|
+
pulse_width: Pulse duration for this limit (seconds).
|
|
40
|
+
Use np.inf for DC limit.
|
|
41
|
+
name: Optional name for this limit point.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
v_max: float
|
|
45
|
+
i_max: float
|
|
46
|
+
pulse_width: float = np.inf
|
|
47
|
+
name: str = ""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class SOAViolation:
|
|
52
|
+
"""Information about an SOA violation.
|
|
53
|
+
|
|
54
|
+
Attributes:
|
|
55
|
+
timestamp: Time of violation (seconds).
|
|
56
|
+
sample_index: Sample index of violation.
|
|
57
|
+
voltage: Voltage at violation point.
|
|
58
|
+
current: Current at violation point.
|
|
59
|
+
limit: The SOA limit that was violated.
|
|
60
|
+
margin: How far inside (negative) or outside (positive) the limit.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
timestamp: float
|
|
64
|
+
sample_index: int
|
|
65
|
+
voltage: float
|
|
66
|
+
current: float
|
|
67
|
+
limit: SOALimit
|
|
68
|
+
margin: float
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def soa_analysis(
|
|
72
|
+
voltage: WaveformTrace,
|
|
73
|
+
current: WaveformTrace,
|
|
74
|
+
limits: list[SOALimit],
|
|
75
|
+
*,
|
|
76
|
+
pulse_width: float | None = None,
|
|
77
|
+
) -> dict[str, Any]:
|
|
78
|
+
"""Analyze voltage-current trajectory against SOA limits.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
voltage: Voltage waveform trace.
|
|
82
|
+
current: Current waveform trace.
|
|
83
|
+
limits: List of SOA limit points.
|
|
84
|
+
pulse_width: Pulse width to use for limit selection.
|
|
85
|
+
If None, uses DC limits.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Dictionary with:
|
|
89
|
+
- passed: True if no violations
|
|
90
|
+
- violations: List of SOAViolation objects
|
|
91
|
+
- v_trajectory: Voltage values
|
|
92
|
+
- i_trajectory: Current values
|
|
93
|
+
- min_margin: Minimum margin to SOA boundary (negative = inside)
|
|
94
|
+
- applicable_limits: Limits used for this pulse width
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
>>> result = soa_analysis(v_ds, i_d, soa_limits)
|
|
98
|
+
>>> if not result['passed']:
|
|
99
|
+
... print(f"SOA violated at {result['violations'][0].timestamp}s")
|
|
100
|
+
"""
|
|
101
|
+
v_data = voltage.data
|
|
102
|
+
i_data = current.data
|
|
103
|
+
|
|
104
|
+
# Ensure same length
|
|
105
|
+
min_len = min(len(v_data), len(i_data))
|
|
106
|
+
v_data = v_data[:min_len]
|
|
107
|
+
i_data = i_data[:min_len]
|
|
108
|
+
sample_period = voltage.metadata.time_base
|
|
109
|
+
|
|
110
|
+
# Select applicable limits based on pulse width
|
|
111
|
+
if pulse_width is None:
|
|
112
|
+
pulse_width = np.inf
|
|
113
|
+
|
|
114
|
+
applicable_limits = [l for l in limits if l.pulse_width >= pulse_width] # noqa: E741
|
|
115
|
+
if not applicable_limits:
|
|
116
|
+
applicable_limits = limits # Use all if none match
|
|
117
|
+
|
|
118
|
+
# Build SOA boundary (interpolate between limit points)
|
|
119
|
+
# Sort by voltage
|
|
120
|
+
sorted_limits = sorted(applicable_limits, key=lambda l: l.v_max) # noqa: E741
|
|
121
|
+
|
|
122
|
+
violations: list[SOAViolation] = []
|
|
123
|
+
margins: list[float] = []
|
|
124
|
+
|
|
125
|
+
for i in range(len(v_data)):
|
|
126
|
+
v = abs(v_data[i])
|
|
127
|
+
current_i = abs(i_data[i])
|
|
128
|
+
|
|
129
|
+
# Find applicable limit (linear interpolation in log-log space)
|
|
130
|
+
i_limit = _interpolate_soa_limit(v, sorted_limits)
|
|
131
|
+
|
|
132
|
+
margin = i_limit - current_i
|
|
133
|
+
margins.append(margin)
|
|
134
|
+
|
|
135
|
+
if current_i > i_limit:
|
|
136
|
+
# Find which specific limit was violated
|
|
137
|
+
for limit in sorted_limits:
|
|
138
|
+
if v <= limit.v_max and current_i > limit.i_max:
|
|
139
|
+
violations.append(
|
|
140
|
+
SOAViolation(
|
|
141
|
+
timestamp=i * sample_period,
|
|
142
|
+
sample_index=i,
|
|
143
|
+
voltage=float(v_data[i]),
|
|
144
|
+
current=float(i_data[i]),
|
|
145
|
+
limit=limit,
|
|
146
|
+
margin=-margin,
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
"passed": len(violations) == 0,
|
|
153
|
+
"violations": violations,
|
|
154
|
+
"v_trajectory": v_data,
|
|
155
|
+
"i_trajectory": i_data,
|
|
156
|
+
"min_margin": float(np.min(margins)) if margins else 0.0,
|
|
157
|
+
"applicable_limits": applicable_limits,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _interpolate_soa_limit(voltage: float, limits: list[SOALimit]) -> float:
|
|
162
|
+
"""Interpolate SOA current limit at given voltage.
|
|
163
|
+
|
|
164
|
+
Uses log-log interpolation between limit points.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
voltage: Voltage at which to interpolate current limit
|
|
168
|
+
limits: List of SOALimit points defining the boundary
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Interpolated current limit in Amps
|
|
172
|
+
"""
|
|
173
|
+
if len(limits) == 0:
|
|
174
|
+
return np.inf # type: ignore[no-any-return]
|
|
175
|
+
|
|
176
|
+
if len(limits) == 1:
|
|
177
|
+
if voltage <= limits[0].v_max:
|
|
178
|
+
return limits[0].i_max
|
|
179
|
+
return 0.0
|
|
180
|
+
|
|
181
|
+
# Find bracketing points
|
|
182
|
+
for i in range(len(limits) - 1):
|
|
183
|
+
if limits[i].v_max <= voltage <= limits[i + 1].v_max:
|
|
184
|
+
# Log-log interpolation
|
|
185
|
+
v1, v2 = limits[i].v_max, limits[i + 1].v_max
|
|
186
|
+
i1, i2 = limits[i].i_max, limits[i + 1].i_max
|
|
187
|
+
|
|
188
|
+
if v1 <= 0 or v2 <= 0 or i1 <= 0 or i2 <= 0:
|
|
189
|
+
# Linear interpolation fallback
|
|
190
|
+
t = (voltage - v1) / (v2 - v1)
|
|
191
|
+
return i1 + t * (i2 - i1)
|
|
192
|
+
|
|
193
|
+
# Log-log
|
|
194
|
+
log_v = np.log10(voltage)
|
|
195
|
+
log_v1, log_v2 = np.log10(v1), np.log10(v2)
|
|
196
|
+
log_i1, log_i2 = np.log10(i1), np.log10(i2)
|
|
197
|
+
|
|
198
|
+
t = (log_v - log_v1) / (log_v2 - log_v1)
|
|
199
|
+
log_i = log_i1 + t * (log_i2 - log_i1)
|
|
200
|
+
return 10**log_i # type: ignore[no-any-return]
|
|
201
|
+
|
|
202
|
+
# Beyond limits
|
|
203
|
+
if voltage < limits[0].v_max:
|
|
204
|
+
return limits[0].i_max
|
|
205
|
+
return 0.0
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def check_soa_violations(
|
|
209
|
+
voltage: WaveformTrace,
|
|
210
|
+
current: WaveformTrace,
|
|
211
|
+
limits: list[SOALimit],
|
|
212
|
+
) -> list[SOAViolation]:
|
|
213
|
+
"""Check for SOA violations and return list of violations.
|
|
214
|
+
|
|
215
|
+
Convenience function that just returns violations.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
voltage: Voltage waveform.
|
|
219
|
+
current: Current waveform.
|
|
220
|
+
limits: SOA limits.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
List of SOA violations (empty if all within limits).
|
|
224
|
+
"""
|
|
225
|
+
result = soa_analysis(voltage, current, limits)
|
|
226
|
+
return result["violations"] # type: ignore[no-any-return]
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def plot_soa(
|
|
230
|
+
voltage: WaveformTrace,
|
|
231
|
+
current: WaveformTrace,
|
|
232
|
+
limits: list[SOALimit],
|
|
233
|
+
*,
|
|
234
|
+
figsize: tuple[float, float] = (10, 8),
|
|
235
|
+
title: str | None = None,
|
|
236
|
+
show_violations: bool = True,
|
|
237
|
+
) -> Figure:
|
|
238
|
+
"""Plot SOA diagram with trajectory and limits.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
voltage: Voltage waveform.
|
|
242
|
+
current: Current waveform.
|
|
243
|
+
limits: SOA limits to plot.
|
|
244
|
+
figsize: Figure size in inches.
|
|
245
|
+
title: Plot title.
|
|
246
|
+
show_violations: If True, highlight violations.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Matplotlib Figure object.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
>>> fig = plot_soa(v_ds, i_d, soa_limits)
|
|
253
|
+
>>> plt.show()
|
|
254
|
+
"""
|
|
255
|
+
import matplotlib.pyplot as plt
|
|
256
|
+
|
|
257
|
+
result = soa_analysis(voltage, current, limits)
|
|
258
|
+
|
|
259
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
260
|
+
|
|
261
|
+
# Plot SOA boundary
|
|
262
|
+
sorted_limits = sorted(limits, key=lambda l: l.v_max) # noqa: E741
|
|
263
|
+
v_boundary = [l.v_max for l in sorted_limits] # noqa: E741
|
|
264
|
+
i_boundary = [l.i_max for l in sorted_limits] # noqa: E741
|
|
265
|
+
|
|
266
|
+
# Add corner points for closed boundary
|
|
267
|
+
v_boundary = [0, *v_boundary, v_boundary[-1], 0]
|
|
268
|
+
i_boundary = [i_boundary[0], *i_boundary, 0, 0]
|
|
269
|
+
|
|
270
|
+
ax.fill(v_boundary, i_boundary, alpha=0.2, color="green", label="Safe Operating Area")
|
|
271
|
+
ax.plot(v_boundary, i_boundary, "g-", linewidth=2)
|
|
272
|
+
|
|
273
|
+
# Plot trajectory
|
|
274
|
+
v_traj = np.abs(result["v_trajectory"])
|
|
275
|
+
i_traj = np.abs(result["i_trajectory"])
|
|
276
|
+
ax.plot(v_traj, i_traj, "b-", linewidth=1, alpha=0.7, label="Operating trajectory")
|
|
277
|
+
|
|
278
|
+
# Highlight violations
|
|
279
|
+
if show_violations and result["violations"]:
|
|
280
|
+
v_viol = [v.voltage for v in result["violations"]]
|
|
281
|
+
i_viol = [v.current for v in result["violations"]]
|
|
282
|
+
ax.scatter(
|
|
283
|
+
np.abs(v_viol),
|
|
284
|
+
np.abs(i_viol),
|
|
285
|
+
c="red",
|
|
286
|
+
s=50,
|
|
287
|
+
marker="x",
|
|
288
|
+
label=f"Violations ({len(result['violations'])})",
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
ax.set_xlabel("Voltage (V)")
|
|
292
|
+
ax.set_ylabel("Current (A)")
|
|
293
|
+
ax.set_xlim(0, None)
|
|
294
|
+
ax.set_ylim(0, None)
|
|
295
|
+
ax.grid(True, alpha=0.3)
|
|
296
|
+
ax.legend()
|
|
297
|
+
|
|
298
|
+
if title:
|
|
299
|
+
ax.set_title(title)
|
|
300
|
+
else:
|
|
301
|
+
status = "PASS" if result["passed"] else "FAIL"
|
|
302
|
+
ax.set_title(f"Safe Operating Area Analysis - {status}")
|
|
303
|
+
|
|
304
|
+
plt.tight_layout()
|
|
305
|
+
return fig
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def create_mosfet_soa(
|
|
309
|
+
v_ds_max: float,
|
|
310
|
+
i_d_max: float,
|
|
311
|
+
p_d_max: float,
|
|
312
|
+
*,
|
|
313
|
+
pulse_limits: dict[float, float] | None = None,
|
|
314
|
+
) -> list[SOALimit]:
|
|
315
|
+
"""Create SOA limits for a MOSFET.
|
|
316
|
+
|
|
317
|
+
Generates typical SOA boundary from datasheet parameters.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
v_ds_max: Maximum drain-source voltage.
|
|
321
|
+
i_d_max: Maximum continuous drain current.
|
|
322
|
+
p_d_max: Maximum power dissipation.
|
|
323
|
+
pulse_limits: Optional dict of {pulse_width: i_max} for pulsed limits.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
List of SOALimit objects defining the boundary.
|
|
327
|
+
|
|
328
|
+
Example:
|
|
329
|
+
>>> limits = create_mosfet_soa(v_ds_max=100, i_d_max=50, p_d_max=150)
|
|
330
|
+
"""
|
|
331
|
+
limits = []
|
|
332
|
+
|
|
333
|
+
# Current limit (horizontal line at I_max)
|
|
334
|
+
limits.append(SOALimit(v_max=1.0, i_max=i_d_max, name="I_max"))
|
|
335
|
+
|
|
336
|
+
# Power limit (hyperbola P = V * I)
|
|
337
|
+
# Find intersection with I_max line
|
|
338
|
+
v_at_imax = p_d_max / i_d_max
|
|
339
|
+
if v_at_imax < v_ds_max:
|
|
340
|
+
limits.append(SOALimit(v_max=v_at_imax, i_max=i_d_max, name="P_max_start"))
|
|
341
|
+
|
|
342
|
+
# Add points along power hyperbola
|
|
343
|
+
for v in np.geomspace(v_at_imax, v_ds_max * 0.9, 5)[1:]:
|
|
344
|
+
i = p_d_max / v
|
|
345
|
+
limits.append(SOALimit(v_max=v, i_max=i, name="P_max"))
|
|
346
|
+
|
|
347
|
+
# Voltage limit
|
|
348
|
+
limits.append(SOALimit(v_max=v_ds_max, i_max=0.1, name="V_max"))
|
|
349
|
+
|
|
350
|
+
# Add pulsed limits if provided
|
|
351
|
+
if pulse_limits:
|
|
352
|
+
for pw, i_max in pulse_limits.items():
|
|
353
|
+
limits.append(
|
|
354
|
+
SOALimit(
|
|
355
|
+
v_max=v_ds_max,
|
|
356
|
+
i_max=i_max,
|
|
357
|
+
pulse_width=pw,
|
|
358
|
+
name=f"Pulse_{pw * 1e6:.0f}us",
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
return limits
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
__all__ = [
|
|
366
|
+
"SOALimit",
|
|
367
|
+
"SOAViolation",
|
|
368
|
+
"check_soa_violations",
|
|
369
|
+
"create_mosfet_soa",
|
|
370
|
+
"plot_soa",
|
|
371
|
+
"soa_analysis",
|
|
372
|
+
]
|