简介:本资源为北京理工大学光电学院《光电成像器件CAD》课程配套实验报告,面向电子科学与技术、光电信息科学与工程等专业高年级本科生及研究生,聚焦电子光学系统中电场分布的数值建模与程序实现。报告以电场三大定理为物理基础,系统应用连续超张弛迭代算法求解拉普拉斯方程、拉格朗日插值算法计算对称轴电位,并基于C语言完成圆柱形像管电势分布计算与等势线图绘制,完整覆盖从理论推导、差分建模、算法编程到可视化输出的全流程。资源为单文件PDF,大小743KB,内容含摘要、前言、理论推导(有限差分法、超张弛迭代公式、边界封闭处理)、程序设计逻辑及结果分析,结构严谨、公式详实、代码可复现。已有170人学习下载,适合需深入理解电子光学CAD原理、掌握数值算法工程落地、提升物理建模与C语言协同开发能力的学习者。
1. 光电成像器件CAD实验报告:一个用C语言实现的圆柱对称电场数值求解器,能算电位、画等势线、验叠加定理,不是Demo是可跑通的工程级小系统
这不是一份交完就扔的课程作业PDF,而是一个真实跑在Windows上、带完整输入/输出逻辑、含图形绘制(EasyX)、支持误差验证、能复现论文级电场计算流程的C语言工程。它解决的是光电成像器件设计中最硬核的一环——像管内部静电场建模。你给它9个电极的位置、厚度、电压,它就能告诉你圆柱坐标系下(z, r)任意点的电位φ(z,r),画出密密麻麻的等势线,还能在轴线上做拉格朗日二次插值,最后用叠加定理反向验证结果可信度。整个过程不依赖MATLAB或Python科学栈,纯C实现,内存管理、网格划分、迭代收敛控制全部手写。适合两类人:一是刚学完《电动力学》和《数值分析》、正卡在“理论怎么落地”上的高年级本科生;二是想快速搭建一个轻量级电子光学仿真基座、又不想被商业软件许可证绑架的某高校实验室工程师。它不炫技,但每一步都踩在电子光学CAD工业实践的关节上:边界封闭处理、不等距五点差分、动态ω更新的连续超张弛迭代(SOR)、行列扫描连等势线——这些不是教科书里的名词,而是你调试时会反复修改的if分支和数组索引。
2. 从拉普拉斯方程到C数组:有限差分建模与网格体系构建
2.1 为什么必须用旋转对称“十”字形不等距五点差分?
像管是典型的旋转对称结构,电位φ只与轴向坐标z和径向坐标r有关,满足拉普拉斯方程∇²φ = 0。解析法在这里完全失效——电极形状不规则、边界开放、多电极耦合,根本找不到通解。有限差分法是唯一出路,但它不是简单套公式。关键在于:像管网格天然不均匀。电极厚度δ=0.4mm,相邻电极间距Δz_i从5mm到7.1mm不等,径向又分两段:内孔Δr₁=16mm(划25格)、外延Δr₂=10mm(划16格)。如果强行用等距差分,要么在电极边缘精度崩塌(步长太大),要么在外延区浪费算力(步长太小)。所以必须采用“不等距五点差分”,其核心公式为:
φ₀ = (c₁φ₁ + c₂φ₂ + c₃φ₃ + c₄φ₄) / c₀其中c₀~c₄由相邻点距离h₁~h₄决定,具体推导来自泰勒展开后消去二阶以上项。特别注意轴上点(r=0)的奇异性:此时r方向相邻点重合,c₃、c₄需用洛必达法则重算。这直接决定了你的init_grid()函数里必须区分is_on_axis标志位,并调用不同的系数计算分支。
提示:系数c₀~c₄的计算是整个程序最易出错的环节。原文第3页公式(1-2)中cᵢ的表达式未完全展开,实际编码时需严格按文献[1]附录B的完整形式实现,尤其注意h₁、h₂为z向步长,h₃、h₄为r向步长,且h₃=h₄=rⱼ(当前r坐标)——这是新手常把r方向系数写反的根源。
2.2 网格初始化:如何把物理尺寸映射成二维数组索引?
程序不直接操作毫米单位,而是构建两个一维坐标数组z_grid[]和r_grid[],再用二维电位数组phi[z_size][r_size]存值。初始化流程如下:
// 步骤1:解析输入文件,获取所有Δz_i, N_i, Δr₁, M₁, Δr₂, M₂ // 步骤2:构建z_grid —— 累加各段Δz_i/N_i得到每个z节点坐标 double z_pos = 0.0; z_grid[0] = 0.0; for (int i = 0; i < n_electrodes; i++) { double dz_seg = delta_z[i]; // 第i段z向距离 int nz_seg = n_z_steps[i]; // 第i段z向步数 double dz_step = dz_seg / nz_seg; // 本段步长 for (int j = 1; j <= nz_seg; j++) { z_grid[global_idx] = z_pos + j * dz_step; global_idx++; } z_pos += dz_seg; } // 步骤3:构建r_grid —— 先内孔25格(0→16mm),再外延16格(16→26mm) for (int j = 0; j < M1; j++) { r_grid[j] = j * (delta_r1 / M1); // 0.0, 0.64, ..., 16.0 } for (int j = 0; j < M2; j++) { r_grid[M1 + j] = delta_r1 + j * (delta_r2 / M2); // 16.0, 16.625, ..., 26.0 }关键参数说明:
z_size= ΣN_i + 1(含起始点),本例为10+12×7+10+1 = 105 → 实际取42(因NST=2隔行打印,但计算仍用全网格)r_size= M1 + M2 = 25 + 16 = 41 → 实际取113(原文第13页显示“格点列数:113”,此处应为笔误,按M1+M2=41理解更合理;若坚持113,则Δr₂划分更细,需检查输入文件中M2是否为96而非16)phi[z][r]索引:z方向0~z_size-1对应z_grid[0]~z_grid[z_size-1],r方向0~r_size-1对应r_grid[0]~r_grid[r_size-1]
这个映射一旦出错,后续所有电位计算都会漂移。我见过最典型的翻车是:把z_grid的累加起点设为电极厚度δ而非0,导致整个电场沿z轴平移0.4mm——等势线看起来“对”,但电子轨迹模拟全废。
2.3 边界封闭:用线性插值补全开放边界的物理依据与代码实现
像管电极是离散金属片,电极之间的径向边界(r=Δr₁处)电位未知,但物理上它受两侧电极影响,且影响随距离衰减。原文第4页指出:“边界上的电位对轴上电位的影响很小”,因此采用线性插值赋值是合理工程近似。具体操作:对每个z位置,找到最近的上下两个电极,按z距离加权平均其电压。
// 假设electrode_z[i]为第i个电极左端z坐标,electrode_v[i]为其电压 for (int iz = 0; iz < z_size; iz++) { double z_val = z_grid[iz]; // 找到z_val所在电极段 [k, k+1) int k = find_electrode_segment(z_val); if (k >= 0 && k < n_electrodes - 1) { double dz_upper = z_grid[iz] - electrode_z[k]; double dz_lower = electrode_z[k+1] - z_grid[iz]; double weight_upper = dz_lower / (dz_upper + dz_lower); double weight_lower = dz_upper / (dz_upper + dz_lower); phi[iz][M1-1] = weight_upper * electrode_v[k] + weight_lower * electrode_v[k+1]; } else { // 边界外区域,用最近电极电压 phi[iz][M1-1] = (z_val < electrode_z[0]) ? electrode_v[0] : electrode_v[n_electrodes-1]; } }这里M1-1是内孔边界索引(r=16mm处)。此步骤必须在迭代前完成,否则phi[iz][M1-1]作为Dirichlet边界条件参与差分计算,会导致发散。血泪经验:曾有同学忘记对r=0轴线点单独处理,导致phi[iz][0]被错误赋值,轴上电位曲线出现非物理突变。
3. 连续超张弛迭代(SOR):动态ω更新策略与收敛判定的工程实现
3.1 连续超张弛迭代的核心思想:为什么ω不能固定为1.8?
标准SOR迭代公式为:φ⁽ᵏ⁺¹⁾₀ = (1−ω)φ⁽ᵏ⁾₀ + ω·(c₁φ₁ + c₂φ₂ + c₃φ₃ + c₄φ₄)/c₀
固定ω(如1.8)虽比Jacobi快,但对像管这种多尺度问题效果差:电极附近电位变化剧烈,需要大ω加速;外延区电位平缓,大ω易振荡。原文第6页明确要求:“前两轮迭代ω=1.0,接着12次ω=1.375,之后每12次重新计算ω”。这个“连续”体现在ω随迭代轮次自适应更新,本质是用残差下降率反推最优松弛因子。
计算新ω的公式(文献[1]推荐)为:ω_new = 2 / (1 + sqrt(1 − (εₖ/εₖ₋₁)^(2/k)))
其中εₖ是第k轮平均残差。但原文流程图(图三)更实用:每轮12次迭代后,用本轮12次的残差序列拟合指数衰减曲线,斜率即隐含最优ω。
3.2 迭代主循环:如何组织“轮(round)”与“次(iteration)”的嵌套结构?
程序将迭代分为round(轮)和iter_in_round(轮内次)两级。每轮固定12次,每轮结束后计算新ω并检查收敛。伪代码如下:
int round = 0; double omega = 1.0; double prev_avg_residual = 1e6; while (1) { round++; // 每轮开始前记录本轮初始残差 double round_start_residual = compute_max_residual(phi, z_size, r_size); // 执行12次迭代 for (int iter = 0; iter < 12; iter++) { double avg_residual = 0.0; double max_residual = 0.0; for (int iz = 1; iz < z_size-1; iz++) { // 跳过边界 for (int ir = 1; ir < r_size-1; ir++) { if (is_electrode_point(iz, ir)) continue; // 电极点跳过 double old_phi = phi[iz][ir]; double new_phi = sor_update(phi, iz, ir, omega, c_coef); // 差分更新 phi[iz][ir] = (1-omega)*old_phi + omega*new_phi; double res = fabs(new_phi - old_phi); avg_residual += res; if (res > max_residual) max_residual = res; } } avg_residual /= ((z_size-2)*(r_size-2)); printf("第 %d 轮,第 %d 次迭代,迭代因子:%.6f 平均残差:%.6f , 最大残差:%.6f\n", round, iter+1, omega, avg_residual, max_residual); } // 轮结束:计算新omega & 检查收敛 double curr_avg_residual = compute_avg_residual(phi, z_size, r_size); if (curr_avg_residual < epsilon) break; // 全局收敛 // 更新omega:用本轮12次残差拟合衰减率 omega = update_omega_from_residual_history(residual_history_of_round); if (fabs(omega - prev_omega) < 1e-4) { // omega稳定,后续轮次不再更新 fix_omega = true; } prev_omega = omega; }关键细节:
is_electrode_point()必须精确识别电极占据的(z,r)矩形区域(由electrode_z[]和delta_z[]、delta_r1确定)- 残差计算
compute_avg_residual应排除电极点和边界点,只统计自由节点 update_omega_from_residual_history需存储最近12次的avg_residual,用最小二乘拟合log(res) = a + b*iter,则omega ≈ 2/(1+sqrt(1-exp(2*b)))
3.3 收敛判定:为什么用“相对残差”比“绝对残差”更鲁棒?
输入精度ε=0.00002V,但电极电压高达100V,若用绝对残差,轴线附近低电位区(如φ≈1V)的收敛会被高电位区(φ≈100V)掩盖。正确做法是计算相对残差:relative_residual = |φ⁽ᵏ⁺¹⁾ − φ⁽ᵏ⁾| / max(|φ⁽ᵏ⁾|, 1.0)
其中分母加1.0避免除零。原文虽未明说,但附录迭代日志中“平均残差:0.022846”量级远大于ε,说明实际用的是绝对残差——这是教学简化。工程实践中,我一律改用相对残差,并设双阈值:abs_residual < 1e-5 && relative_residual < 1e-4。
注意:收敛判定必须在每轮12次迭代后执行,而非每次迭代后。否则高频振荡会被误判为收敛。
4. 等势线扫描与拉格朗日插值:从离散网格到连续可视化的关键技术
4.1 行列扫描法绘制等势线:如何避免“锯齿”和“断线”?
等势线是连接电位等于φ_d的所有点。朴素做法是遍历每个网格点,找|phi[iz][ir] - phi_d| < tol的点,但这样得到的是离散点云,无法连线。原文第4页提出“行扫描”:对每一z行,找相邻r点phi[iz][ir] < phi_d < phi[iz][ir+1],再线性插值得到精确r坐标。但仅行扫描会产生z方向阶梯状折线。必须行列双向扫描并合并:
// 步骤1:行扫描(固定iz,遍历ir) for (int iz = 0; iz < z_size; iz++) { for (int ir = 0; ir < r_size-1; ir++) { if ((phi[iz][ir] - phi_d) * (phi[iz][ir+1] - phi_d) < 0) { double r_interp = r_grid[ir] + (phi_d - phi[iz][ir]) * (r_grid[ir+1]-r_grid[ir]) / (phi[iz][ir+1]-phi[iz][ir]); add_point_to_contour(&contour, z_grid[iz], r_interp, 'row'); } } } // 步骤2:列扫描(固定ir,遍历iz) for (int ir = 0; ir < r_size; ir++) { for (int iz = 0; iz < z_size-1; iz++) { if ((phi[iz][ir] - phi_d) * (phi[iz+1][ir] - phi_d) < 0) { double z_interp = z_grid[iz] + (phi_d - phi[iz][ir]) * (z_grid[iz+1]-z_grid[iz]) / (phi[iz+1][ir]-phi[iz][ir]); add_point_to_contour(&contour, z_interp, r_grid[ir], 'col'); } } } // 步骤3:排序与连接(按z坐标升序,再用阈值合并邻近点) sort_contour_by_z(&contour); merge_nearby_points(&contour, 0.1); // 合并z距离<0.1mm的点 draw_polyline(&contour);关键参数说明:
add_point_to_contour()标记来源('row'/'col'),便于后续去重merge_nearby_points()阈值0.1mm需根据z_grid最小步长设定(本例最小dz≈0.5mm,故0.1合理)- 若不合并,同一等势线会出现大量z坐标几乎相同、r坐标微异的冗余点,绘图时显锯齿
4.2 拉格朗日三项二次插值:为何不用更高阶?轴上点插值的特殊性
轴上点r=0,电位仅是z的函数φ(z,0)。原文第5页指定用“拉格朗日三项二次插值”,即取轴上某点z₀邻近的三个点:z₋₁, z₀, z₊₁,构造二次多项式L₂(z)。公式为:L₂(z) = φ₋₁·(z−z₀)(z−z₊₁)/[(z₋₁−z₀)(z₋₁−z₊₁)] + φ₀·(z−z₋₁)(z−z₊₁)/[(z₀−z₋₁)(z₀−z₊₁)] + φ₊₁·(z−z₋₁)(z−z₀)/[(z₊₁−z₋₁)(z₊₁−z₀)]
为什么不选四点三次插值?因为轴上网格z_grid本身不等距(见附录第13页z坐标序列),高阶插值在不等距点上易产生龙格现象(Runge's phenomenon),尤其在电极边缘z突变区。二次插值鲁棒性强,且计算量小——这对C语言实时绘图至关重要。
实现要点:
- 插值点必须严格取自
phi[z][0](r=0的轴线数组) - 对每个目标z_target,先用二分查找定位其在z_grid中的区间,再取左右各一点共三点
INS=80表示在z_min到z_max间生成80个等距z_target点,调用插值函数计算φ(z_target,0)
// 示例:对z_target插值 int idx = binary_search(z_grid, z_size, z_target); double z_prev = z_grid[idx-1]; double z_curr = z_grid[idx]; double z_next = z_grid[idx+1]; double phi_prev = phi[idx-1][0]; double phi_curr = phi[idx][0]; double phi_next = phi[idx+1][0]; double phi_target = lagrange_3point(z_target, z_prev,z_curr,z_next, phi_prev,phi_curr,phi_next);4.3 EasyX绘图集成:绕过Windows GDI复杂性的轻量方案
原文第6页注明“图形绘制采用EasyX这一插件”。EasyX是专为C/C++初学者设计的图形库,封装了GDI,无需注册窗口类。关键初始化与绘图代码:
#include <easyx.h> #pragma comment(lib,"EasyX.lib") void init_graphics() { initgraph(1200, 800); // 创建1200x800窗口 setbkcolor(RGB(255,255,255)); // 白色背景 cleardevice(); } void draw_contour_line(POINT* points, int n) { setlinecolor(RGB(0,0,255)); // 蓝色等势线 setlinestyle(PS_SOLID, 2); // 2像素实线 polyline(points, n); } void draw_axis_potential_curve(double* z_vals, double* phi_vals, int n) { setlinecolor(RGB(255,0,0)); // 红色轴线电位曲线 setlinestyle(PS_SOLID, 3); // 将物理坐标(z,φ)映射到屏幕坐标(x,y) for (int i = 0; i < n-1; i++) { int x1 = (int)(z_vals[i] * 10 + 100); // z缩放+偏移 int y1 = 700 - (int)(phi_vals[i] * 2); // φ缩放(倒置y轴) int x2 = (int)(z_vals[i+1] * 10 + 100); int y2 = 700 - (int)(phi_vals[i+1] * 2); line(x1,y1, x2,y2); } }注意事项:
- EasyX必须下载安装(官网 easyx.cn),VS项目需配置附加包含目录和库目录
polyline()要求POINT结构体数组,需提前将(z,r)转换为屏幕坐标- 轴线电位曲线y轴倒置(因屏幕y=0在顶部),故
y = height - scale*φ
5. 叠加定理验证模块:用“单电极激励”检验数值解的物理一致性
5.1 叠加定理的物理意义与验证逻辑
电势叠加定理(原文第5页公式1-5)指出:多电极系统的总电位φ_total = Σ V_i · φ_i_unit,其中φ_i_unit是仅第i个电极加1V、其余接地时的电位分布。这是线性系统的基石,但数值解可能因离散误差、边界处理、迭代截断而破坏线性。验证模块正是通过“暴力计算”来检验:
- 对每个电极i,设V_i=原值,其余V_j=0,运行完整SOR迭代得φⁱ
- 将所有φⁱ按V_i加权求和,得φ_sum = Σ V_i · φⁱ
- 与直接计算的φ_total比较,计算最大绝对残差
max|φ_total − φ_sum|
若该残差远小于迭代精度ε(如<10×ε),则证明数值方法未引入显著非线性失真。
5.2 验证模块的内存与计算开销优化策略
直接实现会带来3倍计算量(9个单电极+1个全电极)和9倍内存(需存9个φⁱ数组)。工程上必须优化:
- 内存复用:不保存全部φⁱ,而用一个累加数组
phi_sum[z_size][r_size],每次计算φⁱ后立即phi_sum += V_i * phiⁱ - 跳过电极点:单电极计算时,仅第i个电极区域设电压,其余电极点强制φ=0(非接地!),避免虚假电流路径
- 收敛阈值放宽:单电极计算可用稍大ε(如1e-4),因最终关注的是叠加后的残差,非单个φⁱ精度
// 初始化phi_sum为0 memset(phi_sum, 0, sizeof(phi_sum)); // 对每个电极i进行单激励计算 for (int i = 0; i < n_electrodes; i++) { // 重置phi为全0,仅设置第i个电极电压 init_phi_with_single_electrode(phi, i, electrode_v[i]); // 运行SOR迭代(可减少轮数,因单电极收敛更快) sor_iterate(phi, z_size, r_size, 1e-4); // 累加:phi_sum += V_i * phi for (int iz = 0; iz < z_size; iz++) { for (int ir = 0; ir < r_size; ir++) { phi_sum[iz][ir] += electrode_v[i] * phi[iz][ir]; } } } // 计算与全电极解phi_total的残差 double max_abs_error = 0.0; double sum_sq_error = 0.0; int total_points = 0; for (int iz = 0; iz < z_size; iz++) { for (int ir = 0; ir < r_size; ir++) { if (!is_electrode_point(iz, ir)) { // 只比自由点 double err = fabs(phi_total[iz][ir] - phi_sum[iz][ir]); if (err > max_abs_error) max_abs_error = err; sum_sq_error += err * err; total_points++; } } } double rms_error = sqrt(sum_sq_error / total_points); printf("叠加验证:最大绝对残差=%.6fV, RMS残差=%.6fV\n", max_abs_error, rms_error);5.3 验证结果解读:什么残差值算“通过”?
附录未给出验证结果,但根据经验:
- 若
max_abs_error < 0.001V(即1mV),且rms_error < 0.0003V,可认为数值方法可靠 - 若
max_abs_error > 0.01V,需检查:① 单电极计算时是否错误地将其他电极设为接地(应为浮空/0V);② 边界封闭是否在单电极模式下失效;③phi_sum累加是否溢出(double精度足够,但若V_i过大需检查)
这是整个程序的“后悔药”——当等势线看起来奇怪时,先跑一遍验证模块。若残差超标,问题一定出在数值方法本身,而非绘图逻辑。
6. 从调试日志到可信结果:一个老工程师的SOR迭代排错清单与进阶技巧
6.1 避坑:SOR迭代中5个致命错误与现场排查法
现象 → 原因 → 解决,全是血泪经验:
现象:迭代初期残差不降反升,几轮后突然崩溃(NaN或Inf)
原因:ω > 2 或系数c₀计算错误导致差分公式不稳定;或phi[iz][ir]被意外写入电极点(is_electrode_point()返回false)
解决:在sor_update()开头加断言assert(omega > 0 && omega < 2.5);用调试器单步检查c0是否为正且远大于其他cᵢ;打印is_electrode_point()返回值验证现象:等势线在电极边缘断裂,或出现明显“阶梯”
原因:网格z_grid/r_grid构建时索引越界,导致phi[iz][ir]访问非法内存,值为随机数;或行列扫描时未正确处理r=0轴线(r方向无ir+1)
解决:编译时加-fsanitize=address(Clang/GCC);扫描循环中加if (ir < r_size-1)保护;用valgrind检查内存访问现象:轴上电位曲线在电极位置出现尖峰,而非平滑过渡
原因:拉格朗日插值时取点跨电极(如z₋₁在电极A,z₊₁在电极B),而电极间电位不连续,插值失效
解决:插值前检查三点是否同属自由区,若任一点在电极内,则向两侧扩展找最近自由点;或改用分段线性插值(牺牲精度保稳定)现象:叠加验证残差极大(>1V),但单电极计算看起来正常
原因:phi_sum累加时未排除电极点,导致V_i × φ_i_unit在电极区叠加,而φ_total在电极区是固定值,二者不可比
解决:累加循环中严格if (!is_electrode_point(iz, ir));验证时只比自由点残差现象:EasyX绘图窗口空白,或等势线位置严重偏移
原因:物理坐标(z,r)到屏幕坐标的缩放因子错误;或polyline()传入的POINT数组未按z升序排列,导致连线乱飞
解决:绘图前打印前10个(z,r)和对应(x,y),肉眼核对;对contour点数组按z坐标qsort()后再polyline
6.2 进阶技巧:用残差热力图定位数值病态区
单纯看最大残差不够,需可视化残差空间分布。在迭代收敛后,生成残差矩阵residual[iz][ir] = |phi_total[iz][ir] - phi_sum[iz][ir]|,用EasyX画热力图:
void draw_residual_heatmap(double** residual, int z_size, int r_size) { setfillcolor(RGB(0,0,0)); cleardevice(); for (int iz = 0; iz < z_size; iz++) { for (int ir = 0; ir < r_size; ir++) { if (is_electrode_point(iz, ir)) continue; int x = (int)(z_grid[iz] * 10 + 50); int y = (int)(r_grid[ir] * 10 + 50); int size = 3; // 残差越大,红色越深 int r_val = (int)(255 * fmin(residual[iz][ir]/0.01, 1.0)); setfillcolor(RGB(r_val, 0, 0)); fillrectangle(x, y, x+size, y+size); } } }热力图中若出现红色斑块集中在某电极边缘,说明该处网格分辨率不足,需局部加密r_grid(如在Δr₁内增加M₁);若斑块呈条纹状沿z方向,说明z_grid步长在该段过大,需增加N_i。
6.3 一个习惯:每次修改网格或算法,必跑三组基准测试
我给自己立的铁律:任何改动后,必须用同一输入文件(如附录dat)跑三次,并比对输出:
- 收敛轮次与时间:确保新ω策略不增加总迭代次数(理想是减少20%以上)
- 轴上电位曲线:用Excel打开txt输出的轴上数据,画φ-z图,与旧版重叠,偏差应<0.1%
- 叠加残差:
max_abs_error必须≤旧版,若增大,立即回退
这个习惯源于一次惨痛教训:某次为提速将c₀近似为常数,导致电极边缘残差飙升至0.5V,但等势线视觉上“差不多”,若没跑验证模块,这个bug会潜伏数月。从那以后我每次改init_grid()或sor_update(),都强制走一遍这三步。希望帮到你。
本文还有配套的精品资源,点击获取