spectre-core 0.0.9__py3-none-any.whl → 0.0.10__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 (106) hide show
  1. spectre_core/__init__.py +0 -3
  2. spectre_core/_file_io/__init__.py +15 -0
  3. spectre_core/_file_io/file_handlers.py +128 -0
  4. spectre_core/capture_configs/__init__.py +29 -0
  5. spectre_core/capture_configs/_capture_config.py +85 -0
  6. spectre_core/capture_configs/_capture_templates.py +222 -0
  7. spectre_core/capture_configs/_parameters.py +110 -0
  8. spectre_core/capture_configs/_pconstraints.py +82 -0
  9. spectre_core/capture_configs/_ptemplates.py +450 -0
  10. spectre_core/capture_configs/_pvalidators.py +173 -0
  11. spectre_core/chunks/__init__.py +17 -201
  12. spectre_core/chunks/{base.py → _base.py} +15 -60
  13. spectre_core/chunks/_chunks.py +200 -0
  14. spectre_core/chunks/{factory.py → _factory.py} +6 -7
  15. spectre_core/chunks/library/{callisto/chunk.py → _callisto.py} +4 -7
  16. spectre_core/chunks/library/{fixed/chunk.py → _fixed_center_frequency.py} +7 -64
  17. spectre_core/chunks/library/_swept_center_frequency.py +103 -0
  18. spectre_core/config/__init__.py +20 -0
  19. spectre_core/config/_paths.py +77 -0
  20. spectre_core/config/_time_formats.py +15 -0
  21. spectre_core/exceptions.py +4 -5
  22. spectre_core/logging/__init__.py +11 -0
  23. spectre_core/logging/_configure.py +35 -0
  24. spectre_core/logging/_decorators.py +19 -0
  25. spectre_core/{logging.py → logging/_log_handlers.py} +13 -58
  26. spectre_core/plotting/__init__.py +7 -1
  27. spectre_core/plotting/{base.py → _base.py} +40 -20
  28. spectre_core/plotting/_format.py +18 -0
  29. spectre_core/plotting/{panel_stack.py → _panel_stack.py} +48 -48
  30. spectre_core/plotting/_panels.py +234 -0
  31. spectre_core/post_processing/__init__.py +10 -2
  32. spectre_core/post_processing/_base.py +119 -0
  33. spectre_core/post_processing/{factory.py → _factory.py} +7 -6
  34. spectre_core/post_processing/{post_processor.py → _post_processor.py} +3 -3
  35. spectre_core/post_processing/library/_fixed_center_frequency.py +115 -0
  36. spectre_core/post_processing/library/_swept_center_frequency.py +382 -0
  37. spectre_core/receivers/__init__.py +12 -2
  38. spectre_core/receivers/_base.py +352 -0
  39. spectre_core/receivers/{factory.py → _factory.py} +2 -2
  40. spectre_core/receivers/_spec_names.py +20 -0
  41. spectre_core/receivers/gr/__init__.py +3 -0
  42. spectre_core/receivers/gr/_base.py +33 -0
  43. spectre_core/receivers/gr/_rsp1a.py +158 -0
  44. spectre_core/receivers/gr/_test.py +123 -0
  45. spectre_core/receivers/library/_rsp1a.py +61 -0
  46. spectre_core/receivers/library/_test.py +221 -0
  47. spectre_core/spectrograms/__init__.py +18 -0
  48. spectre_core/spectrograms/{analytical.py → _analytical.py} +29 -27
  49. spectre_core/spectrograms/{array_operations.py → _array_operations.py} +47 -1
  50. spectre_core/spectrograms/{spectrogram.py → _spectrogram.py} +62 -35
  51. spectre_core/spectrograms/{transform.py → _transform.py} +76 -89
  52. spectre_core/{post_processing/library → wgetting}/__init__.py +4 -5
  53. spectre_core/wgetting/_callisto.py +155 -0
  54. {spectre_core-0.0.9.dist-info → spectre_core-0.0.10.dist-info}/METADATA +1 -1
  55. spectre_core-0.0.10.dist-info/RECORD +63 -0
  56. spectre_core/cfg.py +0 -116
  57. spectre_core/chunks/library/__init__.py +0 -8
  58. spectre_core/chunks/library/sweep/__init__.py +0 -0
  59. spectre_core/chunks/library/sweep/chunk.py +0 -400
  60. spectre_core/dynamic_imports.py +0 -22
  61. spectre_core/file_handlers/base.py +0 -68
  62. spectre_core/file_handlers/configs.py +0 -271
  63. spectre_core/file_handlers/json.py +0 -40
  64. spectre_core/file_handlers/text.py +0 -21
  65. spectre_core/plotting/factory.py +0 -26
  66. spectre_core/plotting/format.py +0 -19
  67. spectre_core/plotting/library/__init__.py +0 -7
  68. spectre_core/plotting/library/frequency_cuts/panel.py +0 -74
  69. spectre_core/plotting/library/integral_over_frequency/panel.py +0 -34
  70. spectre_core/plotting/library/spectrogram/panel.py +0 -92
  71. spectre_core/plotting/library/time_cuts/panel.py +0 -77
  72. spectre_core/plotting/panel_register.py +0 -13
  73. spectre_core/post_processing/base.py +0 -132
  74. spectre_core/post_processing/library/fixed/__init__.py +0 -0
  75. spectre_core/post_processing/library/fixed/event_handler.py +0 -40
  76. spectre_core/post_processing/library/sweep/event_handler.py +0 -54
  77. spectre_core/receivers/base.py +0 -422
  78. spectre_core/receivers/library/__init__.py +0 -7
  79. spectre_core/receivers/library/rsp1a/__init__.py +0 -0
  80. spectre_core/receivers/library/rsp1a/gr/__init__.py +0 -0
  81. spectre_core/receivers/library/rsp1a/gr/fixed.py +0 -104
  82. spectre_core/receivers/library/rsp1a/gr/sweep.py +0 -129
  83. spectre_core/receivers/library/rsp1a/receiver.py +0 -68
  84. spectre_core/receivers/library/rspduo/__init__.py +0 -0
  85. spectre_core/receivers/library/rspduo/gr/__init__.py +0 -0
  86. spectre_core/receivers/library/rspduo/gr/tuner_1_fixed.py +0 -114
  87. spectre_core/receivers/library/rspduo/gr/tuner_1_sweep.py +0 -131
  88. spectre_core/receivers/library/rspduo/gr/tuner_2_fixed.py +0 -120
  89. spectre_core/receivers/library/rspduo/gr/tuner_2_sweep.py +0 -119
  90. spectre_core/receivers/library/rspduo/receiver.py +0 -97
  91. spectre_core/receivers/library/test/__init__.py +0 -0
  92. spectre_core/receivers/library/test/gr/__init__.py +0 -0
  93. spectre_core/receivers/library/test/gr/cosine_signal_1.py +0 -83
  94. spectre_core/receivers/library/test/gr/tagged_staircase.py +0 -93
  95. spectre_core/receivers/library/test/receiver.py +0 -203
  96. spectre_core/receivers/validators.py +0 -231
  97. spectre_core/web_fetch/callisto.py +0 -101
  98. spectre_core-0.0.9.dist-info/RECORD +0 -74
  99. /spectre_core/chunks/{chunk_register.py → _register.py} +0 -0
  100. /spectre_core/post_processing/{event_handler_register.py → _register.py} +0 -0
  101. /spectre_core/receivers/{receiver_register.py → _register.py} +0 -0
  102. /spectre_core/{chunks/library/callisto/__init__.py → receivers/gr/_rspduo.py} +0 -0
  103. /spectre_core/{chunks/library/fixed/__init__.py → receivers/library/_rspduo.py} +0 -0
  104. {spectre_core-0.0.9.dist-info → spectre_core-0.0.10.dist-info}/LICENSE +0 -0
  105. {spectre_core-0.0.9.dist-info → spectre_core-0.0.10.dist-info}/WHEEL +0 -0
  106. {spectre_core-0.0.9.dist-info → spectre_core-0.0.10.dist-info}/top_level.txt +0 -0
