🤖 bot4cj 项目深度分析文档

本文档对 bot4cj 项目进行全面、详细的分析,涵盖项目架构、每个模块的实现细节、算法原理、数据流、缺陷与改进建议。目标读者为零基础学习者。

1. 项目总览

1.1 项目是什么

bot4cj 是一个机器人硬件脚本解析器,基于仓颉(Cangjie)编程语言和 Linux I2C 接口。它的核心思想是:

用一种自定义的"矩阵式脚本语言"来描述机器人的硬件构成和动作序列,然后解析并驱动真实硬件执行这些动作。

简单类比:如果把机器人比作一个演员,那么 .mt 脚本就是剧本,bot4cj 就是导演——它读剧本、安排演员(硬件)、指挥表演(执行动作)。

1.2 项目能做什么

📝 解析矩阵式脚本
读取 .mt 文件,解析出硬件定义和动作序列
🔌 驱动 PCA9685
通过 I2C 控制最多 16 路舵机
📐 读取 MPU6050
实时获取姿态数据,带卡尔曼滤波
🔊 控制扬声器
以声音频率替代延时
🌐 HTTP 服务器
通过网络接口远程提交脚本并执行
🧠 神经网络
全连接前馈网络,支持反向传播训练
🎯 深度强化学习
DRL 对机器人动作微调(已注释)
👁️ CNN
卷积神经网络用于视觉识别(C++/FFI)
📊 FFT 频谱分析
对信号进行快速傅里叶变换
⚡ CUDA GPU 加速
矩阵运算和激活函数在 GPU 上执行

1.3 技术栈

层级技术用途
应用层仓颉 (Cangjie)主程序、解析器、机器人结构、数学库
系统层C/C++I2C 驱动、矩阵运算、FFT、CNN、音频
加速层CUDAGPU 矩阵运算、GPU 激活函数
脚本层.mt 矩阵式脚本硬件定义和动作描述
前端层HTML + TailwindWeb 管理界面
工具层Python图片标注工具、API 测试

2. 项目架构与目录结构

bot4cj/
├── src/                          # 源代码根目录
│   ├── main.cj                   # 程序入口:命令行解析、分支选择
│   ├── P.cj                      # 解析器:MatrixObject、MatrixParser、MatrixSaver
│   ├── r.cj                      # 机器人结构:RobotStruct、硬件变量类
│   ├── math/                     # 数学库
│   │   ├── Matrix.cj             # FP32 结构体 + Matrix1 矩阵类(仓颉原生)
│   │   ├── Tensor.cj             # 张量类(多维数组)
│   │   ├── nn.cj                 # 神经网络层 Nn1 + 训练/推理函数
│   │   ├── nns.cj                # 多层神经网络训练/推理(旧版,已注释)
│   │   ├── Af.cj                 # 激活函数枚举
│   │   ├── Ini.cj                # 权重初始化:Xavier 正态/均匀
│   │   ├── kalman.cj             # 一维卡尔曼滤波器(仓颉实现)
│   │   └── fft.cj                # FFT 接口(已注释,改用 C 实现)
│   ├── hd/                       # 硬件驱动
│   │   ├── I2C.cj                # I2C 通信:直接调用 glibc + 互斥锁系统
│   │   ├── PCA9685.cj            # PCA9685 舵机驱动板控制
│   │   ├── MPU6050.cj            # MPU6050 陀螺仪/加速度计 + 守护线程
│   │   ├── Servo.cj              # 舵机类:角度限制 + 偏移 + 回调
│   │   └── snd.cj                # 扬声器类(目前仅延时占位)
│   ├── th/                       # 线程与同步
│   │   ├── mutex.cj              # pthread 互斥锁封装
│   │   └── pthread.cj            # pthread 线程封装
│   ├── cpp/                      # C/C++ 共享库源码
│   │   ├── I2C.c                 # 旧版 I2C 驱动(使用 i2c-smbus)
│   │   ├── Matrix.cpp + .hh      # C++ 模板矩阵类 + C 接口封装
│   │   ├── kalman.c + .h         # 旧版卡尔曼滤波器(C 实现)
│   │   ├── fft1.c                # 基-2 FFT 算法(纯 C)
│   │   ├── fft.cpp + .h          # FFT 封装层(C++ → C 接口)
│   │   ├── snd.cpp               # 音频播放(Windows WaveAPI / Linux ALSA)
│   │   ├── bot4cj.h              # C 头文件:I2C 常量和函数声明
│   │   └── cnn/                  # CNN 卷积神经网络
│   ├── cuda/                     # CUDA GPU 加速
│   └── py/                       # 图片标注工具
├── scripts/                      # 动作脚本
├── public/                       # Web 前端页面
├── test/                         # API 测试
├── Makefile                      # C/C++ 共享库构建
├── cjpm.toml                     # 仓颉包管理配置
└── _run.sh / _set.sh             # 运行和构建脚本

