import logging
from typing import Optional
from functools import partial
from qcodes.utils.helpers import create_on_off_val_mapping as on_off_map
from qcodes.utils.validators import Numbers
from .visa_types import (
ViString, ViAttr, ViSession, ViReal64, ViBoolean, ViInt32,
)
from .dll_wrapper import AttributeWrapper, NamedArgType
from .ni_dll_instrument import NIDLLInstrument
# Constants used for querying attributes.
# These can be found in the RFSG C API documentation, see below.
NIRFSG_ATTR_INSTRUMENT_FIRMWARE_REVISION = AttributeWrapper(ViAttr(1050510), ViString)
NIRFSG_ATTR_INSTRUMENT_MANUFACTURER = AttributeWrapper(ViAttr(1050511), ViString)
NIRFSG_ATTR_INSTRUMENT_MODEL = AttributeWrapper(ViAttr(1050512), ViString)
NIRFSG_ATTR_SPECIFIC_DRIVER_VENDOR = AttributeWrapper(ViAttr(1050513), ViString)
NIRFSG_ATTR_SPECIFIC_DRIVER_REVISION = AttributeWrapper(ViAttr(1050551), ViString)
NIRFSG_ATTR_SERIAL_NUMBER = AttributeWrapper(ViAttr(1150026), ViString)
NIRFSG_ATTR_FREQUENCY = AttributeWrapper(ViAttr(1250001), ViReal64)
NIRFSG_ATTR_POWER_LEVEL = AttributeWrapper(ViAttr(1250002), ViReal64)
NIRFSG_ATTR_OUTPUT_ENABLED = AttributeWrapper(ViAttr(1250004), ViBoolean)
NIRFSG_ATTR_REF_CLOCK_SOURCE = AttributeWrapper(ViAttr(1150001), ViString)
NIRFSG_ATTR_ANALOG_MODULATION_TYPE = AttributeWrapper(ViAttr(1150032), ViInt32)
NIRFSG_ATTR_ANALOG_MODULATION_AM_SENSITIVITY = AttributeWrapper(ViAttr(1150167), ViReal64)
NIRFSG_ATTR_PULSE_MODULATION_ENABLED = AttributeWrapper(ViAttr(1250051), ViBoolean)
logger = logging.getLogger(__name__)
# Name mapping for analog modulation mode.
# These can be found in the NI RFSG header file, found by default in
# C:\Program Files (x86)\IVI Foundation\IVI\Include\niRFSG.h
# or in the online documentation: https://zone.ni.com/reference/en-XX/help/371025V-01/rfsgproperties/pnirfsg_anlgmod.type/
ANALOG_MOD_NAME_MAP = {
"none": 0, # NIRFSG_VAL_NONE
"FM": 2000, # NIRFSG_VAL_FM
"PM": 2001, # NIRFSG_VAL_PM
"AM": 2002, # NIRFSG_VAL_AM
}
CLK_SRC_MAP = {
"onboard": "OnboardClock",
"clk_in": "ClkIn",
"ref_in": "RefIn",
"pxi_clk": "PXI_CLK",
"ref_in_2": "RefIn2",
"pxi_clk_master": "PXI_ClkMaster",
}
[docs]
class NationalInstruments_RFSG(NIDLLInstrument):
r"""
This is the QCoDeS driver for National Instruments RF signal generator
devices based on the NI-RFSG driver. As of NI-RFSG version 18.1, the
supported devices are
PXI-5610, PXI-5650, PXI-5651, PXI-5652, PXI-5670, PXI-5671, PXIe-5611,
PXIe-5644, PXIe-5645, PXIe-5646, PXIe-5650, PXIe-5651, PXIe-5652,
PXIe-5653, PXIe-5654, PXIe-5672, PXIe-5673, PXIe-5673E, PXIe-5820,
PXIe-5840.
Documentation for the NI-RFSG C API can be found by default in the
folder C:\Users\Public\Documents\National Instruments\NI-RFSG\Documentation
Only very basic functionality is implemented.
Tested with
- PXIe-5654
Args:
name: Name for this instrument
resource: Identifier for this instrument in NI MAX.
dll_path: path to the NI-RFSG library DLL. If not provided, use the
default location,
``C:\Program Files\IVI Foundation\IVI\bin\NiRFSG_64.dll``.
id_query: whether to perform an ID query on initialization
reset_device: whether to reset the device on initialization
"""
# default DLL location
dll_path = r"C:\Program Files\IVI Foundation\IVI\bin\NiRFSG_64.dll"
# C:\Program Files (x86)\IVI Foundation\IVI\bin\NiRFSG.dll for 32-bit
def __init__(self, name: str, resource: str,
dll_path: Optional[str] = None,
id_query: bool = False,
reset_device: bool = False,
**kwargs):
super().__init__(name=name, resource=resource,
dll_path=dll_path or self.dll_path,
lib_prefix="niRFSG", **kwargs)
# Wrap DLL calls
self.wrapper.Initiate = self.wrapper.wrap_dll_function_checked( # type: ignore[attr-defined]
name_in_library="Initiate",
argtypes=[NamedArgType("vi", ViSession)]
)
self.wrapper.Abort = self.wrapper.wrap_dll_function_checked( # type: ignore[attr-defined]
name_in_library="Abort",
argtypes=[NamedArgType("vi", ViSession)])
self.wrapper.ConfigureRF = self.wrapper.wrap_dll_function_checked( # type: ignore[attr-defined]
name_in_library="ConfigureRF",
argtypes=[
NamedArgType("vi", ViSession),
NamedArgType("frequency", ViReal64),
NamedArgType("powerLevel", ViReal64),
]
)
self.add_parameter(name="frequency",
unit="Hz",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_FREQUENCY),
set_cmd=self._set_frequency,
)
self.add_parameter(name="power_level",
unit="dBm",
label="power level",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_POWER_LEVEL),
set_cmd=self._set_power_level,
)
self.add_parameter(name="output_enabled",
label="Output enabled",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_OUTPUT_ENABLED),
set_cmd=partial(self.set_attribute,
NIRFSG_ATTR_OUTPUT_ENABLED),
val_mapping=on_off_map(on_val=True, off_val=False),
initial_value=False,
)
self.add_parameter(name="pulse_mod_enabled",
label="Pulse modulation enabled",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_PULSE_MODULATION_ENABLED
),
set_cmd=partial(self.set_attribute,
NIRFSG_ATTR_PULSE_MODULATION_ENABLED
),
val_mapping=on_off_map(on_val=True, off_val=False),
initial_value=False,
)
self.add_parameter(name="analog_mod_type",
label="Analog modulation type",
docstring="Specifies the analog modulation format "
"to use. FM = frequency modulation, PM = "
"phase modulation, AM = amplitude "
"modulation. Set to 'none' to disable "
"analog modulation.",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_ANALOG_MODULATION_TYPE),
set_cmd=partial(self.set_attribute,
NIRFSG_ATTR_ANALOG_MODULATION_TYPE),
val_mapping=ANALOG_MOD_NAME_MAP,
)
self.add_parameter(name="amplitude_mod_sensitivity",
label="Amplitude modulation sensitivity",
docstring="The modulation signal sent to AM IN is "
"scaled by this percentage before "
"multiplying the carrier wave.",
unit="%/V",
get_cmd=partial(
self.get_attribute,
NIRFSG_ATTR_ANALOG_MODULATION_AM_SENSITIVITY
),
set_cmd=partial(
self.set_attribute,
NIRFSG_ATTR_ANALOG_MODULATION_AM_SENSITIVITY
),
vals=Numbers(0, 100),
)
self.add_parameter(name="clock_source",
label="Reference clock source",
docstring="Specify the reference clock source for "
"the device. See the ``vals`` attribute for valid "
"values.\n\nThe values 'ref_in_2' and "
"'pxi_clk_master' are valid for PXIe-5840 with "
"PXIe-5653. For further details, see the NI-RFSG "
"documentation.",
get_cmd=partial(self.get_attribute,
NIRFSG_ATTR_REF_CLOCK_SOURCE),
set_cmd=partial(self.set_attribute,
NIRFSG_ATTR_REF_CLOCK_SOURCE),
val_mapping=CLK_SRC_MAP,
)
self.initiate()
self.connect_message()
[docs]
def initiate(self):
"""
Initiate signal generation. This causes the NI-RFSG device to leave
the Configuration state.
"""
self.wrapper.Initiate(self._handle)
[docs]
def abort(self):
"""
Stop signal generation and return to the Configuration state.
"""
self.wrapper.Abort(self._handle)
def _configure_rf(self, frequency: float, power_level: float,
initiate: bool):
"""
NI-RFSG devices can only set both the frequency and power level
simultatneously. Convenience methods are defined below for setting
them individually.
NOTE: PXI-5670/5671 and PXIe-5672 devices must be in the Configuration
state before calling this function (by calling abort()), that is not
checked here.
Args:
frequency: frequency in Hz
power_level: power level in dBm
initiate: if True, call self.initiate after configuring, which
starts RF output
"""
self.wrapper.ConfigureRF( # type: ignore[attr-defined]
self._handle,
ViReal64(frequency),
ViReal64(power_level)
)
if initiate:
self.initiate()
def _set_frequency(self, frequency: float, initiate: bool = False):
power_level = self.get_attribute(NIRFSG_ATTR_POWER_LEVEL)
self._configure_rf(frequency, power_level, initiate)
def _set_power_level(self, power_level: float, initiate: bool = False):
frequency = self.get_attribute(NIRFSG_ATTR_FREQUENCY)
self._configure_rf(frequency, power_level, initiate)
@property
def vendor(self) -> str:
return self.get_attribute(NIRFSG_ATTR_SPECIFIC_DRIVER_VENDOR)
@property
def model(self) -> str:
return self.get_attribute(NIRFSG_ATTR_INSTRUMENT_MODEL)
@property
def serial(self) -> str:
return self.get_attribute(NIRFSG_ATTR_SERIAL_NUMBER)
@property
def firmware(self) -> str:
return self.get_attribute(NIRFSG_ATTR_INSTRUMENT_FIRMWARE_REVISION)
[docs]
def get_idn(self):
return {
"vendor": self.vendor,
"model": self.model,
"serial": self.serial,
"firmware": self.firmware
}
# class NationalInstruments_RFSG
# shorthand alias for the above
NI_RFSG = NationalInstruments_RFSG