Creating a custom circuit
In this tutorial, we’ll demonstrate how to use partial
to construct a circuit from multiple subdevices.
First, imports:
1import qnngds as qg
2from qnngds import Device
3from qnngds.typing import DeviceSpec, LayerSpec
4import phidl.geometry as pg
5from phidl import quickplot as qp
6from functools import partial
Now, we can define a function which takes as an argument either
a device, or a function which returns a device when called.
Note it is also possible to pass a string that matches the name
of a device registered with the currently active PDK. However,
since we haven’t specified a PDK or registered any devices with it,
we will only be able to use a Device instance or DeviceFactory
(callable functions that produce a Device).
1def ntron_meander(
2 ntron_spec: DeviceSpec,
3 meander_spec: DeviceSpec,
4 output_tee_spec: DeviceSpec,
5 layer_spec: LayerSpec,
6) -> Device:
7 """nTron with meander on drain
8
9 Args:
10 ntron_spec (DeviceSpec): device or callable function that returns a device for the nTron
11 meander_spec (DeviceSpec): specification for drain meander/inductor
12 output_tee_spec (DeviceSpec): specification for tee that connects output, nTron drain, and inductor
13 layer_spec (LayerSpec): layer to put circuit on
14
15 Returns:
16 (Device): nTron with connected meander and tee
17 """
18 D = Device("ntron_meander")
19
20 ntron = D << qg.get_device(ntron_spec, layer=qg.get_layer(layer_spec))
21 meander = D << qg.get_device(meander_spec, layer=qg.get_layer(layer_spec))
22 tee = D << qg.get_device(tee_spec, layer=qg.get_layer(layer_spec))
23
24 tee.connect(port=tee.ports[2], destination=ntron.ports["d"])
25 meander.connect(port=meander.ports[1], destination=tee.ports[1])
26
27 D.add_port(name="g", port=ntron.ports["g"])
28 D.add_port(name="s", port=ntron.ports["s"])
29 D.add_port(name="d", port=meander.ports[2])
30 D.add_port(name="o", port=tee.ports[3])
31
32 return D
Now we can generate some devices. Here we use
a few different examples to illustrate how flexible
the DeviceSpec type is. For the nTron and meander,
we will use the default arguments. Note that for meander_spec
we actually pass an instance of a Device whereas for both
tee_spec and ntron_spec, we pass a DeviceFactory.
1ntron_spec = qg.devices.ntron.smooth
2meander_spec = partial(qg.devices.snspd.basic, wire_width=0.3)
3tee_spec = partial(pg.tee, size=(2, 0.3), stub_size=(0.3, 5), taper_type="fillet")
Now we generate and plot the device.
1D = ntron_meander(ntron_spec, meander_spec, tee_spec, layer_spec=(1, 0))
2qp(D)
Reference
1import qnngds as qg
2from qnngds import Device
3from qnngds.typing import DeviceSpec, LayerSpec
4import phidl.geometry as pg
5from phidl import quickplot as qp
6from functools import partial
7
8
9def ntron_meander(
10 ntron_spec: DeviceSpec,
11 meander_spec: DeviceSpec,
12 output_tee_spec: DeviceSpec,
13 layer_spec: LayerSpec,
14) -> Device:
15 """nTron with meander on drain
16
17 Args:
18 ntron_spec (DeviceSpec): device or callable function that returns a device for the nTron
19 meander_spec (DeviceSpec): specification for drain meander/inductor
20 output_tee_spec (DeviceSpec): specification for tee that connects output, nTron drain, and inductor
21 layer_spec (LayerSpec): layer to put circuit on
22
23 Returns:
24 (Device): nTron with connected meander and tee
25 """
26 D = Device("ntron_meander")
27
28 ntron = D << qg.get_device(ntron_spec, layer=qg.get_layer(layer_spec))
29 meander = D << qg.get_device(meander_spec, layer=qg.get_layer(layer_spec))
30 tee = D << qg.get_device(tee_spec, layer=qg.get_layer(layer_spec))
31
32 tee.connect(port=tee.ports[2], destination=ntron.ports["d"])
33 meander.connect(port=meander.ports[1], destination=tee.ports[1])
34
35 D.add_port(name="g", port=ntron.ports["g"])
36 D.add_port(name="s", port=ntron.ports["s"])
37 D.add_port(name="d", port=meander.ports[2])
38 D.add_port(name="o", port=tee.ports[3])
39
40 return D
41
42
43ntron_spec = qg.devices.ntron.smooth
44meander_spec = partial(qg.devices.snspd.basic, wire_width=0.3)
45tee_spec = partial(pg.tee, size=(2, 0.3), stub_size=(0.3, 5), taper_type="fillet")
46
47D = ntron_meander(ntron_spec, meander_spec, tee_spec, layer_spec=(1, 0))
48qp(D)