3. 核心数据流:从脚本到硬件

这是理解整个项目最关键的部分。以下是数据从脚本文件到硬件执行的完整流程:

┌─────────────┐
│  .mt 脚本文件  │  例如:scripts/test.mt
└──────┬──────┘
       │ 文件读取 (InputStream)
       ▼
┌─────────────┐
│  MatrixParser │  逐字符解析,输出 MatrixObject 对象
│  (src/P.cj)  │  每个 @name...@ 块变成一个 MatrixObject
└──────┬──────┘
       │ LinkedList<MatrixObject>
       ▼
┌─────────────┐
│  RobotStruct  │  从 MatrixObject 列表构建硬件变量字典
│  (src/r.cj)  │  HashMap<String, MatrixVars_Hardware>
└──────┬──────┘
       │
       ├── createAliasVars()     从 @Alias 矩阵创建别名变量
       ├── createI2CVars()       从 @I2C 矩阵创建 I2C 设备变量
       ├── createMPU6050Bind()   从 @MPU6050_BIND 矩阵创建陀螺仪变量
       ├── createPCA9685Vars()   从 @PCA9685 矩阵创建舵机控制板变量
       ├── createServoVars()     从 @Servo 矩阵创建舵机变量
       └── createSpeakerVars()   从 @Speaker 矩阵创建扬声器变量
       │
       ▼
┌─────────────┐
│  active()    │  调用所有硬件变量的 build() 方法(初始化硬件)
└──────┬──────┘
       │
       ▼
┌─────────────┐
│  run()       │  逐行执行 @Action 矩阵中的动作
│  run_drl_    │  每行解析出各硬件的参数,调用 play() 执行
│  action()    │
└──────┬──────┘
       │
       ▼
┌─────────────┐
│  deactive()  │  以倒序调用所有硬件变量的 destroy() 方法
└─────────────┘

关键概念:MatrixVars_Hardware(硬件变量)

这是整个项目的核心抽象。每种硬件(I2C、PCA9685、Servo、Speaker...)都被封装为一个硬件变量,它们:

  1. 通过闭包持有真实的硬件对象(如 I2C_Orig、PCA9685、Servo)
  2. 通过 JsonValue 进行统一接口通信(输入 JsonValue,输出 JsonValue)
  3. 有生命周期:build() 初始化,play() 执行,destroy() 释放

4. 矩阵式脚本语言(.mt)详解

4.1 语法规则

矩阵式脚本是一种声明式、表格型的领域特定语言(DSL),用于描述机器人的硬件构成和动作序列。

基本结构:

@MatrixName          ← 矩阵开始,@ 后跟名称
 col1  col2  col3;   ← 第 0 行:列名声明
 val1  val2  val3;   ← 第 1 行起:数据行
 val4  -    val6;    ← "-" 表示沿用上一行同列的值
@

4.2 各矩阵对象的含义

矩阵名用途关键列
@Alias定义参数别名name, alias
@I2C定义 I2C 总线设备name, path
@PCA9685定义舵机控制板name, I2C, addr
@MPU6050_BIND定义陀螺仪name, I2C, addr
@Speaker定义扬声器name, channels, sample_rate, volumn, max_f, min_f
@Servo定义舵机name, max, min, offset, controller, channel
@Action定义动作序列格式为 硬件名.参数名

4.3 @Action 矩阵详解

@Action 是最核心的矩阵,它定义了机器人的动作序列:

@Action
s1.A  s2.A  s3.A  ...  spk.F  spk.delay;   ← 列名:硬件变量.参数名
  45     -    45  ...     10        200;     ← 第1行:站立姿态
  90     -     -  ...      -         20;     ← 第2行:左后方抬起
  ...
@

4.4 蜘蛛机器人动作示例解读

