
简介这份智能控制期末考试卷以docx格式整理共1个文件压缩包仅73KB面向自动化、测控技术与智能控制方向的学生用于期末冲刺与知识点自查。试卷覆盖定值/程序/随动控制系统分类、被控对象特性参数、控制与扰动通道、传感器与A/D转换、香农定理、干扰抑制与接地策略等基础理论同时对PLC组成及工作过程、状态转移图、DCS结构、CIMS集成、数字PID整定与A/D采样量化编码等高频考点进行系统梳理。内容保留填空、计算、问答三类题型并附有对象特性参数对控制/扰动通道的影响、涡流流量传感器原理、被控参量数字化流程、PID参数整定及主控程序与中断分工等详细解答思路。已有586人学习下载适合备考智能控制、过程控制等课程并希望以试卷方式快速巩固核心知识点的同学。1. 一份智能控制考试卷 docx为什么值得当成工程问题来处理期末出卷这件事表面上是 Word 排版实际上是一条从题库、组卷、公式排版、答题区预留到格式兼容的流水线。智能控制课程的内容跨度大模糊控制、神经网络、PID、状态反馈、最优控制往往同时出现在一张卷子里题型多、公式密、图表杂手工在 Word 里一遍遍调格式效率低且容易出错。把「智能控制期末考试卷.docx」当作一个可编程产出的对象来对待用 python-docx 等手段批量生成、批量校验才是真正稳定的做法。这篇文章适合需要自己出卷的老师、做教务系统对接的工程师以及负责把试卷转成在线格式的文档处理开发。核心思路是先定义试卷结构再写生成脚本最后把 docx 当作可验证的交付物来检查。2. 用 python-docx 搭出智能控制试卷的基本盘2.1 为什么选 python-docx 而不是直接手敲 Word直接操作 Word 界面最痛的三个问题一是公式和表格的对齐不稳定每次修改都要重新调整二是 A/B 卷需要做两遍改题号容易漏三是交出去的 docx 在不同 Office 版本里渲染不一致。python-docx 不直接渲染页面而是操作 docx 背后的 OpenXML 结构生成的文件在 Office 和 WPS 里都能稳定打开这正好解决前两个问题。它不是没有边界。python-docx 对复杂公式的原生支持很弱对文本框、域代码、批注的支持也有限。所以实际出卷中我的原则是文字、表格、简单公式用 python-docx 直接生成复杂公式用插入图片或提前渲染好的 OMML 块。把 Python 当作排版引擎把 Word 当作最终交付容器而不是在 Word 里边想边排。2.2 最小可运行生成一份带页边距和标题的 docx先落一个最简脚本跑通「能生成、能打开」这个闭环。写之前先确认环境Python 3.8 以上安装 python-docxpip install python-docx下面这份代码定义页面尺寸、页边距、默认正文字体和标题层级from docx import Document from docx.shared import Pt, Cm from docx.enum.section import WD_SECTION # 新建空白文档python-docx 默认自带一个空白段落和节 doc Document() # 调整第一个节的页面参数A4 纸页边距上下 2.5cm左右 2.8cm section doc.sections[0] section.page_width Cm(21.0) section.page_height Cm(29.7) section.top_margin Cm(2.5) section.bottom_margin Cm(2.5) section.left_margin Cm(2.8) section.right_margin Cm(2.8) # 修改 Normal 样式正文用宋体西文 Times New Roman小四号 style doc.styles[Normal] style.font.name Times New Roman style.font.size Pt(12) style.element.rPr.rFonts.set(qn(w:eastAsia), 宋体) # 在标题里用 add_headinglevel0 是文档主标题 doc.add_heading(智能控制期末考试卷, level0) doc.save(智能控制期末考试卷.docx)这段代码里有三个需要解释的地方。第一WD_SECTION这个枚举实际使用时并不需要显式导入页面参数是通过section对象设置的它的page_width和page_height控制纸张大小单位是Cm()包装后的 EMU直接传数字会报错。第二style.element.rPr.rFonts.set(qn(w:eastAsia), 宋体)这行是设置中文字体的关键因为 docx 的字体信息分西文和东亚字体两部分只设font.name只影响西文。第三add_heading的 level 从 0 开始0 对应文档主标题1 到 9 对应各级标题这些标题样式在 Word 里是内置的不需要自己创建。跑完这个脚本后用 Office 或 WPS 打开生成的文件检查标题、页边距是否符合要求。如果打开时报「文件已损坏」先看是不是 python-docx 版本太旧pip show python-docx确认版本不低于 0.8.11。2.3 试卷头部信息区的段落与分隔处理一份试卷头部通常有课程名、考试形式、考试时间、考生信息栏这几块。这里用表格和段落混排来做注意不是所有信息都适合用表格表格框线会带出来影响试卷美观。我的做法是考生信息栏用一个隐藏内部框线的表格考试时间等条件用段落加制表位对齐。from docx.shared import Pt, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_ALIGN_VERTICAL # 信息表2 行 4 列第一行课程与考试形式第二行时间与总分 info_table doc.add_table(rows2, cols4) info_table.alignment WD_TABLE_ALIGNMENT.CENTER info_data [ [课程名称, 智能控制, 考试形式, 闭卷], [考试时长, 120 分钟, 总分, 100 分], ] for r, row_data in enumerate(info_data): for c, text in enumerate(row_data): cell info_table.cell(r, c) cell.text text cell.vertical_alignment WD_ALIGN_VERTICAL.CENTER if c % 2 0: # 偶数列表头加粗 for paragraph in cell.paragraphs: for run in paragraph.runs: run.bold TrueWD_TABLE_ALIGNMENT.CENTER控制整个表格在页面水平居中WD_ALIGN_VERTICAL.CENTER控制单元格文字垂直居中。cell.text是直接赋值文本但注意它会把单元格原有段落覆盖所以不要在已有内容的单元格上重复用。表头列用c % 2 0来判断并加粗这是一种取巧但有效的写法因为你已经知道了表格列的物理顺序。3. 智能控制考题内容的填充与排版3.1 题库数据用 JSON 组织别把题目写死在代码里出题量大的时候最常见的是把题目直接写在 Python 代码里这样改一题要动脚本而且无法复用。更合理的做法是把题库独立为一个 JSON 文件每个题目用结构化的字段描述题型、题干、选项、答案、分值、难度。下面是一个智能控制选择题的 JSON 结构示例{ questions: [ { id: q01, type: choice, difficulty: 0.6, score: 5, stem: 模糊控制中隶属度函数的取值区间是, options: [[-1, 1], [0, 1], [0, ∞), (-∞, ∞)], answer: 1 }, { id: q02, type: short_answer, difficulty: 0.8, score: 10, stem: 简述 PID 三个参数对系统动态性能的影响。, answer: 比例项减小稳态误差积分项消除残差微分项抑制超调 } ] }设计这个结构的关键不在字段个数而在让脚本能根据 type 字段决定渲染逻辑。choice、short_answer、calculation 三种题型的答题区格式完全不同选择题后面要括号简答题要留空行计算题要留出大块空白并附公式区。把这些逻辑收拢到一个render_question(doc, q)函数里比散落在主循环里清晰得多。import json def render_question(doc, q): 根据题目类型渲染到文档 stem_text f{q[score]} 分、{q[stem]} doc.add_paragraph(stem_text) if q[type] choice: # 选项用三个连续空格分隔保持题面紧凑 option_line .join(f{chr(65i)}. {opt} for i, opt in enumerate(q[options])) doc.add_paragraph(option_line) doc.add_paragraph(答案____) elif q[type] short_answer: # 简答题预留 4 行答题空白用下划线表示 for _ in range(4): doc.add_paragraph(_ * 40) # 加载全部题目 with open(smart_control_bank.json, encodingutf-8) as f: bank json.load(f)[questions] doc Document() for q in bank: render_question(doc, q) doc.save(智能控制期末考试卷.docx)这段代码有两处值得注意第一chr(65 i)把数字索引转成 A/B/C/D 选项字母比硬编码列表灵活第二简答题的答题下划线用的是全角下划线加 40 个字符长度在 Word 里会自动换行但如果你希望固定行数可以改用带下划线的表格行。答案行写在题目下面会干扰考试实际出卷时应把答案抽离到单独的答案卷用q[answer]字段与试卷文档分开渲染。3.2 公式题的三种处理路径按工程成本排序智能控制试卷绕不开数学公式比如 PID 传递函数K_p K_i/s K_d s模糊规则表面看起来像表格实际上也是公式密集型内容。python-docx 对公式的支持很差但有三条路可选成本从低到高方案做法适用场景注意事项文字与上下标模拟用 Word 的 subscript / superscript 属性拼公式简单代数式分式、根号做不到图片插入先用 LaTeX / MathType 渲染公式存成 PNG再用doc.add_picture()插入复杂公式图片分辨率需 300 DPI 以上OMML 原生公式直接用 OpenXML 数学标记写m:oMath节点需要可编辑公式手写 OMML 代码工作量大实际出卷我的选择是第二套方案LaTeX 渲染公式成 PNG统一缩放到合适宽度再插入。这避免被 Word 公式编辑器版本差异坑到也便于把同一公式复用到在线题库。以下代码做了基于pil的图片尺寸自动压缩from docx.shared import Cm from PIL import Image def add_formula_image(doc, image_path, max_width_cm12): 插入公式图片超宽自动等比缩放 img Image.open(image_path) width_cm img.width * 2.54 / 96 # 假设 PNG 是 96dpi换算成厘米 if width_cm max_width_cm: ratio max_width_cm / width_cm doc.add_picture(image_path, widthCm(max_width_cm)) else: doc.add_picture(image_path, widthCm(width_cm))这里的 DPI 假设是 96但 LaTeX 渲染的图通常是 300 DPI 以上用img.info[dpi]去读真实值更准确。如果拿到一张超大尺寸公式图直接插进 Word 会把页面撑爆缩放判断是必要的。插入后记得加一个居中对齐doc.paragraphs[-1].alignment WD_ALIGN_PARAGRAPH.CENTER因为add_picture会在文档末尾新增一个段这个段的索引就是-1直接设置对齐即可。3.3 评分标准表格的自动生成压轴大题往往配评分标准。用 Word 手动画表很麻烦但用脚本生成一个评分表只需循环加行。智能控制试卷里常见的评分表字段是题号、评分点、分值、扣分标准。先建表头再逐行插入数据框线统一用Table Grid样式from docx.enum.table import WD_TABLE_ALIGNMENT score_table doc.add_table(rows1, cols4) score_table.style Table Grid score_table.alignment WD_TABLE_ALIGNMENT.CENTER headers [题号, 评分点, 分值, 采分说明] for i, text in enumerate(headers): score_table.rows[0].cells[i].text text rubric [ [第5题, 模糊规则数确定, 4, 规则数每缺一条扣 1 分], [第5题, 模糊推理过程, 5, 推理步骤缺失扣 3 分], [第5题, 解模糊结果, 6, 计算结果错误扣 4 分], ] for row_data in rubric: cells score_table.add_row().cells for i, text in enumerate(row_data): cells[i].text textadd_row会在表格末尾追加一行新行自动继承表格样式。这个循环本质上是把二维 list 映射到表格单元格数据来源于rubric这个嵌套列表修改评分点不用动 Word 文件。这里要注意Table Grid样式必须在文档里存在python-docx 默认模板中它是内置的但如果从一个空文档开始创建某些样式可能缺失此时可以用doc.styles.add_style()先创建。4. 批量生成智能控制多套试卷的变体控制4.1 随机抽题的边界难度与知识点双重约束出 A/B 卷时用随机抽题可以提升效率但纯随机会导致两张卷子难度波动大。我的做法是用分层抽样先把题库按「难度」和「知识点」两个维度分组再在每组内固定抽取数量。以智能控制为例知识点分 PID、模糊控制、神经网络控制、状态反馈四类难度分 0.3、0.6、0.9 三档共 12 个桶每桶按计划抽取对应题数。import random def pick_questions(bank, plan): 按 plan 指定的 [知识点][难度] 数量抽题plan 是 dict picked [] for (knowledge_point, difficulty), count in plan.items(): # 筛选桶内题目 bucket [ q for q in bank if q[knowledge] knowledge_point and abs(q[difficulty] - difficulty) 0.1 ] # 如果桶内题目不够记录告警不阻塞生成 if len(bucket) count: print(fWARN: {knowledge_point}/{difficulty} 题库不足需要 {count} 实际 {len(bucket)}) picked.extend(random.sample(bucket, min(count, len(bucket)))) return picked plan { (PID, 0.3): 2, (PID, 0.6): 3, (模糊控制, 0.6): 2, (神经网络控制, 0.9): 3, }random.sample是不重复抽样如果桶内经过去重后题目不够sample会抛异常所以这里先用min(count, len(bucket))截断避免直接崩溃。但因为试卷总分是靠题目分值累加的如果抽出来的题目数量不足总分可能不满 100需要在最后按缺口补抽。4.2 A/B 卷防雷同种子、错位与题目互换A/B 卷之间既不能完全相同又不能难度差异过大。常见做法有两个一是给random.seed()设置不同的种子保证抽题路径不同二是对题目顺序做排列错位把 B 卷的选择题顺序循环位移两位。第二种做法不需要重新抽题简单且体积小def rotate_options(question, shift): 将选项列表循环右移 shift 位同时修正正确答案索引 if question[type] ! choice: return question n len(question[options]) if n 0: return question shift shift % n new_options question[options][-shift:] question[options][:-shift] # 正确答案的下标随位移改变 new_answer (question[answer] shift) % n # 复制一份避免外部引用被修改 return { **question, options: new_options, answer: new_answer, }这个函数的技巧在于它同时处理了选项列表顺序和答案索引。如果只挪选项顺序而忘记改answer生成的试卷答案卷就是错的这个 bug 很隐蔽我在这里吃过亏。用{**question, ...}生成新 dict保证原题库对象不被污染这样同一题库可同时生成多套卷。B 卷所有选择题的 shift 建议设为同一个值保证规则一致便于阅卷。4.3 批量保存一套脚本输出多份文件批量生成不只是循环抽题还要处理文件名上的区分。文件名里带上试卷代号和时间戳避免覆盖。import datetime today datetime.date.today().strftime(%Y%m%d) sets {A: 20240615, B: 20240616} for label, seed in sets.items(): random.seed(seed) picked pick_questions(bank, plan) doc Document() # ... 复用第 2 章的页面设置代码 ... for q in picked: render_question(doc, q) filename f智能控制期末考试卷_{label}_{today}.docx doc.save(filename) print(f生成 {filename}总题数 {len(picked)})每次循环必须新建Document()否则题目会累积到同一份文档里。random.seed()要放在pick_questions调用之前并且每个循环都要重新设置否则进入下一轮时随机序列会接着上次的状态继续而不是从种子重新开始。文件名里的today统一在一次运行内计算防止跨天运行时文件名不一致。5. 输出校验、WPS 兼容与交付前的最后检查5.1 不用打开 Word 就能校验 docx 的完整性生成完 docx 直接拖进 Word 看效果这在批量生成场景下太低效。docx 本质是 zip 压缩包可以先做结构层校验python -c import zipfile; fzipfile.ZipFile(智能控制期末考试卷.docx); print(bad file if f.testzip() else zip ok)testzip()返回None表示压缩包内所有文件 CRC 校验通过。但这只能证明文件不是坏的不能证明 Word 能打开。进一步检查[Content_Types].xml是否存在这是 docx 的核心清单python -c import zipfile; zzipfile.ZipFile(智能控制期末考试卷.docx); print(z.read([Content_Types].xml).decode(utf-8)[:200])更实用的验证是统计题量。如果卷面规定共 6 个大题你希望程序自动检查实际生成的题目数量是否吻合。一个技巧是统计 docx 里add_heading生成的标题级段落数或者统计Table Grid表格数。用 python-docx 读回来做断言from docx import Document doc Document(智能控制期末考试卷.docx) # 统计所有段落的文本找出包含“第X题”格式的题目行 import re questions [p.text for p in doc.paragraphs if re.match(r^第[一二三四五六七八九十]题, p.text.strip())] assert len(questions) 6, f题目数量不正确实际 {len(questions)}为什么不用doc.paragraphs直接数因为有的题目在表格内部表格里的段落不在doc.paragraphs里需要遍历doc.tables。所以严格校验要同时把表格里的文本提取出来合并到整个文档文本集合里再做正则匹配。5.2 兼容性问题WPS 默认不新建 docx 的解法WPS Office 是个绕不开的话题尤其很多学校机房只装 WPS。WPS 打开 docx 基本没问题真正的坑在新建文件WPS 默认新建的是.wps格式扩展名和 Word 不互通。如果你把生成的.docx放在 U 盘里发给别人对方用 WPS 双击打开没问题但如果对方用 WPS 打开后点「另存为」默认保存类型可能改成了 WPS 特有的格式返回来时就不是 docx 了。解决办法是在 WPS 里调整设置这不属于文档结构问题而是用户习惯问题。在 WPS 文字中点击「文件 - 选项 - 常规与保存 - 默认格式」把「默认保存格式」修改为Word 97-2021 文档 (*.docx)。这样以后 WPS 里 CtrlS 保存的才是 .docx。对自动化交付场景建议在脚本里显式检查输出文件扩展名from pathlib import Path def ensure_docx_extension(filename): 把扩展名强制成 .docx避免误存成 .doc p Path(filename) if p.suffix.lower() ! .docx: raise ValueError(f扩展名必须是 .docx当前是 {p.suffix}) return str(p)Path.suffix返回小写化前的原始后缀所以要用.lower()比较。这个函数看似多余但在批量生成文件时能拦住那些因为手误把文件名写成.doc的代码路径。5.3 从 docx 到 PDF 的交付转换很多教务系统要求提交 PDF 版或者需要把试卷转成图片用于在线考试。docx 转 PDF 有两个稳定路径在装有 Office 的 Windows 机器上用docx2pdf在 Linux 上用 LibreOffice 命令行。这里给 Linux 上的无头转换命令libreoffice --headless --convert-to pdf 智能控制期末考试卷_A_20240615.docx --outdir ./pdf_output这条命令的核心参数是三个--headless表示无界面运行--convert-to pdf指定转出格式--outdir设置输出目录。转换后的 PDF 文件名与源文件同名只是扩展名不同。坑在于 LibreOffice 的字体渲染如果系统没有宋体转换出来的 PDF 中文会变成方块需要在服务端安装字体fc-cache -fv fc-list | grep 宋体fc-list输出为空说明字体缺失安装fonts-wqy-zenhei或fonts-noto-cjk可以解决。转换后可以再用pdfinfo命令检查页数是否符合预期pdfinfo ./pdf_output/智能控制期末考试卷_A_20240615.pdf | grep Pages如果页数和 Word 里看到的页数不一致优先怀疑字体替换导致的页码偏移。这个检查习惯能在交付前拦住绝大多数渲染问题。本文还有配套的精品资源点击获取