1.器件库Library结构
器件库的结构与PDK类似,假设我们基于 si_fab 工艺创建一个名为 pteam_library_si_fab 的自定义器件库,其文件目录结构如下所示

luceda_academy/libraris/pteam_library_si_fab
2. ipkiss文件夹结构说明
在 pteam_library_si_fa 文件夹下,有一个名为ipkiss的子目录,包含该库的所有IPKISS相关代码。其下又细分为以下模块:technology、component、all.py
2.1 technology文件夹
该文件夹用于定义工艺信息。因为我们的自定义器件是基于 si_fab PDK 的,因此可以直接继承其工艺定义。通常只需在 technology/__init__.py 中写入如下内容:
# Note: this file may contain additional technology layers that are required for our small pcells library.
# Currently we need to specify this file and load TECH so the library builder knows how to build this library.
from si_fab import technology
TECH = technology.TECH
2.2 components文件夹
这是Library的核心部分,用于存放所有自定义器件的实现。例如:pteam_library_si_fab\ipkiss\pteam_library_si_fab\components\splitter_tree
其中,cell.py包含器件的主体代码,__init__.py 则负责暴露接口,供外部模块导入。

cell.py为SplitterTree的代码
from si_fab import all as pdk
from ipkiss3 import all as i3
class SplitterTree(i3.Circuit):
"""This creates a splitter tree PCell, made of 1x2 splitter elements.
Users can specify the number of tree levels as PCell parameter.
"""
splitter = i3.ChildCellProperty(doc="Splitter used")
levels = i3.IntProperty(default=3, doc="Number of levels")
spacing_x = i3.PositiveNumberProperty(
default=100.0, doc="Spacing between the splitters in x-direction in the last level"
)
spacing_y = i3.PositiveNumberProperty(default=50.0, doc="Spacing in y-direction")
bend_radius = i3.PositiveNumberProperty()
def _default_bend_radius(self):
return 5.0
def _default_splitter(self):
return pdk.MMI1x2Optimized1550()
def _default_insts(self):
insts = dict()
for level in range(self.levels):
for sp in range(int(2**level)):
insts[f"sp_{level}_{sp}"] = self.splitter
return insts
def _default_specs(self):
specs = []
for level in range(self.levels):
for sp in range(int(2**level)):
sp_y = self.spacing_y * 2 ** (self.levels - level - 1)
specs.append(
i3.Place(
f"sp_{level}_{sp}",
(level * self.spacing_x, -0.5 * (2**level - 1) * sp_y + sp * sp_y),
)
)
for level in range(1, self.levels):
for sp in range(int(2**level)):
if sp % 2 == 0:
in_port = f"sp_{level - 1}_{int(sp / 2.0)}:out1"
else:
in_port = f"sp_{level - 1}_{int(sp / 2.0)}:out2"
out_port = f"sp_{level}_{sp}:in1"
specs.append(i3.ConnectManhattan(in_port, out_port, bend_radius=self.bend_radius))
return specs
__init__.py 文件如下所示
from .cell import SplitterTree
2.3 all.py 文件
该文件用于统一导入所有器件,便于在主项目中调用。如下所示
from .components.mzi import MZI
from .components.heated_mux2 import Mux2Heated
from .components.splitter_tree import SplitterTree, RoutedSplitterTree
from .components.mzm import MZModulator
from .components.tunable_delay import TunableDelayLine
from .components.ppc_unit.pcell.cell import PPCUnit
from .components.mux2 import Mux2
__all__ = [
"MZI",
"Mux2Heated",
"SplitterTree",
"RoutedSplitterTree",
"MZModulator",
"TunableDelayLine",
"PPCUnit",
"Mux2",
]
至此,我们完成了自定义器件库 pteam_library_si_fab 的基本搭建。
3. 如何在项目中调用自定义器件库
3.1 要在主项目中使用该库,请将
pteam_library_si_fab/ipkiss
目录标记为 source folder,然后在项目代码中通过 import
语句引入: 
将pteam_library_si_fab/ipkiss标为source
3.2
建议在项目目录下新建一个名为
designs
的文件夹,用于存放线路设计脚本。例如: 
新建一个名为desgin的文件夹存放线路设计的代码,如 designs\iq_modulator\example_iqmodulator_packaged_layout.py,并导入pteam_library_si_fab中MZModulator
4. 如何使自定义器件库中的器件在IPKISS Canvas中也能使用呢?
4.1 概念介绍
什么是IPKISS Canvas?
- PKISS Canvas 是 IPKISS 自3.10版本推出的新功能模块,允许用户通过 GUI 绘制原理图并一键生成版图和布局代码,极大提升了线路设计效率。
- 详细功能介绍请参考:IPKISS Canvas — Luceda Academy 2025.06 documentation。
- 更多使用教学视频请关注 Luceda BiliBili账户:IPKISS Canvas 教程 | 版图对比原理图_哔哩哔哩_bilibili