以 scripts/test.mt 为例,这是一个 8 足蜘蛛机器人的行走步态:

@Action
s1.A  s2.A  s3.A  s4.A  s5.A  s6.A  s7.A  s8.A  s9.A  s10.A  spk.F  spk.delay;
  45     -    45     -    45     -    45     -    90     90     10        200;  # 站立
  90     -     -     -     -     -     -     -     -      -      -         20;  # 左后方抬起
  45     -     -     -     -     -     -     -     -      -      0        500;  # 恢复站立
   -     -    90     -     -     -    45     -     -      -      -         20;  # 右后方抬起
  ...
@

5. 解析器模块详解

5.1 MatrixObject 类

用途:表示解析后的一个矩阵对象,对应脚本中 @name ... @ 之间的内容。

MatrixObject {
    name: String                         ← 矩阵名称
    values: ArrayList<ArrayList<String>> ← 二维字符串矩阵
}
方法功能
hasName()是否已命名
[](row, col)像数组一样用下标访问
indexOfCol(row, key)在某行中查找列号
addRune(c)添加字符到缓冲区
submitName()提交名字
submitItem()提交元素
submitLine(count)提交一行,检查列数一致性
save(output)将矩阵对象写回文件流

5.2 MatrixParser 类

用途:将输入流逐字符解析为 MatrixObject 对象。

算法:有限状态机(FSM)

标志含义
flag是否遇到结束的 @
nl是否处于新行起始位置
cm是否处于注释中
nm是否正在解析名称行(@ 后的第一行)
输入字符 c
├── 如果在注释中 (cm=true)
│   ├── c == '\n' → 注释结束,nl=true, cm=false
│   └── 其他 → 忽略
├── 如果在新行起始 (nl=true)
│   ├── c 是空白 → 维持现状
│   ├── c == '\n' → 空行,行号+1
│   ├── c == '@' 且未命名 → 开始名称行,nm=true
│   ├── c == '@' 且已命名 → 结束标志,flag=true
│   └── 其他 → 内容字符,加入缓冲区
├── 如果不在新行 (nl=false)
│   ├── 在名称行且遇空白 → 提交名字
│   ├── 遇空白/制表符 → 提交当前元素
│   ├── c == ';' → 提交元素并提交行
│   └── 其他 → 加入缓冲区

5.4 异常体系

异常类含义
ParseExcept解析异常基类
BufOverTheLine缓冲区过长
DoesNotSync矩阵行没对齐(列数不一致)
UnknowExcept未知异常兜底

6. 机器人结构模块详解

6.1 MatrixVars_Hardware 基类

这是整个硬件抽象的核心。

MatrixVars_Hardware(基类)
├── things: (JsonValue) → JsonValue    ← 事件回调(核心!)
├── rise: Option<() → Unit>           ← 初始化回调
├── free: Option<() → Unit>           ← 释放回调
├── play(input) → things(input)        ← 执行动作
├── build() → rise()                   ← 初始化硬件
└── destroy() → free()                 ← 释放硬件

为什么用 JsonValue 通信?不同硬件需要不同参数:

6.2 各硬件变量类

MtVars_I2C(I2C 变量)

things 支持 4 种模式:

MtVars_Servo(舵机变量)

Servo.setAngle() 逻辑:

角度 = 输入角度 + 偏移值(offset)
如果 角度 > 最大值(max) → 角度 = max
如果 角度 < 最小值(min) → 角度 = min
调用回调函数设置角度

6.3 RobotStruct 类

RobotStruct(input)
  ├── readMatrix(input)         解析所有矩阵对象
  └── createHardVars()          创建硬件变量字典
        ├── createAliasVars()
        ├── createI2CVars()
        ├── createMPU6050Bind()
        ├── createPCA9685Vars()
        ├── createServoVars()
        └── createSpeakerVars()

active()                         初始化所有硬件
run() → run_drl_action()         执行动作
deactive()                       倒序释放所有硬件

7. 硬件驱动层详解

7.1 I2C 通信

项目直接在仓颉中通过 foreign func 声明并调用 Linux glibc 的原生函数:

foreign func open(path: CString, flag: Int32, ...): Int32
foreign func close(fd: Int32): Int32
foreign func ioctl(fd: Int32, addr: UInt64, ...): Int32
foreign func read(fd: Int32, buf: CPointer<Unit>, count: UIntNative): IntNative
foreign func write(fd: Int32, buf: CPointer<Unit>, count: UIntNative): IntNative

