ad9913

class rfblocks.ad9913(cs: str | None = None, io_update: str | None = None, reset: str | None = None, ps0: str | None = None, ps1: str | None = None, ps2: str | None = None, sysclk: float = 250.0, board_model: str = '20dB')[source]

Encapsulates control for the AD9913 DDS.

Documentation for the AD9913 DDS signal source rfblocks module can be found here: An AD9913 DDS Signal Source.

Parameters:
  • cs (str) – The AD9913 chip select (~CS) controller pin.

  • io_update (str) – The AD9913 IO update (IO_UPDATE) controller pin.

  • reset (str) – The AD9913 reset (MASTER_RESET) controller pin.

  • ps0 (str) – The AD9913 profile select 0 (PS0) controller pin.

  • ps1 (str) – The AD9913 profile select 1 (PS1) controller pin.

  • ps2 (str) – The AD9913 profile select 2 (PS2) controller pin.

  • sysclk (float) – The system clock input frequency in MHz.

MAX_LEVEL = 1023

The AD9913 has a 10-bit DAC.

MAX_PHOFFSET = 16383

The AD9913 has a 14-bit phase offset word.

class ProfileControl(value)[source]

An enum representing the profile control setting types. (INTERNAL, PINS)

class Subsystem(value)[source]

An enum containing the device subsystem selectors. (DIGITAL, DAC, INPUT_CLOCK, ALL)

class SweepRampType(value)[source]

An enum containing possible sweep ramp type settings. (SWEEP_OFF, RAMP_UP, RAMP_DOWN, RAMP_BIDIR)

class SweepTriggerSource(value)[source]

An enum containing possible sweep trigger source settings. (PROFILE_PINS, REGISTER)

class SweepTriggerType(value)[source]

An enum containing possible sweep trigger type settings. (EDGE_TRIGGER, STATE_TRIGGER)

class SweepType(value)[source]

An enum containing possible sweep type settings. (FREQUENCY, PHASE)

classmethod board_models() List[source]

Returns a list containing the board model names for which calibration data is available.

Classmethod:

property cal_data: Dict[float, List[float]]

The calibration data for the DDS board associated with this AD9913 instance.

The format for the data is:

{
     freq-0: [slope-0, intercept-0],
     freq-1: [slope-1, intercept-1],
     ...
     freq-n [slope-n, intercept-n]
}

where the frequencies run from 0 to 100MHz.

The slope and intercept data are derived from calibration measurements using the procedure documented in Calibration Procedure.

Note that calibration measurements are made down to 5MHz so the values measured at 5MHz are also used for 0MHz. This allows slope and intercept numbers to be interpolated for f < 5MHz.

chip_reset() str[source]

Reset the chip internal logic to default states.

Returns:

A string containing the controller commands required to reset the chip.

>>> dds2 = ad9913('d3', 'd4', ps0='c5', ps1='c6', ps2='c7', reset='b1')
>>> dds2.chip_reset()
'HB1:LB1:'
config_cfr1(update: bool = True) str[source]

Configure the CFR1 register value.

Parameters:

update (bool) – Set to True if the CFR1 should be updated immediately, False if the value should be buffered only.

This will configure and optionally update the device CFR1 register using the current value stored in self.cfr1.

Returns:

The command string required to set the device CFR1 register.

config_modulus_params(a: int, b: int, x: int) str[source]

Configure the modulus parameter registers, update the output frequency.

Parameters:
  • a (32-bit integer) – The A value as calculated by modulus_parameters.

  • b (32-bit integer) – The B value as calculated by modulus_parameters.

  • x (32-bit integer) – The X value as calculated by modulus_parameters.

Returns:

The command string required to configure and update the modulus parameter registers.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.config_modulus_params(*dds1.modulus_parameters(25.0))
'LD1:W06,00,00,00,05,19,99,99,99:HD1:LD1:W07,00,00,00,00,00,00,00,03:HD1:HD2:LD2:'
>>> dds1.config_modulus_params(*dds1.modulus_parameters(0.5820761))
'LD1:W06,00,95,02,F9,00,98,96,77:HD1:LD1:W07,00,00,00,00,00,25,B8,41:HD1:HD2:LD2:'
config_output_level(level: int, update: bool = True) str[source]

Configure and update the current device output level.

Parameters:

level (integer) – A 10 bit value specifying the full scale DAC output current.

Returns:

The command string required to configure and update the current device full scale DAC output current.

Return type:

str

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.config_output_level(1023)
'LD1:W02,00,7f,13,FF:HD1:HD2:LD2:'
>>> dds1.config_output_level(511)
'LD1:W02,00,7f,11,FF:HD1:HD2:LD2:'
>>> dds1.config_output_level(15)
'LD1:W02,00,7f,10,0F:HD1:HD2:LD2:'
>>> dds1.config_output_level(4095)
'LD1:W02,00,7f,13,FF:HD1:HD2:LD2:'
>>> dds1.config_output_level(-20)
'LD1:W02,00,7f,10,01:HD1:HD2:LD2:'
config_phase_offset(phoffset_word: int, update: bool = True) str[source]

Configure and update the current device phase offset.

Parameters:

phoffset_word (14-bit integer) – The DDS phase offset word for the desired phase offset.

Returns:

The command string required to configure the current device phase offset and update the associated register.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.config_phase_offset(dds1.phase_offset_word(180.0))
'LD1:W04,20,00:HD1:HD2:LD2:'
>>> dds1.config_phase_offset(dds1.phase_offset_word(90.0))
'LD1:W04,10,00:HD1:HD2:LD2:'
>>> dds1.config_phase_offset(dds1.phase_offset_word(45.0))
'LD1:W04,08,00:HD1:HD2:LD2:'
>>> dds1.config_phase_offset(dds1.phase_offset_word(1.0))
'LD1:W04,00,2D:HD1:HD2:LD2:'
>>> dds1.config_phase_offset(dds1.phase_offset_word(0.1))
'LD1:W04,00,04:HD1:HD2:LD2:'
config_profile(prof: int, tuning_word: int, phoffset_word: int = 0) str[source]

Configure and update the tuning word for the specified DDS profile.

Parameters:
  • prof (integer) – The number of the DDS profile to update. (valid profiles are 0..7)

  • tuning_word (32-bit integer) – The DDS tuning word for the desired profile output frequency.

  • phoffset_word (14-bit integer) – The phase offset word for the desired profile phase offset.

Returns:

The command string required to configure the tuning word and phase offset for the specified profile and update the associated register.

>>> dds2 = ad9913('d3', 'd4', ps0='c5', ps1='c6', ps2='c7', sysclk=250.0)
>>> baseFreq = 10.0
>>> for prof in range(7):
...     outFreq = baseFreq + prof
...     phOffset = prof * 15.0
...     dds2.config_profile(prof, dds2.tuning_word(outFreq))
... 
'LD3:W09,00,00,0A,3D,70,A4:HD3:HD4:LD4:'
'LD3:W0A,00,00,0B,43,95,81:HD3:HD4:LD4:'
'LD3:W0B,00,00,0C,49,BA,5E:HD3:HD4:LD4:'
'LD3:W0C,00,00,0D,4F,DF,3B:HD3:HD4:LD4:'
'LD3:W0D,00,00,0E,56,04,19:HD3:HD4:LD4:'
'LD3:W0E,00,00,0F,5C,28,F6:HD3:HD4:LD4:'
'LD3:W0F,00,00,10,62,4D,D3:HD3:HD4:LD4:'
config_sweep_limits(sweep_type: SweepType, start: float, end: float, falling_delta: float, rising_delta: float) str[source]

Configure sweep limits and deltas.

Parameters:
  • sweep_type (ad9913.SweepType) – The sweep type. Either SweepType.FREQUENCY or SweepType.PHASE

  • start (float) – The starting point of the sweep. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • end (float) – The end point of the sweep. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • falling_delta (float) – The falling delta tuning step. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • rising_delta (float) – The rising delta tuning step. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

Returns:

The command string required to configure and update the sweep limit and delta registers.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> sweepStart = 1.0
>>> sweepEnd = 20.0
>>> sweepDelta = 0.1
>>> dds1.config_sweep_limits(
...     ad9913.SweepType.FREQUENCY,
...     sweepStart, sweepEnd,
...     sweepDelta, sweepDelta)
'LD1:W06,14,7A,E1,48,01,06,24,DD:HD1:LD1:W07,00,1A,36,E3,00,1A,36,E3:HD1:HD2:LD2:'
>>> sweepStart = 0.0
>>> sweepEnd = 115.0
>>> sweepDelta = 1.0
>>> dds1.config_sweep_limits(
...     ad9913.SweepType.PHASE,
...     sweepStart, sweepEnd,
...     sweepDelta, sweepDelta)
'LD1:W06,51,C4,00,00,00,00,00,00:HD1:LD1:W07,00,00,00,2E,00,00,00,2E:HD1:HD2:LD2:'
config_sweep_params(sweep_type: SweepType, start: float, end: float, falling_delta: float, rising_delta: float, falling_rate: float, rising_rate: float, dwell: bool = False, trigger_source: SweepTriggerSource = SweepTriggerSource.REGISTER, trigger_type: SweepTriggerType = SweepTriggerType.STATE_TRIGGER) str[source]

