Analogue-to-digital converter¶
This notebook demonstrates how to model the digital behaviour of a realistic arbitrary waveform generator (AWG) in the qruise-toolset
. To simulate this, we'll create a signal chain that includes the AWG acting as the source and an analogue-to-digital converter (ADC) to transform the AWG's analogue output into a digital signal.
The tutorial consists of the following:
- Motivation for using an ADC
- Defining parameters
- Constructing the signal chain
- Visualising the converted signal
1. Motivation for using an ADC¶
We're surrounded by digital technology: mobile phones, computers, audio recorders, and many other devices that use binary representations of information originally derived from analogue signals. At the heart of this technology is the analogue-to-digital converter (ADC).
Think of a digital image: a photograph of a continuous scene is broken down into a grid of pixels. The smaller the pixels (i.e., the higher the resolution), the more detailed and accurate the image is compared to the true scene. Similarly, an ADC approximates the amplitude of a continuous signal using discrete values.
Every ADC is characterised by its number of bits, which determines the resolution of the quantisation process. For instance, if an ADC has 4 bits and an operational range from $-2.5 \text{ V}$ to $2.5 \text{ V}$, it can represent 16 discrete, evenly spaced voltage levels with an increment of $0.333 \text{ V}$, i.e.,
$$ \{-2.5 \text{ V}, -2.167\text{ V}, -1.833\text{ V}, ..., 1.833\text{ V}, 2.167\text{ V}, 2.5\text{ V} \} . $$
A higher number of bits corresponds to a closer representation of the digital signal to the original analogue one. In practice, ADC devices have an effective number of bits due to noise and quantisation errors, which is always smaller than the number of bits.
Let's now consider the arbitrary waveform generator (AWG) we want to use to generate a Gaussian pulse. In reality, the AWG cannot produce a perfect analogue Gaussian waveform; instead, it generates a digital approximation, with its accuracy determined by the number of bits. To model a realistic representation of the AWG output, an ADC can be included as a component in the signal chain.
Tip: Make sure that your environment is correctly set to handle float64
precision by setting JAX_ENABLE_X64=True
or add
import jax
jax.config.update("jax_enable_x64", True)
to your scripts' preamble.
2. Defining parameters¶
We start by defining the time parameters for our pulse. These include the start and end times of the pulse ($t_0$ and $t_\text{final}$, respectively). We then define a time span consisting of $N$ evenly spaced points between $t_0$ and $t_\text{final}$.
import jax.numpy as jnp
t0 = 0.0 # start time of pulse (s)
t_final = 20e-9 # end (final) time of pulse (s)
N = int(1e3) # number of time points
t_span = jnp.linspace(t0, t_final, N) # time span array
We also need to define the parameters of the Gaussian function, $G(t)$, which in the qruise-toolset
takes the generic form:
$$ G(t; a, \sigma, \mu) = \frac{a}{\sigma\sqrt{2\pi}} \mathrm{exp}\left[-\frac{(t - \mu)^2}{2\sigma^2}\right].$$
This is characterised by three parameters:
$a$, a scalar that adjusts the amplitude of the pulse
$\sigma$, the pulse variance
$\mu$, the time at which it reaches its maximum amplitude
For this example, we'll set $a = \sigma \sqrt{2\pi}$ and $\mu=\frac{t_\text{final}}{2}$, so that the Gaussian function reaches a peak value of $1.0$ in the centre of the simulation time window. We arbitrarily define $\sigma = \frac{1}{4} t_\text{final}$.
sigma = 0.25 * t_final
amplitude = sigma * jnp.sqrt(2.0 * jnp.pi)
mean = t_final / 2.0
For the ADC, we only need to define the number of bits (nob
) and the operational voltage range (min_range
to max_range
).
nob = 8 # number of bits
min_range = -2.5 # V_min (V)
max_range = 2.5 # V_max (V)
Note: There are two additional parameters, alpha
and epsilon
, that determine the degree of rounding used in the ADC conversion. These have default values, so only need to be defined if you want to alter the degree of rounding. You can read more about this in the API reference for the ADC class.
3. Constructing the signal chain¶
As mentioned above, the signal chain will consist of two components: the source signal (our Gaussian AWG) and the analogue-to-digital component. We start by storing the parameters of the two components in dictionaries (gauss_params
and adc_params
), and then we define instances of the Gaussian()
and ADC()
component classes.
from qruise.toolset import Gaussian, ADC
# store Gaussian parameters in dictionary
gauss_params = {
"amplitude": (amplitude, True),
"mean": (mean, True),
"sigma": (sigma, True),
}
# store ADC parameters in dictionary
adc_params = {
"nob": (nob, True),
"min_range": (min_range, True),
"max_range": (max_range, True),
}
gauss = Gaussian() # define instance of Gaussian class
adc = ADC() # define instance of ADC class
Note: The argument True
in the gauss_params
and adc_params
dictionaries indicates that the parameter is modifiable (e.g., for optimisation), but this is not relevant for this tutorial.
We then create a Signal()
chain and add our Gaussian and ADC instances to it as components named "AWG" and "ADC", respectively.
from qruise.toolset import Signal
# create signal chain named "ADCSimulation"
signal = Signal("ADCSimulation")
# add Gaussian and ADC as components named "AWG" and "ADC"
signal.add_from(["AWG", "ADC"], [gauss(), adc()], [gauss_params, adc_params])
Now we need to evaluate the signal chain over the time span we defined earlier (t_span
).
# extract signal chain function and parameter dictionary
signal_chain, signal_params = signal.function()
# evaluate signal over defined time span
adc_result = signal_chain(t_span, signal_params)
4. Visualising the converted signal¶
Let's plot the result to see if it worked. For this we'll use the PlotUtil
module from the qruise-toolset
.
from qruise.toolset import PlotUtil
canvas = PlotUtil(x_axis_label="t [s]", y_axis_label="Amplitude [a.u.]", notebook=True)
canvas.plot(t_span, adc_result, labels=["ADC Gaussian"])
canvas.show_canvas()
Great! You can see the Gaussian pulse now has a step-like profile, indicating that our analogue-to-digital conversion was successful.