7.2 I2C 互斥锁系统

MAIN_LOCK (主锁)          ← 保护 LOCKS 数组的操作
  └── LOCKS[0..19] (锁具数组)   ← 每个 I2C 设备一个锁
        └── I2C_Lock {
              i2c_fd: Int32      ← 绑定的 I2C 设备文件句柄
              lock: CPointer     ← pthread_mutex_t 指针
              is_active: Bool    ← 是否激活
            }

7.3 PCA9685 舵机控制板

角度转 PWM:

脉宽 = 0.5 + (2.5 - 0.5) * (angle / 180.0)    ← 0°→0.5ms, 180°→2.5ms
OFF值 = 脉宽 * 4096 / 20                        ← 20ms 周期, 12位分辨率
setPWM(channel, ON=0, OFF=计算值)

7.4 MPU6050 陀螺仪/加速度计

守护线程 mpu6050_main():

  1. 读取原始传感器数据
  2. 对 6 个轴分别进行卡尔曼滤波
  3. 打印滤波后的数据
  4. 睡眠 10ms

7.6 Spk 扬声器类

当前状态:仅实现了延时功能,实际发声被注释掉。C++ 实现的音频播放(src/cpp/snd.cpp)是完整的,支持 Windows WaveAPI 和 Linux ALSA。


8. 数学库详解

8.2 Matrix1 矩阵类

数据布局:一维数组 Array<FP32>,行优先存储。

arr[row * col + col]  ← 元素访问公式
运算符号含义形状要求
矩阵加法A + B逐元素相加同形状
广播加法A + s每个元素加标量-
矩阵减法A - B逐元素相减同形状
逐元素乘A * B逐元素相乘(Hadamard积)同形状
矩阵乘法A.dot(B)矩阵点积(MatMul)A.col == B.row
转置A.T()行列互换-

矩阵乘法算法(dot):

对于结果矩阵的每个元素 (i, j):
    sum = 0
    对于 k in 0..A.col:
        sum += A[i, k] * B[k, j]
    结果[i, j] = sum

时间复杂度:O(m × n × k)


9. 神经网络模块详解

9.1 Nn1 全连接层

class Nn1 {
    inputno: Int64          ← 输入维度
    outputno: Int64         ← 输出维度
    weights: Matrix1        ← 权重矩阵 (inputno, outputno)
    bias: Matrix1           ← 偏置向量 (1, outputno)
    learning_rate: FP32     ← 学习率
    f: Af                   ← 激活函数
}

forward() 前向传播: a = f(Wx + b)

backward() 反向传播:

δ = errs * f'(z)             ← 误差 × 激活函数导数
weights_grad = x^T · δ       ← 权重梯度
bias_grad = δ                ← 偏置梯度
errs_up = δ · W^T            ← 传给上一层的误差

9.2 激活函数

函数公式导数用途
Sigmoidf(x) = 1/(1+e^(-x))f'(x) = f(x)(1-f(x))二分类输出层
ReLUf(x) = max(0, x)f'(x) = 1 if x>0, else 0隐藏层
Leaky_ReLUf(x) = x if x>0, else αxf'(x) = 1 if x>0, else α隐藏层
Tanhf(x) = tanh(x)f'(x) = 1 - tanh²(x)隐藏层
Softmaxf(x_i) = e^(x_i) / Σe^(x_j)雅可比矩阵多分类输出层

9.3 Xavier 权重初始化

σ = sqrt(2 / (fan_in + fan_out))      ← Xavier 正态
limit = sqrt(6 / (fan_in + fan_out))    ← Xavier 均匀(Glorot)

10. 卡尔曼滤波详解

卡尔曼滤波是一种最优估计算法,用于从含有噪声的测量数据中估计系统的真实状态。

一维卡尔曼滤波器 5 个核心公式

步骤公式含义
预测状态X_mid = A · X_last根据上一次最优估计预测当前状态
预测协方差P_mid = A · P_last + Q预测的不确定性增大(+系统噪声Q)
计算卡尔曼增益kg = P_mid / (P_mid + R)测量越可靠(R小),增益越大
更新状态X_now = X_mid + kg · (dat - X_mid)用测量值修正预测值
更新协方差P_now = (1 - kg) · P_mid估计的不确定性减小