Configure sweep parameters.

Parameters:
  • sweep_type (ad9913.SweepType) – The sweep type. Either SweepType.FREQUENCY or SweepType.PHASE

  • start (float) – The starting point of the sweep. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • end (float) – The end point of the sweep. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • falling_delta (float) – The falling delta tuning step. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • rising_delta (float) – The rising delta tuning step. This is specified as MHz for a FREQUENCY sweep or as degrees for a PHASE sweep.

  • falling_rate (float) – The falling sweep ramp rate in seconds.

  • rising_rate (float) – The rising sweep ramp rate in seconds.

  • dwell (bool) – If set to False dwell is de-activated and the device reverts to it’s initial state after the completion of a sweep. If set to True, the dwell is active and the device will hold at the final state after completion of the sweep.

  • trigger_source (ad9913.SweepTriggerSource) – Set the device to trigger sweep using either the profile pins or the CFR1[22:20] register bits. The default is to use the CFR1[22:20] register bits as the trigger source.

  • trigger_type (ad9913.SweepTriggerType) – Set the device to trigger either on an EDGE transition or when the profile pins/CFR1[22:20] bits are in a specified STATE. The default is to use STATE_TRIGGER.

Returns:

The command string required to configure the sweep parameter registers.

>>> dds1 = ad9913('d1', 'd2')
>>> sweepStart = 1.0
>>> sweepEnd = 2.0
>>> sweepDelta = 0.1
>>> sweepRate = 1e-6
>>> dds1.config_sweep_params(
...     ad9913.SweepType.FREQUENCY,
...     sweepStart, sweepEnd,
...     sweepDelta, sweepDelta,
...     sweepRate, sweepRate)
'LD1:W06,02,0C,49,BA,01,06,24,DD:HD1:LD1:W07,00,1A,36,E3,00,1A,36,E3:HD1:HD2:LD2:LD1:W08,00,FA,00,FA:HD1:HD2:LD2:LD1:W00,08,00,03,00:HD1:HD2:LD2:'
config_sweep_rates(falling: float, rising: float) str[source]

Configure the sweep ramp rates.

Parameters:
  • falling (float) – The falling sweep ramp rate in seconds.

  • rising (float) – The rising sweep ramp rate in seconds.

Returns:

The command string required to configure and update the sweep rate registers.

Note

Note that there is granularity with the sweep ramp rates. This will depend on the system clock. With the default system clock of 250 MHz the smallest possible step is 4 nS. This will also be the smallest increment between step sizes.

Since the ramp rate registers are 16 bits, the largest possible step size (with a 250 MHz system clock) will be 262 uS.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> risingSweepRate = 1e-6
>>> fallingSweepRate = 2e-6
>>> dds1.config_sweep_rates(fallingSweepRate, risingSweepRate)
'LD1:W08,01,F4,00,FA:HD1:HD2:LD2:'
>>> risingSweepRate = 10e-9
>>> fallingSweepRate = 20e-9
>>> dds1.config_sweep_rates(fallingSweepRate, risingSweepRate)
'LD1:W08,00,05,00,02:HD1:HD2:LD2:'
config_tuning_word(tuning_word: int, update: bool = True) str[source]

Configure and update the current device tuning word.

Parameters:

tuning_word (32-bit integer) – The DDS tuning word for the desired output frequency.

Returns:

The command string required to configure the current device tuning word and update the associated register.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.config_tuning_word(dds1.tuning_word(50.0))
'LD1:W03,33,33,33,33:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(10.0))
'LD1:W03,0A,3D,70,A4:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(5.0))
'LD1:W03,05,1E,B8,52:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(1.0))
'LD1:W03,01,06,24,DD:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(0.1))
'LD1:W03,00,1A,36,E3:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(0.001))
'LD1:W03,00,00,43,1C:HD1:HD2:LD2:'
>>> dds1.config_tuning_word(dds1.tuning_word(0.00001))
'LD1:W03,00,00,00,AC:HD1:HD2:LD2:'
modulus_parameters(fout: float) Tuple[int, int, int][source]

Calculate the DDS modulus parameters for a specified output frequency.

Parameters:

fout (float) – The desired output frequency in MHz.

Returns:

A tuple containing the modulus parameters: (A, B, X) or None if the specified output frequency cannot be produced.

Raises:

ModulusConstraintException If the specified frequency cannot be exactly synthesized

Note

