信号与系统学习:波形变换、周期判定与系统建模的实用方法

发布时间:2026/9/18 6:14:22
信号与系统学习:波形变换、周期判定与系统建模的实用方法
简介《信号与系统第三版陈生潭著课后习题答案》为电子工程、通信及相关专业学习信号与系统课程的学生提供配套解析适合正在夯实基础、备考期末或考研复习的读者参考使用。整份资源为1份PDF文档总大小6.39MB排版清晰可方便在电脑、平板或手机上阅读和打印。目前已有六百八十三人学习使用。内容围绕教材重点章节展开系统覆盖连续与离散信号的波形图绘制、典型信号如指数信号、正弦信号、阶跃信号以及指数序列、正弦序列的图形识别、信号解析表达式的求解以及周期信号的判断与周期计算等核心环节针对阶跃函数性质、信号平移、反转、展缩变换等容易出错的地方给出了较为详细的推导过程和说明有助于学生将理论知识点转化为实际分析与解题能力。1. 从波形图到解析表达式信号与系统第一道坎的拆解思路手头这份陈生潭《信号与系统》第三版的课后习题答案第一章花了大量篇幅在波形绘制、信号平移反转、周期判定这类基本功上。很多人觉得这些题简单但真正动手做才发现卡壳点往往不在计算而在对阶跃函数、冲激函数这些奇异信号的理解以及对波形变换操作顺序的把握。这份答案的典型价值在于它不只是给出最终波形还把每种变换的中间步骤拆开了——比如先反转再平移还是先平移再反转两种路径画出来的波形很容易搞混。本文从这些习题里挑出几个有代表性的技术点结合数值验证手段讲讲这类题怎么做、参数怎么调、验证时看什么。适合正在学信号与系统、准备考研专业课或者做信号处理相关开发但基础需要回炉的读者。2. 连续信号的波形变换平移、反转、展缩的运算顺序2.1 为什么先平移再反转和先反转再平移结果不同答案中反复出现的一个操作模式是f(at b)类信号的波形变换。以习题中f(-t 2)为例常见做法有两种路径方法一先反转再平移先将f(t)反转得到f(-t)然后将整个波形右移 2 个单位得到f(-(t-2)) f(-t2)。方法二先平移再反转先将f(t)左移 2 个单位得到f(t2)再反转得到f(-t2)。这两条路径的视觉效果完全不同——方法一里右移是在反转后的坐标系上操作方法二里左移是在原始坐标系上操作。习题 1-4 中的信号f(2 - t)就是这个典型答案明确标注了翻转后右移 2 个单位或左移 2 个单位后翻转两种等价路径。判断平移方向的技巧先把f(at b)改写成f(a(t b/a))然后看b/a的符号。b/a 0时波形在时间轴上向左移b/a 0时向右移。这个b/a才是真正的平移量直接看b的符号容易出错。2.2 用 Python 验证波形变换的数值结果理论推完建议用数值方法验证一遍。以下代码用 numpy 构造一个分段信号分别实现平移、反转、展缩三种操作import numpy as np import matplotlib.pyplot as plt t np.linspace(-4, 6, 1000) # 原始信号宽度为 2 的矩形脉冲幅度 1 f lambda x: ((x 0) (x 2)).astype(float) # 平移: f(t - 1) - 右移 1 个单位 f_shift f(t - 1) # 反转: f(-t) - 关于 t0 对称翻转 f_reverse f(-t) # 展缩: f(2t) - 时间轴压缩 2 倍 f_scale f(2 * t) # 复合操作: f(-t 2) f(-(t - 2)) f_composite f(-t 2) fig, axes plt.subplots(2, 2, figsize(10, 6)) for ax, signal, title in zip( axes.flat, [f_shift, f_reverse, f_scale, f_composite], [f(t-1), f(-t), f(2t), f(-t2)] ): ax.plot(t, signal) ax.set_title(title) ax.set_ylim(-0.2, 1.2) plt.tight_layout() plt.show()代码逻辑说明f是原始矩形脉冲的 lambda 表达式f(t-1)等写法利用了 numpy 的数组广播机制逐元素计算函数值。f(-t2)的写法直接对应f(-(t-2))即反转后右移 2 个单位。关键参数说明np.linspace(-4, 6, 1000)的时间范围选择要覆盖信号在变换前后的全部非零区间构造矩形脉冲时用的是(x 0) (x 2)这种布尔掩码而非np.where是为了避免在边界处产生歧义——0 取左边界2 取右边界符合阶跃函数的惯例。如果把边界条件写成(x 0) (x 2)采样点恰好落在边界上时波形会出现异常尖峰这是数值绘图常见的坑。2.3 常见误用混淆f(atb)与f(a(tb))习题答案里叮嘱的另一点是f(2t - 4)化成f(2(t - 2))再做展缩平移而不是先对2t展缩再平移几步。很多初学者遇到的典型错误是把f(2t - 4)当成先压缩 2 倍再左移 4 个单位正确做法是先压缩 2 倍再右移 2 个单位。原因在于波形变换的运算对象是自变量t本身f(2t - 4)的平移量必须从2t - 4 2(t - 2)中提取。如果先把2t - 4看成2(t - 2)那么平移量是-(-2)即右移 2 个单位。做题时建议每一步都写出中间函数表达式而不是直接在原图上比划。这样即便最后图形画错了中间步骤还能看出是哪一步的符号出了问题。3. 周期信号判定有理数比值判据及其边界情形3.1 连续时间信号的周期相加判据习题第 3 题涉及一个基础判定规则两个周期分别为T1和T2的连续信号相加当T1/T2为有理数时和信号是周期的周期取T1和T2的最小公倍数当比值为无理数时和信号非周期。这个题里最典型的是cos(t) cos(√2 t)的情形。T1 2πT2 2π/√2比值为√2无理数所以整个信号不是周期的。这组题目还考察了三角恒等变换的灵活运用比如sin(2t) cos(t/3)这类利用和差化积把非线性运算转化为标准周期信号的线性组合从而应用周期判据这比盲目套用公式更有效。判断时有个容易踩的坑正弦/余弦信号经过偶次幂运算后周期可能减半。比如cos²(t)的周期是π而不是2π因为cos²(t) (1cos(2t))/2。习题中有一道cos²(2t) sin(√2 t)如果直接把cos²(2t)的周期当成π会得到两个分量周期比值为π / (√2π) 1/√2依然是无理数结论不变但如果题目换成cos²(t) cos(2t)前者周期π、后者周期也是π比值为有理数和信号是周期的——这里把cos²(t)当成周期2π就会得出错误结论因为两者最小公倍数的计算起点就错了。3.2 离散序列的周期判定与数值验证离散信号部分有个关键区别序列周期必须是正整数。sin[0.5n]这类信号即使形式上像正弦只要数字频率0.5与2π的比值不是有理数序列就不是周期的。这一点在习题中通过cos(0.5πn)和sin(0.3πn)这类例子反复训练。import numpy as np def is_periodic(seq_func, n_max200, max_period50): 检测一个离散序列是否为周期序列 seq_func: 接受整数 n 返回序列值的函数 n_max: 检测的序列长度 max_period: 尝试的最大周期 n np.arange(n_max) seq seq_func(n) for T in range(1, max_period 1): # 比较 seq[n] 与 seq[nT]允许浮点误差 if np.allclose(seq[:n_max - T], seq[T:], atol1e-8): return True, T return False, None # 测试1: cos(0.5π n)周期应为4 is_periodic(lambda n: np.cos(0.5 * np.pi * n)) # 输出: (True, 4) # 测试2: sin(0.3π n)周期应为20 is_periodic(lambda n: np.sin(0.3 * np.pi * n)) # 输出: (True, 20) # 测试3: cos(0.5n)数字频率 0.5/(2π) 为无理数非周期 is_periodic(lambda n: np.cos(0.5 * n)) # 输出: (False, None)代码逻辑is_periodic枚举 1 到max_period范围内的所有可能周期对每个候选周期T比较序列的前n_max - T个点与后n_max - T个点是否一致。np.allclose的atol参数设为1e-8是为了容忍浮点运算的舍入误差——如果直接用比较cos(π/2)的数值结果未必严格等于 0会误判为非周期。n_max取值 200 足够覆盖题目里最长的周期如 20max_period取 50 则是对检测范围的一个合理上界。3.3 周期计算中的最小公倍数陷阱答案里有一道sin(3t) cos(2t) tan(t/2)的复合信号周期计算T1 2π/3、T2 π、T3 2π最小公倍数为2π。这类题的计算不复杂但容易忽略的是三个信号的周期比T1/T2 2/3、T2/T3 1/2都是有理数但需要逐个验证两两比值不能只看其中两组就下结论。如果其中一组比值为无理数整个信号就直接判为非周期不需要继续算最小公倍数。另外注意周期信号相加后如果出现某些分量的系数恰好为零实际周期可能比理论最小公倍数更小。比如sin(t) sin(2t)的理论周期是2π但如果在某道题里发现化简后实际周期只是π需要警惕是否在化简过程中丢失了奇次谐波分量——这种情况在三角恒等变换后偶尔出现验证时值得多做一步检查。4. 从电路到系统方程微分方程与差分方程的建模路径4.1 RLC 电路的输入输出方程KCL/KVL 与消元法答案第 1-12 题给出了一个 RLC 电路的标准解法流程先列 KCL 和 KVL 方程再消去中间变量最后整理成只含输入输出的一阶或二阶微分方程。以电路习题为例其推导过程可以概括为标记节点电压和回路电流写出节点 KCL 方程电容电流与电压的关系i_C C dv_C/dt写出回路 KVL 方程电感电压与电流的关系v_L L di_L/dt将中间变量逐一代入消去非输入输出变量整理成标准形式a_2 y(t) a_1 y(t) a_0 y(t) b_1 x(t) b_0 x(t)这套方法放到更一般的电路里依然成立。实际做题时如果电路里电容和电感个数加起来超过 2 个消元复杂度会急剧上升。这时候建议先用符号计算工具做一次代数消元再用人工验证import sympy as sp t sp.symbols(t) R, L, C sp.symbols(R L C, positiveTrue) x sp.Function(x) y sp.Function(y) # 以典型二阶电路为例: y (R/L) y (1/LC) y (1/LC) x # 验证特征方程根与元件参数的关系 s sp.symbols(s) char_eq sp.Eq(s**2 (R/L) * s 1/(L*C), 0) roots sp.solve(char_eq, s) roots代码说明sympy的Function(x)和Function(y)只是声明符号函数不展开具体表达式。输出结果会给出特征根s1, s2的解析形式——若(R/L)^2 - 4/(LC) 0为过阻尼等于 0 为临界阻尼小于 0 为欠阻尼。这个判断在后续分析系统响应时直接决定了解的形式是实指数、te^(-αt)还是衰减振荡。参数说明positiveTrue约束 R、L、C 为正数可以避免sympy在求根时产生不必要的分支讨论。sp.Eq定义了方程对象sp.solve返回的是符号解列表。4.2 差分方程的建立从实际问题到递推关系答案里的人口模型和经济开发区模型是差分方程建模的典型素材。人口模型的递推关系是y[n] (1 α - β) y[n-1] x[n]其中α是出生率、β是死亡率、x[n]是第n年迁入人口。这是一个一阶线性常系数差分方程整理成标准形是y[n] - (1 α - β) y[n-1] x[n]。经济开发区模型的递推关系更复杂一些第n年的资金总额y[n] (1 20%) y[n-2] (1 5%) x[n-1] x[n]它依赖y[n-2]而不是y[n-1]因为资金投入后第二年度才开始有回报第三年度起回报率稳定在 20%。这意味着系统的记忆长度是 2 年对应的差分方程阶数是 2。import numpy as np def simulate_diff_eq(a_coeffs, b_coeffs, x, y_init): 求解差分方程: sum_{k0}^{N} a_k y[n-k] sum_{k0}^{M} b_k x[n-k] a_coeffs: 包含 a_0, a_1, ..., a_N其中 a_0 通常为 1 b_coeffs: 包含 b_0, b_1, ..., b_M x: 输入序列 y_init: 初始条件 [y[-1], y[-2], ...] N len(a_coeffs) - 1 M len(b_coeffs) - 1 y np.zeros(len(x)) y_history list(y_init) # y[-1], y[-2], ... for n in range(len(x)): # 计算输入项 input_sum sum(b_coeffs[k] * (x[n - k] if n - k 0 else 0) for k in range(M 1)) # 计算输出历史项 output_sum sum(a_coeffs[k] * (y_history[-k] if k 0 and k len(y_history) else 0) for k in range(1, N 1)) y[n] (input_sum - output_sum) / a_coeffs[0] y_history.insert(0, y[n]) return y # 人口模型: y[n] - 1.01 y[n-1] x[n]出生率1%、死亡率0.5%逐年迁入100人 x np.full(20, 100) y simulate_diff_eq([1, -1.005], [1], x, [0]) print(y[:5]) # 前5年的资金总额这个函数里有个值得注意的边界处理计算x[n-k]时如果n-k 0则视为 0这是因果系统的默认假设——输入在n0之前不存在。y_history用insert(0, ...)维护最近N个输出值保证y_history[-k]永远指向y[n-k]。如果初始条件给的是y[0]而不是y[-1]需要先手动迭代一步算出y[0]再传入。4.3 状态空间方程为什么选电容电压和电感电流作为状态变量答案第 1-16 题要求以电容电压和电感电流为状态变量写出电路的状态空间方程。选择这两类物理量作为状态变量的原因在于电容的储能1/2 C v_C²和电感的储能1/2 L i_L²决定了系统的动态行为——给定当前时刻的状态变量值和输入系统的未来演化就完全确定了。电阻上的电压电流由其他变量代数决定不携带记忆信息所以不需要作为状态变量。写状态方程的步骤可以抽象成一套固定的流程先选状态变量再列 KCL/KVL 方程然后把所有状态变量的一阶导数单独解出来最后整理成矩阵形式x(t) A x(t) B u(t)。这里面最容易出错的地方有两个一是电容电压和电感电流的参考方向必须和列方程时保持一致否则符号会乱二是如果有受控源消元时容易产生循环依赖需要耐心代入。5. LTI 系统性质判断与做题自查的实用技巧5.1 线性、时不变、因果、稳定四个性质的快速判断流程习题中反复出现的四性质判断可以整理成一套固定步骤线性先检查响应是否可分解为零输入响应和零状态响应之和。习题中的典型反例是y(t) x²(t)——不满足可分解性直接判非线性时不变把输入延迟T看输出是否也延迟T。这里有个技巧如果系统方程中有任何显含t的系数比如乘了一个2t几乎可以立刻判定为时变系统因果输出是否只依赖当前和过去的输入。积分从-∞到t的运算是因果的从t到∞的积分是非因果的稳定有界输入是否保证有界输出。y(t) ∫ x(τ)dτ从-∞到t就是不稳定的因为常数输入会产生线性增大的输出答案里有一道综合题让判断y(t) x(2t)的因果性。很多学生容易出错输入x(t)在t1时刻的值影响输出y(t)在t0.5时刻的值也就是说系统预见了未来的输入所以是非因果的。这是一个很典型的反直觉结论考试中也经常出现——凡是输入参数被压缩时间的系统x(at)a 1必然是非因果的。5.2 用响应的线性组合验证系统性质课后习题里有这么一类题已知线性系统在两对初始状态和输入下的响应求第三对状态和输入下的响应。这类题的解法不复杂但做起来容易漏项。要理解这类题的正确做法关键在于把完全响应拆成零输入响应加零状态响应首先从已知条件中分离出零输入部分和零状态部分然后利用线性系统的比例性和叠加性进行组合运算。验证方法也很直接预设一个满足线性性的系统模型把已知条件代入确认分离出来的零输入/零状态响应满足可加性和齐次性。import numpy as np # 验证: 给定系统输出 y(t) 2*y_zi(t) 3*y_zs(t) # 在已知 y_zi1, y_zs1, y_zi2, y_zs2 的情况下计算组合响应 t np.linspace(0, 5, 500) # 模拟零输入响应: 指数衰减 y_zi1 2 * np.exp(-2 * t) # 初始状态1 y_zi2 3 * np.exp(-2 * t) # 初始状态2 # 模拟零状态响应 y_zs1 np.exp(-t) * np.sin(2 * t) # 输入1 y_zs2 0.5 * np.exp(-t) * np.sin(2 * t) # 输入2 0.5 * 输入1 # 新状态: x1 系数为 2, x2 系数为 3; 新输入: 系数为 4 y_expected (2 * y_zi1 3 * y_zi2) (4 * y_zs1) # 模拟另一种加和路径确认结果一致 y_alternative (2 * y_zi1 4 * y_zs1) (3 * y_zi2) np.allclose(y_expected, y_alternative, atol1e-10)代码逻辑这段代码验证的是线性系统的分步计算一致性——先把输入 1 的零输入和零状态部分组合起来再加上输入 2 的部分与统一按线性组合计算的结果一致。np.allclose返回True说明分解路径不影响最终结果这正是线性系统的核心性质。5.3 做题自查的三个实用技巧做完波形变换题后推荐三个快速自查的方法第一数值抽查。用 Python 把最终波形算出来和手绘结果做对比。重点检查信号值跳变点的横坐标是否和理论推导一致——如果答案是右移 2 个单位那么原信号在t0处的跳变点应该出现在t2处。第二边界确认。如果信号是因果的t0时为零做完平移展缩后要重新检查因果性是否被破坏。比如f(t)是因果的但f(-t2)在t0区间有值这是正常的因为反转操作会改变信号的时间方向。这里的关键是看题目是否要求信号保持因果性还是单纯画波形。第三周期信号验证做傅里叶级数展开对比各分量频率的比值。比如习题中cos(2πt) sin(4πt)的频率比是 1:2周期取T 1如果展开后出现第三项cos(√2 πt)整个信号就不是周期的。这个检查比直接目测波形更可靠尤其是当信号包含多个分量时波形形状可能与周期性判断的结果互相干扰。可以用scipy.fft对采样序列做快速傅里叶变换观察频谱中是否存在非整数倍基频的谱线——如果有说明混入了非周期分量周期性判定需要重新审视。本文还有配套的精品资源点击获取