11. FFT 快速傅里叶变换详解

快速傅里叶变换(FFT)是一种高效计算离散傅里叶变换(DFT)的算法。将时域信号转换为频域表示。

DFT 公式: X[k] = Σ x[n] · e^(-j·2π·k·n/N)

算法:Cooley-Tukey 基-2 FFT —— 将 N 点 DFT 分解为两个 N/2 点 DFT,递归分解,时间复杂度从 O(N²) 降低到 O(N·log N)。

蝶形运算

对于每一级 l:
    对于每一组 j:
        对于每个蝶形 k:
            t = A[jl1k] · W[ij]           ← 旋转因子乘法
            A[jl1k] = A[jl0k] - t         ← 蝶形运算上支
            A[jl0k] = A[jl0k] + t         ← 蝶形运算下支

12. CNN 卷积神经网络详解

12.1 CNN 架构

CNN 模块完全用 C++ 实现,通过 C 接口(extern "C")暴露给仓颉调用。

层文件功能
ConvLayerconv.cpp/h2D 卷积层 + 反向传播 + 参数更新
PoolingLayerpooling.cpp/h最大/平均池化
GlobalAveragePoolingga_pooling.cpp/h全局平均池化
FlattenLayerflatten.cpp/h展平(4D → 2D)
ImageLoaderimgl.cpp/h图像加载 + 归一化

卷积层前向传播

对于每个输出通道 oc:
    对于每个空间位置 (oh, ow):
        sum = bias[oc]
        对于每个输入通道 ic:
            对于每个核位置 (kh, kw):
                sum += weight[oc,ic,kh,kw] * input[ic,oh*stride+kh,ow*stride+kw]
        output[oc,oh,ow] = sum

13. CUDA GPU 加速详解

13.1 CUDA 矩阵运算

__global__ void _devAdd(float* d1, float* d2, float* r, int64_t n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;  ← 计算全局线程ID
    if (i < n) {
        r[i] = d1[i] + d2[i];                        ← 每个线程处理一个元素
    }
}
函数功能
Cu4cj_Orig(n)在 GPU 上分配 n 个 float 的内存
Cu4cj_Zero(n)在 GPU 上分配并清零
Cu4cj_ToDev(h, n)主机 → 设备拷贝
Cu4cj_ToHost(d, h, n)设备 → 主机拷贝
Cu4cj_Free(d)释放 GPU 内存

14. 线程与同步模块详解

直接封装 pthread 互斥锁和线程:

foreign func pthread_mutex_init(mutex, attr): Int32
foreign func pthread_mutex_destroy(mutex): Int32
foreign func pthread_mutex_lock(mutex): Int32
foreign func pthread_mutex_unlock(mutex): Int32
public class Pth {
    init(_main, args) → pthread_create(...)   ← 创建线程
    join(retval) → pthread_join(...)           ← 等待线程结束
    close() → pthread_cancel(...)              ← 取消线程
}

15. HTTP 服务器模块详解

路径方法功能
/api/v2/bot_runPOST接收动作脚本并执行
/GET返回前端页面
/api/v1/fsPOST文件系统操作(列表目录)

16. 辅助工具详解


17. 构建系统详解

目标源文件输出用途
libi2c4cj.soI2C.cI2C 驱动旧版(已弃用)
libsnd4cj.sosnd.cpp音频播放WaveAPI / ALSA
libmt4cj.soMatrix.cpp / matrix.cu矩阵运算CPU 或 GPU 版本
libfft4cj.sofft1.c + fft.cppFFT快速傅里叶变换
libcnn4cj.socnn_i.cpp + ...CNN卷积神经网络

18. 全局缺陷与改进建议

18.1 严重缺陷

