pyadi-jif 0.1.0__py2.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 (73) hide show
  1. adijif/__init__.py +32 -0
  2. adijif/adijif.py +1 -0
  3. adijif/cli.py +21 -0
  4. adijif/clocks/__init__.py +10 -0
  5. adijif/clocks/ad9523.py +321 -0
  6. adijif/clocks/ad9523_1_bf.py +91 -0
  7. adijif/clocks/ad9528.py +444 -0
  8. adijif/clocks/ad9528_bf.py +70 -0
  9. adijif/clocks/ad9545.py +553 -0
  10. adijif/clocks/clock.py +153 -0
  11. adijif/clocks/hmc7044.py +558 -0
  12. adijif/clocks/hmc7044_bf.py +68 -0
  13. adijif/clocks/ltc6952.py +624 -0
  14. adijif/clocks/ltc6952_bf.py +67 -0
  15. adijif/clocks/ltc6953.py +509 -0
  16. adijif/common.py +70 -0
  17. adijif/converters/__init__.py +3 -0
  18. adijif/converters/ad9081.py +679 -0
  19. adijif/converters/ad9081_dp.py +206 -0
  20. adijif/converters/ad9081_util.py +124 -0
  21. adijif/converters/ad9084.py +588 -0
  22. adijif/converters/ad9084_dp.py +111 -0
  23. adijif/converters/ad9084_draw.py +203 -0
  24. adijif/converters/ad9084_util.py +365 -0
  25. adijif/converters/ad9144.py +316 -0
  26. adijif/converters/ad9144_bf.py +44 -0
  27. adijif/converters/ad9680.py +201 -0
  28. adijif/converters/ad9680_bf.py +43 -0
  29. adijif/converters/ad9680_draw.py +184 -0
  30. adijif/converters/adc.py +83 -0
  31. adijif/converters/adrv9009.py +426 -0
  32. adijif/converters/adrv9009_bf.py +43 -0
  33. adijif/converters/adrv9009_util.py +89 -0
  34. adijif/converters/converter.py +399 -0
  35. adijif/converters/dac.py +85 -0
  36. adijif/converters/resources/AD9084_JTX_JRX.xlsx +0 -0
  37. adijif/converters/resources/ad9081_JRx_204B.csv +180 -0
  38. adijif/converters/resources/ad9081_JRx_204C.csv +411 -0
  39. adijif/converters/resources/ad9081_JTx_204B.csv +1488 -0
  40. adijif/converters/resources/ad9081_JTx_204C.csv +1064 -0
  41. adijif/converters/resources/full_rx_mode_table_ad9081.csv +1904 -0
  42. adijif/converters/resources/full_tx_mode_table_ad9081.csv +994 -0
  43. adijif/d2/__init__.py +26 -0
  44. adijif/d2/d2lib.h +81 -0
  45. adijif/draw.py +498 -0
  46. adijif/fpgas/__init__.py +1 -0
  47. adijif/fpgas/fpga.py +64 -0
  48. adijif/fpgas/xilinx/__init__.py +1143 -0
  49. adijif/fpgas/xilinx/bf.py +101 -0
  50. adijif/fpgas/xilinx/pll.py +232 -0
  51. adijif/fpgas/xilinx/sevenseries.py +531 -0
  52. adijif/fpgas/xilinx/ultrascaleplus.py +485 -0
  53. adijif/fpgas/xilinx/xilinx_draw.py +516 -0
  54. adijif/gekko_trans.py +295 -0
  55. adijif/jesd.py +760 -0
  56. adijif/plls/__init__.py +3 -0
  57. adijif/plls/adf4030.py +259 -0
  58. adijif/plls/adf4371.py +419 -0
  59. adijif/plls/adf4382.py +581 -0
  60. adijif/plls/pll.py +103 -0
  61. adijif/solvers.py +54 -0
  62. adijif/sys/__init__.py +1 -0
  63. adijif/sys/s_plls.py +185 -0
  64. adijif/system.py +567 -0
  65. adijif/system_draw.py +65 -0
  66. adijif/types.py +151 -0
  67. adijif/utils.py +191 -0
  68. pyadi_jif-0.1.0.dist-info/METADATA +62 -0
  69. pyadi_jif-0.1.0.dist-info/RECORD +73 -0
  70. pyadi_jif-0.1.0.dist-info/WHEEL +6 -0
  71. pyadi_jif-0.1.0.dist-info/licenses/AUTHORS.rst +13 -0
  72. pyadi_jif-0.1.0.dist-info/licenses/LICENSE +277 -0
  73. pyadi_jif-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,316 @@
