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.
- adijif/__init__.py +32 -0
- adijif/adijif.py +1 -0
- adijif/cli.py +21 -0
- adijif/clocks/__init__.py +10 -0
- adijif/clocks/ad9523.py +321 -0
- adijif/clocks/ad9523_1_bf.py +91 -0
- adijif/clocks/ad9528.py +444 -0
- adijif/clocks/ad9528_bf.py +70 -0
- adijif/clocks/ad9545.py +553 -0
- adijif/clocks/clock.py +153 -0
- adijif/clocks/hmc7044.py +558 -0
- adijif/clocks/hmc7044_bf.py +68 -0
- adijif/clocks/ltc6952.py +624 -0
- adijif/clocks/ltc6952_bf.py +67 -0
- adijif/clocks/ltc6953.py +509 -0
- adijif/common.py +70 -0
- adijif/converters/__init__.py +3 -0
- adijif/converters/ad9081.py +679 -0
- adijif/converters/ad9081_dp.py +206 -0
- adijif/converters/ad9081_util.py +124 -0
- adijif/converters/ad9084.py +588 -0
- adijif/converters/ad9084_dp.py +111 -0
- adijif/converters/ad9084_draw.py +203 -0
- adijif/converters/ad9084_util.py +365 -0
- adijif/converters/ad9144.py +316 -0
- adijif/converters/ad9144_bf.py +44 -0
- adijif/converters/ad9680.py +201 -0
- adijif/converters/ad9680_bf.py +43 -0
- adijif/converters/ad9680_draw.py +184 -0
- adijif/converters/adc.py +83 -0
- adijif/converters/adrv9009.py +426 -0
- adijif/converters/adrv9009_bf.py +43 -0
- adijif/converters/adrv9009_util.py +89 -0
- adijif/converters/converter.py +399 -0
- adijif/converters/dac.py +85 -0
- adijif/converters/resources/AD9084_JTX_JRX.xlsx +0 -0
- adijif/converters/resources/ad9081_JRx_204B.csv +180 -0
- adijif/converters/resources/ad9081_JRx_204C.csv +411 -0
- adijif/converters/resources/ad9081_JTx_204B.csv +1488 -0
- adijif/converters/resources/ad9081_JTx_204C.csv +1064 -0
- adijif/converters/resources/full_rx_mode_table_ad9081.csv +1904 -0
- adijif/converters/resources/full_tx_mode_table_ad9081.csv +994 -0
- adijif/d2/__init__.py +26 -0
- adijif/d2/d2lib.h +81 -0
- adijif/draw.py +498 -0
- adijif/fpgas/__init__.py +1 -0
- adijif/fpgas/fpga.py +64 -0
- adijif/fpgas/xilinx/__init__.py +1143 -0
- adijif/fpgas/xilinx/bf.py +101 -0
- adijif/fpgas/xilinx/pll.py +232 -0
- adijif/fpgas/xilinx/sevenseries.py +531 -0
- adijif/fpgas/xilinx/ultrascaleplus.py +485 -0
- adijif/fpgas/xilinx/xilinx_draw.py +516 -0
- adijif/gekko_trans.py +295 -0
- adijif/jesd.py +760 -0
- adijif/plls/__init__.py +3 -0
- adijif/plls/adf4030.py +259 -0
- adijif/plls/adf4371.py +419 -0
- adijif/plls/adf4382.py +581 -0
- adijif/plls/pll.py +103 -0
- adijif/solvers.py +54 -0
- adijif/sys/__init__.py +1 -0
- adijif/sys/s_plls.py +185 -0
- adijif/system.py +567 -0
- adijif/system_draw.py +65 -0
- adijif/types.py +151 -0
- adijif/utils.py +191 -0
- pyadi_jif-0.1.0.dist-info/METADATA +62 -0
- pyadi_jif-0.1.0.dist-info/RECORD +73 -0
- pyadi_jif-0.1.0.dist-info/WHEEL +6 -0
- pyadi_jif-0.1.0.dist-info/licenses/AUTHORS.rst +13 -0
- pyadi_jif-0.1.0.dist-info/licenses/LICENSE +277 -0
- pyadi_jif-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from adijif.clocks.clock import clock
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class hmc7044_bf(clock):
|
|
8
|
+
"""Brute force methods for calculating clocks
|
|
9
|
+
|
|
10
|
+
These are currently meant for debug to compare against
|
|
11
|
+
the solver solutions
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def list_available_references(self, divider_set):
|
|
15
|
+
"""list_available_references: Based on config list possible
|
|
16
|
+
references that can be generated based on VCO and output
|
|
17
|
+
dividers
|
|
18
|
+
"""
|
|
19
|
+
# Check input
|
|
20
|
+
ref = {
|
|
21
|
+
"n2": 2,
|
|
22
|
+
"vco": 3000000000,
|
|
23
|
+
"r2": 24,
|
|
24
|
+
"required_output_divs": np.array([1.0]),
|
|
25
|
+
}
|
|
26
|
+
for key in ref:
|
|
27
|
+
if key not in divider_set:
|
|
28
|
+
raise Exception(
|
|
29
|
+
"Input must be of type dict with fields: " + str(ref.keys())
|
|
30
|
+
)
|
|
31
|
+
return [divider_set["vco"] / div for div in self.d_available]
|
|
32
|
+
|
|
33
|
+
def find_dividers(self, vcxo, rates, find=3):
|
|
34
|
+
if self.use_vcxo_double:
|
|
35
|
+
vcxo *= 2
|
|
36
|
+
|
|
37
|
+
even = np.arange(2, 4096, 2, dtype=int)
|
|
38
|
+
odivs = np.append([1, 3, 5], even)
|
|
39
|
+
|
|
40
|
+
rates = np.array(rates)
|
|
41
|
+
mod = np.gcd.reduce(np.array(rates, dtype=int))
|
|
42
|
+
vcos = []
|
|
43
|
+
configs = []
|
|
44
|
+
|
|
45
|
+
# for n in range(self.n2_divider_min, self.n2_divider_max):
|
|
46
|
+
for n in self.n2:
|
|
47
|
+
# for r in range(self.r2_divider_min, self.r2_divider_max):
|
|
48
|
+
for r in self.r2:
|
|
49
|
+
# Check VCO in range and output clock a multiple of required reference
|
|
50
|
+
f = vcxo * n / r
|
|
51
|
+
if f >= self.vco_min and f <= self.vco_max:
|
|
52
|
+
# Check if required dividers for output clocks are in set
|
|
53
|
+
if f % mod == 0:
|
|
54
|
+
d = f / rates
|
|
55
|
+
if np.all(np.in1d(d, odivs)) and f not in vcos:
|
|
56
|
+
if f not in vcos:
|
|
57
|
+
vcos.append(f)
|
|
58
|
+
config = {
|
|
59
|
+
"n2": n,
|
|
60
|
+
"r2": r,
|
|
61
|
+
"vco": f,
|
|
62
|
+
"required_output_divs": d,
|
|
63
|
+
}
|
|
64
|
+
configs.append(config)
|
|
65
|
+
if len(configs) >= find:
|
|
66
|
+
return configs
|
|
67
|
+
|
|
68
|
+
return configs
|
adijif/clocks/ltc6952.py
ADDED
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
"""LTC6952 clock chip model."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Union
|
|
4
|
+
|
|
5
|
+
from docplex.cp.solution import CpoSolveResult # type: ignore
|
|
6
|
+
|
|
7
|
+
from adijif.clocks.ltc6952_bf import ltc6952_bf
|
|
8
|
+
from adijif.solvers import CpoExpr, GK_Intermediate
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ltc6952(ltc6952_bf):
|
|
12
|
+
"""LTC6952 clock chip model.
|
|
13
|
+
|
|
14
|
+
This model currently supports VCXO+PLL2 configurations
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name = "LTC6952"
|
|
18
|
+
|
|
19
|
+
vcxo = 125000000
|
|
20
|
+
|
|
21
|
+
# Ranges
|
|
22
|
+
r2_divider_min = 1
|
|
23
|
+
r2_divider_max = 1023
|
|
24
|
+
r2_available = [*range(1, 1023 + 1)]
|
|
25
|
+
n2_divider_min = 1
|
|
26
|
+
n2_divider_max = 65535
|
|
27
|
+
n2_available = [*range(1, 65535 + 1)]
|
|
28
|
+
|
|
29
|
+
""" Output dividers """
|
|
30
|
+
d_available = [
|
|
31
|
+
1,
|
|
32
|
+
2,
|
|
33
|
+
3,
|
|
34
|
+
4,
|
|
35
|
+
5,
|
|
36
|
+
6,
|
|
37
|
+
7,
|
|
38
|
+
8,
|
|
39
|
+
9,
|
|
40
|
+
10,
|
|
41
|
+
11,
|
|
42
|
+
12,
|
|
43
|
+
13,
|
|
44
|
+
14,
|
|
45
|
+
15,
|
|
46
|
+
16,
|
|
47
|
+
17,
|
|
48
|
+
18,
|
|
49
|
+
19,
|
|
50
|
+
20,
|
|
51
|
+
21,
|
|
52
|
+
22,
|
|
53
|
+
23,
|
|
54
|
+
24,
|
|
55
|
+
25,
|
|
56
|
+
26,
|
|
57
|
+
27,
|
|
58
|
+
28,
|
|
59
|
+
29,
|
|
60
|
+
30,
|
|
61
|
+
31,
|
|
62
|
+
32,
|
|
63
|
+
34,
|
|
64
|
+
36,
|
|
65
|
+
38,
|
|
66
|
+
40,
|
|
67
|
+
42,
|
|
68
|
+
44,
|
|
69
|
+
46,
|
|
70
|
+
48,
|
|
71
|
+
50,
|
|
72
|
+
52,
|
|
73
|
+
54,
|
|
74
|
+
56,
|
|
75
|
+
58,
|
|
76
|
+
60,
|
|
77
|
+
62,
|
|
78
|
+
64,
|
|
79
|
+
68,
|
|
80
|
+
72,
|
|
81
|
+
76,
|
|
82
|
+
80,
|
|
83
|
+
84,
|
|
84
|
+
88,
|
|
85
|
+
92,
|
|
86
|
+
96,
|
|
87
|
+
100,
|
|
88
|
+
104,
|
|
89
|
+
108,
|
|
90
|
+
112,
|
|
91
|
+
116,
|
|
92
|
+
120,
|
|
93
|
+
124,
|
|
94
|
+
128,
|
|
95
|
+
136,
|
|
96
|
+
144,
|
|
97
|
+
152,
|
|
98
|
+
160,
|
|
99
|
+
168,
|
|
100
|
+
176,
|
|
101
|
+
184,
|
|
102
|
+
192,
|
|
103
|
+
200,
|
|
104
|
+
208,
|
|
105
|
+
216,
|
|
106
|
+
224,
|
|
107
|
+
232,
|
|
108
|
+
240,
|
|
109
|
+
248,
|
|
110
|
+
256,
|
|
111
|
+
272,
|
|
112
|
+
288,
|
|
113
|
+
304,
|
|
114
|
+
320,
|
|
115
|
+
336,
|
|
116
|
+
352,
|
|
117
|
+
368,
|
|
118
|
+
384,
|
|
119
|
+
400,
|
|
120
|
+
416,
|
|
121
|
+
432,
|
|
122
|
+
448,
|
|
123
|
+
464,
|
|
124
|
+
480,
|
|
125
|
+
496,
|
|
126
|
+
512,
|
|
127
|
+
544,
|
|
128
|
+
576,
|
|
129
|
+
608,
|
|
130
|
+
640,
|
|
131
|
+
672,
|
|
132
|
+
704,
|
|
133
|
+
736,
|
|
134
|
+
768,
|
|
135
|
+
800,
|
|
136
|
+
832,
|
|
137
|
+
864,
|
|
138
|
+
896,
|
|
139
|
+
928,
|
|
140
|
+
960,
|
|
141
|
+
992,
|
|
142
|
+
1024,
|
|
143
|
+
1088,
|
|
144
|
+
1152,
|
|
145
|
+
1216,
|
|
146
|
+
1280,
|
|
147
|
+
1344,
|
|
148
|
+
1408,
|
|
149
|
+
1472,
|
|
150
|
+
1536,
|
|
151
|
+
1600,
|
|
152
|
+
1664,
|
|
153
|
+
1728,
|
|
154
|
+
1792,
|
|
155
|
+
1856,
|
|
156
|
+
1920,
|
|
157
|
+
1984,
|
|
158
|
+
2048,
|
|
159
|
+
2176,
|
|
160
|
+
2304,
|
|
161
|
+
2432,
|
|
162
|
+
2560,
|
|
163
|
+
2688,
|
|
164
|
+
2816,
|
|
165
|
+
2944,
|
|
166
|
+
3072,
|
|
167
|
+
3200,
|
|
168
|
+
3328,
|
|
169
|
+
3456,
|
|
170
|
+
3584,
|
|
171
|
+
3712,
|
|
172
|
+
3840,
|
|
173
|
+
3968,
|
|
174
|
+
4096,
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
# Defaults
|
|
178
|
+
_d: Union[int, List[int]] = [
|
|
179
|
+
1,
|
|
180
|
+
2,
|
|
181
|
+
3,
|
|
182
|
+
4,
|
|
183
|
+
5,
|
|
184
|
+
6,
|
|
185
|
+
7,
|
|
186
|
+
8,
|
|
187
|
+
9,
|
|
188
|
+
10,
|
|
189
|
+
11,
|
|
190
|
+
12,
|
|
191
|
+
13,
|
|
192
|
+
14,
|
|
193
|
+
15,
|
|
194
|
+
16,
|
|
195
|
+
17,
|
|
196
|
+
18,
|
|
197
|
+
19,
|
|
198
|
+
20,
|
|
199
|
+
21,
|
|
200
|
+
22,
|
|
201
|
+
23,
|
|
202
|
+
24,
|
|
203
|
+
25,
|
|
204
|
+
26,
|
|
205
|
+
27,
|
|
206
|
+
28,
|
|
207
|
+
29,
|
|
208
|
+
30,
|
|
209
|
+
31,
|
|
210
|
+
32,
|
|
211
|
+
34,
|
|
212
|
+
36,
|
|
213
|
+
38,
|
|
214
|
+
40,
|
|
215
|
+
42,
|
|
216
|
+
44,
|
|
217
|
+
46,
|
|
218
|
+
48,
|
|
219
|
+
50,
|
|
220
|
+
52,
|
|
221
|
+
54,
|
|
222
|
+
56,
|
|
223
|
+
58,
|
|
224
|
+
60,
|
|
225
|
+
62,
|
|
226
|
+
64,
|
|
227
|
+
68,
|
|
228
|
+
72,
|
|
229
|
+
76,
|
|
230
|
+
80,
|
|
231
|
+
84,
|
|
232
|
+
88,
|
|
233
|
+
92,
|
|
234
|
+
96,
|
|
235
|
+
100,
|
|
236
|
+
104,
|
|
237
|
+
108,
|
|
238
|
+
112,
|
|
239
|
+
116,
|
|
240
|
+
120,
|
|
241
|
+
124,
|
|
242
|
+
128,
|
|
243
|
+
136,
|
|
244
|
+
144,
|
|
245
|
+
152,
|
|
246
|
+
160,
|
|
247
|
+
168,
|
|
248
|
+
176,
|
|
249
|
+
184,
|
|
250
|
+
192,
|
|
251
|
+
200,
|
|
252
|
+
208,
|
|
253
|
+
216,
|
|
254
|
+
224,
|
|
255
|
+
232,
|
|
256
|
+
240,
|
|
257
|
+
248,
|
|
258
|
+
256,
|
|
259
|
+
272,
|
|
260
|
+
288,
|
|
261
|
+
304,
|
|
262
|
+
320,
|
|
263
|
+
336,
|
|
264
|
+
352,
|
|
265
|
+
368,
|
|
266
|
+
384,
|
|
267
|
+
400,
|
|
268
|
+
416,
|
|
269
|
+
432,
|
|
270
|
+
448,
|
|
271
|
+
464,
|
|
272
|
+
480,
|
|
273
|
+
496,
|
|
274
|
+
512,
|
|
275
|
+
544,
|
|
276
|
+
576,
|
|
277
|
+
608,
|
|
278
|
+
640,
|
|
279
|
+
672,
|
|
280
|
+
704,
|
|
281
|
+
736,
|
|
282
|
+
768,
|
|
283
|
+
800,
|
|
284
|
+
832,
|
|
285
|
+
864,
|
|
286
|
+
896,
|
|
287
|
+
928,
|
|
288
|
+
960,
|
|
289
|
+
992,
|
|
290
|
+
1024,
|
|
291
|
+
1088,
|
|
292
|
+
1152,
|
|
293
|
+
1216,
|
|
294
|
+
1280,
|
|
295
|
+
1344,
|
|
296
|
+
1408,
|
|
297
|
+
1472,
|
|
298
|
+
1536,
|
|
299
|
+
1600,
|
|
300
|
+
1664,
|
|
301
|
+
1728,
|
|
302
|
+
1792,
|
|
303
|
+
1856,
|
|
304
|
+
1920,
|
|
305
|
+
1984,
|
|
306
|
+
2048,
|
|
307
|
+
2176,
|
|
308
|
+
2304,
|
|
309
|
+
2432,
|
|
310
|
+
2560,
|
|
311
|
+
2688,
|
|
312
|
+
2816,
|
|
313
|
+
2944,
|
|
314
|
+
3072,
|
|
315
|
+
3200,
|
|
316
|
+
3328,
|
|
317
|
+
3456,
|
|
318
|
+
3584,
|
|
319
|
+
3712,
|
|
320
|
+
3840,
|
|
321
|
+
3968,
|
|
322
|
+
4096,
|
|
323
|
+
]
|
|
324
|
+
_n2: Union[int, List[int]] = [*range(1, 65535 + 1)]
|
|
325
|
+
_r2: Union[int, List[int]] = [*range(1, 1023 + 1)]
|
|
326
|
+
|
|
327
|
+
# Limits
|
|
328
|
+
""" Internal limits """
|
|
329
|
+
_vco_min = 1e6 # uses external VCO limits need to be set by the user
|
|
330
|
+
_vco_max = 4500e6
|
|
331
|
+
pfd_max = 167e6
|
|
332
|
+
vcxo_min = 1e6
|
|
333
|
+
vcxo_max = 500e6
|
|
334
|
+
|
|
335
|
+
minimize_feedback_dividers = False
|
|
336
|
+
|
|
337
|
+
# State management
|
|
338
|
+
_clk_names: List[str] = []
|
|
339
|
+
|
|
340
|
+
@property
|
|
341
|
+
def vco_min(self) -> float:
|
|
342
|
+
"""Actual lower VCO frequency.
|
|
343
|
+
|
|
344
|
+
Valid range 1->4500 MHz
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
float: Current vco minimum value
|
|
348
|
+
"""
|
|
349
|
+
return self._vco_min
|
|
350
|
+
|
|
351
|
+
@vco_min.setter
|
|
352
|
+
def vco_min(self, value: float) -> None:
|
|
353
|
+
"""Actual lower VCO frequency.
|
|
354
|
+
|
|
355
|
+
Valid range 1->4500 MHz
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
value (float): Allowable values for vco min
|
|
359
|
+
|
|
360
|
+
"""
|
|
361
|
+
self._vco_min = value
|
|
362
|
+
|
|
363
|
+
@property
|
|
364
|
+
def vco_max(self) -> float:
|
|
365
|
+
"""Actual upper VCO frequency.
|
|
366
|
+
|
|
367
|
+
Valid range 1->4500 MHz
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
float: Current vco minimum value
|
|
371
|
+
"""
|
|
372
|
+
return self._vco_max
|
|
373
|
+
|
|
374
|
+
@vco_max.setter
|
|
375
|
+
def vco_max(self, value: float) -> None:
|
|
376
|
+
"""Actual upper VCO frequency.
|
|
377
|
+
|
|
378
|
+
Valid range 1->4500 MHz
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
value (float): Allowable values for vco min
|
|
382
|
+
|
|
383
|
+
"""
|
|
384
|
+
self._vco_max = value
|
|
385
|
+
|
|
386
|
+
@property
|
|
387
|
+
def d(self) -> Union[int, List[int]]:
|
|
388
|
+
"""Output dividers.
|
|
389
|
+
|
|
390
|
+
Valid dividers are 1,2,3,4,5,6..32->(even)->4096
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
int: Current allowable dividers
|
|
394
|
+
"""
|
|
395
|
+
return self._d
|
|
396
|
+
|
|
397
|
+
@d.setter
|
|
398
|
+
def d(self, value: Union[int, List[int]]) -> None:
|
|
399
|
+
"""Output dividers.
|
|
400
|
+
|
|
401
|
+
Valid dividers are 1,2,3,4,5,6..32->(even)->4096
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
value (int, list[int]): Allowable values for divider
|
|
405
|
+
|
|
406
|
+
"""
|
|
407
|
+
self._check_in_range(value, self.d_available, "d")
|
|
408
|
+
self._d = value
|
|
409
|
+
|
|
410
|
+
@property
|
|
411
|
+
def n2(self) -> Union[int, List[int]]:
|
|
412
|
+
"""n2: VCO feedback divider.
|
|
413
|
+
|
|
414
|
+
Valid dividers are 1->65536
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
int: Current allowable dividers
|
|
418
|
+
"""
|
|
419
|
+
return self._n2
|
|
420
|
+
|
|
421
|
+
@n2.setter
|
|
422
|
+
def n2(self, value: Union[int, List[int]]) -> None:
|
|
423
|
+
"""VCO feedback divider.
|
|
424
|
+
|
|
425
|
+
Valid dividers are 1->65536
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
value (int, list[int]): Allowable values for divider
|
|
429
|
+
|
|
430
|
+
"""
|
|
431
|
+
self._check_in_range(value, self.n2_available, "n2")
|
|
432
|
+
self._n2 = value
|
|
433
|
+
|
|
434
|
+
@property
|
|
435
|
+
def r2(self) -> Union[int, List[int]]:
|
|
436
|
+
"""VCXO input dividers.
|
|
437
|
+
|
|
438
|
+
Valid dividers are 1->4096
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
int: Current allowable dividers
|
|
442
|
+
"""
|
|
443
|
+
return self._r2
|
|
444
|
+
|
|
445
|
+
@r2.setter
|
|
446
|
+
def r2(self, value: Union[int, List[int]]) -> None:
|
|
447
|
+
"""VCXO input dividers.
|
|
448
|
+
|
|
449
|
+
Valid dividers are 1->4096
|
|
450
|
+
|
|
451
|
+
Args:
|
|
452
|
+
value (int, list[int]): Allowable values for divider
|
|
453
|
+
|
|
454
|
+
"""
|
|
455
|
+
self._check_in_range(value, self.r2_available, "r2")
|
|
456
|
+
self._r2 = value
|
|
457
|
+
|
|
458
|
+
def get_config(self, solution: CpoSolveResult = None) -> Dict:
|
|
459
|
+
"""Extract configurations from solver results.
|
|
460
|
+
|
|
461
|
+
Collect internal clock chip configuration and output clock definitions
|
|
462
|
+
leading to connected devices (converters, FPGAs)
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
solution (CpoSolveResult): CPlex solution. Only needed for CPlex solver
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
Dict: Dictionary of clocking rates and dividers for configuration
|
|
469
|
+
|
|
470
|
+
Raises:
|
|
471
|
+
Exception: If solver is not called first
|
|
472
|
+
"""
|
|
473
|
+
if not self._clk_names:
|
|
474
|
+
raise Exception("set_requested_clocks must be called before get_config")
|
|
475
|
+
|
|
476
|
+
if solution:
|
|
477
|
+
self.solution = solution
|
|
478
|
+
|
|
479
|
+
out_dividers = [self._get_val(x) for x in self.config["out_dividers"]]
|
|
480
|
+
|
|
481
|
+
clk: float = (
|
|
482
|
+
self.vcxo # type: ignore # noqa: B950
|
|
483
|
+
* self._get_val(self.config["n2"]) # type: ignore # noqa: B950
|
|
484
|
+
/ self._get_val(self.config["r2"]) # type: ignore # noqa: B950
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
config: Dict = {
|
|
488
|
+
"r2": self._get_val(self.config["r2"]),
|
|
489
|
+
"n2": self._get_val(self.config["n2"]),
|
|
490
|
+
"VCO": clk,
|
|
491
|
+
"vcxo": self.vcxo,
|
|
492
|
+
"out_dividers": out_dividers,
|
|
493
|
+
"output_clocks": [],
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
output_cfg = {}
|
|
497
|
+
for i, div in enumerate(out_dividers):
|
|
498
|
+
rate = clk / div # type: ignore # noqa: B950
|
|
499
|
+
output_cfg[self._clk_names[i]] = {"rate": rate, "divider": div}
|
|
500
|
+
|
|
501
|
+
config["output_clocks"] = output_cfg
|
|
502
|
+
|
|
503
|
+
self._saved_solution = config
|
|
504
|
+
|
|
505
|
+
return config
|
|
506
|
+
|
|
507
|
+
def _setup_solver_constraints(self, vcxo: int) -> None:
|
|
508
|
+
"""Apply constraints to solver model.
|
|
509
|
+
|
|
510
|
+
Args:
|
|
511
|
+
vcxo (int): VCXO frequency in hertz
|
|
512
|
+
"""
|
|
513
|
+
self.vcxo = vcxo
|
|
514
|
+
self.config = {
|
|
515
|
+
"r2": self._convert_input(self._r2, "r2"),
|
|
516
|
+
"n2": self._convert_input(self._n2, "n2"),
|
|
517
|
+
}
|
|
518
|
+
# self.config = {"r2": self.model.Var(integer=True, lb=1, ub=4095, value=1)}
|
|
519
|
+
# self.config["n2"] = self.model.Var(
|
|
520
|
+
# integer=True, lb=8, ub=4095
|
|
521
|
+
# ) # FIXME: CHECK UB
|
|
522
|
+
|
|
523
|
+
# PLL2 equations
|
|
524
|
+
self._add_equation(
|
|
525
|
+
[
|
|
526
|
+
vcxo / self.config["r2"] <= self.pfd_max,
|
|
527
|
+
vcxo / self.config["r2"] * self.config["n2"] <= self.vco_max,
|
|
528
|
+
vcxo / self.config["r2"] * self.config["n2"] >= self.vco_min,
|
|
529
|
+
]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
# Objectives
|
|
533
|
+
if self.minimize_feedback_dividers:
|
|
534
|
+
self.model.minimize(self.config["r2"])
|
|
535
|
+
# self.model.Obj(self.config["r2"])
|
|
536
|
+
|
|
537
|
+
def _setup(self, vcxo: int) -> None:
|
|
538
|
+
# Setup clock chip internal constraints
|
|
539
|
+
|
|
540
|
+
# FIXME: ADD SPLIT m1 configuration support
|
|
541
|
+
|
|
542
|
+
# Setup clock chip internal constraints
|
|
543
|
+
self._setup_solver_constraints(vcxo)
|
|
544
|
+
|
|
545
|
+
# Add requested clocks to output constraints
|
|
546
|
+
self.config["out_dividers"] = []
|
|
547
|
+
self._clk_names = [] # Reset
|
|
548
|
+
|
|
549
|
+
def _get_clock_constraint(
|
|
550
|
+
self, clk_name: List[str]
|
|
551
|
+
) -> Union[int, float, CpoExpr, GK_Intermediate]:
|
|
552
|
+
"""Get abstract clock output.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
clk_name (str): String of clock name
|
|
556
|
+
|
|
557
|
+
Returns:
|
|
558
|
+
(int or float or CpoExpr or GK_Intermediate): Abstract
|
|
559
|
+
or concrete clock reference
|
|
560
|
+
|
|
561
|
+
Raises:
|
|
562
|
+
Exception: Invalid solver
|
|
563
|
+
"""
|
|
564
|
+
if self.solver == "gekko":
|
|
565
|
+
__d = self._d if isinstance(self._d, list) else [self._d]
|
|
566
|
+
|
|
567
|
+
if __d.sort() != self.d_available.sort():
|
|
568
|
+
raise Exception("For solver gekko d is not configurable for LTC6952")
|
|
569
|
+
# Since d is so disjoint it is very annoying to solve.
|
|
570
|
+
mp = self.model.Var(integer=True, lb=1, ub=32)
|
|
571
|
+
nx = self.model.Var(integer=True, lb=0, ub=7)
|
|
572
|
+
od = self.model.Intermediate(mp * pow(2, nx))
|
|
573
|
+
elif self.solver == "CPLEX":
|
|
574
|
+
od = self._convert_input(self._d, "d_" + str(clk_name))
|
|
575
|
+
else:
|
|
576
|
+
raise Exception("Unknown solver {}".format(self.solver))
|
|
577
|
+
|
|
578
|
+
self.config["out_dividers"].append(od)
|
|
579
|
+
self._clk_names.append(clk_name)
|
|
580
|
+
return self.vcxo / self.config["r2"] * self.config["n2"] / od
|
|
581
|
+
|
|
582
|
+
def set_requested_clocks(
|
|
583
|
+
self, vcxo: int, out_freqs: List, clk_names: List[str]
|
|
584
|
+
) -> None:
|
|
585
|
+
"""Define necessary clocks to be generated in model.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
vcxo (int): VCXO frequency in hertz
|
|
589
|
+
out_freqs (List): list of required clocks to be output
|
|
590
|
+
clk_names (List[str]): list of strings of clock names
|
|
591
|
+
|
|
592
|
+
Raises:
|
|
593
|
+
Exception: If len(out_freqs) != len(clk_names)
|
|
594
|
+
"""
|
|
595
|
+
if len(clk_names) != len(out_freqs):
|
|
596
|
+
raise Exception("clk_names is not the same size as out_freqs")
|
|
597
|
+
|
|
598
|
+
# Setup clock chip internal constraints
|
|
599
|
+
self._setup(vcxo)
|
|
600
|
+
self._clk_names = clk_names
|
|
601
|
+
|
|
602
|
+
# Add requested clocks to output constraints
|
|
603
|
+
for out_freq in out_freqs:
|
|
604
|
+
if self.solver == "gekko":
|
|
605
|
+
__d = self._d if isinstance(self._d, list) else [self._d]
|
|
606
|
+
if __d.sort() != self.d_available.sort():
|
|
607
|
+
raise Exception(
|
|
608
|
+
"For solver gekko d is not configurable for LTC6952"
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
mp = self.model.Var(integer=True, lb=1, ub=32)
|
|
612
|
+
nx = self.model.Var(integer=True, lb=0, ub=7)
|
|
613
|
+
od = self.model.Intermediate(mp * pow(2, nx))
|
|
614
|
+
|
|
615
|
+
elif self.solver == "CPLEX":
|
|
616
|
+
od = self._convert_input(self._d, "d_" + str(out_freq))
|
|
617
|
+
|
|
618
|
+
self._add_equation(
|
|
619
|
+
[self.vcxo / self.config["r2"] * self.config["n2"] / od == out_freq]
|
|
620
|
+
)
|
|
621
|
+
self.config["out_dividers"].append(od)
|
|
622
|
+
|
|
623
|
+
# Objectives
|
|
624
|
+
# self.model.Obj(-1*eo) # Favor even dividers
|