spectre-core 0.0.9__py3-none-any.whl → 0.0.11__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 (109) 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 +171 -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 +13 -2
  38. spectre_core/receivers/_base.py +180 -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/_rspduo.py +227 -0
  45. spectre_core/receivers/gr/_test.py +123 -0
  46. spectre_core/receivers/library/_rsp1a.py +61 -0
  47. spectre_core/receivers/library/_rspduo.py +69 -0
  48. spectre_core/receivers/library/_sdrplay_receiver.py +185 -0
  49. spectre_core/receivers/library/_test.py +221 -0
  50. spectre_core/spectrograms/__init__.py +18 -0
  51. spectre_core/spectrograms/{analytical.py → _analytical.py} +29 -27
  52. spectre_core/spectrograms/{array_operations.py → _array_operations.py} +47 -1
  53. spectre_core/spectrograms/{spectrogram.py → _spectrogram.py} +62 -35
  54. spectre_core/spectrograms/{transform.py → _transform.py} +76 -89
  55. spectre_core/{post_processing/library → wgetting}/__init__.py +4 -5
  56. spectre_core/wgetting/_callisto.py +155 -0
  57. {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/METADATA +1 -1
  58. spectre_core-0.0.11.dist-info/RECORD +64 -0
  59. spectre_core/cfg.py +0 -116
  60. spectre_core/chunks/library/__init__.py +0 -8
  61. spectre_core/chunks/library/callisto/__init__.py +0 -0
  62. spectre_core/chunks/library/fixed/__init__.py +0 -0
  63. spectre_core/chunks/library/sweep/__init__.py +0 -0
  64. spectre_core/chunks/library/sweep/chunk.py +0 -400
  65. spectre_core/dynamic_imports.py +0 -22
  66. spectre_core/file_handlers/base.py +0 -68
  67. spectre_core/file_handlers/configs.py +0 -271
  68. spectre_core/file_handlers/json.py +0 -40
  69. spectre_core/file_handlers/text.py +0 -21
  70. spectre_core/plotting/factory.py +0 -26
  71. spectre_core/plotting/format.py +0 -19
  72. spectre_core/plotting/library/__init__.py +0 -7
  73. spectre_core/plotting/library/frequency_cuts/panel.py +0 -74
  74. spectre_core/plotting/library/integral_over_frequency/panel.py +0 -34
  75. spectre_core/plotting/library/spectrogram/panel.py +0 -92
  76. spectre_core/plotting/library/time_cuts/panel.py +0 -77
  77. spectre_core/plotting/panel_register.py +0 -13
  78. spectre_core/post_processing/base.py +0 -132
  79. spectre_core/post_processing/library/fixed/__init__.py +0 -0
  80. spectre_core/post_processing/library/fixed/event_handler.py +0 -40
  81. spectre_core/post_processing/library/sweep/event_handler.py +0 -54
  82. spectre_core/receivers/base.py +0 -422
  83. spectre_core/receivers/library/__init__.py +0 -7
  84. spectre_core/receivers/library/rsp1a/__init__.py +0 -0
  85. spectre_core/receivers/library/rsp1a/gr/__init__.py +0 -0
  86. spectre_core/receivers/library/rsp1a/gr/fixed.py +0 -104
  87. spectre_core/receivers/library/rsp1a/gr/sweep.py +0 -129
  88. spectre_core/receivers/library/rsp1a/receiver.py +0 -68
  89. spectre_core/receivers/library/rspduo/__init__.py +0 -0
  90. spectre_core/receivers/library/rspduo/gr/__init__.py +0 -0
  91. spectre_core/receivers/library/rspduo/gr/tuner_1_fixed.py +0 -114
  92. spectre_core/receivers/library/rspduo/gr/tuner_1_sweep.py +0 -131
  93. spectre_core/receivers/library/rspduo/gr/tuner_2_fixed.py +0 -120
  94. spectre_core/receivers/library/rspduo/gr/tuner_2_sweep.py +0 -119
  95. spectre_core/receivers/library/rspduo/receiver.py +0 -97
  96. spectre_core/receivers/library/test/__init__.py +0 -0
  97. spectre_core/receivers/library/test/gr/__init__.py +0 -0
  98. spectre_core/receivers/library/test/gr/cosine_signal_1.py +0 -83
  99. spectre_core/receivers/library/test/gr/tagged_staircase.py +0 -93
  100. spectre_core/receivers/library/test/receiver.py +0 -203
  101. spectre_core/receivers/validators.py +0 -231
  102. spectre_core/web_fetch/callisto.py +0 -101
  103. spectre_core-0.0.9.dist-info/RECORD +0 -74
  104. /spectre_core/chunks/{chunk_register.py → _register.py} +0 -0
  105. /spectre_core/post_processing/{event_handler_register.py → _register.py} +0 -0
  106. /spectre_core/receivers/{receiver_register.py → _register.py} +0 -0
  107. {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/LICENSE +0 -0
  108. {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/WHEEL +0 -0
  109. {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ #
5
+ # SPDX-License-Identifier: GPL-3.0
6
+ #
7
+ # GNU Radio Python Flow Graph
8
+ # Title: Test receiver
9
+ # GNU Radio version: 3.10.1.1
10
+
11
+ # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
12
+ # This file is part of SPECTRE
13
+ # SPDX-License-Identifier: GPL-3.0-or-later
14
+
15
+ #
16
+ # Test receiver top blocks
17
+ #
18
+
19
+ from functools import partial
20
+ from dataclasses import dataclass
21
+
22
+ from gnuradio import gr
23
+ from gnuradio import blocks
24
+ from gnuradio import spectre
25
+ from gnuradio import analog
26
+
27
+ from spectre_core.capture_configs import Parameters, PNames
28
+ from spectre_core.config import get_chunks_dir_path
29
+ from ._base import capture
30
+
31
+
32
+ class _cosine_signal_1(gr.top_block):
33
+ def __init__(self,
34
+ tag: str,
35
+ parameters: Parameters):
36
+ gr.top_block.__init__(self, catch_exceptions=True)
37
+
38
+ ##################################################
39
+ # Unpack capture config
40
+ ##################################################
41
+ samp_rate = parameters.get_parameter_value(PNames.SAMPLE_RATE)
42
+ batch_size = parameters.get_parameter_value(PNames.BATCH_SIZE)
43
+ frequency = parameters.get_parameter_value(PNames.FREQUENCY)
44
+ amplitude = parameters.get_parameter_value(PNames.AMPLITUDE)
45
+
46
+ ##################################################
47
+ # Blocks
48
+ ##################################################
49
+ self.spectre_batched_file_sink_0 = spectre.batched_file_sink(get_chunks_dir_path(),
50
+ tag,
51
+ batch_size,
52
+ samp_rate)
53
+ self.blocks_throttle_0_1 = blocks.throttle(gr.sizeof_float*1,
54
+ samp_rate,
55
+ True)
56
+ self.blocks_throttle_0 = blocks.throttle(gr.sizeof_float*1,
57
+ samp_rate,
58
+ True)
59
+ self.blocks_null_source_1 = blocks.null_source(gr.sizeof_float*1)
60
+ self.blocks_float_to_complex_1 = blocks.float_to_complex(1)
61
+ self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate,
62
+ analog.GR_COS_WAVE,
63
+ frequency,
64
+ amplitude,
65
+ 0,
66
+ 0)
67
+
68
+
69
+ ##################################################
70
+ # Connections
71
+ ##################################################
72
+ self.connect((self.analog_sig_source_x_0, 0), (self.blocks_throttle_0, 0))
73
+ self.connect((self.blocks_float_to_complex_1, 0), (self.spectre_batched_file_sink_0, 0))
74
+ self.connect((self.blocks_null_source_1, 0), (self.blocks_throttle_0_1, 0))
75
+ self.connect((self.blocks_throttle_0, 0), (self.blocks_float_to_complex_1, 0))
76
+ self.connect((self.blocks_throttle_0_1, 0), (self.blocks_float_to_complex_1, 1))
77
+
78
+
79
+ class _tagged_staircase(gr.top_block):
80
+ def __init__(self,
81
+ tag: str,
82
+ parameters: Parameters):
83
+ gr.top_block.__init__(self, catch_exceptions=True)
84
+
85
+ ##################################################
86
+ # Unpack capture config
87
+ ##################################################
88
+ step_increment = parameters.get_parameter_value(PNames.STEP_INCREMENT)
89
+ samp_rate = parameters.get_parameter_value(PNames.SAMPLE_RATE)
90
+ min_samples_per_step = parameters.get_parameter_value(PNames.MIN_SAMPLES_PER_STEP)
91
+ max_samples_per_step = parameters.get_parameter_value(PNames.MAX_SAMPLES_PER_STEP)
92
+ frequency_step = parameters.get_parameter_value(PNames.FREQUENCY_STEP)
93
+ batch_size = parameters.get_parameter_value(PNames.BATCH_SIZE)
94
+
95
+ ##################################################
96
+ # Blocks
97
+ ##################################################
98
+ self.spectre_tagged_staircase_0 = spectre.tagged_staircase(min_samples_per_step,
99
+ max_samples_per_step,
100
+ frequency_step,
101
+ step_increment,
102
+ samp_rate)
103
+ self.spectre_batched_file_sink_0 = spectre.batched_file_sink(get_chunks_dir_path(),
104
+ tag,
105
+ batch_size,
106
+ samp_rate,
107
+ True,
108
+ 'rx_freq',
109
+ 0) # zero means the center frequency is unset
110
+ self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate, True)
111
+
112
+
113
+ ##################################################
114
+ # Connections
115
+ ##################################################
116
+ self.connect((self.blocks_throttle_0, 0), (self.spectre_batched_file_sink_0, 0))
117
+ self.connect((self.spectre_tagged_staircase_0, 0), (self.blocks_throttle_0, 0))
118
+
119
+
120
+ @dataclass(frozen=True)
121
+ class CaptureMethods:
122
+ cosine_signal_1 = partial(capture, top_block_cls=_cosine_signal_1)
123
+ tagged_staircase = partial(capture, top_block_cls=_tagged_staircase)
@@ -0,0 +1,61 @@
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
+ from dataclasses import dataclass
7
+ from functools import partial
8
+
9
+ from spectre_core.capture_configs import (
10
+ CaptureModes
11
+ )
12
+ from ..gr._rsp1a import CaptureMethods
13
+ from .._spec_names import SpecNames
14
+ from ._sdrplay_receiver import SDRPlayReceiver
15
+ from .._register import register_receiver
16
+
17
+ @dataclass
18
+ class Modes:
19
+ FIXED_CENTER_FREQUENCY = CaptureModes.FIXED_CENTER_FREQUENCY
20
+ SWEPT_CENTER_FREQUENCY = CaptureModes.SWEPT_CENTER_FREQUENCY
21
+
22
+ @register_receiver("rsp1a")
23
+ class _Receiver(SDRPlayReceiver):
24
+ def __init__(self,
25
+ name: str,
26
+ mode: Optional[str]):
27
+ super().__init__(name,
28
+ mode)
29
+
30
+
31
+ def _add_specs(self) -> None:
32
+ self.add_spec( SpecNames.SAMPLE_RATE_LOWER_BOUND, 200e3 ) # Hz
33
+ self.add_spec( SpecNames.SAMPLE_RATE_UPPER_BOUND, 10e6 ) # Hz
34
+ self.add_spec( SpecNames.FREQUENCY_LOWER_BOUND , 1e3 ) # Hz
35
+ self.add_spec( SpecNames.FREQUENCY_UPPER_BOUND , 2e9 ) # Hz
36
+ self.add_spec( SpecNames.IF_GAIN_UPPER_BOUND , -20 ) # dB
37
+ self.add_spec( SpecNames.RF_GAIN_UPPER_BOUND , 0 ) # dB
38
+ self.add_spec( SpecNames.API_RETUNING_LATENCY , 50 * 1e-3 ) # s
39
+ self.add_spec( SpecNames.BANDWIDTH_OPTIONS,
40
+ [200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000])
41
+
42
+
43
+ def _add_capture_methods(self) -> None:
44
+ self.add_capture_method(Modes.FIXED_CENTER_FREQUENCY,
45
+ CaptureMethods.fixed_center_frequency)
46
+ self.add_capture_method(Modes.SWEPT_CENTER_FREQUENCY,
47
+ CaptureMethods.swept_center_frequency)
48
+
49
+
50
+ def _add_capture_templates(self):
51
+ self.add_capture_template(Modes.FIXED_CENTER_FREQUENCY,
52
+ self._get_capture_template_fixed_center_frequency())
53
+ self.add_capture_template(Modes.SWEPT_CENTER_FREQUENCY,
54
+ self._get_capture_template_swept_center_frequency())
55
+
56
+
57
+ def _add_pvalidators(self):
58
+ self.add_pvalidator(Modes.FIXED_CENTER_FREQUENCY,
59
+ self._get_pvalidator_fixed_center_frequency())
60
+ self.add_pvalidator(Modes.SWEPT_CENTER_FREQUENCY,
61
+ self._get_pvalidator_swept_center_frequency())
@@ -0,0 +1,69 @@
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
+ from dataclasses import dataclass
7
+ from functools import partial
8
+
9
+ from spectre_core.capture_configs import (
10
+ CaptureModes
11
+ )
12
+ from ..gr._rspduo import CaptureMethods
13
+ from .._spec_names import SpecNames
14
+ from ._sdrplay_receiver import SDRPlayReceiver
15
+ from .._register import register_receiver
16
+
17
+ @dataclass
18
+ class Modes:
19
+ TUNER_1_FIXED_CENTER_FREQUENCY = f"tuner-1-{CaptureModes.FIXED_CENTER_FREQUENCY}"
20
+ TUNER_2_FIXED_CENTER_FREQUENCY = f"tuner-2-{CaptureModes.FIXED_CENTER_FREQUENCY}"
21
+ TUNER_1_SWEPT_CENTER_FREQUENCY = f"tuner-1-{CaptureModes.SWEPT_CENTER_FREQUENCY}"
22
+
23
+
24
+ @register_receiver("rspduo")
25
+ class _Receiver(SDRPlayReceiver):
26
+ def __init__(self,
27
+ name: str,
28
+ mode: Optional[str]):
29
+ super().__init__(name,
30
+ mode)
31
+
32
+
33
+ def _add_specs(self) -> None:
34
+ self.add_spec( SpecNames.SAMPLE_RATE_LOWER_BOUND, 200e3 ) # Hz
35
+ self.add_spec( SpecNames.SAMPLE_RATE_UPPER_BOUND, 10e6 ) # Hz
36
+ self.add_spec( SpecNames.FREQUENCY_LOWER_BOUND , 1e3 ) # Hz
37
+ self.add_spec( SpecNames.FREQUENCY_UPPER_BOUND , 2e9 ) # Hz
38
+ self.add_spec( SpecNames.IF_GAIN_UPPER_BOUND , -20 ) # dB
39
+ self.add_spec( SpecNames.RF_GAIN_UPPER_BOUND , 0 ) # dB
40
+ self.add_spec( SpecNames.API_RETUNING_LATENCY , 50 * 1e-3 ) # s
41
+ self.add_spec( SpecNames.BANDWIDTH_OPTIONS,
42
+ [200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000])
43
+
44
+
45
+ def _add_capture_methods(self) -> None:
46
+ self.add_capture_method(Modes.TUNER_1_FIXED_CENTER_FREQUENCY,
47
+ CaptureMethods.tuner_1_fixed_center_frequency)
48
+ self.add_capture_method(Modes.TUNER_2_FIXED_CENTER_FREQUENCY,
49
+ CaptureMethods.tuner_2_fixed_center_frequency)
50
+ self.add_capture_method(Modes.TUNER_1_SWEPT_CENTER_FREQUENCY,
51
+ CaptureMethods.tuner_1_swept_center_frequency)
52
+
53
+
54
+ def _add_capture_templates(self):
55
+ self.add_capture_template(Modes.TUNER_1_FIXED_CENTER_FREQUENCY,
56
+ self._get_capture_template_fixed_center_frequency())
57
+ self.add_capture_template(Modes.TUNER_2_FIXED_CENTER_FREQUENCY,
58
+ self._get_capture_template_fixed_center_frequency())
59
+ self.add_capture_template(Modes.TUNER_1_SWEPT_CENTER_FREQUENCY,
60
+ self._get_capture_template_swept_center_frequency())
61
+
62
+
63
+ def _add_pvalidators(self):
64
+ self.add_pvalidator(Modes.TUNER_1_FIXED_CENTER_FREQUENCY,
65
+ self._get_pvalidator_fixed_center_frequency())
66
+ self.add_pvalidator(Modes.TUNER_2_FIXED_CENTER_FREQUENCY,
67
+ self._get_pvalidator_fixed_center_frequency())
68
+ self.add_pvalidator(Modes.TUNER_1_SWEPT_CENTER_FREQUENCY,
69
+ self._get_pvalidator_swept_center_frequency())
@@ -0,0 +1,185 @@
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 abc import ABC, abstractmethod
6
+ from typing import Callable, Optional
7
+ from numbers import Number
8
+
9
+ from spectre_core.capture_configs import (
10
+ CaptureTemplate, CaptureModes, Parameters, Bound, PValidators, PNames,
11
+ get_base_capture_template, get_base_ptemplate, OneOf, CaptureConfig
12
+ )
13
+ from .._base import BaseReceiver
14
+ from .._spec_names import SpecNames
15
+
16
+ class SDRPlayReceiver(BaseReceiver):
17
+ def _get_pvalidator_fixed_center_frequency(self) -> Callable:
18
+ def pvalidator(parameters: Parameters):
19
+ PValidators.fixed_center_frequency(parameters)
20
+ return pvalidator
21
+
22
+
23
+ def _get_pvalidator_swept_center_frequency(self) -> None:
24
+ def pvalidator(parameters: Parameters):
25
+ PValidators.swept_center_frequency(parameters,
26
+ self.get_spec(SpecNames.API_RETUNING_LATENCY))
27
+ return pvalidator
28
+
29
+
30
+ def _get_capture_template_fixed_center_frequency(self) -> CaptureTemplate:
31
+ #
32
+ # Create the base template
33
+ #
34
+ capture_template = get_base_capture_template( CaptureModes.FIXED_CENTER_FREQUENCY )
35
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.BANDWIDTH) )
36
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.IF_GAIN) )
37
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.RF_GAIN) )
38
+
39
+ #
40
+ # Update the defaults
41
+ #
42
+ capture_template.set_defaults(
43
+ (PNames.BATCH_SIZE, 3.0),
44
+ (PNames.CENTER_FREQUENCY, 95800000),
45
+ (PNames.SAMPLE_RATE, 600000),
46
+ (PNames.BANDWIDTH, 600000),
47
+ (PNames.WINDOW_HOP, 512),
48
+ (PNames.WINDOW_SIZE, 1024),
49
+ (PNames.WINDOW_TYPE, "blackman"),
50
+ (PNames.RF_GAIN, -30),
51
+ (PNames.IF_GAIN, -30)
52
+ )
53
+
54
+ #
55
+ # Adding pconstraints
56
+ #
57
+ capture_template.add_pconstraint(
58
+ PNames.CENTER_FREQUENCY,
59
+ [
60
+ Bound(
61
+ lower_bound=self.get_spec(SpecNames.FREQUENCY_LOWER_BOUND),
62
+ upper_bound=self.get_spec(SpecNames.FREQUENCY_UPPER_BOUND)
63
+ )
64
+ ]
65
+ )
66
+ capture_template.add_pconstraint(
67
+ PNames.SAMPLE_RATE,
68
+ [
69
+ Bound(
70
+ lower_bound=self.get_spec(SpecNames.SAMPLE_RATE_LOWER_BOUND),
71
+ upper_bound=self.get_spec(SpecNames.SAMPLE_RATE_UPPER_BOUND)
72
+ )
73
+ ]
74
+ )
75
+ capture_template.add_pconstraint(
76
+ PNames.BANDWIDTH,
77
+ [
78
+ OneOf(
79
+ self.get_spec( SpecNames.BANDWIDTH_OPTIONS )
80
+ )
81
+ ]
82
+ )
83
+ capture_template.add_pconstraint(
84
+ PNames.IF_GAIN,
85
+ [
86
+ Bound(
87
+ upper_bound=self.get_spec(SpecNames.IF_GAIN_UPPER_BOUND)
88
+ )
89
+ ]
90
+ )
91
+ capture_template.add_pconstraint(
92
+ PNames.RF_GAIN,
93
+ [
94
+ Bound(
95
+ upper_bound=self.get_spec(SpecNames.RF_GAIN_UPPER_BOUND)
96
+ )
97
+ ]
98
+ )
99
+ return capture_template
100
+
101
+
102
+ def _get_capture_template_swept_center_frequency(self) -> CaptureTemplate:
103
+ #
104
+ # Create the base template
105
+ #
106
+ capture_template = get_base_capture_template( CaptureModes.SWEPT_CENTER_FREQUENCY )
107
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.BANDWIDTH) )
108
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.IF_GAIN) )
109
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.RF_GAIN) )
110
+
111
+
112
+ #
113
+ # Update the defaults
114
+ #
115
+ capture_template.set_defaults(
116
+ (PNames.BATCH_SIZE, 4.0),
117
+ (PNames.MIN_FREQUENCY, 95000000),
118
+ (PNames.MAX_FREQUENCY, 100000000),
119
+ (PNames.SAMPLES_PER_STEP, 80000),
120
+ (PNames.FREQUENCY_STEP, 1536000),
121
+ (PNames.SAMPLE_RATE, 1536000),
122
+ (PNames.BANDWIDTH, 1536000),
123
+ (PNames.WINDOW_HOP, 512),
124
+ (PNames.WINDOW_SIZE, 1024),
125
+ (PNames.WINDOW_TYPE, "blackman"),
126
+ (PNames.RF_GAIN, -30),
127
+ (PNames.IF_GAIN, -30)
128
+ )
129
+
130
+
131
+ #
132
+ # Adding pconstraints
133
+ #
134
+ capture_template.add_pconstraint(
135
+ PNames.MIN_FREQUENCY,
136
+ [
137
+ Bound(
138
+ lower_bound=self.get_spec(SpecNames.FREQUENCY_LOWER_BOUND),
139
+ upper_bound=self.get_spec(SpecNames.FREQUENCY_UPPER_BOUND)
140
+ )
141
+ ]
142
+ )
143
+ capture_template.add_pconstraint(
144
+ PNames.MAX_FREQUENCY,
145
+ [
146
+ Bound(
147
+ lower_bound=self.get_spec(SpecNames.FREQUENCY_LOWER_BOUND),
148
+ upper_bound=self.get_spec(SpecNames.FREQUENCY_UPPER_BOUND)
149
+ )
150
+ ]
151
+ )
152
+ capture_template.add_pconstraint(
153
+ PNames.SAMPLE_RATE,
154
+ [
155
+ Bound(
156
+ lower_bound=self.get_spec(SpecNames.SAMPLE_RATE_LOWER_BOUND),
157
+ upper_bound=self.get_spec(SpecNames.SAMPLE_RATE_UPPER_BOUND)
158
+ )
159
+ ]
160
+ )
161
+ capture_template.add_pconstraint(
162
+ PNames.BANDWIDTH,
163
+ [
164
+ OneOf(
165
+ self.get_spec( SpecNames.BANDWIDTH_OPTIONS )
166
+ )
167
+ ]
168
+ )
169
+ capture_template.add_pconstraint(
170
+ PNames.IF_GAIN,
171
+ [
172
+ Bound(
173
+ upper_bound=self.get_spec(SpecNames.IF_GAIN_UPPER_BOUND)
174
+ )
175
+ ]
176
+ )
177
+ capture_template.add_pconstraint(
178
+ PNames.RF_GAIN,
179
+ [
180
+ Bound(
181
+ upper_bound=self.get_spec(SpecNames.RF_GAIN_UPPER_BOUND)
182
+ )
183
+ ]
184
+ )
185
+ return capture_template
@@ -0,0 +1,221 @@
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 dataclasses import dataclass
6
+ from typing import Optional, Callable
7
+
8
+ from spectre_core.capture_configs import (
9
+ CaptureTemplate, CaptureModes, Parameters, Bound, PValidators, PNames,
10
+ get_base_capture_template, make_base_capture_template, get_base_ptemplate
11
+ )
12
+ from ..gr._test import CaptureMethods
13
+ from .._spec_names import SpecNames
14
+ from .._base import BaseReceiver
15
+ from .._register import register_receiver
16
+
17
+
18
+ @dataclass
19
+ class Modes:
20
+ COSINE_SIGNAL_1 = "cosine-signal-1"
21
+ TAGGED_STAIRCASE = "tagged-staircase"
22
+
23
+
24
+ @register_receiver("test")
25
+ class _Receiver(BaseReceiver):
26
+ def __init__(self,
27
+ name: str,
28
+ mode: Optional[str]):
29
+ super().__init__(name,
30
+ mode)
31
+
32
+
33
+ def _add_specs(self) -> None:
34
+ self.add_spec( SpecNames.SAMPLE_RATE_LOWER_BOUND, 64000 )
35
+ self.add_spec( SpecNames.SAMPLE_RATE_UPPER_BOUND, 640000 )
36
+ self.add_spec( SpecNames.FREQUENCY_LOWER_BOUND , 16000 )
37
+ self.add_spec( SpecNames.FREQUENCY_UPPER_BOUND , 160000 )
38
+
39
+
40
+ def _add_capture_methods(self) -> None:
41
+ self.add_capture_method( Modes.COSINE_SIGNAL_1 , CaptureMethods.cosine_signal_1 )
42
+ self.add_capture_method( Modes.TAGGED_STAIRCASE, CaptureMethods.tagged_staircase)
43
+
44
+
45
+ def _add_pvalidators(self) -> None:
46
+ self.add_pvalidator( Modes.COSINE_SIGNAL_1 , self.__get_pvalidator_cosine_signal_1() )
47
+ self.add_pvalidator( Modes.TAGGED_STAIRCASE, self.__get_pvalidator_tagged_staircase() )
48
+
49
+
50
+ def _add_capture_templates(self) -> None:
51
+ self.add_capture_template( Modes.COSINE_SIGNAL_1 , self.__get_capture_template_cosine_signal_1() )
52
+ self.add_capture_template( Modes.TAGGED_STAIRCASE, self.__get_capture_template_tagged_staircase() )
53
+
54
+
55
+ def __get_capture_template_cosine_signal_1(self) -> CaptureTemplate:
56
+ #
57
+ # Create the base template
58
+ #
59
+ capture_template = get_base_capture_template( CaptureModes.FIXED_CENTER_FREQUENCY )
60
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.AMPLITUDE) )
61
+ capture_template.add_ptemplate( get_base_ptemplate(PNames.FREQUENCY) )
62
+
63
+ #
64
+ # Update the defaults
65
+ #
66
+ capture_template.set_defaults(
67
+ (PNames.BATCH_SIZE, 3.0),
68
+ (PNames.CENTER_FREQUENCY, 16000),
69
+ (PNames.AMPLITUDE, 2.0),
70
+ (PNames.FREQUENCY, 32000),
71
+ (PNames.SAMPLE_RATE, 128000),
72
+ (PNames.WINDOW_HOP, 512),
73
+ (PNames.WINDOW_SIZE, 512),
74
+ (PNames.WINDOW_TYPE, "boxcar")
75
+ )
76
+
77
+ #
78
+ # Enforce defaults
79
+ #
80
+ capture_template.enforce_defaults(
81
+ PNames.TIME_RESOLUTION,
82
+ PNames.TIME_RANGE,
83
+ PNames.FREQUENCY_RESOLUTION,
84
+ PNames.WINDOW_TYPE
85
+ )
86
+
87
+
88
+ #
89
+ # Adding pconstraints
90
+ #
91
+ capture_template.add_pconstraint(
92
+ PNames.SAMPLE_RATE,
93
+ [
94
+ Bound(
95
+ lower_bound=self.get_spec(SpecNames.SAMPLE_RATE_LOWER_BOUND),
96
+ upper_bound=self.get_spec(SpecNames.SAMPLE_RATE_UPPER_BOUND)
97
+ )
98
+ ]
99
+ )
100
+ capture_template.add_pconstraint(
101
+ PNames.FREQUENCY,
102
+ [
103
+ Bound(
104
+ lower_bound=self.get_spec(SpecNames.FREQUENCY_LOWER_BOUND),
105
+ upper_bound=self.get_spec(SpecNames.FREQUENCY_UPPER_BOUND)
106
+ )
107
+ ]
108
+ )
109
+ return capture_template
110
+
111
+
112
+ def __get_capture_template_tagged_staircase(self) -> CaptureTemplate:
113
+ #
114
+ # Make the base template
115
+ #
116
+ capture_template = make_base_capture_template(
117
+ PNames.TIME_RESOLUTION,
118
+ PNames.FREQUENCY_RESOLUTION,
119
+ PNames.TIME_RANGE,
120
+ PNames.SAMPLE_RATE,
121
+ PNames.BATCH_SIZE,
122
+ PNames.WINDOW_TYPE,
123
+ PNames.WINDOW_HOP,
124
+ PNames.WINDOW_SIZE,
125
+ PNames.EVENT_HANDLER_KEY,
126
+ PNames.CHUNK_KEY,
127
+ PNames.WATCH_EXTENSION,
128
+ PNames.MIN_SAMPLES_PER_STEP,
129
+ PNames.MAX_SAMPLES_PER_STEP,
130
+ PNames.FREQUENCY_STEP,
131
+ PNames.STEP_INCREMENT,
132
+ PNames.OBS_ALT,
133
+ PNames.OBS_LAT,
134
+ PNames.OBS_LON,
135
+ PNames.OBJECT,
136
+ PNames.ORIGIN,
137
+ PNames.TELESCOPE,
138
+ PNames.INSTRUMENT
139
+ )
140
+
141
+ #
142
+ # Update the defaults
143
+ #
144
+ capture_template.set_defaults(
145
+ (PNames.BATCH_SIZE, 3.0),
146
+ (PNames.FREQUENCY_STEP, 128000),
147
+ (PNames.MAX_SAMPLES_PER_STEP, 5000),
148
+ (PNames.MIN_SAMPLES_PER_STEP, 4000),
149
+ (PNames.SAMPLE_RATE, 128000),
150
+ (PNames.STEP_INCREMENT, 200),
151
+ (PNames.WINDOW_HOP, 512),
152
+ (PNames.WINDOW_SIZE, 512),
153
+ (PNames.WINDOW_TYPE, "boxcar"),
154
+ (PNames.EVENT_HANDLER_KEY, CaptureModes.SWEPT_CENTER_FREQUENCY),
155
+ (PNames.CHUNK_KEY, CaptureModes.SWEPT_CENTER_FREQUENCY),
156
+ (PNames.WATCH_EXTENSION, "bin")
157
+ )
158
+
159
+
160
+ #
161
+ # Enforce defaults
162
+ #
163
+ capture_template.enforce_defaults(
164
+ PNames.TIME_RESOLUTION,
165
+ PNames.TIME_RANGE,
166
+ PNames.FREQUENCY_RESOLUTION,
167
+ PNames.WINDOW_TYPE,
168
+ PNames.EVENT_HANDLER_KEY,
169
+ PNames.CHUNK_KEY,
170
+ PNames.WATCH_EXTENSION
171
+ )
172
+
173
+ return capture_template
174
+
175
+
176
+ def __get_pvalidator_cosine_signal_1(self) -> Callable:
177
+ def pvalidator(parameters: Parameters):
178
+ PValidators.window(parameters)
179
+
180
+ sample_rate = parameters.get_parameter_value(PNames.SAMPLE_RATE)
181
+ frequency = parameters.get_parameter_value(PNames.FREQUENCY)
182
+ window_size = parameters.get_parameter_value(PNames.WINDOW_SIZE)
183
+
184
+ # check that the sample rate is an integer multiple of the underlying signal frequency
185
+ if sample_rate % frequency != 0:
186
+ raise ValueError("The sampling rate must be some integer multiple of frequency")
187
+
188
+ a = sample_rate/frequency
189
+ if a < 2:
190
+ raise ValueError((f"The ratio of sampling rate over frequency must be greater than two. "
191
+ f"Got {a}"))
192
+
193
+ # analytical requirement
194
+ # if p is the number of sampled cycles, we can find that p = window_size / a
195
+ # the number of sampled cycles must be a positive natural number.
196
+ p = window_size / a
197
+ if window_size % a != 0:
198
+ raise ValueError((f"The number of sampled cycles must be a positive natural number. "
199
+ f"Computed that p={p}"))
200
+ return pvalidator
201
+
202
+
203
+ def __get_pvalidator_tagged_staircase(self) -> None:
204
+ def pvalidator(parameters: Parameters):
205
+ PValidators.window(parameters)
206
+
207
+ freq_step = parameters.get_parameter_value(PNames.FREQUENCY_STEP)
208
+ sample_rate = parameters.get_parameter_value(PNames.SAMPLE_RATE)
209
+ min_samples_per_step = parameters.get_parameter_value(PNames.MIN_SAMPLES_PER_STEP)
210
+ max_samples_per_step = parameters.get_parameter_value(PNames.MAX_SAMPLES_PER_STEP)
211
+
212
+ if freq_step != sample_rate:
213
+ raise ValueError(f"The frequency step must be equal to the sampling rate")
214
+
215
+
216
+ if min_samples_per_step > max_samples_per_step:
217
+ raise ValueError((f"Minimum samples per step cannot be greater than the maximum samples per step. "
218
+ f"Got {min_samples_per_step}, which is greater than {max_samples_per_step}"))
219
+
220
+ return pvalidator
221
+
@@ -1,3 +1,21 @@
1
1
  # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
2
  # This file is part of SPECTRE
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
+
5
+ from ._analytical import (
6
+ get_analytical_spectrogram, validate_analytically, TestResults
7
+ )
8
+ from ._spectrogram import (
9
+ Spectrogram, FrequencyCut, TimeCut, SpectrumTypes, TimeTypes
10
+ )
11
+ from ._transform import (
12
+ frequency_chop, time_chop, frequency_average, time_average,
13
+ join_spectrograms
14
+ )
15
+
16
+ __all__ = [
17
+ "get_analytical_spectrogram", "validate_analytically", "TestResults",
18
+ "Spectrogram", "FrequencyCut", "TimeCut", "SpectrumTypes", "frequency_chop",
19
+ "time_chop", "frequency_average","time_average", "join_spectrograms",
20
+ "TimeTypes"
21
+ ]