Note that if A == 0 then the output frequency can be produced using the more usual accumulator based method (that is, the modulus feature is unnecessary).

See Analog Devices application note AN-953 Direct Digital Synthesis (DDS) with a Programmable Modulus

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.modulus_parameters(25.0)
(3, 5, 429496729)
>>> dds1.modulus_parameters(5.0)
(23, 25, 85899345)
>>> dds1.modulus_parameters(5.01)
(1912, 3125, 86071144)
>>> dds1.modulus_parameters(5.00001)
(280739, 390625, 85899517)
>>> dds1.modulus_parameters(5.00000001)
Traceback (most recent call last):
    ...
ModulusConstraintException
>>> dds1.modulus_parameters(0.0005821)
(3924336, 9765625, 10000)
phase_offset_word(ph_degrees: float) int[source]

Calculate the DDS phase offset word for a specified phase offset.

Parameters:

ph_degrees (float) – The desired phase offset in degrees.

Returns:

An integer containing the 14-bit phase offset word.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> hex(dds1.phase_offset_word(180.0))
'0x2000'
>>> hex(dds1.phase_offset_word(90.0))
'0x1000'
>>> hex(dds1.phase_offset_word(45.0))
'0x800'
>>> hex(dds1.phase_offset_word(1.0))
'0x2d'
>>> hex(dds1.phase_offset_word(0.1))
'0x4'
>>> hex(dds1.phase_offset_word(359))
'0x3fd2'
>>> hex(dds1.phase_offset_word(359.9))
'0x3ffb'
>>> hex(dds1.phase_offset_word(900.0))
'0x2000'
pin_config() str[source]

Initialize controller pin configuration.

Returns:

A string specifying the commands required to initialize the connected controller pins.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds1.pin_config()
'OD1:HD1:OD2:LD2:'
>>> dds2 = ad9913('d3', 'd4', ps0='c5', ps1='c6', ps2='c7', reset='b1')
>>> dds2.pin_config()
'OD3:HD3:OD4:LD4:OB1:LB1:OC5:LC5:OC6:LC6:OC7:LC7:'
power_control(mode: int, subsystem: Subsystem) str[source]

Power down some or all of the DDS circuitry.

Parameters:
  • mode (int) – Specify ad9913.POWER_DOWN or ad9913.POWER_UP.

  • subsystem (ad9913.Subsystem) –

    Specify which DDS functions to power down:

    • Subsystem.DIGITAL (CFR1[6])

    • Subsystem.DAC (CFR1[5])

    • Subsystem.INPUT_CLOCK (CFR1[4])

    • Subsystem.ALL (CFR1[6..4])

Returns:

A string containing the commands required to power down/up the specified DDS functions.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds2 = ad9913('d3', 'd4', ps0='c5', ps1='c6', ps2='c7', reset='b1')
>>> dds1.power_control(ad9913.POWER_DOWN, ad9913.Subsystem.DAC)
'LD1:W00,00,00,00,20:HD1:HD2:LD2:'
>>> dds1.power_control(ad9913.POWER_DOWN, ad9913.Subsystem.DIGITAL)
'LD1:W00,00,00,00,60:HD1:HD2:LD2:'
>>> dds1.power_control(ad9913.POWER_DOWN, ad9913.Subsystem.INPUT_CLOCK)
'LD1:W00,00,00,00,70:HD1:HD2:LD2:'
>>> dds1.power_control(ad9913.POWER_UP, ad9913.Subsystem.ALL)
'LD1:W00,00,00,00,00:HD1:HD2:LD2:'
>>> dds1.power_control(ad9913.POWER_DOWN,ad9913.Subsystem.DAC)
'LD1:W00,00,00,00,20:HD1:HD2:LD2:'
>>> dds1.power_control(ad9913.POWER_UP, ad9913.Subsystem.DAC)
'LD1:W00,00,00,00,00:HD1:HD2:LD2:'
>>> dds2.power_control(ad9913.POWER_UP, ad9913.Subsystem.ALL)
'LD3:W00,00,00,00,00:HD3:HD4:LD4:'
ps_bits(sym: int) int | None[source]

Convert a symbol to profile select pin specification.

>>> dds = ad9913('C5', 'B7', 'C4', ps0='D0', ps1='D1', ps2='D2',
...     board_model='20dB')
>>> hex(dds.ps_bits(1))
'0x1'
>>> hex(dds.ps_bits(7))
'0x7'
>>> dds2 = ad9913('C6', 'B6', 'C4', ps0='D4', ps1='D5', ps2='D6',
...     board_model='27dB-RF')
>>> hex(dds2.ps_bits(1))
'0x10'
>>> hex(dds2.ps_bits(7))
'0x70'
property ps_mask: int | None
property ps_pins: List[int] | None

