|
| 1 | +"""Tests for AD9084 combined RX+TX model.""" |
| 2 | + |
| 3 | +import pytest |
| 4 | + |
| 5 | +import adijif |
| 6 | +from adijif.converters.ad9084 import ad9084, ad9084_rx, ad9084_tx |
| 7 | + |
| 8 | +# ── Instantiation ──────────────────────────────────────────────────────────── |
| 9 | + |
| 10 | + |
| 11 | +def test_ad9084_instantiation(): |
| 12 | + """Verify AD9084 combined model instantiates without error.""" |
| 13 | + dev = ad9084(solver="CPLEX") |
| 14 | + assert dev is not None |
| 15 | + |
| 16 | + |
| 17 | +def test_ad9084_name(): |
| 18 | + """Verify AD9084 combined model has the expected name.""" |
| 19 | + dev = ad9084(solver="CPLEX") |
| 20 | + assert dev.name == "AD9084" |
| 21 | + |
| 22 | + |
| 23 | +def test_ad9084_converter_type(): |
| 24 | + """Verify AD9084 combined model reports adc_dac converter type.""" |
| 25 | + dev = ad9084(solver="CPLEX") |
| 26 | + assert dev.converter_type == "adc_dac" |
| 27 | + |
| 28 | + |
| 29 | +def test_ad9084_nested_attribute(): |
| 30 | + """Verify _nested lists both adc and dac.""" |
| 31 | + dev = ad9084(solver="CPLEX") |
| 32 | + assert dev._nested == ["adc", "dac"] |
| 33 | + |
| 34 | + |
| 35 | +def test_ad9084_has_adc_sub_converter(): |
| 36 | + """Verify AD9084 combined model exposes an adc sub-converter.""" |
| 37 | + dev = ad9084(solver="CPLEX") |
| 38 | + assert hasattr(dev, "adc") |
| 39 | + assert isinstance(dev.adc, ad9084_rx) |
| 40 | + |
| 41 | + |
| 42 | +def test_ad9084_has_dac_sub_converter(): |
| 43 | + """Verify AD9084 combined model exposes a dac sub-converter.""" |
| 44 | + dev = ad9084(solver="CPLEX") |
| 45 | + assert hasattr(dev, "dac") |
| 46 | + assert isinstance(dev.dac, ad9084_tx) |
| 47 | + |
| 48 | + |
| 49 | +def test_ad9084_via_system(): |
| 50 | + """Verify AD9084 combined model can be created through the system factory.""" |
| 51 | + sys = adijif.system( |
| 52 | + "ad9084", "hmc7044", "xilinx", 125000000, solver="CPLEX" |
| 53 | + ) |
| 54 | + assert sys.converter.name == "AD9084" |
| 55 | + |
| 56 | + |
| 57 | +def test_ad9084_accessible_from_adijif(): |
| 58 | + """Verify ad9084 is exported at the adijif package level.""" |
| 59 | + assert hasattr(adijif, "ad9084") |
| 60 | + assert adijif.ad9084 is ad9084 |
| 61 | + |
| 62 | + |
| 63 | +# ── Sub-converter defaults ──────────────────────────────────────────────────── |
| 64 | + |
| 65 | + |
| 66 | +def test_ad9084_adc_is_ad9084_rx(): |
| 67 | + """Verify the adc sub-converter is an AD9084_RX instance.""" |
| 68 | + dev = ad9084(solver="CPLEX") |
| 69 | + assert dev.adc.name == "AD9084_RX" |
| 70 | + assert dev.adc.converter_type == "adc" |
| 71 | + |
| 72 | + |
| 73 | +def test_ad9084_dac_is_ad9084_tx(): |
| 74 | + """Verify the dac sub-converter is an AD9084_TX instance.""" |
| 75 | + dev = ad9084(solver="CPLEX") |
| 76 | + assert dev.dac.name == "AD9084_TX" |
| 77 | + assert dev.dac.converter_type == "dac" |
| 78 | + |
| 79 | + |
| 80 | +def test_ad9084_clock_limits_match_rx(): |
| 81 | + """Verify combined model clock limits reflect the RX limits.""" |
| 82 | + dev = ad9084(solver="CPLEX") |
| 83 | + assert dev.converter_clock_min == ad9084_rx.converter_clock_min |
| 84 | + assert dev.converter_clock_max == ad9084_rx.converter_clock_max |
| 85 | + |
| 86 | + |
| 87 | +# ── _get_converters ────────────────────────────────────────────────────────── |
| 88 | + |
| 89 | + |
| 90 | +def test_ad9084_get_converters_returns_two(): |
| 91 | + """Verify _get_converters returns both sub-converters.""" |
| 92 | + dev = ad9084(solver="CPLEX") |
| 93 | + convs = dev._get_converters() |
| 94 | + assert len(convs) == 2 |
| 95 | + |
| 96 | + |
| 97 | +def test_ad9084_get_converters_contains_adc_and_dac(): |
| 98 | + """Verify _get_converters list contains the adc and dac sub-converters.""" |
| 99 | + dev = ad9084(solver="CPLEX") |
| 100 | + convs = dev._get_converters() |
| 101 | + assert dev.adc in convs |
| 102 | + assert dev.dac in convs |
| 103 | + |
| 104 | + |
| 105 | +# ── Clock names ────────────────────────────────────────────────────────────── |
| 106 | + |
| 107 | + |
| 108 | +def test_ad9084_clock_names_count(): |
| 109 | + """Verify get_required_clock_names returns three names.""" |
| 110 | + dev = ad9084(solver="CPLEX") |
| 111 | + names = dev.get_required_clock_names() |
| 112 | + assert len(names) == 3 |
| 113 | + |
| 114 | + |
| 115 | +def test_ad9084_clock_names_direct(): |
| 116 | + """Verify clock names under direct clocking use the dac_clock prefix.""" |
| 117 | + dev = ad9084(solver="CPLEX") |
| 118 | + dev.adc.clocking_option = "direct" |
| 119 | + names = dev.get_required_clock_names() |
| 120 | + assert names[0] == "ad9084_dac_clock" |
| 121 | + assert names[1] == "ad9084_adc_sysref" |
| 122 | + assert names[2] == "ad9084_dac_sysref" |
| 123 | + |
| 124 | + |
| 125 | +def test_ad9084_clock_names_pll(): |
| 126 | + """Verify clock names under PLL clocking use the pll_ref prefix.""" |
| 127 | + dev = ad9084(solver="CPLEX") |
| 128 | + dev.adc._clocking_option = "integrated_pll" |
| 129 | + names = dev.get_required_clock_names() |
| 130 | + assert names[0] == "ad9084_pll_ref" |
| 131 | + |
| 132 | + |
| 133 | +# ── validate_config ─────────────────────────────────────────────────────────── |
| 134 | + |
| 135 | + |
| 136 | +def test_ad9084_validate_config_delegates_to_sub_converters(): |
| 137 | + """Verify validate_config calls through to both sub-converters. |
| 138 | +
|
| 139 | + Confirm that an error from either sub-converter propagates out of the |
| 140 | + combined validate_config, proving delegation rather than a no-op. |
| 141 | + """ |
| 142 | + dev = ad9084(solver="CPLEX") |
| 143 | + # Default TX state (mode "2", sample_clock 8 GHz) has a bit clock that |
| 144 | + # exceeds the JESD204C lane-rate limit, so validate_config must raise. |
| 145 | + with pytest.raises(Exception, match="bit clock"): |
| 146 | + dev.validate_config() |
| 147 | + |
| 148 | + |
| 149 | +# ── empty quick_configuration_modes ────────────────────────────────────────── |
| 150 | + |
| 151 | + |
| 152 | +def test_ad9084_quick_configuration_modes_empty(): |
| 153 | + """Verify combined model has empty quick_configuration_modes.""" |
| 154 | + dev = ad9084(solver="CPLEX") |
| 155 | + assert dev.quick_configuration_modes == {} |
| 156 | + |
| 157 | + |
| 158 | +# ── Sub-converter independence ──────────────────────────────────────────────── |
| 159 | + |
| 160 | + |
| 161 | +def test_ad9084_adc_sample_clock_settable(): |
| 162 | + """Verify the adc sub-converter sample clock can be modified.""" |
| 163 | + dev = ad9084(solver="CPLEX") |
| 164 | + dev.adc.sample_clock = 1e9 |
| 165 | + assert dev.adc.sample_clock == 1e9 |
| 166 | + |
| 167 | + |
| 168 | +def test_ad9084_dac_sample_clock_settable(): |
| 169 | + """Verify the dac sub-converter sample clock can be modified.""" |
| 170 | + dev = ad9084(solver="CPLEX") |
| 171 | + dev.dac.sample_clock = 2e9 |
| 172 | + assert dev.dac.sample_clock == 2e9 |
| 173 | + |
| 174 | + |
| 175 | +def test_ad9084_adc_mode_change_does_not_affect_dac(): |
| 176 | + """Verify changing the ADC JESD mode does not change the DAC mode.""" |
| 177 | + dev = ad9084(solver="CPLEX") |
| 178 | + original_dac_L = dev.dac.L |
| 179 | + dev.adc.set_quick_configuration_mode("47", "jesd204c") |
| 180 | + assert dev.dac.L == original_dac_L |
| 181 | + |
| 182 | + |
| 183 | +def test_ad9084_dac_mode_change_does_not_affect_adc(): |
| 184 | + """Verify changing the DAC JESD mode does not change the ADC mode.""" |
| 185 | + dev = ad9084(solver="CPLEX") |
| 186 | + original_adc_L = dev.adc.L |
| 187 | + dev.dac.set_quick_configuration_mode("2", "jesd204c") |
| 188 | + assert dev.adc.L == original_adc_L |
| 189 | + |
| 190 | + |
| 191 | +# ── System factory integration ──────────────────────────────────────────────── |
| 192 | + |
| 193 | + |
| 194 | +def test_ad9084_system_has_nested_converters(): |
| 195 | + """Verify system created with ad9084 exposes _nested on the converter.""" |
| 196 | + sys = adijif.system( |
| 197 | + "ad9084", "hmc7044", "xilinx", 125000000, solver="CPLEX" |
| 198 | + ) |
| 199 | + assert sys.converter._nested == ["adc", "dac"] |
| 200 | + |
| 201 | + |
| 202 | +def test_ad9084_system_sub_converters_accessible(): |
| 203 | + """Verify adc and dac are accessible from the converter in a system context.""" |
| 204 | + sys = adijif.system( |
| 205 | + "ad9084", "hmc7044", "xilinx", 125000000, solver="CPLEX" |
| 206 | + ) |
| 207 | + assert isinstance(sys.converter.adc, ad9084_rx) |
| 208 | + assert isinstance(sys.converter.dac, ad9084_tx) |
| 209 | + |
| 210 | + |
| 211 | +def test_ad9084_system_full_solve(): |
| 212 | + """Verify a system with the ad9084 converter can solve without error.""" |
| 213 | + sys = adijif.system( |
| 214 | + "ad9084", "hmc7044", "xilinx", 125000000, solver="CPLEX" |
| 215 | + ) |
| 216 | + sys.fpga.setup_by_dev_kit_name("vcu118") |
| 217 | + |
| 218 | + converter_rate = int(20e9) |
| 219 | + cddc_dec = 4 |
| 220 | + fddc_dec = 2 |
| 221 | + sys.converter.adc.sample_clock = converter_rate / (cddc_dec * fddc_dec) |
| 222 | + sys.converter.adc.datapath.cddc_decimations = [cddc_dec] * 4 |
| 223 | + sys.converter.adc.datapath.fddc_decimations = [fddc_dec] * 8 |
| 224 | + sys.converter.adc.datapath.fddc_enabled = [True] * 8 |
| 225 | + sys.converter.adc.clocking_option = "direct" |
| 226 | + sys.add_pll_inline("adf4382", 125e6, sys.converter) |
| 227 | + # sys.add_pll_sysref("adf4030", 125e6, sys.converter, sys.fpga) |
| 228 | + |
| 229 | + sys.converter.dac.sample_clock = converter_rate / (cddc_dec * fddc_dec) |
| 230 | + sys.converter.dac.datapath.cduc_interpolation = 4 |
| 231 | + sys.converter.dac.clocking_option = "direct" |
| 232 | + # sys.add_pll_inline("adf4382", 125e6, sys.converter) |
| 233 | + # sys.add_pll_sysref("adf4030", 125e6, sys.converter, sys.fpga) |
| 234 | + |
| 235 | + # JESD |
| 236 | + mode_rx = adijif.utils.get_jesd_mode_from_params( |
| 237 | + sys.converter.adc, M=4, L=8, S=1, Np=16, jesd_class="jesd204c" |
| 238 | + ) |
| 239 | + assert mode_rx |
| 240 | + mode_rx = mode_rx[0]["mode"] |
| 241 | + sys.converter.adc.set_quick_configuration_mode(mode_rx, "jesd204c") |
| 242 | + mode_tx = adijif.utils.get_jesd_mode_from_params( |
| 243 | + sys.converter.dac, M=4, L=8, S=1, Np=16, jesd_class="jesd204c" |
| 244 | + ) |
| 245 | + assert mode_tx |
| 246 | + mode_tx = mode_tx[0]["mode"] |
| 247 | + sys.converter.dac.set_quick_configuration_mode(mode_tx, "jesd204c") |
| 248 | + |
| 249 | + cfg = sys.solve() |
| 250 | + |
| 251 | + assert cfg is not None |
0 commit comments