@@ -1,77 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from typing import Optional
6
-
7
- from spectre_core.spectrograms.spectrogram import TimeCut
8
- from spectre_core.spectrograms.spectrogram import Spectrogram
9
- from spectre_core.plotting.base import BaseTimeSeriesPanel, CutsPanel
10
- from spectre_core.plotting.format import DEFAULT_FORMATS
11
- from spectre_core.plotting.panel_register import register_panel
12
-
13
- TIME_CUTS_PANEL_NAME = "time_cuts"
14
-
15
- @register_panel(TIME_CUTS_PANEL_NAME)
16
- class Panel(BaseTimeSeriesPanel, CutsPanel):
17
- def __init__(self,
18
- name: str,
19
- spectrogram: Spectrogram,
20
- time_type: str = "seconds",
21
- *frequencies: list[float],
22
- dBb: bool = False,
23
- peak_normalise: bool = False,
24
- background_subtract: bool = False,
25
- cmap: str = DEFAULT_FORMATS.cuts_cmap,
26
- **kwargs):
27
- super().__init__(name,
28
- spectrogram,
29
- time_type,
30
- **kwargs)
31
- self._frequencies = frequencies
32
- self._cmap = cmap
33
- self._dBb = dBb
34
- self._peak_normalise = peak_normalise
35
- self._background_subtract = background_subtract
36
- # map each cut frequency to the corresponding TimeCut dataclass
37
- self._time_cuts: Optional[dict[float, TimeCut]] = {}
38
-
39
-
40
- @property
41
- def time_cuts(self) -> dict[float, TimeCut]:
42
- if not self._time_cuts:
43
- for frequency in self._frequencies:
44
- time_cut = self._spectrogram.get_time_cut(frequency,
45
- dBb = self._dBb,
46
- peak_normalise = self._peak_normalise,
47
- correct_background = self._background_subtract,
48
- return_time_type=self._time_type)
49
- self._time_cuts[time_cut.frequency] = time_cut
50
- return self._time_cuts
51
-
52
-
53
- @property
54
- def frequencies(self) -> list[float]:
55
- return list(self.time_cuts.keys())
56
-
57
-
58
- def draw(self):
59
- for frequency, color in self.bind_to_colors():
60
- time_cut = self.time_cuts[frequency]
61
- self.ax.step(self.times,
62
- time_cut.cut,
63
- where='mid',
64
- color = color)
65
-
66
-
67
- def annotate_y_axis(self) -> None:
68
- if self._dBb:
69
- self.ax.set_ylabel('dBb')
70
- elif self._peak_normalise:
71
- return # no y-axis label
72
- else:
73
- self.ax.set_ylabel(f'{self._spectrogram.spectrum_type.capitalize()}')
74
-
75
-
76
- def bind_to_colors(self):
77
- return super().bind_to_colors(self.frequencies, cmap = self._cmap)
@@ -1,13 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
-
6
- # Global dictionaries to hold the mappings
7
- panels = {}
8
-
9
- def register_panel(panel_name: str):
10
- def decorator(cls):
11
- panels[panel_name] = cls
12
- return cls
13
- return decorator
@@ -1,132 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from logging import getLogger
6
- _LOGGER = getLogger(__name__)
7
-
8
- from queue import Queue
9
- from typing import Optional
10
- from abc import ABC, abstractmethod
11
- from math import floor
12
-
13
- from watchdog.events import (
14
- FileSystemEventHandler,
15
- FileCreatedEvent,
16
- )
17
-
18
- from spectre_core.chunks.factory import get_chunk_from_tag
19
- from spectre_core.file_handlers.configs import CaptureConfig
20
- from spectre_core.spectrograms.spectrogram import Spectrogram
21
- from spectre_core.spectrograms.transform import join_spectrograms
22
- from spectre_core.spectrograms.transform import (
23
- time_average,
24
- frequency_average
25
- )
26
-
27
-
28
- class BaseEventHandler(ABC, FileSystemEventHandler):
29
- def __init__(self,
30
- tag: str):
31
- self._tag = tag
32
-
33
- self._Chunk = get_chunk_from_tag(tag)
34
-
35
- self._capture_config = CaptureConfig(tag)
36
-
37
- self._watch_extension = self._capture_config.get("watch_extension")
38
- if self._watch_extension is None:
39
- raise KeyError("The watch extension has not been specified in the capture config")
40
-
41
- # attribute to store the next file to be processed
42
- # (specifically, the absolute file path of the file)
43
- self._queued_file: Optional[str] = None
44
-
45
- # spectrogram cache stores spectrograms in memory
46
- # such that they can be periodically written to files
47
- # according to the joining time.
48
- self._spectrogram: Optional[Spectrogram] = None
49
-
50
-
51
-
52
- @abstractmethod
53
- def process(self,
54
- absolute_file_path: str) -> None:
55
- """Process the file stored at the input absolute file path.
56
-
57
- To be implemented by derived classes.
58
- """
59
-
60
-
61
- def on_created(self,
62
- event: FileCreatedEvent):
63
- """Process a newly created batch file, only once the next batch is created.
64
-
65
- Since we assume that the batches are non-overlapping in time, this guarantees
66
- we avoid post processing a file while it is being written to. Files are processed
67
- sequentially, in the order they are created.
68
- """
69
-
70
- # the 'src_path' attribute holds the absolute path of the newly created file
71
- absolute_file_path = event.src_path
72
-
73
- # only 'notice' a file if it ends with the appropriate extension
74
- # as defined in the capture config
75
- if absolute_file_path.endswith(self._watch_extension):
76
- _LOGGER.info(f"Noticed {absolute_file_path}")
77
-
78
- # If there exists a queued file, try and process it
79
- if self._queued_file is not None:
80
- try:
81
- self.process(self._queued_file)
82
- except Exception:
83
- _LOGGER.error(f"An error has occured while processing {self._queued_file}",
84
- exc_info=True)
85
- # flush any internally stored spectrogram on error to avoid lost data
86
- self._flush_spectrogram()
87
- # re-raise the exception to the main thread
88
- raise
89
-
90
- # Queue the current file for processing next
91
- _LOGGER.info(f"Queueing {absolute_file_path} for post processing")
92
- self._queued_file = absolute_file_path
93
-
94
-
95
- def _average_in_time(self,
96
- spectrogram: Spectrogram) -> Spectrogram:
97
- _LOGGER.info("Averaging spectrogram in time")
98
- requested_time_resolution = self._capture_config['time_resolution'] # [s]
99
- if requested_time_resolution is None:
100
- raise KeyError(f"Time resolution has not been specified in the capture config")
101
- average_over = floor(requested_time_resolution/spectrogram.time_resolution) if requested_time_resolution > spectrogram.time_resolution else 1
102
- return time_average(spectrogram, average_over)
103
-
104
-
105
- def _average_in_frequency(self,
106
- spectrogram: Spectrogram) -> Spectrogram:
107
- _LOGGER.info("Averaging spectrogram in frequency")
108
- frequency_resolution = self._capture_config['frequency_resolution'] # [Hz]
109
- if frequency_resolution is None:
110
- raise KeyError(f"Frequency resolution has not been specified in the capture config")
111
- average_over = floor(frequency_resolution/spectrogram.frequency_resolution) if frequency_resolution > spectrogram.frequency_resolution else 1
112
- return frequency_average(spectrogram, average_over)
113
-
114
-
115
- def _join_spectrogram(self,
116
- spectrogram: Spectrogram) -> None:
117
- _LOGGER.info("Joining spectrogram")
118
- if self._spectrogram is None:
119
- self._spectrogram = spectrogram
120
- else:
121
- self._spectrogram = join_spectrograms([self._spectrogram, spectrogram])
122
-
123
- if self._spectrogram.time_range >= self._capture_config['joining_time']:
124
- self._flush_spectrogram()
125
-
126
-
127
- def _flush_spectrogram(self) -> None:
128
- if self._spectrogram:
129
- _LOGGER.info(f"Flushing spectrogram to file with chunk start time {self._spectrogram.chunk_start_time}")
130
- self._spectrogram.save()
131
- _LOGGER.info("Flush successful, resetting spectrogram cache")
132
- self._spectrogram = None # reset the cache
File without changes
@@ -1,40 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from logging import getLogger
6
- _LOGGER = getLogger(__name__)
7
-
8
- import os
9
-
10
- from spectre_core.post_processing.base import BaseEventHandler
11
- from spectre_core.post_processing.event_handler_register import register_event_handler
12
-
13
- @register_event_handler("fixed")
14
- class EventHandler(BaseEventHandler):
15
- def __init__(self, *args, **kwargs):
16
- super().__init__(*args, **kwargs)
17
-
18
-
19
- def process(self,
20
- absolute_file_path: str):
21
- _LOGGER.info(f"Processing: {absolute_file_path}")
22
- file_name = os.path.basename(absolute_file_path)
23
- base_file_name, _ = os.path.splitext(file_name)
24
- chunk_start_time, _ = base_file_name.split('_')
25
- chunk = self._Chunk(chunk_start_time, self._tag)
26
-
27
- _LOGGER.info("Creating spectrogram")
28
- spectrogram = chunk.build_spectrogram()
29
-
30
- spectrogram = self._average_in_time(spectrogram)
31
- spectrogram = self._average_in_frequency(spectrogram)
32
- self._join_spectrogram(spectrogram)
33
-
34
- bin_chunk = chunk.get_file('bin')
35
- _LOGGER.info(f"Deleting {bin_chunk.file_path}")
36
- bin_chunk.delete()
37
-
38
- hdr_chunk = chunk.get_file('hdr')
39
- _LOGGER.info(f"Deleting {hdr_chunk.file_path}")
40
- hdr_chunk.delete()
@@ -1,54 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from logging import getLogger
6
- _LOGGER = getLogger(__name__)
7
-
8
- import os
9
-
10
- from spectre_core.chunks.base import BaseChunk
11
- from spectre_core.post_processing.base import BaseEventHandler
12
- from spectre_core.post_processing.event_handler_register import register_event_handler
13
-
14
- @register_event_handler("sweep")
15
- class EventHandler(BaseEventHandler):
16
- def __init__(self, *args, **kwargs):
17
- super().__init__(*args, **kwargs)
18
-
19
- self.previous_chunk: BaseChunk = None # cache for previous chunk
20
-
21
-
22
- def process(self,
23
- absolute_file_path: str):
24
- _LOGGER.info(f"Processing: {absolute_file_path}")
25
- file_name = os.path.basename(absolute_file_path)
26
- base_file_name, _ = os.path.splitext(file_name)
27
- chunk_start_time, _ = base_file_name.split('_')
28
- chunk = self._Chunk(chunk_start_time, self._tag)
29
-
30
- _LOGGER.info("Creating spectrogram")
31
- spectrogram = chunk.build_spectrogram(previous_chunk = self.previous_chunk)
32
-
33
- spectrogram = self._average_in_time(spectrogram)
34
- spectrogram = self._average_in_frequency(spectrogram)
35
- self._join_spectrogram(spectrogram)
36
-
37
- # if the previous chunk has not yet been set, it means we are processing the first chunk
38
- # so we don't need to handle the previous chunk
39
- if self.previous_chunk is None:
40
- # instead, only set it for the next time this method is called
41
- self.previous_chunk = chunk
42
-
43
- # otherwise the previous chunk is defined (and by this point has already been processed)
44
- else:
45
- bin_chunk = self.previous_chunk.get_file('bin')
46
- _LOGGER.info(f"Deleting {bin_chunk.file_path}")
47
- bin_chunk.delete()
48
-
49
- hdr_chunk = self.previous_chunk.get_file('hdr')
50
- _LOGGER.info(f"Deleting {hdr_chunk.file_path}")
51
- hdr_chunk.delete()
52
-
53
- # and reassign the current chunk to be used as the previous chunk at the next call of this method
54
- self.previous_chunk = chunk