从零构建你的第一个调幅信号用Matlab亲手“听见”无线电还记得第一次用收音机调台旋钮转动间从嘈杂的静电噪声里忽然捕捉到清晰人声或音乐时的那种奇妙感觉吗那背后就是调幅AM技术在默默工作。对于很多电子工程、通信专业的学生或是无线电爱好者来说理解调幅原理是踏入信号处理世界的第一块敲门砖。然而书本上的公式和框图有时显得过于抽象难以形成直观感受。今天我们就换一种方式——不满足于“知道”而要亲手“创造”。我们将完全从零开始使用Matlab这个强大的数学工具一步步搭建一个完整的调幅信号模拟系统。这不是一次简单的代码复制粘贴而是一次从概念到波形从数学表达式到听觉体验的完整旅程。无论你是刚接触信号与系统课程的学生还是希望用实践巩固理论的爱好者跟随本文你不仅能得到可运行的代码更能获得一种“亲手操控电波”的深刻理解。1. 启程之前理解我们为何要“调制”在打开Matlab之前让我们先花点时间抛开复杂的术语用最朴素的方式理解调制的核心价值。想象一下你站在一个巨大的体育馆中央想要对远处的朋友喊一句话。如果直接喊你的声音低频信号可能传不了多远就被环境噪音吞没了。但如果你手里有一个哨子高频载波你可以通过改变吹哨的力度来“携带”你的声音信息——用力吹代表“1”轻轻吹代表“0”。远处的人虽然听不清你的原话却能清晰地听到哨声力度的变化从而解读出信息。这个“用哨声携带话音”的过程就是调制思想的精髓。在无线电通信中这个“哨子”就是高频正弦波称为载波你的“声音”就是我们需要传输的调制信号比如音频。调幅就是让载波的振幅随着调制信号的瞬时值成比例地变化。注意这里有一个关键点常被初学者忽略——调制后的信号其频率成分发生了根本变化。它不再是原始音频信号的简单放大而是将音频信号的频谱“搬移”到了载波频率的两侧形成了所谓的“边带”。这正是天线能够高效辐射信号的关键。为什么非得这么做主要有两个物理层面的硬约束天线尺寸天线的有效长度通常需要与发射信号的波长成正比。语音信号的频率很低比如1kHz波长长达300公里制造对应的天线是不现实的。而将信号调制到高频比如1MHz波长300米后天线的尺寸就变得非常实用。信号分辨与抗干扰不同电台使用不同频率的载波就像高速公路上的不同车道避免了相互干扰。如果所有声音信号都挤在20Hz-20kHz的“原始车道”上发射全球的广播将乱成一锅粥。理解了这些我们接下来的Matlab模拟就有了灵魂——我们不仅仅是在画几条曲线而是在虚拟世界中重构一套符合物理规律的通信系统。2. 搭建舞台Matlab环境与基础信号生成工欲善其事必先利其器。我们首先确保Matlab环境就绪并定义好这次模拟的“演员”调制信号和载波。我个人的习惯是在开始一个项目时先新建一个独立的脚本文件例如AM_Simulation.m并在开头用注释清晰标明模拟的参数。这样做的好处是日后回顾或修改代码时能立刻理解当时的设定。%% AM信号模拟 - 参数初始化 clear all; close all; clc; % 清空工作区、关闭所有图形、清空命令窗口 % 1. 时间轴设置 fs 100000; % 采样频率 (Hz)决定了时间分辨率 T_total 0.02; % 总模拟时间 (秒)20毫秒足够观察多个周期 t 0:1/fs:T_total; % 时间向量从0到T_total步长为1/fs N length(t); % 总采样点数 % 2. 调制信号 (低频代表信息) fm 1000; % 调制信号频率 1 kHz (典型音频范围) Am 0.8; % 调制信号振幅 m_t Am * cos(2*pi*fm*t); % 调制信号表达式 % 3. 载波信号 (高频负责运载) fc 10000; % 载波频率 10 kHz Ac 1; % 载波振幅 c_t Ac * cos(2*pi*fc*t); % 载波信号表达式上面代码中采样频率fs设置为100kHz这是一个需要仔细考虑的值。它必须大于信号中最高频率成分的两倍奈奎斯特采样定理。这里我们的最高频率成分将是载波加上边带大约在11kHz左右因此100kHz的采样率绰绰有余能保证波形不失真。为了直观感受这两个信号我们可以先绘制它们的时域图。但更有趣的是观察它们的频谱这能提前揭示调制的本质。%% 绘制原始信号及其频谱 figure(Position, [100, 100, 1200, 800]); % 子图1: 调制信号时域 subplot(3,2,1); plot(t*1000, m_t, b, LineWidth, 1.5); % 时间转换为毫秒显示 xlabel(时间 (ms)); ylabel(幅度); title(调制信号 m(t) (1 kHz)); grid on; xlim([0, 5]); % 只看前5ms % 子图2: 调制信号频谱 subplot(3,2,2); M_f abs(fftshift(fft(m_t)/N)); freq (-N/2:N/2-1)*(fs/N); plot(freq/1000, M_f, b, LineWidth, 1.5); xlabel(频率 (kHz)); ylabel(幅度谱); title(调制信号频谱); grid on; xlim([-2, 2]); % 集中在低频附近 % 子图3: 载波信号时域 subplot(3,2,3); plot(t*1000, c_t, r, LineWidth, 1.5); xlabel(时间 (ms)); ylabel(幅度); title(载波信号 c(t) (10 kHz)); grid on; xlim([0, 0.5]); % 高频信号看更短的时间 % 子图4: 载波信号频谱 subplot(3,2,4); C_f abs(fftshift(fft(c_t)/N)); plot(freq/1000, C_f, r, LineWidth, 1.5); xlabel(频率 (kHz)); ylabel(幅度谱); title(载波信号频谱); grid on; xlim([-12, 12]); % 集中在10kHz附近运行这部分代码你会看到四个图。左边是缓慢变化的低频调制波和它的单一谱线右边是快速振荡的高频载波和它的谱线。它们目前还是两个独立的个体。接下来我们将让它们发生“化学反应”。3. 核心魔术调幅公式的代码实现与深度分析调幅的数学表达式非常简洁但内涵丰富。标准调幅AM信号的公式为s_AM(t) [Ac m(t)] * cos(2πfc t)其中Ac是载波振幅m(t)是调制信号。关键在于[Ac m(t)]这部分它构成了载波的时变包络。这个包络的形状必须始终大于零否则会导致“过调制”在解调时引起失真。这就是为什么我们之前设置Am0.8而Ac1确保Ac Am。让我们在Matlab中实现它并仔细剖析结果%% 生成标准调幅信号 % 关键步骤将调制信号叠加到直流分量上形成时变包络 envelope Ac m_t; % 这就是信号的包络线 s_AM envelope .* c_t; % 用包络去乘载波得到AM信号 % 绘制AM信号及其包络 subplot(3,2,5); plot(t*1000, s_AM, Color, [0.2, 0.6, 0.2], LineWidth, 1); % AM信号 hold on; plot(t*1000, envelope, k--, LineWidth, 2); % 上包络线 plot(t*1000, -envelope, k--, LineWidth, 2); % 下包络线 hold off; xlabel(时间 (ms)); ylabel(幅度); title(标准调幅信号 s\_{AM}(t) 及其包络); legend(AM信号, 包络线, Location, northeast); grid on; xlim([0, 5]); % 绘制AM信号频谱 subplot(3,2,6); S_AM_f abs(fftshift(fft(s_AM)/N)); plot(freq/1000, S_AM_f, Color, [0.2, 0.6, 0.2], LineWidth, 1.5); xlabel(频率 (kHz)); ylabel(幅度谱); title(调幅信号频谱 (含载波与边带)); grid on; xlim([-12, 12]);现在请将注意力集中在右下角的频谱图上。你会发现一个神奇的现象原来在1kHz和10kHz的单一线谱不见了取而代之的是三个峰频率成分中心频率 (kHz)物理意义载波10原始的高频载波不携带信息上边带 (USB)11载波频率 调制频率 (101)下边带 (LSB)9载波频率 - 调制频率 (10-1)这就是频谱搬移调制信号的信息1kHz被完整地复制并搬移到了载波频率的两侧。载波分量本身功率很大但不含信息两个边带则携带了完全相同的信息。这也引出了通信中一个重要的概念抑制载波双边带DSB-SC调制。如果我们能在发射前把中间那个强大的载波分量抑制掉就可以节省大量发射功率。你可以尝试修改代码将envelope Ac m_t改为envelope m_t即去掉直流分量Ac再看看频谱图会发生什么变化——中间的载波峰会消失只剩下左右两个边带。提示观察时域图中AM信号的包络它的形状是否和原始的调制信号m(t)一模一样是的这正是包络检波器解调的原理基础。接收机只需要用一个二极管和电容电路“跟踪”这个包络的起伏就能还原出原始声音。4. 引入真实感复杂调制信号与调制深度的影响单一频率的正弦波作为调制信号虽然易于分析但毕竟过于理想。真实的声音或数据信号要复杂得多。让我们模拟一个更贴近现实的场景用一个包含两个频率分量的信号来调制。%% 使用复杂调制信号 % 生成一个由两个正弦波叠加的调制信号 fm1 800; fm2 1200; Am1 0.4; Am2 0.4; m_t_complex Am1*cos(2*pi*fm1*t) Am2*cos(2*pi*fm2*t); % 生成AM信号 envelope_complex Ac m_t_complex; s_AM_complex envelope_complex .* c_t; % 绘制对比 figure(Position, [100, 100, 1000, 600]); % 复杂调制信号 subplot(2,2,1); plot(t*1000, m_t_complex, b, LineWidth, 1.5); xlabel(时间 (ms)); ylabel(幅度); title(复杂调制信号 (800Hz 1200Hz)); grid on; xlim([0, 10]); % 复杂调制信号的AM波形 subplot(2,2,2); plot(t*1000, s_AM_complex, Color, [0.5, 0, 0.8], LineWidth, 1); hold on; plot(t*1000, envelope_complex, k--, LineWidth, 2); plot(t*1000, -envelope_complex, k--, LineWidth, 2); hold off; xlabel(时间 (ms)); ylabel(幅度); title(对应的AM信号); grid on; xlim([0, 10]); % 复杂调制信号的频谱 subplot(2,2,3); M_f_complex abs(fftshift(fft(m_t_complex)/N)); plot(freq/1000, M_f_complex, b, LineWidth, 1.5); xlabel(频率 (kHz)); ylabel(幅度谱); title(复杂调制信号频谱); grid on; xlim([-2, 2]); % 复杂AM信号频谱 subplot(2,2,4); S_AM_f_complex abs(fftshift(fft(s_AM_complex)/N)); plot(freq/1000, S_AM_f_complex, Color, [0.5, 0, 0.8], LineWidth, 1.5); xlabel(频率 (kHz)); ylabel(幅度谱); title(复杂AM信号频谱); grid on; xlim([-12, 12]);观察新的频谱图右下你会看到载波10kHz两侧不再是一对边带而是两对边带在9.2kHz 10.8kHz对应800Hz以及8.8kHz 11.2kHz对应1200Hz。这清晰地展示了调制信号的整个频谱都被线性地搬移到了载频两侧。如果调制信号是一段带宽为B的音频那么AM信号的总带宽就是2B。这就是为什么中波广播电台之间需要有至少9kHz的间隔音频带宽约4.5kHz。另一个至关重要的参数是调制深度调制度定义为m Am / Ac。它衡量了调制信号对载波幅度改变的“强度”。m 1正常调制包络清晰无失真。m 1100%调制包络在谷底刚好触零效率最高但临界。m 1过调制包络会交叉产生严重失真。让我们用代码快速感受一下不同调制深度的影响%% 调制深度对比 Ac_fixed 1; Am_values [0.5, 1.0, 1.5]; % 对应调制深度 m 0.5, 1.0, 1.5 figure; for i 1:3 Am Am_values(i); m_t_test Am * cos(2*pi*fm*t); envelope_test Ac_fixed m_t_test; s_AM_test envelope_test .* c_t; subplot(3,1,i); plot(t*1000, s_AM_test, LineWidth, 1); hold on; plot(t*1000, envelope_test, r--, LineWidth, 1.5); plot(t*1000, -envelope_test, r--, LineWidth, 1.5); hold off; title(sprintf(调制深度 m %.1f (Am%.1f, Ac1), Am/Ac_fixed, Am)); xlabel(时间 (ms)); ylabel(幅度); grid on; xlim([0, 5]); if i 3 legend(AM信号, 包络, Location, best); end end运行后你会直观看到m1.5时红色包络线发生了交叉这意味着部分信息在传输中会丢失。在实际的广播系统中调制深度通常被谨慎地控制在95%以下以留出安全余量。5. 从发射到接收模拟信道衰减与包络检波一个完整的通信链路模拟离不开信道和接收机。我们简化信道模型只考虑信号幅度的衰减并加入一点高斯白噪声来模拟现实中的干扰。然后我们将实现最简单的包络检波来恢复信号。%% 模拟传输与包络检波 % 1. 信号通过信道衰减噪声 attenuation 0.3; % 信道衰减因子 received_signal attenuation * s_AM; % 衰减 SNR_dB 20; % 信噪比 (dB)可以调整看效果 noise_power var(received_signal) / (10^(SNR_dB/10)); noise sqrt(noise_power) * randn(size(received_signal)); received_signal_noisy received_signal noise; % 2. 包络检波 % 理想包络检波先全波整流再低通滤波 rectified_signal abs(received_signal_noisy); % 全波整流 % 设计一个简单的低通滤波器以提取包络 % 截止频率应略高于调制信号最高频率远低于载波频率 fc_lpf 1500; % 低通滤波器截止频率 1.5kHz [b, a] butter(4, fc_lpf/(fs/2), low); % 4阶巴特沃斯低通滤波器 demodulated_signal filtfilt(b, a, rectified_signal); % 零相位滤波 % 3. 绘制结果对比 figure(Position, [100, 100, 1000, 800]); % 原始调制信号 subplot(4,1,1); plot(t*1000, m_t, b, LineWidth, 1.5); title(原始调制信号 m(t)); xlabel(时间 (ms)); ylabel(幅度); grid on; xlim([5, 15]); % 避开起始瞬态 % 接收到的含噪AM信号 subplot(4,1,2); plot(t*1000, received_signal_noisy, Color, [0.8, 0.4, 0], LineWidth, 0.5); title(接收到的含噪AM信号); xlabel(时间 (ms)); ylabel(幅度); grid on; xlim([5, 15]); % 整流后的信号 subplot(4,1,3); plot(t*1000, rectified_signal, Color, [0.1, 0.5, 0.1], LineWidth, 0.5); hold on; % 画出整流后信号的粗略包络用于示意 [up, lo] envelope(rectified_signal, 100, peak); % 使用envelope函数找峰值 plot(t*1000, up, r-, LineWidth, 1.5); hold off; title(全波整流后的信号及其包络示意); xlabel(时间 (ms)); ylabel(幅度); legend(整流信号, 包络趋势, Location, best); grid on; xlim([5, 15]); % 解调出的信号 vs 原始信号 subplot(4,1,4); plot(t*1000, demodulated_signal, r, LineWidth, 1.5); hold on; plot(t*1000, m_t * attenuation, b--, LineWidth, 1.5); % 经过衰减的原始信号用于对比 hold off; title(包络检波输出红 vs 衰减后的原始信号蓝虚线); xlabel(时间 (ms)); ylabel(幅度); legend(解调信号, 原始信号(衰减后), Location, best); grid on; xlim([5, 15]);这段代码模拟了完整的后半程。你可以尝试调整SNR_dB的值比如改为10或5观察噪声增大时解调信号质量如何恶化。包络检波器结构简单但抗噪声性能较差且存在“门限效应”——当信噪比低于某个值时解调性能会急剧下降。这也是更先进的调制方式如FM被开发出来的原因之一。6. 进阶探索从模拟到听觉体验理论学习与波形观察固然重要但若能“亲耳听到”自己生成的信号理解会更加深刻。Matlab可以让我们轻松做到这一点。但需要注意的是我们模拟的载波频率10kHz高于人耳听阈所以我们需要先通过解调还原出音频再用声卡播放。%% 可选听觉体验生成并播放一段AM调制的声音 % 注意此部分需要电脑有声卡支持且音量不宜过大 % 生成一段更复杂的调制信号模拟语音片段 fs_audio 8000; % 音频采样率 duration 3; % 秒 t_audio 0:1/fs_audio:duration; % 用两个随时间变化的频率模拟音调变化 f1 300 100*sin(2*pi*0.5*t_audio); % 频率在200-400Hz变化 f2 800 200*sin(2*pi*1*t_audio); % 频率在600-1000Hz变化 audio_signal 0.5*sin(2*pi*f1.*t_audio) 0.3*sin(2*pi*f2.*t_audio); audio_signal audio_signal / max(abs(audio_signal)); % 归一化 % 对这段音频进行AM调制 fc_audio 10000; % 载波频率 % 需要对音频信号重采样以匹配载波生成的高采样率 audio_resampled resample(audio_signal, fs, fs_audio); % 确保长度匹配 min_len min(length(t), length(audio_resampled)); t_trim t(1:min_len); audio_trim audio_resampled(1:min_len); Ac_audio 1; m_audio 0.7 * audio_trim; % 调制深度0.7 envelope_audio Ac_audio m_audio; c_audio cos(2*pi*fc_audio*t_trim); s_AM_audio envelope_audio .* c_audio; % 模拟接收和解调简化版 % 1. 加噪声 rx_signal 0.5*s_AM_audio 0.05*randn(size(s_AM_audio)); % 2. 包络检波 rectified abs(rx_signal); % 设计低通滤波器提取音频 [b_audio, a_audio] butter(6, 4000/(fs/2), low); demod_audio filtfilt(b_audio, a_audio, rectified); % 3. 去除直流分量并下采样回音频采样率 demod_audio demod_audio - mean(demod_audio); demod_audio_resampled resample(demod_audio, fs_audio, fs); demod_audio_resampled demod_audio_resampled / max(abs(demod_audio_resampled)); % 播放原始音频和解调音频请谨慎调节音量 fprintf(准备播放原始音频...\n); pause(1); soundsc(audio_signal, fs_audio); % 播放原始音频 pause(duration 1); fprintf(准备播放从AM信号解调出的音频...\n); pause(1); soundsc(demod_audio_resampled, fs_audio); % 播放解调音频运行这段代码注意音量你会先听到一段“叮咚”变化的模拟音频然后听到一段夹杂着噪声和失真的相同音频从AM信号中恢复出来。这种亲耳所闻的对比比任何文字描述都更能让你理解噪声、失真和调制深度对通信质量的影响。整个项目做下来我最大的体会是动手模拟一遍那些原本停留在书本上的概念——频谱搬移、边带、调制深度、包络检波——都变成了屏幕上可操控、可观察、甚至可聆听的实体。你可以随意修改代码中的任何一个参数把载波频率fc改成1MHz观察频谱的移动把调制信号换成一段真实的音频文件尝试实现一个同步检波器相干解调并与包络检波对比性能。这些探索中的每一个发现都会让你对通信系统的理解加深一分。无线电的世界不再神秘它就在你的代码和屏幕上的波形里。