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,391 @@
|
|
|
1
|
+
"""Chunked wavelet transform for memory-bounded processing.
|
|
2
|
+
|
|
3
|
+
This module implements memory-bounded wavelet transforms (CWT and DWT)
|
|
4
|
+
with segment processing and boundary handling.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.analyzers.spectral.chunked_wavelet import cwt_chunked, dwt_chunked
|
|
9
|
+
>>> coeffs = cwt_chunked('large_signal.bin', scales=[1, 2, 4, 8], wavelet='morl')
|
|
10
|
+
>>> print(f"CWT coefficients shape: {coeffs.shape}")
|
|
11
|
+
|
|
12
|
+
References:
|
|
13
|
+
pywt (PyWavelets) for wavelet transforms
|
|
14
|
+
Mallat, S. (1999). "A Wavelet Tour of Signal Processing"
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import Iterator, Sequence
|
|
26
|
+
|
|
27
|
+
from numpy.typing import NDArray
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def cwt_chunked(
|
|
31
|
+
file_path: str | Path,
|
|
32
|
+
scales: Sequence[float],
|
|
33
|
+
wavelet: str = "morl",
|
|
34
|
+
*,
|
|
35
|
+
chunk_size: int | float = 1e6,
|
|
36
|
+
overlap_factor: float = 2.0,
|
|
37
|
+
sample_rate: float = 1.0,
|
|
38
|
+
dtype: str = "float32",
|
|
39
|
+
) -> tuple[NDArray[Any], NDArray[Any]]:
|
|
40
|
+
"""Compute continuous wavelet transform for large files.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Processes signal in chunks with overlap to handle boundaries,
|
|
44
|
+
computes CWT per chunk, and stitches results.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
file_path: Path to signal file (binary format).
|
|
48
|
+
scales: Scales for CWT (wavelet dilations).
|
|
49
|
+
wavelet: Wavelet name ('morl', 'mexh', 'cmor', etc.).
|
|
50
|
+
chunk_size: Chunk size in samples.
|
|
51
|
+
overlap_factor: Overlap factor for boundaries (e.g., 2.0 = 2x max scale).
|
|
52
|
+
sample_rate: Sample rate in Hz.
|
|
53
|
+
dtype: Data type of input file ('float32' or 'float64').
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Tuple of (coefficients, frequencies) where:
|
|
57
|
+
- coefficients: CWT coefficients (scales x time).
|
|
58
|
+
- frequencies: Corresponding frequencies for each scale.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
ImportError: If pywt (PyWavelets) is not installed.
|
|
62
|
+
ValueError: If file cannot be read or scales invalid.
|
|
63
|
+
|
|
64
|
+
Example:
|
|
65
|
+
>>> scales = np.arange(1, 128)
|
|
66
|
+
>>> coeffs, freqs = cwt_chunked(
|
|
67
|
+
... 'signal.bin',
|
|
68
|
+
... scales=scales,
|
|
69
|
+
... wavelet='morl',
|
|
70
|
+
... chunk_size=1e6,
|
|
71
|
+
... sample_rate=1e6
|
|
72
|
+
... )
|
|
73
|
+
>>> print(f"CWT shape: {coeffs.shape}")
|
|
74
|
+
|
|
75
|
+
References:
|
|
76
|
+
MEM-007: Chunked Wavelet Transform
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
import pywt
|
|
80
|
+
except ImportError as e:
|
|
81
|
+
raise ImportError(
|
|
82
|
+
"pywt (PyWavelets) is required for wavelet transforms. "
|
|
83
|
+
"Install with: pip install PyWavelets"
|
|
84
|
+
) from e
|
|
85
|
+
|
|
86
|
+
chunk_size = int(chunk_size)
|
|
87
|
+
scales: NDArray[np.float64] = np.asarray(scales) # type: ignore[no-redef]
|
|
88
|
+
|
|
89
|
+
# Calculate boundary overlap (proportional to max scale)
|
|
90
|
+
max_scale = np.max(scales)
|
|
91
|
+
boundary_overlap = int(overlap_factor * max_scale)
|
|
92
|
+
|
|
93
|
+
# Determine dtype
|
|
94
|
+
np_dtype = np.float32 if dtype == "float32" else np.float64
|
|
95
|
+
bytes_per_sample = 4 if dtype == "float32" else 8
|
|
96
|
+
|
|
97
|
+
# Open file and get total size
|
|
98
|
+
file_path = Path(file_path)
|
|
99
|
+
file_size_bytes = file_path.stat().st_size
|
|
100
|
+
total_samples = file_size_bytes // bytes_per_sample
|
|
101
|
+
|
|
102
|
+
# Process chunks
|
|
103
|
+
coeffs_list: list[NDArray[Any]] = []
|
|
104
|
+
chunks = _generate_chunks(file_path, total_samples, chunk_size, boundary_overlap, np_dtype)
|
|
105
|
+
|
|
106
|
+
for chunk_data in chunks:
|
|
107
|
+
# Compute CWT for this chunk
|
|
108
|
+
coeffs_chunk, freqs = pywt.cwt(
|
|
109
|
+
chunk_data,
|
|
110
|
+
scales,
|
|
111
|
+
wavelet,
|
|
112
|
+
sampling_period=1 / sample_rate,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Remove boundary overlap regions (except first/last chunk)
|
|
116
|
+
if len(coeffs_list) > 0:
|
|
117
|
+
# Remove left boundary
|
|
118
|
+
trim_left = boundary_overlap
|
|
119
|
+
coeffs_chunk = coeffs_chunk[:, trim_left:]
|
|
120
|
+
|
|
121
|
+
coeffs_list.append(coeffs_chunk)
|
|
122
|
+
|
|
123
|
+
# Concatenate all chunks
|
|
124
|
+
if len(coeffs_list) == 0:
|
|
125
|
+
raise ValueError(f"No chunks processed from {file_path}")
|
|
126
|
+
|
|
127
|
+
coefficients = np.concatenate(coeffs_list, axis=1)
|
|
128
|
+
|
|
129
|
+
return coefficients, freqs
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def dwt_chunked(
|
|
133
|
+
file_path: str | Path,
|
|
134
|
+
wavelet: str = "db4",
|
|
135
|
+
level: int | None = None,
|
|
136
|
+
*,
|
|
137
|
+
chunk_size: int | float = 1e6,
|
|
138
|
+
mode: str = "symmetric",
|
|
139
|
+
dtype: str = "float32",
|
|
140
|
+
) -> list[NDArray[Any]]:
|
|
141
|
+
"""Compute discrete wavelet transform for large files.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
Processes signal in chunks and computes multilevel DWT.
|
|
145
|
+
Handles boundaries using specified extension mode.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
file_path: Path to signal file (binary format).
|
|
149
|
+
wavelet: Wavelet name ('db4', 'haar', 'sym5', etc.).
|
|
150
|
+
level: Decomposition level (None = maximum level).
|
|
151
|
+
chunk_size: Chunk size in samples.
|
|
152
|
+
mode: Signal extension mode for boundaries.
|
|
153
|
+
dtype: Data type of input file ('float32' or 'float64').
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List of coefficient arrays [cA_n, cD_n, ..., cD_1] where:
|
|
157
|
+
- cA_n: Approximation coefficients at level n.
|
|
158
|
+
- cD_i: Detail coefficients at level i.
|
|
159
|
+
|
|
160
|
+
Raises:
|
|
161
|
+
ImportError: If pywt is not installed.
|
|
162
|
+
ValueError: If file cannot be read.
|
|
163
|
+
|
|
164
|
+
Example:
|
|
165
|
+
>>> coeffs = dwt_chunked(
|
|
166
|
+
... 'signal.bin',
|
|
167
|
+
... wavelet='db4',
|
|
168
|
+
... level=5,
|
|
169
|
+
... chunk_size=1e6
|
|
170
|
+
... )
|
|
171
|
+
>>> print(f"Approximation shape: {coeffs[0].shape}")
|
|
172
|
+
|
|
173
|
+
References:
|
|
174
|
+
MEM-007: Chunked Wavelet Transform
|
|
175
|
+
Daubechies, I. (1992). "Ten Lectures on Wavelets"
|
|
176
|
+
"""
|
|
177
|
+
try:
|
|
178
|
+
import pywt
|
|
179
|
+
except ImportError as e:
|
|
180
|
+
raise ImportError(
|
|
181
|
+
"pywt (PyWavelets) is required for wavelet transforms. "
|
|
182
|
+
"Install with: pip install PyWavelets"
|
|
183
|
+
) from e
|
|
184
|
+
|
|
185
|
+
chunk_size = int(chunk_size)
|
|
186
|
+
|
|
187
|
+
# Determine dtype
|
|
188
|
+
np_dtype = np.float32 if dtype == "float32" else np.float64
|
|
189
|
+
bytes_per_sample = 4 if dtype == "float32" else 8
|
|
190
|
+
|
|
191
|
+
# Get wavelet filter length for overlap calculation
|
|
192
|
+
wavelet_obj = pywt.Wavelet(wavelet)
|
|
193
|
+
filter_len = wavelet_obj.dec_len
|
|
194
|
+
boundary_overlap = filter_len * (2 ** (level or 1))
|
|
195
|
+
|
|
196
|
+
# Open file and get total size
|
|
197
|
+
file_path = Path(file_path)
|
|
198
|
+
file_size_bytes = file_path.stat().st_size
|
|
199
|
+
total_samples = file_size_bytes // bytes_per_sample
|
|
200
|
+
|
|
201
|
+
# Process chunks
|
|
202
|
+
coeffs_list: list[list[NDArray[Any]]] = []
|
|
203
|
+
chunk_starts: list[int] = [] # Track chunk start positions in original signal
|
|
204
|
+
chunks = _generate_chunks(file_path, total_samples, chunk_size, boundary_overlap, np_dtype)
|
|
205
|
+
|
|
206
|
+
current_offset = 0
|
|
207
|
+
for chunk_data in chunks:
|
|
208
|
+
# Compute DWT for this chunk
|
|
209
|
+
coeffs_chunk = pywt.wavedec(chunk_data, wavelet, mode=mode, level=level)
|
|
210
|
+
coeffs_list.append(coeffs_chunk)
|
|
211
|
+
chunk_starts.append(current_offset)
|
|
212
|
+
# Move offset by chunk_size (not including overlap)
|
|
213
|
+
current_offset = min(current_offset + chunk_size, total_samples)
|
|
214
|
+
|
|
215
|
+
# Merge coefficients from all chunks
|
|
216
|
+
if len(coeffs_list) == 0:
|
|
217
|
+
raise ValueError(f"No chunks processed from {file_path}")
|
|
218
|
+
|
|
219
|
+
# For DWT, we need to handle overlaps properly at each decomposition level
|
|
220
|
+
# At each level j, the downsampling factor is 2^j
|
|
221
|
+
# We trim the overlap region at each level based on the decomposition level
|
|
222
|
+
|
|
223
|
+
num_levels = len(coeffs_list[0])
|
|
224
|
+
merged_coeffs = []
|
|
225
|
+
|
|
226
|
+
for level_idx in range(num_levels):
|
|
227
|
+
# Calculate the effective overlap for this decomposition level
|
|
228
|
+
# Each level is downsampled by factor of 2 from previous level
|
|
229
|
+
downsample_factor = 2**level_idx
|
|
230
|
+
level_overlap = boundary_overlap // downsample_factor
|
|
231
|
+
|
|
232
|
+
if len(coeffs_list) == 1:
|
|
233
|
+
# Only one chunk - no overlap to handle
|
|
234
|
+
merged_coeffs.append(coeffs_list[0][level_idx])
|
|
235
|
+
else:
|
|
236
|
+
# Multiple chunks - need to handle overlaps
|
|
237
|
+
merged_level_coeffs = []
|
|
238
|
+
|
|
239
|
+
for chunk_idx, chunk_coeffs in enumerate(coeffs_list):
|
|
240
|
+
level_coeffs = chunk_coeffs[level_idx]
|
|
241
|
+
|
|
242
|
+
if chunk_idx == 0:
|
|
243
|
+
# First chunk - keep all except right overlap
|
|
244
|
+
if level_overlap > 0 and len(level_coeffs) > level_overlap:
|
|
245
|
+
merged_level_coeffs.append(level_coeffs[:-level_overlap])
|
|
246
|
+
else:
|
|
247
|
+
merged_level_coeffs.append(level_coeffs)
|
|
248
|
+
elif chunk_idx == len(coeffs_list) - 1:
|
|
249
|
+
# Last chunk - trim left overlap, keep rest
|
|
250
|
+
if level_overlap > 0 and len(level_coeffs) > level_overlap:
|
|
251
|
+
merged_level_coeffs.append(level_coeffs[level_overlap:])
|
|
252
|
+
else:
|
|
253
|
+
# If overlap is too large, keep small center portion
|
|
254
|
+
center_start = max(0, level_overlap // 2)
|
|
255
|
+
merged_level_coeffs.append(level_coeffs[center_start:])
|
|
256
|
+
else:
|
|
257
|
+
# Middle chunks - trim both sides
|
|
258
|
+
if level_overlap > 0 and len(level_coeffs) > 2 * level_overlap:
|
|
259
|
+
merged_level_coeffs.append(level_coeffs[level_overlap:-level_overlap])
|
|
260
|
+
else:
|
|
261
|
+
# If overlap is too large, keep small center portion
|
|
262
|
+
center_start = max(0, level_overlap // 2)
|
|
263
|
+
center_end = max(center_start + 1, len(level_coeffs) - level_overlap // 2)
|
|
264
|
+
merged_level_coeffs.append(level_coeffs[center_start:center_end])
|
|
265
|
+
|
|
266
|
+
# Concatenate the trimmed coefficients
|
|
267
|
+
if merged_level_coeffs:
|
|
268
|
+
merged_coeffs.append(np.concatenate(merged_level_coeffs))
|
|
269
|
+
else:
|
|
270
|
+
# Fallback: concatenate all if trimming failed
|
|
271
|
+
level_coeffs_list = [chunk_coeffs[level_idx] for chunk_coeffs in coeffs_list]
|
|
272
|
+
merged_coeffs.append(np.concatenate(level_coeffs_list))
|
|
273
|
+
|
|
274
|
+
return merged_coeffs
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _generate_chunks(
|
|
278
|
+
file_path: Path,
|
|
279
|
+
total_samples: int,
|
|
280
|
+
chunk_size: int,
|
|
281
|
+
boundary_overlap: int,
|
|
282
|
+
dtype: type,
|
|
283
|
+
) -> Iterator[NDArray[Any]]:
|
|
284
|
+
"""Generate overlapping chunks from file.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
file_path: Path to binary file.
|
|
288
|
+
total_samples: Total number of samples in file.
|
|
289
|
+
chunk_size: Samples per chunk.
|
|
290
|
+
boundary_overlap: Overlap samples between chunks.
|
|
291
|
+
dtype: NumPy dtype for data.
|
|
292
|
+
|
|
293
|
+
Yields:
|
|
294
|
+
Chunk arrays with boundary overlap.
|
|
295
|
+
"""
|
|
296
|
+
offset = 0
|
|
297
|
+
|
|
298
|
+
with open(file_path, "rb") as f:
|
|
299
|
+
while offset < total_samples:
|
|
300
|
+
# Calculate chunk boundaries
|
|
301
|
+
chunk_start = max(0, offset - boundary_overlap)
|
|
302
|
+
chunk_end = min(total_samples, offset + chunk_size)
|
|
303
|
+
chunk_len = chunk_end - chunk_start
|
|
304
|
+
|
|
305
|
+
# Seek and read
|
|
306
|
+
f.seek(chunk_start * dtype().itemsize)
|
|
307
|
+
chunk_data: NDArray[np.float64] = np.fromfile(f, dtype=dtype, count=chunk_len)
|
|
308
|
+
|
|
309
|
+
if len(chunk_data) == 0:
|
|
310
|
+
break
|
|
311
|
+
|
|
312
|
+
yield chunk_data
|
|
313
|
+
|
|
314
|
+
# Advance offset
|
|
315
|
+
offset += chunk_size
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def cwt_chunked_generator(
|
|
319
|
+
file_path: str | Path,
|
|
320
|
+
scales: Sequence[float],
|
|
321
|
+
wavelet: str = "morl",
|
|
322
|
+
*,
|
|
323
|
+
chunk_size: int | float = 1e6,
|
|
324
|
+
**kwargs: Any, # type: ignore[name-defined]
|
|
325
|
+
) -> Iterator[tuple[NDArray[Any], NDArray[Any]]]: # type: ignore[name-defined]
|
|
326
|
+
"""Generator version that yields CWT chunks.
|
|
327
|
+
|
|
328
|
+
Yields CWT coefficients for each chunk, useful for streaming processing.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
file_path: Path to signal file.
|
|
332
|
+
scales: Scales for CWT.
|
|
333
|
+
wavelet: Wavelet name.
|
|
334
|
+
chunk_size: Chunk size in samples.
|
|
335
|
+
**kwargs: Additional arguments.
|
|
336
|
+
|
|
337
|
+
Yields:
|
|
338
|
+
Tuples of (coefficients, frequencies) for each chunk.
|
|
339
|
+
|
|
340
|
+
Raises:
|
|
341
|
+
ImportError: If pywt (PyWavelets) is not installed.
|
|
342
|
+
|
|
343
|
+
Example:
|
|
344
|
+
>>> for coeffs_chunk, freqs in cwt_chunked_generator('file.bin', scales=[1, 2, 4]):
|
|
345
|
+
... # Process each chunk separately
|
|
346
|
+
... print(f"Chunk shape: {coeffs_chunk.shape}")
|
|
347
|
+
"""
|
|
348
|
+
try:
|
|
349
|
+
import pywt
|
|
350
|
+
except ImportError as e:
|
|
351
|
+
raise ImportError(
|
|
352
|
+
"pywt (PyWavelets) is required for wavelet transforms. "
|
|
353
|
+
"Install with: pip install PyWavelets"
|
|
354
|
+
) from e
|
|
355
|
+
|
|
356
|
+
chunk_size = int(chunk_size)
|
|
357
|
+
scales: NDArray[np.float64] = np.asarray(scales) # type: ignore[no-redef]
|
|
358
|
+
|
|
359
|
+
# Determine dtype
|
|
360
|
+
dtype = kwargs.get("dtype", "float32")
|
|
361
|
+
np_dtype = np.float32 if dtype == "float32" else np.float64
|
|
362
|
+
bytes_per_sample = 4 if dtype == "float32" else 8
|
|
363
|
+
|
|
364
|
+
# Open file and get total size
|
|
365
|
+
file_path = Path(file_path)
|
|
366
|
+
file_size_bytes = file_path.stat().st_size
|
|
367
|
+
total_samples = file_size_bytes // bytes_per_sample
|
|
368
|
+
|
|
369
|
+
# Calculate boundary overlap
|
|
370
|
+
max_scale = np.max(scales)
|
|
371
|
+
boundary_overlap = int(kwargs.get("overlap_factor", 2.0) * max_scale)
|
|
372
|
+
|
|
373
|
+
# Process chunks
|
|
374
|
+
sample_rate = kwargs.get("sample_rate", 1.0)
|
|
375
|
+
chunks = _generate_chunks(file_path, total_samples, chunk_size, boundary_overlap, np_dtype)
|
|
376
|
+
|
|
377
|
+
for chunk_data in chunks:
|
|
378
|
+
coeffs_chunk, freqs = pywt.cwt(
|
|
379
|
+
chunk_data,
|
|
380
|
+
scales,
|
|
381
|
+
wavelet,
|
|
382
|
+
sampling_period=1 / sample_rate,
|
|
383
|
+
)
|
|
384
|
+
yield coeffs_chunk, freqs
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
__all__ = [
|
|
388
|
+
"cwt_chunked",
|
|
389
|
+
"cwt_chunked_generator",
|
|
390
|
+
"dwt_chunked",
|
|
391
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""FFT analysis functions.
|
|
2
|
+
|
|
3
|
+
This module provides FFT-based spectral analysis including chunked processing
|
|
4
|
+
for large datasets.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from numpy.typing import NDArray
|
|
13
|
+
|
|
14
|
+
# Re-export file-based chunked FFT functions
|
|
15
|
+
from oscura.analyzers.spectral.chunked_fft import (
|
|
16
|
+
fft_chunked as fft_chunked_file,
|
|
17
|
+
)
|
|
18
|
+
from oscura.analyzers.spectral.chunked_fft import (
|
|
19
|
+
fft_chunked_parallel,
|
|
20
|
+
streaming_fft,
|
|
21
|
+
welch_psd_chunked,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def fft_chunked(
|
|
26
|
+
data: NDArray[np.floating[Any]],
|
|
27
|
+
chunk_size: int = 8192,
|
|
28
|
+
*,
|
|
29
|
+
window: str = "hann",
|
|
30
|
+
overlap_pct: float = 50.0,
|
|
31
|
+
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
32
|
+
"""Compute FFT on large array using chunked processing.
|
|
33
|
+
|
|
34
|
+
Processes array in overlapping segments to handle large datasets
|
|
35
|
+
that may not fit in FFT at once.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
data: Input signal array.
|
|
39
|
+
chunk_size: Size of each processing chunk.
|
|
40
|
+
window: Window function name.
|
|
41
|
+
overlap_pct: Overlap percentage between chunks (0-100).
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Tuple of (frequencies, magnitudes) arrays.
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
>>> signal = np.sin(2 * np.pi * 1000 * np.linspace(0, 1, 1000000))
|
|
48
|
+
>>> freqs, mags = fft_chunked(signal, chunk_size=4096)
|
|
49
|
+
"""
|
|
50
|
+
data = np.asarray(data, dtype=np.float64).ravel()
|
|
51
|
+
|
|
52
|
+
# Calculate overlap
|
|
53
|
+
hop_size = int(chunk_size * (1 - overlap_pct / 100))
|
|
54
|
+
|
|
55
|
+
# Generate window
|
|
56
|
+
from scipy import signal as sp_signal
|
|
57
|
+
|
|
58
|
+
window_arr = sp_signal.get_window(window, chunk_size)
|
|
59
|
+
|
|
60
|
+
# Process chunks
|
|
61
|
+
chunks = []
|
|
62
|
+
for i in range(0, len(data) - chunk_size + 1, hop_size):
|
|
63
|
+
chunk = data[i : i + chunk_size]
|
|
64
|
+
windowed = chunk * window_arr
|
|
65
|
+
|
|
66
|
+
# Compute FFT
|
|
67
|
+
fft_result = np.fft.rfft(windowed)
|
|
68
|
+
magnitude = np.abs(fft_result)
|
|
69
|
+
chunks.append(magnitude)
|
|
70
|
+
|
|
71
|
+
# Average all chunks
|
|
72
|
+
if chunks:
|
|
73
|
+
avg_magnitude = np.mean(chunks, axis=0)
|
|
74
|
+
else:
|
|
75
|
+
# Handle case where signal shorter than chunk_size
|
|
76
|
+
windowed = data * sp_signal.get_window(window, len(data))
|
|
77
|
+
fft_result = np.fft.rfft(windowed)
|
|
78
|
+
avg_magnitude = np.abs(fft_result)
|
|
79
|
+
|
|
80
|
+
# Generate frequency array
|
|
81
|
+
frequencies = np.fft.rfftfreq(chunk_size, d=1.0)
|
|
82
|
+
|
|
83
|
+
return frequencies, avg_magnitude
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
__all__ = [
|
|
87
|
+
"fft_chunked",
|
|
88
|
+
"fft_chunked_file",
|
|
89
|
+
"fft_chunked_parallel",
|
|
90
|
+
"streaming_fft",
|
|
91
|
+
"welch_psd_chunked",
|
|
92
|
+
]
|