
简介这份《信号与系统》课后答案PDF面向电子工程、通信工程等专业学生及备考南京邮电大学信号与系统分析的学习者聚焦课程习题的对照与复盘尤其适合在周期性判断、离散序列周期、信号合成与抽样等基础章节查漏补缺。资源共1个PDF文件约1.12MB内容围绕第一章基本概念展开涵盖连续时间信号与离散时间序列的周期性判定、基本周期求解、周期信号相加条件证明、均匀抽样后序列波形分析以及能量信号、功率信号与非能非功信号的判别并给出较完整的推导过程和结论。已有3935人学习说明其在课程同步练习和期末复习中有一定参考价值读者可据此核对解题思路理解频率比是否为有理数、抽样间隔与数字角频率之间的关系并借助典型例题梳理易混概念。整体篇幅集中、查阅方便适合作为课堂笔记之外的辅助答案材料。1. 信号与系统课后答案 PDF 不是答案书先当校验器用某同学把信号与系统课后答案 PDF 打印成册一章一章对红笔勾完觉得稳了期中卷子发下来 52 分。翻他的本子三百多道题只有一行行“与答案一致”没有一行写“为什么这一步能这么变”。问题不在答案在于把答案当成了终点。信号与系统这门课的答案有个特殊之处同一个结果能有五六种写法——指数形式、三角形式、留数形式、部分分式形式看起来不一样的和真算错的外观上几乎无法区分反过来看起来一样的也可能藏着收敛域漏写、2π 位置错、单边双边混用这类致命问题。所以这份 PDF 的正确用法是当校验器先自己算再拿它投票对不上时按约定的差异逐条排查而不是照着抄一遍步骤。这篇写给正在啃这门课、手里已经有一份课后答案 PDF 的人也写给想把对答案这件事沉淀成可复用流程的人。2. 从 PDF 到可检索题库文本层判定与题号重建拿到一份几百页的答案 PDF第一反应不该是打开第一页开始读而是先弄清楚它的排版属性。文本层、扫描层、混合层三种情况对应的处理成本差十倍以上文本层半小时能建完索引扫描层要先渲染再识别、公式区域还得单独裁混合层最麻烦正文能抽但公式变成了图片抽出来的文本会在关键位置断掉。先花五分钟做判定能省掉后面几天的返工。2.1 三行统计判断这份 PDF 是文本层还是扫描层pdfplumber 把每一页解析成字符对象、图片对象和线条对象的集合。文本层页面的chars数量通常上千扫描层几乎是 0因为整页就是一张位图。import pdfplumber PDF_PATH signals_systems_answers.pdf with pdfplumber.open(PDF_PATH) as pdf: print(总页数:, len(pdf.pages)) for i, page in enumerate(pdf.pages[:20], start1): n_chars len(page.chars) # 字符对象数文本层页面通常上千 n_images len(page.images) # 图片对象数扫描页通常 12 text page.extract_text() or n_lines len(text.splitlines()) print(fp{i:03d} chars{n_chars:5d} images{n_images:2d} lines{n_lines:3d})这段代码只做一件事抽样前 20 页把三个指标打出来。逻辑说明上没什么玄学关键是阈值怎么定。chars的绝对数量受字号、页边距、公式密度影响很大所以别死记一个数先看分布如果 20 页里有 18 页的chars都在 800 以上剩下 2 页低那多半是插图页而不是扫描页如果整批chars都低于 100 而images稳定为 1直接判定扫描件走 OCR 路线。参数上还有两个细节值得注意。extract_text()默认按字符的 top 坐标排序遇到双栏排版会把左右两栏串成一行视觉上很乱但用于判断“有没有文本层”完全够用。真正抽取阶段要换成extract_text(layoutTrue)它保留列间空白双栏串行会明显减少。类型前 20 页表现处理方式预计耗时纯文本层chars 普遍 800lines 连续pdfplumber 直接抽正则切题号半小时到两小时扫描层chars 50images ≥ 1300dpi 渲染后 OCR公式单独裁图一到三天混合层部分页 chars 在 200800 之间正文走文本层公式段落人工补或裁图识别半天到两天混合层的识别有个小技巧按行统计字符密度。正文段落每行的chars分布稳定公式行会骤降找到密度断崖的位置就找到了公式区。这一步不用写复杂代码把每页的len(line)打印出来扫一眼就能看出来。2.2 信号与系统课后答案 PDF 的题号抽取从整页文本到三列索引题号是整份答案 PDF 里最稳定的锚点。不管答案正文多乱题号一定出现在每道题的开头而且格式高度可预测2-15、2.15、2.15(a)、题 2-15基本逃不出这四种。import re, csv, pdfplumber QID re.compile( r^\s*(?:题\s*)?(\d{1,2})\s*[-–.]\s*(\d{1,3})\s* r(?:[(]\s*([a-z0-9])\s*[)])? ) def split_by_anchor(page_text, pattern): 把一页文本按题号锚点切成 (锚点行, 正文块) 列表 lines page_text.splitlines() idx [i for i, ln in enumerate(lines) if pattern.match(ln)] blocks [] for k, i in enumerate(idx): j idx[k 1] if k 1 len(idx) else len(lines) blocks.append((lines[i], \n.join(lines[i 1:j]).strip())) return blocks rows [] with pdfplumber.open(PDF_PATH) as pdf: for pno, page in enumerate(pdf.pages, start1): # 裁掉上下各 5% 的页眉页脚避免页码混进正文块 body page.crop((0, 0.05 * page.height, page.width, 0.95 * page.height)) text body.extract_text(layoutTrue) or for head, content in split_by_anchor(text, QID): m QID.match(head) chap, num, sub m.group(1), m.group(2), m.group(3) or rows.append({ page: pno, qid: f{chap}-{num}{sub}, head: head.strip()[:100], content: content[:2000], }) with open(answer_index.csv, w, newline, encodingutf-8-sig) as f: w csv.DictWriter(f, fieldnames[page, qid, head, content]) w.writeheader() w.writerows(rows) print(抽到题号条数:, len(rows))逻辑说明里最重要的是“为什么先抽锚点再切块”而不是一次性用正则把题号和答案一起抓出来。答案正文可能跨页、跨栏、跨段一次性正则几乎必然在跨页处崩掉。先拿到“题号 → 起始行”的锚点序列再按相邻锚点之间的区间切块跨页的那道题会自动把下一页开头的内容吞进自己的块尾——这恰好是想要的行为。参数说明上crop的 5% 是个经验值主要针对页脚页码和页眉书名如果你的 PDF 页边距特别窄这个比例要往下调否则会切掉正文首行。content截到 2000 字符是为了控制 CSV 体积真要完整正文把这个上限放开、或者改成把每块单独存成一个 txt 文件索引 CSV 里只留页码和锚点行。中文编码固定用utf-8-sig否则用表格软件打开会乱码。layoutTrue在双栏页面上仍有局限题号可能被并到行中间这时把pattern.match换成pattern.search同时在切块前把长行按两个以上连续空格劈开。这个修补不复杂但一定要在抽完之后抽查别直接进下一步。2.3 题号体系对不上时用一张映射表把两本书钉在一起真实情况里答案 PDF 的题号和课本的题号经常不是一套。有的按节编号有的按章编号有的答案里连小节标题都没了只剩纯序号。硬对齐会浪费大量时间一张三列映射表就能解决。book_qidanswer_qidmatch_typenote2-152-15exact直接命中2-162-17offset答案 PDF 多插了一道例题2-18missing答案 PDF 无此题去别处找2-19a2-19manual答案未分子问需人工拆生成这张表的思路是先把两边的题号都列成有序集合求差集看差集是不是常数偏移。是的话批量加偏移量不是的话把连续匹配的段落找出来只在断点处人工干预。一份三百题规模的答案 PDF自动对齐能覆盖 70% 到 85%剩下的二三十题手工标一遍二十分钟的事。提示missing那几行别急着补。有些课后题本来就是证明题或编程题答案 PDF 里没有是正常的先把它们单独拉一个列表避免每次翻到都重新确认一遍。3. 逐题反向校验用 sympy 把变换、卷积和系统响应重算一遍对答案这件事最容易翻车的地方是只比对最后一行。信号与系统的题最后一行往往是某种化简形式两条完全不同的推导路径可能收敛到同一个式子也可能收敛到两个看起来不一样但等价的式子。真正可靠的比对方式是走三条互相独立的路径三条都过才算通过。3.1 三个校验锚点可逆性、极点与收敛域、变换域乘积第一个锚点是可逆性。正变换做一遍再反变换做一遍看能不能回到原函数。这个检查抓的是定义层面的一致性——如果你的正变换用的是教材约定反变换也必须用同一套中间混入别的约定会立刻暴露。第二个锚点是极点位置与收敛域。极点决定自由响应的形式收敛域决定因果性与单双边。很多答案 PDF 只写极点不写收敛域或者只在章首统一声明“以下默认因果”这种省略在简单题里没事在多值反变换的题里就是灾难。第三个锚点是变换域乘积等于时域卷积。这条路径和前两条完全独立前两条都在同一个变换域里打转第三条跨越两个域一旦结果一致基本可以排除计算错误。三条都过还和答案对不上那八成是约定差异不是算错。3.2 拉普拉斯与 Z 变换的校验脚本骨架import sympy as sp t, s, z, n sp.symbols(t s z n, realTrue) w sp.symbols(omega, realTrue) f_repr sp.symbols(f_repr, realTrue) # sympy 傅里叶变换的默认自变量 def ctft(expr): 封装成教材约定 F(jw) ∫ f(t) e^{-jwt} dt F_f sp.fourier_transform(expr, t, f_repr) # sympy 内部用 e^{-j2πf t} return sp.simplify(F_f.subs(f_repr, w / (2 * sp.pi))) def ztrans(expr): 单边 Z 变换sympy 无内置函数用求和代替 return sp.simplify(sp.summation(expr * z**(-n), (n, 0, sp.oo))) # 例f(t) e^{-3t} u(t) f sp.exp(-3 * t) * sp.Heaviside(t) Fs sp.laplace_transform(f, t, s, nocondsTrue) print(L{f} , sp.simplify(Fs)) # 1/(s 3) print(回验 , sp.simplify(sp.inverse_laplace_transform(Fs, s, t))) print(CTFT , ctft(f)) # 1/(3 I*omega) # 例x[n] a^n u[n] a sp.symbols(a, realTrue) print(Z{x} , ztrans(a**n * sp.Heaviside(n)))逻辑说明部分重点看两个封装。ctft这个 wrapper 不是可选的是必须的sympy 的fourier_transform用的是e^{-j2πft}定义和绝大多数教材的e^{-jωt}差一个 2π 换元。直接拿输出和答案比对会得到“差 2π”的假警报然后开始怀疑自己或者怀疑答案浪费一晚上。这里做的替换是f ω/(2π)注意只有一个替换、没有额外系数因为两个定义都是关于各自自变量的密度函数。ztrans用求和实现原因是 sympy 没有内置 Z 变换。这让它天然只支持单边n 从 0 到无穷双边 Z 变换要把下界改成-sp.oo。另外sp.summation返回的结果经常带Piecewise条件那个条件就是收敛域的一部分别急着用simplify把它抹掉先看一眼条件里的不等式是不是|a/z| 1这种形式。参数说明还有一处容易忽略Heaviside(0)在 sympy 里默认是1/2教材里多数写u(0)1。这个差异在纯符号推导里看不出来但在画图、做初值定理、或者跟数值结果比对时会显形。要么全程用sp.Heaviside(t, 1)显式指定要么在结论里注明这个约定差异。3.3 卷积和差分方程两条互相独立的验证路径离散卷积用 numpy 最快但索引起点必须自己记这是最容易被忽略的一步。import numpy as np x np.array([1, 2, 3]) # x[0]1, x[1]2, x[2]3 h np.array([1, -1]) # h[0]1, h[1]-1 y np.convolve(x, h, modefull) n0 0 0 # 起点 x 起点 h 起点 print(n0, y) # 0, [1 1 1 -3] # 连续卷积y(t) ∫ x(τ)h(t-τ)dτ tau sp.symbols(tau, realTrue) xt sp.exp(-2 * t) * sp.Heaviside(t) ht sp.Heaviside(t) yt sp.integrate(xt.subs(t, tau) * ht.subs(t, t - tau), (tau, -sp.oo, sp.oo)) print(sp.simplify(yt)) # (1 - exp(-2t)) * Heaviside(t) / 2离散那段的逻辑说明np.convolve只关心数值不关心时间轴。如果x是从n-2开始的序列你传进去的是[x[-2], x[-1], x[0], ...]输出的第一个元素对应的是n-20-2不是 0。所以每次卷积前先把两个序列的起点写下来卷积后把n0补上否则答非所问。连续那段两个subs的写法值得注意积分变量必须是tau而不是t。x(t-τ)要写成xt.subs(t, t - tau)h(τ)写成ht.subs(t, tau)——顺序很容易搞反搞反之后得到的是相关而不是卷积结果对称性完全不同但在某些例子里数值恰好一样属于典型的“错得看不出来”。差分方程这条路径用scipy.signal独立验证from scipy import signal b, a [1.0], [1.0, -0.8] # y[n] - 0.8y[n-1] x[n] _, h signal.dimpulse((b, a, 1), n8) print(h[0].ravel()) # [1, 0.8, 0.64, ...]这条路径的价值在于它绕开了符号推导dimpulse直接由系数递推和手推的h[n]0.8^n u[n]对不上说明系数抄错了或者方程整理错了。三步验证下来还和答案 PDF 不一致那基本可以确定是约定问题而非计算问题。4. 符号约定对照答案和你课本对不上的六组地方约定差异是这类答案 PDF 最集中的坑源。同一道题你的推导和答案逐行不同但可能都对只是站在不同的定义上。把下面六组先对齐能少掉大半的自我怀疑。4.1 变换定义里的 2π 与正负号项目常见约定 A常见约定 B换算关系连续傅里叶变换F(ω)∫f(t)e^{-jωt}dtF(f)∫f(t)e^{-j2πft}dtF(ω)F(f)取fω/2π反变换系数1/(2π)在反变换前1在正变换前系数整体平移指数符号正变换e^{-jωt}正变换e^{jωt}频谱整体共轭翻转傅里叶级数指数型系数含1/T三角型系数含2/Ta_n、b_n与c_n差因子 2Z 变换用z^{-n}用z^{n}收敛域内外互换DFT 与 DTFTX(e^{jω})连续X[k]离散ω2πk/N这张表最实用的地方是第二行和最后一行。系数位置决定了你在做能量计算、帕塞瓦尔定理验证时会不会差一个2π而 DFT 与 DTFT 的关系决定了你在用 FFT 做数值验证时横轴该用k还是ω以及幅值要不要除以N。注意numpy.fft用普通频率形式且不做1/N归一化教材用角频率形式且在反变换处带1/(2π)。用 FFT 验证手算频谱时横轴换算、幅值换算、相位符号三样都要动缺一不可。4.2 收敛域、冲激尺度与初值终值定理的适用边界收敛域这条经常被简化成“默认因果”。简化在单边题里没问题但在双边题里直接错。以F(s)1/(sa)为例ROC: Re(s) -a对应e^{-at}u(t)ROC: Re(s) -a对应-e^{-at}u(-t)两个结果符号相反、支撑区间相反只写极点位置是分不出来的。离散同理H(z)1/(1-az^{-1})|z||a|是右边序列|z||a|是左边序列且带负号。冲激尺度这条考的是δ(at)δ(t)/|a|。很多答案 PDF 在化简过程中直接用了这个等式却没标出来你按原式推就会差一个系数。相关的还有u(t)在 0 点的取值以及δ(t)与u(t)的求导关系在 0 点附近的处理——这些细节在纯符号层面无害但在数值仿真里会变成一两个采样点的偏差采样率越高偏差越明显。初值定理和终值定理各有前提条件不满足时公式给出的是错误答案而不是近似答案。终值定理要求sF(s)的极点全部位于左半平面离散情形是(z-1)X(z)的极点全部位于单位圆内只要虚轴上有一对共轭极点稳态值就不存在套公式算出来的数字没有任何意义。初值定理要求F(s)是真分式分子阶数高于或等于分母时先做长除。4.3 部分分式展开系数对但形式错的三种典型第一种是假分式没做长除。分子阶数不低于分母时直接展开会得到一堆看似合理的系数但缺少多项式部分反变换里少了冲激项。第二种是重极点。F(s)1/(sa)^2需要写成A/(sa) B/(sa)^2两项只写一项的话系数怎么算都不对或者算出来只有一个系数被强行凑上。三重极点要三行规律是先按最高次写到一次。第三种是共轭极点写成了复指数还是三角。1/(s^22s5)的极点是-1±2j写成e^{-t}(Acos2t Bsin2t)和写成两个复指数项再合并最终结果一致但中间系数完全不同。拿答案比对时先在同一个形式下对齐再去比数值。留数法求系数有个隐藏前提只对单极点成立。(sa)F(s)在s-a处取值这个操作在单极点时给出A在重极点时给出的只是最高次项的系数剩下的还得再求导。翻车现场通常是系数算出来一半对一半错然后怀疑是符号问题。5. 避坑与排查拿课后答案刷题最常见的 5 类翻车下面五条都是“看起来算对了、实际错了”的类型共同特点是结果和答案长得像只是差一点点。5.1 五条血泪记录现象、原因、解决第一条变换结果一致反变换差一个u(t)或差一个负号。现象是拉普拉斯变换算出来和答案完全一样反变换回去少了阶跃、或者符号反了怎么检查都找不到算术错误。原因是收敛域没写题目默认的是单边还是双边没有确认答案 PDF 在章首统一声明过一次“本章默认因果”你翻到中间早就忘了。解决办法是每题强制在变换结果后面手写一行ROC:双边题尤其要写清楚。写不出来就说明这题还没做完。第二条离散卷积结果比手算短一截或者多出尾部一项。现象是np.convolve的输出长度是len(x)len(h)-1和手算对不上或者数值对得上但时间轴整体平移了。原因是序列起点不是 0np.convolve不知道这件事。解决办法是全程维护起点变量n0 nx0 nh0输出索引显式写成n0 np.arange(len(y))。养成习惯之后这类错基本绝迹。第三条sympy 的傅里叶变换结果多了或少了 2π。现象是用sp.fourier_transform算出来的式子和答案差一个常数因子或者ω位置上出现2π。原因是 sympy 用e^{-j2πft}定义。解决办法是用本文 3.2 的 wrapper 做一次fω/(2π)替换不要手工调系数手工调必然在一次次的题里调错方向。第四条终值定理算出稳态值数值仿真却发散。现象是套lim_{s→0}sF(s)得到一个有限数但用scipy.signal跑阶跃响应输出一路涨上去。原因是系统在虚轴上有极点稳态根本不存在。解决办法是在套公式之前先算极点np.roots(a)实部只要有一个 ≥ 0 就停下来别往下算。这条在考试里也是高频陷阱。第五条采样定理相关的题答案差整整 2 倍。现象是奈奎斯特频率算出来是答案的一半或两倍。原因是角频率和普通频率混用了rad/s与Hz之间差一个2π而很多答案 PDF 在题干里用rad/s、在结论里写Hz中间不声明。解决办法是全程带单位先把所有频率统一到Hz算完再换回去中间过程一个2π都不许省。5.2 一份五分钟排错清单对不上答案时按顺序过一遍绝大多数问题在前三步就能定位。顺序检查项判断依据处理1单位是否统一频率是 Hz 还是 rad/s全部换成 Hz 再比2收敛域是否写出双边题有没有 ROC 行补 ROC 后重做反变换3序列/信号起点离散题起点是不是 0补 n0 偏移4单边还是双边变换是否含 t0 部分与章首声明对齐5变换定义约定2π 与正负号用 wrapper 重算6形式是否等价三角 vs 指数统一形式后再比数值第六步是最容易被跳过的一步。两个形式上完全不同的表达式可能恒等尤其在含sin、cos、复指数的结果里。判断方法很土但有效随便代三个数值进去看数值是否一致。三个点都对上基本可以认为等价。6. 数值反演兜底当答案、课本和你的推导三方打架时符号推导走到最后三方不一致继续在纸上纠缠的收益很低这时候让数值投票。思路是把系统函数直接喂给scipy.signal算出频响和冲激响应再和手算结果在几个频点、几个时间点上比数值。这一步不关心形式只关心数。import numpy as np from scipy import signal # H(s) 1/(s^2 3s 2)手算应为 1/((s1)(s2)) sys_c signal.lti([1.0], [1.0, 3.0, 2.0]) w np.array([0.1, 1.0, 10.0]) _, H signal.freqresp(sys_c, ww) print(np.round(np.abs(H), 6)) print(np.round(np.angle(H), 6))比对时看两个量幅值和相位。手算的|H(jω)| 1/sqrt((2-ω²)² 9ω²)在ω1处是1/sqrt(19)0.3162脚本输出对上就说明分母系数没抄错。相位更容易暴露符号问题ω0.1时相位接近 0ω10时接近-π如果符号反了一眼就能看出来。连续系统想验证离散结论用cont2discrete做一次离散化再跑lfilter把离散冲激响应和手算的h[n]逐点比。这一步的价值在于它同时验证了 Z 变换结果、差分方程系数、以及收敛域对应的因果性——三条线上任何一条错了冲激响应的形状都会变。我自己踩得最深的一次是一道二阶系统的阶跃响应答案 PDF 写的是欠阻尼我算出来是临界阻尼反复检查了四遍推导都没找到问题。最后把阻尼比代进signal.lti跑了一遍发现是我把特征方程的中间项系数抄成了2实际是2√2一个根号被我漏掉了。纸面推导里根号和数字长得很像眼睛会自己骗自己。从那以后我养成一个习惯凡是含根号、含2π、含分数的题算完一定用数值过一遍哪怕只代一个点。符号推导负责给形式数值负责给信心两样都有了才敢在答案 PDF 上打那个勾。希望帮到你。本文还有配套的精品资源点击获取