提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
学习通过python绘制klayout
本文仅做摘抄,具体参考Nazca官网
一、基本语句
1.创建层
with nd.Cell(name='Cell_A') as cella:# 创建一个版图 放置一个版图
cellb.put() #可以将创建好的层放置新的层 但原来的cell不会改变
2.put 语句
调用 **put**
def put(self, *args, flip=False, flop=False, array=None, scale=1.0,
drc=None, **kwargs):
args:引脚名称 最多为5个
x,y,a:放置位置和旋转角度
flip:垂直翻转
float:水平翻转
scale:缩放
put():
put(0):放置在层的默认位置,一般为(0,0)
put():放置在上一个结构后面
put(x,y):放置在(x,y)位置
3. 引脚
C.default_pins('bert', 'ernie'):每个结构都有起始引脚和终止引脚,
使用put()就是在终止引脚的后面接上初始引脚,改变初始引脚和终止引脚的默认名
默认为 :a0,b0
#C.autobbox = True :使每个引脚可视化
e1 = nd.strt(length=5).put()
e2 = nd.bend(angle=45).put()
nd.Pin(name='bert', pin=e1.pin['a0']).put() :定义初始引脚为结构一的初始引脚
nd.Pin(name='ernie', pin=e2.pin['b0']).put() :定义终止引脚为结构二的终止引脚,这样方便put()添加结构在结构二的后面而不是结构一的后面
不更改引脚位置,put()的默认位置不会改变
nd.put_stub() :使初始引脚可视化
4.截面
nd.add_xsection(name='XS1'):创建一个名为 XS1 的截面:在绘制结构的时候会采用这个XS1的界面绘制
xs1.width = 3.0 设置XS1的基础宽度
xs1.radius= 50.0 设置XS1的基础半径
如果这个界面中有三个层,则会在这个三个层中均绘制改结构
例子:
nd.add_layer(name='L1', layer=1)
nd.add_layer(name='L2', layer=(2, 0))
nd.add_layer(name='L3', layer=(3, 10))
创建层
nd.add_layer2xsection(xsection='XS1', layer='L1')
nd.add_layer2xsection(xsection='XS1', layer='L1', leftedge=(3.0, 1.0), rightedge=(1.0, 1.0))
nd.add_layer2xsection(xsection='XS1', layer='L1', leftedge=(-1.0, -1.0), rightedge=(-3.0, -1.0))
在一个层上添加截面
nd.add_layer2xsection(xsection='XS1', layer='L1')
nd.add_layer2xsection(xsection='XS1', layer='L3', growx=5.0)
将三个层接入截面XS1:growx为在 x 方向上对称增长 5.0 单位
nd.add_layer2xsection(xsection='XS1', layer='L2', leftedge=(0.5, 2), rightedge=(-0.5, -2))
leftedge 边界延长值0.5*width+2 um right同理 所有的距离计算都是从0开始的向左右两边而不是从边界
5. Interconnects.Interconnect
interconnects.Interconnect 是一个强大的工具,允许设计者通过定义截面、设置互连属性和创建各种布局元素(如直线、弯曲和渐变)来实现复杂的光学设计。
def __init__(
self,
radius=None, 默认半径,单位为微米
width=None, 默认波导宽度,单位为微米
angle=90, 弯曲的默认角度(默认=90度)
xs=None, 波导截面(默认='nazca')
layer=None, 在其中绘制互连的图层。优先使用 xs 而不是图层来存储额外的信息,如偏移、折射率等。(默认=None)
adapt_width=False, 将互连宽度适应连接的引脚(默认=False)
adapt_xs=False, 将互连宽度适应连接的引脚(默认=False)
instantiate=False, 实例化互连单元(默认=False)
pinstyle=None, 互连引脚的可视化样式。默认=None,使用 cfg 中的默认 pinstyle
offset=None, 如果不为 None,则用提供的偏移值或函数覆盖 xsection 的直线-弯曲偏移(默认=None)。
varname=None,
doc='',
PCB=False, 则将弯曲的最大角度设置为 45 度(默认=False)。
modes=None,
):
连接到其他互连
ic.connect(width1=3.0, length=30, ic=other_ic).put()
示例
import nazca as nd
# 创建截面
nd.add_xsection(name='XS1', width=3.0, radius=50.0)
# 创建互连对象
ic = nd.interconnects.Interconnect(xs='XS1')
# 创建布局
ic.strt(length=10).put(0) # 添加直线
ic.bend(angle=45).put() # 添加弯曲
ic.taper(length=15, width2=2.0).put() # 添加渐变
# 导出 GDS
nd.export_gds()
6.Free form parametric curves 平滑曲线连接
import numpy as np
import nazca as nd
# create functions x, y, w for the viper-based mask_element:定义x,y,w
def x(t, radius, angle, **kwargs):
"""X as function of t and free parameters."""
return radius * np.cos(t * angle * np.pi / 180) 返回函数可自定义 通过自定义函数去设计两段波导的平滑链接
def y(t, radius, angle, **kwargs):
"""Y as function of t and free parameters."""
return radius * np.sin(t * angle * np.pi / 180)
def w(t, width1=None, width2=None, **kwargs):
"""Width as function of t, width1 and width2 and free parameters."""
return width1 + (width2 - width1) * t
# create the new parametric function using the template Tp_viper():定义bend初始参数半径和角度
params = {'radius': 100, 'angle':90} # include defaults for *all* free parameters used in the functions x, y and w.
tapered_bend = nd.Tp_viper(x, y, w, xs='Deep', **params):定义弯曲函数名
tapered_bend(angle=-300, radius=60, width1=20, width2=0.5, N=2000).put():绘制从当前角度转300度,宽度从20 um到0.5 um
点数为2000的平滑曲线连接
7.绘制text
# example created by Bright Photonics
import nazca as nd
message = 'Nazca-Design'
nd.text(text=message, height=30, layer=1, align='cc').put(0, 0)
f = nd.Font('cousine')
f.text(text=message, height=20, layer=2, align='cc').put(0, 40)
nd.export_gds()
二、基本结构
1. taper
nd.taper(length=10, width1=1, width2=5).put(0)
#放置一个taper:它的长度为 10 单位,起始宽度为 1 单位,终止宽度为 5 单位。
def Tp_taper(
length=100, #长度
width1=2, #起始宽度
width2=3, #终止宽度
shift=0, #旋转
xs=None, #放置的x的位置
layer=None, #层
name=None, #名字
modes=None, #包含网表模式标签的整数列表
)
2.bend
nd.bend(angle=90).put(0)
#放置一个90°的弯曲
def Tp_arc(
radius=10, 半径
width=1.0, 波导宽度
angle=90, 弧的角度
xs=None, 放置的X的位置
layer=None, 层
offset=None,偏移量
name=None, 名字
modes=None,
)
3.strt
nd.strt(10).put(0)
#放置一个长度为10的直线结构
def Tp_straight(
length=10, 长度
width=1.0, 宽度
xs=None, X位置
layer=None, 层
edge1=None, 边缘1的形状函数,NONE为直线
edge2=None, 边缘2的形状函数
edgepoints=50,边缘的点数
name=None, 名字
modes=None,
)
4.ptaper
ptaper: 放置一个边界为曲线的taper
def Tp_ptaper(
length=100, 长度
width1=1.0, 初始宽度
width2=3.0, 终止宽度
xs=None,
layer=None,
name=None,
modes=None,
)
5.Sbend
sinebend: S_bend
def Tp_sinecurve(
width=1.0, 波导宽度
distance=200, 整体长度
offset=20, y_span=20 um
xs=None,
layer=None,
name=None,
)
6.euler:欧拉弯曲
def Tp_euler(
width1=1.0, 起始宽度
width2=1.0, 终止宽度
radius=50, 半径
angle=90, 角度
xs=None,
layer=None,
name='euler',
modes=None,
)
7.创建多边形
bb_body = [(5.0, -5.0), (5.0, -1.0), (0.0, -1.0), (0.0, 1.0),
(5.0, 1.0), (5.0, 5.0), (35.0, 5.0), (35.0, 3.5),
(40.0, 3.5), (40.0, 1.5), (35.0, 1.5), (35.0, -1.5),
(40.0, -1.5), (40.0, -3.5), (35.0, -3.5), (35.0, -5.0)] 设置点
nd.Polygon(points=bb_body, layer='layer3').put(0)
nd.Pin('a0').put(0, 0, 180) 设置引脚
nd.Pin('b0').put(40, 2.5, 0)
nd.Pin('b1').put(40, -2.5, 0)
nd.put_stub()
基本设置
矩形: 使用四个点定义矩形的顶点。
rectangle = nd.Polygon(layer=1, points=[(x1, y1), (x2, y1), (x2, y2), (x1, y2)])
三角形: 通过三个点定义三角形。
triangle = nd.Polygon(layer=1, points=[(x1, y1), (x2, y2), (x3, y3)])
圆形: 使用geom.circle函数创建圆形。
circle = nd.Polygon(layer=1, points=geom.circle(radius=radius))
多边形: 可以定义任意形状的多边形,通过指定多个点。
polygon = nd.Polygon(layer=1, points=[(x1, y1), (x2, y2), (x3, y3), ...])
环形: 使用geom.ring函数创建环形,指定内外半径。
ring = nd.Polygon(layer=1, points=geom.ring(radius=outer_radius, inner_radius=inner_radius))
建立基础结构 np.geometries
import nazca as nd
with nd.Cell('hole') as hole:
hole_shape = nd.geometries.circle(radius=0.05, N=8)
nd.Polygon(points=hole_shape).put(0)
hole.put(array=[20, [0.25, 0], 30, [0, 0.30]])
hole.put(5, -5, array=[40, [0.20, 0.10], 50, [0.10, 0.30]])
nd.export_gds()
三.常用函数或结构
1.合并和删除多边形
def merge_polygons(cell, layers):
"""Merge all polygons per layer after flattening <cell>.
Cell <cell> itself will not be affected. Note that a merged polygons may
still consist of multiple polygons (islands).
Args:
cell (Cell): cell to process
layers (list of str): names of layers to merge polygons in
Returns:
dict: {layer_name: merged_polygon}
"""
pgons = defaultdict(list)
for params in nd.cell_iter(cell, flat=True):
for pgon, xy, bbox in params.iters['polygon']:
for lay in layers:
if pgon.layer == lay:
pgons[lay].append(xy)
for lay in layers:
pgons[lay] = nd.clipper.merge_polygons(pgons[lay])
return pgons
def remove_polygons(cell, layers):
"""Remove all polygons in <layers> from <cell>.
Args:
cell (Cell): cell to process
layers (list of str): names of layers to delete polygons from
Returns:
None
"""
for params in nd.cell_iter(cell):
if params.cell_start:
pgons = []
for pgon in params.cell.polygons:
if pgon[1].layer not in layers:
pgons.append(pgon)
params.cell.polygons = pgons
return None