1
+ """AD9144 high speed DAC clocking model."""
2
+
3
+ from typing import Any, Dict, List, Union
4
+
5
+ import numpy as np
6
+
7
+ from adijif.converters.ad9144_bf import ad9144_bf
8
+
9
+ from ..solvers import CpoSolveResult # noqa: I202
10
+
11
+
12
+ def _convert_to_config(
13
+ L: Union[int, float],
14
+ M: Union[int, float],
15
+ F: Union[int, float],
16
+ S: Union[int, float],
17
+ # HD: Union[int, float],
18
+ N: Union[int, float],
19
+ Np: Union[int, float],
20
+ # CS: Union[int, float],
21
+ DualLink: bool,
22
+ ) -> Dict:
23
+ # return {"L": L, "M": M, "F": F, "S": S, "HD": HD, "N": N, "Np": Np, "CS": CS}
24
+ return {
25
+ "L": L,
26
+ "M": M,
27
+ "F": F,
28
+ "S": S,
29
+ "HD": 1 if F == 1 else 0,
30
+ "Np": Np,
31
+ "CS": 0,
32
+ "DualLink": DualLink,
33
+ }
34
+
35
+
36
+ # IF F==1, HD=1, otherwise 0
37
+ quick_configuration_modes = {
38
+ str(0): _convert_to_config(DualLink=False, M=4, L=8, S=1, F=1, N=16, Np=16),
39
+ str(1): _convert_to_config(DualLink=False, M=4, L=8, S=2, F=2, N=16, Np=16),
40
+ str(2): _convert_to_config(DualLink=False, M=4, L=4, S=1, F=2, N=16, Np=16),
41
+ str(3): _convert_to_config(DualLink=False, M=4, L=2, S=1, F=4, N=16, Np=16),
42
+ str(4): _convert_to_config(DualLink=False, M=2, L=4, S=1, F=1, N=16, Np=16),
43
+ str(5): _convert_to_config(DualLink=False, M=2, L=4, S=2, F=2, N=16, Np=16),
44
+ str(6): _convert_to_config(DualLink=False, M=2, L=2, S=1, F=2, N=16, Np=16),
45
+ str(7): _convert_to_config(DualLink=False, M=2, L=1, S=1, F=4, N=16, Np=16),
46
+ # 8 is missing in datasheet
47
+ str(9): _convert_to_config(DualLink=False, M=1, L=2, S=1, F=1, N=16, Np=16),
48
+ str(10): _convert_to_config(DualLink=False, M=1, L=1, S=1, F=2, N=16, Np=16),
49
+ }
50
+
51
+ quick_configuration_modes = {
52
+ **quick_configuration_modes,
53
+ **{
54
+ str(4)
55
+ + "-DL": _convert_to_config(DualLink=False, M=2, L=4, S=1, F=1, N=16, Np=16),
56
+ str(5)
57
+ + "-DL": _convert_to_config(DualLink=False, M=2, L=4, S=2, F=2, N=16, Np=16),
58
+ str(6)
59
+ + "-DL": _convert_to_config(DualLink=False, M=2, L=2, S=1, F=2, N=16, Np=16),
60
+ str(7)
61
+ + "-DL": _convert_to_config(DualLink=False, M=2, L=1, S=1, F=4, N=16, Np=16),
62
+ # 8 is missing in datasheet
63
+ str(9)
64
+ + "-DL": _convert_to_config(DualLink=False, M=1, L=2, S=1, F=1, N=16, Np=16),
65
+ str(10)
66
+ + "-DL": _convert_to_config(DualLink=False, M=1, L=1, S=1, F=2, N=16, Np=16),
67
+ },
68
+ }
69
+
70
+
71
+ class ad9144(ad9144_bf):
72
+ """AD9144 high speed DAC model.
73
+
74
+ This model supports both direct clock configurations and on-board
75
+ generation
76
+
77
+ Clocking: AD9144 has directly clocked DAC that have optional input dividers.
78
+ The sample rate can be determined as follows:
79
+
80
+ baseband_sample_rate = (input_clock / input_clock_divider) / datapath_decimation
81
+ """
82
+
83
+ name = "AD9144"
84
+ converter_type = "DAC"
85
+
86
+ # JESD parameters
87
+ _jesd_params_to_skip_check = ["DualLink", "K"]
88
+ DualLink = False
89
+ available_jesd_modes = ["jesd204b"]
90
+ K_available = [16, 32]
91
+ _K = 32 # Valid for all cases pg 31 of datasheet
92
+ L_available = [1, 2, 4, 8]
93
+ M_available = [1, 2, 4, 4]
94
+ N_available = [*range(7, 16 + 1)]
95
+ Np_available = [8, 16]
96
+ F_available = [1, 2, 4, 8, 16]
97
+ CS_available = [0, 1, 2, 3]
98
+ CF_available = [0]
99
+ S_available = [1, 2]
100
+
101
+ # Clock constraints
102
+ clocking_option_available = ["integrated_pll", "direct"]
103
+ _clocking_option = "direct"
104
+
105
+ converter_clock_min = 420e6 # checked by dac
106
+ converter_clock_max = 2.8e9 # checked by dac
107
+
108
+ bit_clock_min_available = {"jesd204b": 1.44e9} # checked by jesd
109
+ bit_clock_max_available = {"jesd204b": 12.4e9} # checked by jesd
110
+
111
+ sample_clock_min = 1.44e9 / 40 # checked by jesd
112
+ sample_clock_max = 1.06e9 # checked by jesd
113
+
114
+ interpolation_available = [1, 2, 4, 8]
115
+ _interpolation = 1
116
+
117
+ quick_configuration_modes = {"jesd204b": quick_configuration_modes}
118
+
119
+ # Input clock requirements
120
+ input_clock_divider_available = [
121
+ 1,
122
+ 2,
123
+ 4,
124
+ 8,
125
+ 16,
126
+ ] # only used with integrated PLL for now
127
+
128
+ # Integrated PLL limits
129
+ pfd_min = 35e6
130
+ pfd_max = 80e6
131
+
132
+ # With integrated PLL
133
+ input_clock_min = 35e6
134
+ input_clock_max = 1e9
135
+
136
+ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
137
+ """Initialize AD9144 class.
138
+
139
+ Objects will default to mode 0x88 with 1e9 sample_clock.
140
+
141
+ Args:
142
+ *args (Any): Pass through arguments
143
+ **kwargs (Any): Pass through keyword arguments
144
+ """
145
+ # Set default mode
146
+ self.set_quick_configuration_mode(str(9))
147
+ self.sample_clock = 1e9
148
+ super().__init__(*args, **kwargs)
149
+ # self._init_diagram()
150
+
151
+ def get_config(self, solution: CpoSolveResult = None) -> Dict:
152
+ """Extract configurations from solver results.
153
+
154
+ Collect internal converter configuration and output clock definitions
155
+ leading to connected devices (clock chips, FPGAs)
156
+
157
+ Args:
158
+ solution (CpoSolveResult): CPlex solution. Only needed for CPlex solver
159
+
160
+ Returns:
161
+ Dict: Dictionary of clocking rates and dividers for configuration
162
+ """
163
+ config: Dict = {
164
+ "clocking_option": self.clocking_option,
165
+ "interpolation": self._interpolation,
166
+ }
167
+ if self.clocking_option == "direct":
168
+ return config
169
+
170
+ if self.solver == "CPLEX":
171
+ if solution:
172
+ self.solution = solution
173
+ config.update(
174
+ {
175
+ "BCount": self._get_val(self.config["BCount"]),
176
+ "ref_div_factor": self._get_val(self.config["ref_div_factor"]),
177
+ "lo_div_mode": np.log2(
178
+ self._get_val(self.config["lo_div_mode_p2"])
179
+ ),
180
+ }
181
+ )
182
+ return config
183
+
184
+ def get_required_clock_names(self) -> List[str]:
185
+ """Get list of strings of names of requested clocks.
186
+
187
+ This list of names is for the clocks defined by get_required_clocks
188
+
189
+ Returns:
190
+ List[str]: List of strings of clock names in order
191
+ """
192
+ # clk = (
193
+ # "AD9144_dac_clock" if self.clocking_option == "direct" else "AD9144_pll_ref"
194
+ # )
195
+ clk = "ad9144_ref_clk"
196
+ return [clk, "ad9144_sysref"]
197
+
198
+ def _check_valid_internal_configuration(self) -> None:
199
+ mode = self._check_valid_jesd_mode()
200
+ # cfg = self.quick_configuration_modes[self.jesd_class][mode]
201
+
202
+ if mode in ["0", "4", "9"]:
203
+ assert self.K == 32, "K must be 32 for JESD mode 0, 4, or 9"
204
+
205
+ def _pll_config(self) -> Dict:
206
+ dac_clk = self.interpolation * self.sample_clock
207
+ self.config["dac_clk"] = self._convert_input(dac_clk, "dac_clk")
208
+
209
+ self.config["BCount"] = self._convert_input([*range(6, 127 + 1)], name="BCount")
210
+
211
+ # Datasheet says refclk div can support 32 but tables do not reflect this and
212
+ # a div of 32 would put you under supported range
213
+
214
+ if self.solver == "gekko":
215
+ self.config["ref_div_factor"] = self.model.sos1(
216
+ self.input_clock_divider_available
217
+ )
218
+ # self.config["ref_div_factor_i"] = self.model.Var(
219
+ # integer=True, lb=0, ub=4, value=4
220
+ # )
221
+ # self.config["ref_div_factor"] = self.model.Intermediate(
222
+ # 2 ** (self.config["ref_div_factor_i"])
223
+ # )
224
+
225
+ self.config["ref_clk"] = self.model.Var(
226
+ integer=False, lb=35e6, ub=1e9, value=35e6
227
+ )
228
+ elif self.solver == "CPLEX":
229
+ self.config["ref_div_factor"] = self._convert_input(
230
+ self.input_clock_divider_available, "ref_div_factor"
231
+ )
232
+
233
+ self.config["ref_clk"] = (
234
+ self.config["dac_clk"]
235
+ * self.config["ref_div_factor"]
236
+ / self.config["BCount"]
237
+ / 2
238
+ )
239
+
240
+ if dac_clk > 2800e6:
241
+ raise Exception("DAC Clock too fast")
242
+ elif dac_clk >= 1500e6:
243
+ self.config["lo_div_mode_p2"] = self._convert_input(
244
+ 2 ** (1 + 1), name="lo_div_mode_p2"
245
+ )
246
+ elif dac_clk >= 720e6:
247
+ self.config["lo_div_mode_p2"] = self._convert_input(
248
+ 2 ** (2 + 1), name="lo_div_mode_p2"
249
+ )
250
+ elif dac_clk >= 420e6:
251
+ self.config["lo_div_mode_p2"] = self._convert_input(
252
+ 2 ** (3 + 1), name="lo_div_mode_p2"
253
+ )
254
+ else:
255
+ raise Exception("DAC Clock too slow")
256
+
257
+ self.config["vco"] = self._add_intermediate(
258
+ self.config["dac_clk"] * self.config["lo_div_mode_p2"]
259
+ )
260
+
261
+ self._add_equation(
262
+ [
263
+ self.config["ref_div_factor"] * self.pfd_min < self.config["ref_clk"],
264
+ self.config["ref_div_factor"] * self.pfd_max > self.config["ref_clk"],
265
+ self.config["ref_clk"] >= self.input_clock_min,
266
+ self.config["ref_clk"] <= self.input_clock_max,
267
+ ]
268
+ )
269
+
270
+ if self.solver == "gekko":
271
+ self._add_equation(
272
+ [
273
+ self.config["ref_clk"] * 2 * self.config["BCount"]
274
+ == self.config["dac_clk"] * self.config["ref_div_factor"]
275
+ ]
276
+ )
277
+
278
+ return self.config["ref_clk"]
279
+
280
+ def get_required_clocks(self) -> List:
281
+ """Generate list required clocks.
282
+
283
+ For AD9144 this will contain [converter clock, sysref requirement SOS]
284
+
285
+ Returns:
286
+ List: List of dictionaries of solver components
287
+ """
288
+ self.config = {}
289
+
290
+ self.config["lmfc_divisor_sysref"] = self._convert_input(
291
+ [*range(1, 20 + 1)], name="lmfc_divisor_sysref"
292
+ )
293
+
294
+ self.config["sysref"] = self._add_intermediate(
295
+ self.multiframe_clock / (self.config["lmfc_divisor_sysref"])
296
+ )
297
+
298
+ if self.clocking_option == "direct":
299
+ clk = self.sample_clock * self.interpolation
300
+ # LaneRate = (20 × DataRate × M)/L
301
+ assert (
302
+ self.bit_clock == (20 * self.sample_clock * self.M) / self.L
303
+ ), "AD9144 direct clock requirement invalid"
304
+ else:
305
+ # vco = dac_clk * 2^(LO_DIV_MODE + 1)
306
+ # 6 GHz <= vco <= 12 GHz
307
+ # BCount = floor( dac_clk/(2 * ref_clk/ref_div ) )
308
+ # 5 <= BCount <= 127
309
+ # ref_div = 2^ref_div_mode = 1,2,4,8,16
310
+ clk = self._pll_config() # type: ignore
311
+
312
+ # Objectives
313
+ # self.model.Obj(self.config["sysref"]) # This breaks many searches
314
+ # self.model.Obj(-1*self.config["lmfc_divisor_sysref"])
315
+
316
+ return [clk, self.config["sysref"]]
@@ -0,0 +1,44 @@
1
+ import numpy as np
2
+
3
+ from adijif.converters.dac import dac
4
+
5
+
6
+ class ad9144_bf(dac):
7
+ """Brute force methods for calculating clocks
8
+
9
+ These are currently meant for debug to compare against
10
+ the solver solutions
11
+ """
12
+
13
+ def device_clock_available(self):
14
+ """Generate list of possible device clocks"""
15
+ raise Exception("Not implemented")
16
+ # aicd = sorted(self.available_input_clock_dividers)
17
+
18
+ # dev_clocks = []
19
+ # for div in aicd:
20
+ # in_clock = self.sample_clock * self.datapath_decimation * div
21
+ # if in_clock <= self.max_input_clock:
22
+ # dev_clocks.append(in_clock)
23
+ # if not dev_clocks:
24
+ # raise Exception(
25
+ # "No device clocks possible in current config. Sample rate too high"
26
+ # )
27
+ # return dev_clocks
28
+
29
+ def device_clock_ranges(self):
30
+ """Generate min and max values for device clock"""
31
+
32
+ clks = self.device_clock_available()
33
+ return np.min(clks), np.max(clks)
34
+
35
+ def sysref_clock_ranges(self):
36
+ """sysref must be multiple of LMFC"""
37
+ lmfc = self.multiframe_clock
38
+ return lmfc / 2048, lmfc / 2
39
+
40
+ def sysref_met(self, sysref_clock, sample_clock):
41
+ if sysref_clock % self.multiframe_clock != 0:
42
+ raise Exception("SYSREF not a multiple of LMFC")
43
+ if (self.multiframe_clock / sysref_clock) < 2 * self.input_clock_divider:
44
+ raise Exception("SYSREF not a multiple of LMFC > 1")
@@ -0,0 +1,201 @@
1
+ """AD9680 high speed ADC clocking model."""
2
+
3
+ from typing import Any, Dict, List, Union
4
+
5
+ from adijif.converters.ad9680_bf import ad9680_bf
6
+
7
+ from ..solvers import CpoSolveResult # noqa: I202
8
+ from .ad9680_draw import ad9680_draw # noqa: I202
9
+
10
+
11
+ def _convert_to_config(
12
+ L: Union[int, float],
13
+ M: Union[int, float],
14
+ F: Union[int, float],
15
+ S: Union[int, float],
16
+ HD: Union[int, float],
17
+ N: Union[int, float],
18
+ Np: Union[int, float],
19
+ CS: Union[int, float],
20
+ ) -> Dict:
21
+ # return {"L": L, "M": M, "F": F, "S": S, "HD": HD, "N": N, "Np": Np, "CS": CS}
22
+ return {
23
+ "L": L,
24
+ "M": M,
25
+ "F": F,
26
+ "S": S,
27
+ "HD": HD,
28
+ "Np": Np,
29
+ "jesd_class": "jesd204b",
30
+ }
31
+
32
+
33
+ quick_configuration_modes = {
34
+ # M = 1
35
+ str(0x01): _convert_to_config(1, 1, 2, 1, 0, -1, 16, -1),
36
+ str(0x40): _convert_to_config(2, 1, 1, 1, 1, -1, 16, -1),
37
+ str(0x41): _convert_to_config(2, 1, 2, 2, 0, -1, 16, -1),
38
+ str(0x80): _convert_to_config(4, 1, 1, 2, 1, -1, 16, -1),
39
+ str(0x81): _convert_to_config(4, 1, 2, 4, 0, -1, 16, -1),
40
+ # M = 2
41
+ str(0x0A): _convert_to_config(1, 2, 4, 1, 0, -1, 16, -1),
42
+ str(0x49): _convert_to_config(2, 2, 2, 1, 0, -1, 16, -1),
43
+ str(0x88): _convert_to_config(4, 2, 1, 1, 1, -1, 16, -1),
44
+ str(0x89): _convert_to_config(4, 2, 2, 2, 0, -1, 16, -1),
45
+ # M = 4
46
+ str(0x13): _convert_to_config(1, 4, 8, 1, 0, -1, 16, -1),
47
+ str(0x52): _convert_to_config(2, 4, 4, 1, 0, -1, 16, -1),
48
+ str(0x91): _convert_to_config(4, 4, 2, 1, 0, -1, 16, -1),
49
+ # M = 8
50
+ str(0x1C): _convert_to_config(1, 8, 16, 1, 0, -1, 16, -1),
51
+ str(0x5B): _convert_to_config(2, 8, 8, 1, 0, -1, 16, -1),
52
+ str(0x9A): _convert_to_config(4, 8, 4, 1, 0, -1, 16, -1),
53
+ }
54
+
55
+
56
+ class ad9680(ad9680_draw, ad9680_bf):
57
+ """AD9680 high speed ADC model.
58
+
59
+ This model supports direct clock configurations
60
+
61
+ Clocking: AD9680 has directly clocked ADC that have optional input dividers.
62
+ The sample rate can be determined as follows:
63
+
64
+ baseband_sample_rate = (input_clock / input_clock_divider) / datapath_decimation
65
+ """
66
+
67
+ name = "AD9680"
68
+ converter_type = "ADC"
69
+
70
+ # JESD parameters
71
+ _jesd_params_to_skip_check = ["DualLink", "CS", "N", "HD"]
72
+ available_jesd_modes = ["jesd204b"]
73
+ K_available = [4, 8, 12, 16, 20, 24, 28, 32]
74
+ L_available = [1, 2, 4]
75
+ M_available = [1, 2, 4, 8]
76
+ N_available = [*range(7, 16)]
77
+ Np_available = [8, 16]
78
+ F_available = [1, 2, 4, 8, 16]
79
+ CS_available = [0, 1, 2, 3]
80
+ CF_available = [0]
81
+ S_available = [1, 2, 4]
82
+
83
+ # Clock constraints
84
+ clocking_option_available = ["direct"]
85
+ _clocking_option = "direct"
86
+ converter_clock_min = 300e6
87
+ converter_clock_max = 1.25e9
88
+ bit_clock_min_available = {"jesd204b": 3.125e9}
89
+ bit_clock_max_available = {"jesd204b": 12.5e9}
90
+ sample_clock_min = 300e6
91
+ sample_clock_max = 1250e6
92
+ decimation_available = [1, 2, 4, 8, 16]
93
+ _decimation = 1
94
+ _lmfc_sys_divisor = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
95
+
96
+ quick_configuration_modes = {"jesd204b": quick_configuration_modes}
97
+
98
+ # Input clock requirements
99
+ input_clock_divider_available = [1, 2, 4, 8] # FIXME
100
+ input_clock_divider = 1 # FIXME
101
+ input_clock_max = 4e9 # FIXME
102
+
103
+ """ Clocking
104
+ AD9680 has directly clocked ADCs that have optional input dividers.
105
+ The sample rate can be determined as follows:
106
+
107
+ baseband_sample_rate = (input_clock / input_clock_divider) / datapath_decimation
108
+ """
109
+
110
+ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
111
+ """Initialize AD9680 class.
112
+
113
+ Objects will default to mode 0x88 with 1e9 sample_clock.
114
+
115
+ Args:
116
+ *args (Any): Pass through arguments
117
+ **kwargs (Any): Pass through keyword arguments
118
+ """
119
+ # Set default mode
120
+ self.set_quick_configuration_mode(str(0x88))
121
+ self.K = 32
122
+ self.sample_clock = 1e9
123
+ super().__init__(*args, **kwargs)
124
+ self._init_diagram()
125
+
126
+ def _check_valid_jesd_mode(self) -> str:
127
+ """Verify current JESD configuration for part is valid.
128
+
129
+ Returns:
130
+ str: Current JESD mode
131
+ """
132
+ if self.F == 1:
133
+ assert self.K in [20, 24, 28, 32], "Invalid K value for F=1"
134
+ if self.F == 2:
135
+ assert self.K in [12, 16, 20, 24, 28, 32], "Invalid K value for F=1"
136
+ if self.F == 4:
137
+ assert self.K in [8, 12, 16, 20, 24, 28, 32], "Invalid K value for F=1"
138
+ if self.F in [8, 16]:
139
+ assert self.K in [4, 8, 12, 16, 20, 24, 28, 32], "Invalid K value for F=1"
140
+
141
+ return super()._check_valid_jesd_mode()
142
+
143
+ def get_config(self, solution: CpoSolveResult = None) -> Dict:
144
+ """Extract configurations from solver results.
145
+
146
+ Collect internal converter configuration and output clock definitions
147
+ leading to connected devices (clock chips, FPGAs)
148
+
149
+ Args:
150
+ solution (CpoSolveResult): CPlex solution. Only needed for CPlex solver
151
+
152
+ Returns:
153
+ Dict: Dictionary of clocking rates and dividers for configuration
154
+ """
155
+ if solution:
156
+ self._saved_solution = solution
157
+ return {"clocking_option": self.clocking_option, "decimation": self.decimation}
158
+
159
+ def get_required_clock_names(self) -> List[str]:
160
+ """Get list of strings of names of requested clocks.
161
+
162
+ This list of names is for the clocks defined by get_required_clocks
163
+
164
+ Returns:
165
+ List[str]: List of strings of clock names in order
166
+ """
167
+ return ["AD9680_ref_clk", "AD9680_sysref"]
168
+
169
+ def get_required_clocks(self) -> List:
170
+ """Generate list required clocks.
171
+
172
+ For AD9680 this will contain [converter clock, sysref requirement SOS]
173
+
174
+ Returns:
175
+ List: List of solver variables, equations, and constants
176
+ """
177
+ # possible_sysrefs = []
178
+ # for n in range(1, 10):
179
+ # r = self.multiframe_clock / (n * n)
180
+ # if r == int(r) and r > 1e6:
181
+ # possible_sysrefs.append(r)
182
+ # self.config = {"sysref": self.model.sos1(possible_sysrefs)}
183
+
184
+ self.config = {}
185
+ self.config["lmfc_divisor_sysref"] = self._convert_input(
186
+ self._lmfc_sys_divisor,
187
+ default=self._lmfc_sys_divisor[-1],
188
+ name="AD9680_lmfc_divisor_sysref",
189
+ )
190
+
191
+ self.config["lmfc_divisor_sysref_squared"] = self._add_intermediate(
192
+ self.config["lmfc_divisor_sysref"] * self.config["lmfc_divisor_sysref"]
193
+ )
194
+ self.config["sysref"] = self._add_intermediate(
195
+ self.multiframe_clock / self.config["lmfc_divisor_sysref_squared"]
196
+ )
197
+
198
+ # Objectives
199
+ # self.model.Obj(self.config["sysref"]) # This breaks many searches
200
+
201
+ return [self.converter_clock, self.config["sysref"]]
@@ -0,0 +1,43 @@
1
+ import numpy as np
2
+
3
+ from adijif.converters.adc import adc
4
+
5
+
6
+ class ad9680_bf(adc):
7
+ """Brute force methods for calculating clocks
8
+
9
+ These are currently meant for debug to compare against
10
+ the solver solutions
11
+ """
12
+
13
+ def device_clock_available(self):
14
+ """Generate list of possible device clocks"""
15
+ aicd = sorted(self.input_clock_divider_available)
16
+
17
+ dev_clocks = []
18
+ for div in aicd:
19
+ in_clock = self.sample_clock * self.decimation * div
20
+ if in_clock <= self.input_clock_max:
21
+ dev_clocks.append(in_clock)
22
+ if not dev_clocks:
23
+ raise Exception(
24
+ "No device clocks possible in current config. Sample rate too high"
25
+ )
26
+ return dev_clocks
27
+
28
+ def device_clock_ranges(self):
29
+ """Generate min and max values for device clock"""
30
+
31
+ clks = self.device_clock_available()
32
+ return np.min(clks), np.max(clks)
33
+
34
+ def sysref_clock_ranges(self):
35
+ """sysref must be multiple of LMFC"""
36
+ lmfc = self.multiframe_clock
37
+ return lmfc / 2048, lmfc / 2
38
+
39
+ def sysref_met(self, sysref_clock, sample_clock):
40
+ if sysref_clock % self.multiframe_clock != 0:
41
+ raise Exception("SYSREF not a multiple of LMFC")
42
+ if (self.multiframe_clock / sysref_clock) < 2 * self.input_clock_divider:
43
+ raise Exception("SYSREF not a multiple of LMFC > 1")