The controller pins within the controller ps_port to which the PS0, PS1, PS2 device pins are assigned. This will be None if one of more of the pins are either unassigned to the controller or if the pins are assigned across multiple controller ports.

Note that this property is read-only.

property ps_port: str | None

The controller port which the PS0, PS1, PS2 device pins are assigned. This will be None if one of more of the pins are either unassigned to the controller or if the pins are assigned across multiple controller ports.

Note that this property is read-only.

set_active_profile(prof: int) None[source]

Set the active profile.

Parameters:

prof (integer) – The number of the DDS profile to update. (valid profiles are 0..7)

set_aux_accumulator_enable(enable: bool) None[source]
>>> dds1 = ad9913('d1', 'd2')
>>> dds1.set_aux_accumulator_enable(True)
>>> dds1.config_cfr1()
'LD1:W00,00,00,08,00:HD1:HD2:LD2:'
>>> dds1.set_aux_accumulator_enable(False)
>>> dds1.config_cfr1()
'LD1:W00,00,00,00,00:HD1:HD2:LD2:'
set_profile_control(ctl: ProfileControl) None[source]

Set direct switch profile control method.

Parameters:

ctl (ad9913.ProfileControl) – Whether profile is controlled by pins or internally (via SPI)

set_sweep_dwell(dwell_active: bool = False) None[source]

Set the sweep dwell state.

Parameters:

dwell_active (bool) – If set to False dwell is de-activated and the device reverts to it’s initial state after the completion of a sweep. If set to True, the dwell is active and the device will hold at the final state after completion of the sweep.

set_sweep_mode(sweep_mode: SweepRampType) None[source]

Set the sweep ramp type.

Parameters:

sweep_mode (ad9913.SweepRampType) –

The sweep ramp type to configure. This will be one of:

  • SweepRampType.SWEEP_OFF

  • SweepRampType.RAMP_UP

  • SweepRampType.RAMP_DOWN

  • SweepRampType.RAMP_BIDIR

>>> dds1 = ad9913('d1', 'd2')
>>> dds1.set_sweep_mode(ad9913.SweepRampType.RAMP_UP)
>>> dds1.config_cfr1()
'LD1:W00,00,10,00,00:HD1:HD2:LD2:'
set_sweep_trigger_source(trigger_source: SweepTriggerSource) None[source]

Set the sweep trigger source.

Parameters:

trigger_source (ad9913.SweepTriggerSource) – Set the device to trigger sweep using either the profile pins or the CFR1[22:20] register bits.

>>> dds1 = ad9913('d1', 'd2')
>>> dds1.set_sweep_trigger_source(ad9913.SweepTriggerSource.PROFILE_PINS)
>>> dds1.config_cfr1()
'LD1:W00,00,00,00,00:HD1:HD2:LD2:'
>>> dds1.set_sweep_trigger_source(ad9913.SweepTriggerSource.REGISTER)
>>> dds1.config_cfr1()
'LD1:W00,08,00,00,00:HD1:HD2:LD2:'
set_sweep_trigger_type(trigger_type: SweepTriggerType) None[source]

Set the sweep trigger type.

Parameters:

trigger_type (ad9913.SweepTriggerType) –

set_sweep_type(sweep_type: SweepType) None[source]

Set the sweep type.

Parameters:

sweep_type (ad9913.SweepType) –

The sweep type to configure. This will be one of:

  • SweepType.FREQUENCY

  • SweepType.PHASE

tuning_word(fout: float) int[source]

Calculate the DDS tuning word for a specified output frequency.

Parameters:

fout (float) – The desired output frequency in MHz.

Returns:

An integer containing the 32-bit tuning word.

>>> dds1 = ad9913('d1', 'd2', sysclk=250.0)
>>> dds2 = ad9913('d1', 'd2', sysclk=200.0)
>>> hex(dds1.tuning_word(50.0))
'0x33333333'
>>> hex(dds2.tuning_word(50.0))
'0x40000000'
>>> hex(dds1.tuning_word(10.0))
'0xa3d70a4'
>>> hex(dds1.tuning_word(5.0))
'0x51eb852'
>>> hex(dds1.tuning_word(1.0))
'0x10624dd'
>>> hex(dds1.tuning_word(0.00001))
'0xac'
>>> hex(dds1.tuning_word(0.0005821))
'0x2710'
>>> hex(dds1.tuning_word(0.00058211))
'0x2711'