mirror of https://github.com/m-labs/artiq.git
phaser: document, elaborate comments, some fixes
This commit is contained in:
parent
e505dfed5b
commit
c3728678d6
|
@ -1,6 +1,6 @@
|
||||||
from artiq.language.core import kernel, delay_mu, delay
|
from artiq.language.core import kernel, delay_mu, delay
|
||||||
from artiq.coredevice.rtio import rtio_output, rtio_input_data
|
from artiq.coredevice.rtio import rtio_output, rtio_input_data
|
||||||
from artiq.language.units import us, ns
|
from artiq.language.units import us, ns, MHz
|
||||||
from artiq.language.types import TInt32
|
from artiq.language.types import TInt32
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,36 +57,56 @@ class Phaser:
|
||||||
Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion,
|
Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion,
|
||||||
quadrature modulation compensation and interpolation features.
|
quadrature modulation compensation and interpolation features.
|
||||||
|
|
||||||
The coredevice produces 2 IQ data streams with 25 MS/s 14 bit. Each
|
The coredevice produces 2 IQ data streams with 25 MS/s and 14 bit per
|
||||||
data stream supports 5 independent numerically controlled oscillators (NCOs)
|
quadrature. Each data stream supports 5 independent numerically controlled
|
||||||
added together for each channel. Together with a data clock, framing
|
IQ oscillators (NCOs, DDSs with 32 bit frequency, 16 bit phase, 15 bit
|
||||||
marker, a checksum and metadata for register access the data is sent in
|
amplitude, and phase accumulator clear functionality) added together.
|
||||||
groups of 8 samples over 1.5 Gb/s FastLink via a single EEM connector.
|
See :class:`PhaserChannel` and :class:`PhaserOscillator`.
|
||||||
|
|
||||||
On Phaser the data streams are buffered and interpolated from 25 MS/s to 500
|
Together with a data clock, framing marker, a checksum and metadata for
|
||||||
MS/s 16 bit followed by a 500 MS/s digital upconverter in the FPGA.
|
register access the streams are sent in groups of 8 samples over 1.5 Gb/s
|
||||||
|
FastLink via a single EEM connector from coredevice to Phaser.
|
||||||
|
|
||||||
|
On Phaser in the FPGA the data streams are buffered and interpolated
|
||||||
|
from 25 MS/s to 500 MS/s 16 bit followed by a 500 MS/s digital upconverter
|
||||||
|
with adjustable frequency and phase. The interpolation passband is 20 MHz
|
||||||
|
wide, passband ripple is less than 1e-3 amplitude, stopband attenuation
|
||||||
|
is better than 75 dB at offsets > 15 MHz and better than 90 dB at offsets
|
||||||
|
> 30 MHz.
|
||||||
|
|
||||||
The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel
|
The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel
|
||||||
LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC.
|
LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. On the
|
||||||
|
DAC 2x interpolation, sinx/x compensation, quadrature modulator compensation,
|
||||||
|
fine and coarse mixing as well as group delay capabilities are available.
|
||||||
|
|
||||||
The four analog DAC outputs are passed through anti-aliasing filters and In
|
The latency/group delay from the RTIO events setting
|
||||||
the baseband variant, the even channels feed 31.5 dB range and are
|
:class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all they
|
||||||
available on the front panel. The odd outputs are available on MMCX
|
way to the DAC outputs is deterministic. This enables deterministic
|
||||||
connectors on board.
|
absolute phase with respect to other RTIO input and output events.
|
||||||
|
|
||||||
|
The four analog DAC outputs are passed through anti-aliasing filters.
|
||||||
|
|
||||||
|
In the baseband variant, the even/in-phase DAC channels feed 31.5 dB range
|
||||||
|
attenuators and are available on the front panel. The odd outputs are
|
||||||
|
available at MMCX connectors on board.
|
||||||
|
|
||||||
In the upconverter variant, each of the two IQ (in-phase and quadrature)
|
In the upconverter variant, each of the two IQ (in-phase and quadrature)
|
||||||
output pairs feeds a one quadrature upconverter with integrated PLL/VCO.
|
output pairs feeds a one quadrature upconverter with integrated PLL/VCO.
|
||||||
The output from the upconverter passes through the step attenuator and is
|
This analog quadrature upconverter supports offset tuning for carrier and
|
||||||
available at the front panel.
|
sideband suppression. The output from the upconverter passes through the
|
||||||
|
31.5 dB range step attenuator and is available at the front panel.
|
||||||
|
|
||||||
The DAC, the TRF upconverters and the two attenuators are configured
|
The DAC, the analog quadrature upconverters and the two attenuators are
|
||||||
through a shared SPI bus that is accessed and controlled via FPGA
|
configured through a shared SPI bus that is accessed and controlled via FPGA
|
||||||
registers.
|
registers.
|
||||||
|
|
||||||
:param channel: Base RTIO channel number
|
:param channel: Base RTIO channel number
|
||||||
:param core_device: Core device name (default: "core")
|
:param core_device: Core device name (default: "core")
|
||||||
:param miso_delay: Fastlink MISO signal delay to account for cable
|
:param miso_delay: Fastlink MISO signal delay to account for cable
|
||||||
and buffer round trip. This might be automated later.
|
and buffer round trip. This might be automated later.
|
||||||
|
|
||||||
|
:attr:`channel`: List of two :class:`PhaserChannel` to access oscillators
|
||||||
|
and digital upconverter.
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"}
|
kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"}
|
||||||
|
|
||||||
|
@ -176,7 +196,7 @@ class Phaser:
|
||||||
:param duty: Duty cycle (0. to 1.)
|
:param duty: Duty cycle (0. to 1.)
|
||||||
"""
|
"""
|
||||||
pwm = int32(round(duty*255.))
|
pwm = int32(round(duty*255.))
|
||||||
if pwm < 0 or pwm > 0xff:
|
if pwm < 0 or pwm > 255:
|
||||||
raise ValueError("invalid duty cycle")
|
raise ValueError("invalid duty cycle")
|
||||||
self.set_fan_mu(pwm)
|
self.set_fan_mu(pwm)
|
||||||
|
|
||||||
|
@ -191,8 +211,8 @@ class Phaser:
|
||||||
:param dac_resetb: Active low DAC reset pin
|
:param dac_resetb: Active low DAC reset pin
|
||||||
:param dac_sleep: DAC sleep pin
|
:param dac_sleep: DAC sleep pin
|
||||||
:param dac_txena: Enable DAC transmission pin
|
:param dac_txena: Enable DAC transmission pin
|
||||||
:param trf0_ps: TRF0 upconverter power save
|
:param trf0_ps: Quadrature upconverter 0 power save
|
||||||
:param trf1_ps: TRF1 upconverter power save
|
:param trf1_ps: Quadrature upconverter 1 power save
|
||||||
:param att0_rstn: Active low attenuator 0 reset
|
:param att0_rstn: Active low attenuator 0 reset
|
||||||
:param att1_rstn: Active low attenuator 1 reset
|
:param att1_rstn: Active low attenuator 1 reset
|
||||||
"""
|
"""
|
||||||
|
@ -209,8 +229,8 @@ class Phaser:
|
||||||
Bit flags are:
|
Bit flags are:
|
||||||
|
|
||||||
* `PHASER_STA_DAC_ALARM`: DAC alarm pin
|
* `PHASER_STA_DAC_ALARM`: DAC alarm pin
|
||||||
* `PHASER_STA_TRF0_LD`: TRF0 lock detect pin
|
* `PHASER_STA_TRF0_LD`: Quadrature upconverter 0 lock detect
|
||||||
* `PHASER_STA_TRF1_LD`: TRF1 lock detect pin
|
* `PHASER_STA_TRF1_LD`: Quadrature upconverter 1 lock detect
|
||||||
* `PHASER_STA_TERM0`: ADC channel 0 termination indicator
|
* `PHASER_STA_TERM0`: ADC channel 0 termination indicator
|
||||||
* `PHASER_STA_TERM1`: ADC channel 1 termination indicator
|
* `PHASER_STA_TERM1`: ADC channel 1 termination indicator
|
||||||
* `PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers can be
|
* `PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers can be
|
||||||
|
@ -255,7 +275,7 @@ class Phaser:
|
||||||
"""
|
"""
|
||||||
if div < 2 or div > 257:
|
if div < 2 or div > 257:
|
||||||
raise ValueError("invalid divider")
|
raise ValueError("invalid divider")
|
||||||
if length < 0 or length > 8:
|
if length < 1 or length > 8:
|
||||||
raise ValueError("invalid length")
|
raise ValueError("invalid length")
|
||||||
self.write8(PHASER_ADDR_SPI_SEL, select)
|
self.write8(PHASER_ADDR_SPI_SEL, select)
|
||||||
self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5))
|
self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5))
|
||||||
|
@ -298,8 +318,8 @@ class Phaser:
|
||||||
"""Read from a DAC register.
|
"""Read from a DAC register.
|
||||||
|
|
||||||
:param addr: Register address to read from
|
:param addr: Register address to read from
|
||||||
:param div: SPI clock divider. Needs to be at least 250 to read the
|
:param div: SPI clock divider. Needs to be at least 250 (1 µs SPI
|
||||||
temperature register.
|
clock) to read the temperature register.
|
||||||
"""
|
"""
|
||||||
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
|
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
|
||||||
self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0)
|
self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0)
|
||||||
|
@ -308,7 +328,7 @@ class Phaser:
|
||||||
self.spi_write(0)
|
self.spi_write(0)
|
||||||
delay_mu(t_xfer)
|
delay_mu(t_xfer)
|
||||||
data = self.spi_read() << 8
|
data = self.spi_read() << 8
|
||||||
delay(10*us) # slack
|
delay(20*us) # slack
|
||||||
self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1)
|
self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1)
|
||||||
self.spi_write(0)
|
self.spi_write(0)
|
||||||
delay_mu(t_xfer)
|
delay_mu(t_xfer)
|
||||||
|
@ -317,12 +337,27 @@ class Phaser:
|
||||||
|
|
||||||
|
|
||||||
class PhaserChannel:
|
class PhaserChannel:
|
||||||
"""Phaser channel IQ pair"""
|
"""Phaser channel IQ pair.
|
||||||
kernel_invariants = {"channel", "phaser"}
|
|
||||||
|
|
||||||
def __init__(self, phaser, channel):
|
:attr:`oscillator`: List of five :class:`PhaserOscillator`.
|
||||||
|
|
||||||
|
.. note:: The amplitude sum of the oscillators must be less than one to
|
||||||
|
avoid clipping or overflow. If any of the DDS or DUC frequencies are
|
||||||
|
non-zero, it is not sufficient to ensure that the sum in each
|
||||||
|
quadrature is within range.
|
||||||
|
|
||||||
|
.. note:: The interpolation filter on Phaser has an intrinsic sinc-like
|
||||||
|
overshoot in its step response. That overshoot is an direct consequence
|
||||||
|
of its near-brick-wall frequency response. For large and wide-band
|
||||||
|
changes in oscillator parameters, the overshoot can lead to clipping
|
||||||
|
or overflow after the interpolation. Either band-limit any changes
|
||||||
|
in the oscillator parameters or back off the amplitude sufficiently.
|
||||||
|
"""
|
||||||
|
kernel_invariants = {"index", "phaser"}
|
||||||
|
|
||||||
|
def __init__(self, phaser, index):
|
||||||
self.phaser = phaser
|
self.phaser = phaser
|
||||||
self.channel = channel
|
self.index = index
|
||||||
self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)]
|
self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)]
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -334,7 +369,7 @@ class PhaserChannel:
|
||||||
|
|
||||||
:return: DAC data as 32 bit IQ. I in the 16 LSB, Q in the 16 MSB
|
:return: DAC data as 32 bit IQ. I in the 16 LSB, Q in the 16 MSB
|
||||||
"""
|
"""
|
||||||
return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.channel << 4))
|
return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4))
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_dac_test(self, data: TInt32):
|
def set_dac_test(self, data: TInt32):
|
||||||
|
@ -342,20 +377,18 @@ class PhaserChannel:
|
||||||
|
|
||||||
:param data: 32 bit IQ test data, I in the 16 LSB, Q in the 16 MSB
|
:param data: 32 bit IQ test data, I in the 16 LSB, Q in the 16 MSB
|
||||||
"""
|
"""
|
||||||
self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.channel << 4), data)
|
self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_duc_cfg(self, clr=0, clr_once=0, select=0):
|
def set_duc_cfg(self, clr=0, clr_once=0, select=0):
|
||||||
"""Set the digital upconverter and interpolator configuration.
|
"""Set the digital upconverter and interpolator configuration.
|
||||||
|
|
||||||
:param clr: Keep the phase accumulator cleared
|
:param clr: Keep the phase accumulator cleared (persistent)
|
||||||
:param clr_once: Clear the phase accumulator for one cycle
|
:param clr_once: Clear the phase accumulator for one cycle
|
||||||
:param select: Select the data to send to the DAC (0: DUC data, 1: test
|
:param select: Select the data to send to the DAC (0: DUC data, 1: test
|
||||||
data)
|
data, other values: reserved)
|
||||||
"""
|
"""
|
||||||
if select < 0 or select > 3:
|
self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.index << 4),
|
||||||
raise ValueError("invalid data select")
|
|
||||||
self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.channel << 4),
|
|
||||||
((clr & 1) << 0) | ((clr_once & 1) << 1) |
|
((clr & 1) << 0) | ((clr_once & 1) << 1) |
|
||||||
((select & 3) << 2))
|
((select & 3) << 2))
|
||||||
|
|
||||||
|
@ -363,26 +396,27 @@ class PhaserChannel:
|
||||||
def set_duc_frequency_mu(self, ftw):
|
def set_duc_frequency_mu(self, ftw):
|
||||||
"""Set the DUC frequency.
|
"""Set the DUC frequency.
|
||||||
|
|
||||||
:param ftw: DUC frequency tuning word
|
:param ftw: DUC frequency tuning word (32 bit)
|
||||||
"""
|
"""
|
||||||
self.phaser.write32(PHASER_ADDR_DUC0_F + (self.channel << 4), ftw)
|
self.phaser.write32(PHASER_ADDR_DUC0_F + (self.index << 4), ftw)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_duc_frequency(self, frequency):
|
def set_duc_frequency(self, frequency):
|
||||||
"""Set the DUC frequency.
|
"""Set the DUC frequency.
|
||||||
|
|
||||||
:param frequency: DUC frequency in Hz
|
:param frequency: DUC frequency in Hz (passband from -200 MHz to
|
||||||
|
200 MHz, wrapping around at +- 250 MHz)
|
||||||
"""
|
"""
|
||||||
ftw = int32(round(frequency*((1 << 32)/500e6)))
|
ftw = int32(round(frequency*((1 << 32)/(500*MHz))))
|
||||||
self.set_duc_frequency_mu(ftw)
|
self.set_duc_frequency_mu(ftw)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_duc_phase_mu(self, pow):
|
def set_duc_phase_mu(self, pow):
|
||||||
"""Set the DUC phase offset
|
"""Set the DUC phase offset
|
||||||
|
|
||||||
:param pow: DUC phase offset word
|
:param pow: DUC phase offset word (16 bit)
|
||||||
"""
|
"""
|
||||||
addr = PHASER_ADDR_DUC0_P + (self.channel << 4)
|
addr = PHASER_ADDR_DUC0_P + (self.index << 4)
|
||||||
self.phaser.write8(addr, pow >> 8)
|
self.phaser.write8(addr, pow >> 8)
|
||||||
self.phaser.write8(addr + 1, pow)
|
self.phaser.write8(addr + 1, pow)
|
||||||
|
|
||||||
|
@ -403,7 +437,7 @@ class PhaserChannel:
|
||||||
"""
|
"""
|
||||||
div = 34 # 30 ns min period
|
div = 34 # 30 ns min period
|
||||||
t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns)
|
t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns)
|
||||||
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div,
|
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div,
|
||||||
end=1)
|
end=1)
|
||||||
self.phaser.spi_write(data)
|
self.phaser.spi_write(data)
|
||||||
delay_mu(t_xfer)
|
delay_mu(t_xfer)
|
||||||
|
@ -425,17 +459,17 @@ class PhaserChannel:
|
||||||
|
|
||||||
The current attenuation value is read without side effects.
|
The current attenuation value is read without side effects.
|
||||||
|
|
||||||
:return: Current attenuation
|
:return: Current attenuation in machine units
|
||||||
"""
|
"""
|
||||||
div = 34
|
div = 34
|
||||||
t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns)
|
t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns)
|
||||||
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div,
|
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div,
|
||||||
end=0)
|
end=0)
|
||||||
self.phaser.spi_write(0)
|
self.phaser.spi_write(0)
|
||||||
delay_mu(t_xfer)
|
delay_mu(t_xfer)
|
||||||
data = self.phaser.spi_read()
|
data = self.phaser.spi_read()
|
||||||
delay(10*us) # slack
|
delay(20*us) # slack
|
||||||
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div,
|
self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div,
|
||||||
end=1)
|
end=1)
|
||||||
self.phaser.spi_write(data)
|
self.phaser.spi_write(data)
|
||||||
delay_mu(t_xfer)
|
delay_mu(t_xfer)
|
||||||
|
@ -443,7 +477,7 @@ class PhaserChannel:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def trf_write(self, data, readback=False):
|
def trf_write(self, data, readback=False):
|
||||||
"""Write 32 bits to a TRF upconverter.
|
"""Write 32 bits to upconverter.
|
||||||
|
|
||||||
:param data: Register data (32 bit) containing encoded address
|
:param data: Register data (32 bit) containing encoded address
|
||||||
:param readback: Whether to return the read back MISO data
|
:param readback: Whether to return the read back MISO data
|
||||||
|
@ -459,7 +493,7 @@ class PhaserChannel:
|
||||||
if i == 0 or i == 3:
|
if i == 0 or i == 3:
|
||||||
if i == 3:
|
if i == 3:
|
||||||
end = 1
|
end = 1
|
||||||
self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.channel,
|
self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.index,
|
||||||
div=div, lsb_first=1, clk_phase=clk_phase,
|
div=div, lsb_first=1, clk_phase=clk_phase,
|
||||||
end=end)
|
end=end)
|
||||||
self.phaser.spi_write(data)
|
self.phaser.spi_write(data)
|
||||||
|
@ -468,34 +502,38 @@ class PhaserChannel:
|
||||||
if readback:
|
if readback:
|
||||||
read >>= 8
|
read >>= 8
|
||||||
read |= self.phaser.spi_read() << 24
|
read |= self.phaser.spi_read() << 24
|
||||||
delay(10*us) # slack
|
delay(20*us) # slack
|
||||||
return read
|
return read
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def trf_read(self, addr, cnt_mux_sel=0) -> TInt32:
|
def trf_read(self, addr, cnt_mux_sel=0) -> TInt32:
|
||||||
"""TRF upconverter register read.
|
"""Quadrature upconverter register read.
|
||||||
|
|
||||||
:param addr: Register address to read (0 to 7)
|
:param addr: Register address to read (0 to 7)
|
||||||
:param cnt_mux_sel: Report VCO counter min frequency
|
:param cnt_mux_sel: Report VCO counter min or max frequency
|
||||||
or max frequency
|
|
||||||
:return: Register data (32 bit)
|
:return: Register data (32 bit)
|
||||||
"""
|
"""
|
||||||
self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27))
|
self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27))
|
||||||
# single clk pulse with ~LE to start readback
|
# single clk pulse with ~LE to start readback
|
||||||
self.phaser.spi_cfg(select=0, div=34, end=1, length=1)
|
self.phaser.spi_cfg(select=0, div=34, end=1, length=1)
|
||||||
self.phaser.spi_write(0)
|
self.phaser.spi_write(0)
|
||||||
delay((1 + 1)*32*4*ns)
|
delay((1 + 1)*34*4*ns)
|
||||||
return self.trf_write(0x00000008, readback=True)
|
return self.trf_write(0x00000008, readback=True)
|
||||||
|
|
||||||
|
|
||||||
class PhaserOscillator:
|
class PhaserOscillator:
|
||||||
"""Phaser IQ channel oscillator"""
|
"""Phaser IQ channel oscillator (NCO/DDS).
|
||||||
|
|
||||||
|
.. note:: Latencies between oscillators within a channel and between
|
||||||
|
oscillator paramters (amplitude and phase/frequency) are deterministic
|
||||||
|
(with respect to the 25 MS/s sample clock) but not matched.
|
||||||
|
"""
|
||||||
kernel_invariants = {"channel", "base_addr"}
|
kernel_invariants = {"channel", "base_addr"}
|
||||||
|
|
||||||
def __init__(self, channel, oscillator):
|
def __init__(self, channel, index):
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.base_addr = ((self.channel.phaser.channel_base + 1 +
|
self.base_addr = ((self.channel.phaser.channel_base + 1 +
|
||||||
self.channel.channel) << 8) | (oscillator << 1)
|
self.channel.index) << 8) | (index << 1)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_frequency_mu(self, ftw):
|
def set_frequency_mu(self, ftw):
|
||||||
|
@ -509,9 +547,10 @@ class PhaserOscillator:
|
||||||
def set_frequency(self, frequency):
|
def set_frequency(self, frequency):
|
||||||
"""Set Phaser MultiDDS frequency.
|
"""Set Phaser MultiDDS frequency.
|
||||||
|
|
||||||
:param frequency: Frequency in Hz
|
:param frequency: Frequency in Hz (passband from -10 MHz to 10 MHz,
|
||||||
|
wrapping around at +- 12.5 MHz)
|
||||||
"""
|
"""
|
||||||
ftw = int32(round(frequency*((1 << 32)/125e6)))
|
ftw = int32(round(frequency*((1 << 32)/(25*MHz))))
|
||||||
self.set_frequency_mu(ftw)
|
self.set_frequency_mu(ftw)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
|
Loading…
Reference in New Issue