编号缺陷位置详细说明严重程度
D1析构器调用时间不确定r.cj:28 仓颉的 GC 不保证析构器调用时间,I2C 文件描述符可能泄漏 高
D2扬声器仅延时未发声hd/snd.cj:17 play() 只 sleep,C++ 实现的 play_frequency() 未被调用 高
D3MPU6050 线程无法安全退出hd/MPU6050.cj:115 mpu6050_main() 是无限循环,pthread_cancel 可能在不安全点中断 高
D4I2C 锁系统线性扫描hd/I2C.cj:129 每次加锁/解锁都遍历 20 个元素的数组,O(n) 复杂度 中
D5xavierUniformInit 每个元素新建 Randommath/Ini.cj:30 循环内每次 DateTime.now().nanosecond + Random(),种子可能重复 中
D6Softmax 雅可比矩阵反向传播未正确使用math/Af.cj:246 softmax_jacobian 返回 n×n 矩阵,但 backward 调用者期望与输入同形状 高
D8tanh 导数输入错误math/Af.cj:194-206 计算 1 - x*x 用的是原始输入 x,应改为 1 - y*y 高
D9I2C 读寄存器返回 Int8 而非 UInt8hd/I2C.cj:81 负值寄存器数据会出错 中
D10MPU6050 ADDR_0 和 ADDR_1 相同hd/MPU6050.cj:14-15 两个地址常量都是 0x68,ADDR_1 应为 0x69 中

18.2 设计缺陷

编号缺陷详细说明建议
D12JsonValue 通信开销大每次硬件操作都要构造/解析 JSON对高频路径提供直接调用接口
D13硬件变量创建顺序硬编码createHardVars() 中顺序固定使用依赖图自动排序
D14无 batch 训练支持神经网络每次只训练一个样本增加 batch 维度
D15无 Adam 优化器仓颉版 Nn1 只有 SGD实现 Adam 优化器
D20无单元测试数学库、解析器等无自动化测试添加测试框架

18.3 安全缺陷

编号缺陷详细说明
D21文件系统 API 无认证/api/v1/fs 可列出任意目录内容
D22HTTP 服务器无认证/api/v2/bot_run 可执行任意脚本
D23路径遍历风险文件系统 API 接受用户输入的路径

19. 学习路线图

📝 第一阶段(1-2天)
理解脚本语言
阅读 scripts/test.mt,理解 .mt 语法,手动写一个简单脚本
🔍 第二阶段(2-3天)
理解解析器
从 MatrixObject 开始,跟踪 MatrixParser 的状态机逻辑
🔌 第三阶段(3-5天)
理解硬件驱动
学习 I2C 通信原理,阅读 PCA9685、MPU6050 驱动代码
🏗️ 第四阶段(2-3天)
理解机器人结构
理解闭包设计,跟踪硬件变量创建和 run_drl_action() 流程
🧠 第五阶段(3-5天)
理解神经网络
学习矩阵运算、激活函数,手动计算前向/反向传播
🚀 第六阶段(选学)
理解高级功能
卡尔曼滤波、FFT 蝶形运算、CNN、CUDA GPU 编程

附录 A:仓颉语言关键语法速查

语法含义对应语言
package foo声明包Java package
import std.io.*导入Java import
class A <: B继承Java extends
open class允许继承Java 非 final
let / var不可变/可变Kotlin val/var
Option<T>可选类型Java Optional
Some(v) / None有值/无值Optional.of/present
if (let Some(v) <- expr)if-let 解构Swift if-let
match(expr) { case ... }模式匹配Kotlin when / Rust match
foreign funcFFI 声明Java native / Rust extern
unsafe { }不安全块Rust unsafe
CPointer<T>C 指针Rust *mut T
@CC 兼容注解使结构体内存布局兼容 C
operator func []运算符重载C++ operator[]
extend A { }扩展方法Kotlin extension

附录 B:术语表

术语英文含义
舵机Servo一种可以精确控制角度的电机
I2CInter-Integrated Circuit一种两线制串行总线协议
PWMPulse Width Modulation脉宽调制,通过改变脉冲宽度控制输出
陀螺仪Gyroscope测量角速度的传感器
前向传播Forward Propagation神经网络从输入到输出的计算过程
反向传播Backpropagation神经网络从输出到输入的梯度计算过程
梯度下降Gradient Descent沿梯度反方向更新参数以最小化损失
学习率Learning Rate每次参数更新的步长
激活函数Activation Function引入非线性的函数(如 ReLU、Sigmoid)
卡尔曼增益Kalman Gain决定多大程度上相信测量值 vs 预测值
傅里叶变换Fourier Transform将信号从时域转换到频域
蝶形运算Butterfly OperationFFT 中的基本计算单元
卷积Convolution滑动窗口加权求和的运算
池化Pooling降采样操作(取最大值或平均值)
FFIForeign Function Interface调用其他语言函数的接口
DRLDeep Reinforcement Learning深度强化学习
↑