什么是*.iclib?
- *.iclib定义PDK在Canvas的库文件,包含PDK/Library中所有器件symbol(原理图),是使用 Canvas 功能的基础配置文件。
- Luceda 的每个PDK通常都会提供一个 .iclib 文件,位于 all.py 同一目录下。如果缺失,请联系 Luceda 支持并提供您使用的PDK版本号,我们会协助与流片厂沟通并更新资源。

4.2 如何为自己的器件库创建*.iclib呢?
通过运行 build_iclib.py 脚本生成对应的 .iclib 文件。流程如下:
- 导入自定义库:import pteam_library_si_fab.all as pteam_lib
- 给每个器件设置一个symbol:"MZI": {"image": SymbolImage.MZI},
- 修改要输出的iclib文件名和library name
- 运行代码(build_iclib.py),
生成
.iclib
文件,测试效果
import pteam_library_si_fab.all as pteam_lib # noqa
from ipkiss3.all.canvas import export_ipkiss_library, SymbolImage
import os
import argparse
def build_iclib(dst_path=None):
lib_path = os.path.dirname(os.path.abspath(pteam_lib.__file__))
if dst_path is None:
dst_path = lib_path
iclib_dst = os.path.join(dst_path, "pteam_library_si_fab.iclib")
print(f"Exporting iclib to {iclib_dst}")
export_ipkiss_library(
library_path=lib_path,
library_name="pteam_library_si_fab",
output_path=iclib_dst,
symbols={
"MZI": {
"image": SymbolImage.MZI,
"terms_positions": {
"elec1": [-0.4, 1],
"elec2": [0.4, 1],
"in2": [-1, 0.4],
"in1": [-1, -0.5],
"out2": [1, 0.4],
"out1": [1, -0.5],
},
},
"Mux2Heated": {
"width": 175,
"height": 75,
"terms_positions": {
"ht_in0": [-0.7, 1],
"ht_out0": [-0.5, 1],
"ht_in1": [-0.3, 1],
"ht_out1": [-0.1, 1],
"ht_in2": [0.1, 1],
"ht_out2": [0.3, 1],
"ht_in3": [0.5, 1],
"ht_out3": [0.7, 1],
},
},
"TunableDelayLine": {
"width": 150,
},
"SplitterTree": {
"image": SymbolImage.DEMUX,
},
"MZModulator": {
"image": SymbolImage.MZM,
"width": 100,
"terms_positions": {
"SR_pad": [-0.9, 1],
"G3_pad": [-0.6, 1],
"SL_pad": [-0.9, -1],
"G1_pad": [-0.6, -1],
},
},
},
)
parser = argparse.ArgumentParser(description="build pteam_library_si_fab iclib")
parser.add_argument("-o", "--output-dir", dest="output_dir")
args = parser.parse_args()
build_iclib(args.output_dir)
ps: 代码来源于luceda_academy\libraries\pteam_library_si_fab\building\build_iclib.py