新北市网站建设_网站建设公司_导航易用性_seo优化
2026/1/9 2:11:54 网站建设 项目流程

AM(DSB-LC)调制过程

1. 引入与方法概述(原文要点整理与解释)

原文(要点):有几种方法可以产生 AM(DSB-LC)。一种特别容易解释的方法使用两个步骤:
① 通过添加 DC 偏置信号 B 来偏移消息信号 m(t);
② 将偏移消息信号 [B + m(t)] 乘以某个更高频率的正弦载波信号。

解释与讲授要点
将基带消息信号 m(t) 先加上一个恒定直流分量 B(称为偏置或载波分量),使得到的信号始终或在多数时间为正(或至少相对于零电平偏移)。然后将该偏移后的信号与高频正弦(或余弦)载波逐点相乘,得到幅度随基带信号变化的载波,即产生了含载波的振幅调制信号(DSB-LC,Double SideBand — Large Carrier)。


2. 数学表达(原文公式与释义)

原文公式:为在数学上表达该过程,AM 信号方程可以写为

逐项释义与展开


3. 实验示例与图示观察

原文要点:图 15.2 显示了 100 ms 的语音信号。图 15.3 显示了添加来自图 15.2 的语音信号和 5 mV 偏置的结果。在图 15.3 中,很明显语音信号加上 5 mV 并不总是保持正值。消息振幅需要降低或偏差值需要增加;否则,如果要将包络检波器用于消息恢复,将导致失真。图 15.4 显示了添加 20 mV 偏置的结果,很明显语音信号加偏置现在在所示的时间段内保持为正。图 15.5 显示语音信号调制(DSB-LC)一个 12 kHz 载波。

逐句讲解与技术说明

  • 图 15.2(原始 100 ms 语音信号):这是一段采样后的基带语音波形,纵轴为电压,横轴为时间(ms)。语音信号在时间上是变化的,有正有负,峰值幅度决定了后续偏置的大小需求。


4. 关键概念延伸

包络检波的前提条件


5. MATLAB 实现要点

原文要点:AM 生成过程的最后一步是将正确偏置的消息信号乘以正弦信号(称为载波)。乘法是逐点操作,因此必须使用 MATLAB® 运算符“.*”。

实现步骤(示例化、可直接用于讲授或实验)

示例伪代码(MATLAB 风格)

% m: 基带列向量,Fs: 采样率 N = length(m); t = (0:N-1)'/Fs; B = 1.2 * max(abs(m)); % 举例:留 20% 安全裕度 Ac = 1; % 载波幅度(可调) fc = 12000; % 12 kHz 示例载波 carrier = cos(2*pi*fc*t); s = Ac * (B + m) .* carrier; % 逐点乘法 plot(t(1:round(0.1*Fs)), s(1:round(0.1*Fs))); % 绘制前 100 ms

关于 MATLAB 中的注意事项

  • 使用逐点操作(.*,./,.^)而不是矩阵乘法。

  • 若对小信号幅度(mV 级)进行仿真,注意数值精度与绘图纵轴刻度。

  • 如果准备将仿真结果送到硬件或 DSP(例如书中示例基于 TMS320C6x),应注意定点化、剪切以及采样率匹配问题。


6. 总结

核心结论

数字信号处理(DSP)在实际硬件系统中运行的几个核心原则:实时性约束中断驱动机制以及数据表示的物理限制

第一层面:为什么不能等待?(实时性的本质)

首先,我们要理解 DSP 和普通电脑处理文件的区别。

在普通的计算机处理中(比如你在电脑上编辑一个 Word 文档或处理一张照片),你通常拥有整个文件的数据。你可以随时读取文件的开头、中间或结尾,处理器可以花 1 秒钟也可以花 10 秒钟,只要最后结果出来就行。这叫做“离线处理”。

但 DSP 处理来自 ADC(模数转换器)的数据是实时的,就像你在接听电话或观看直播。

  • 流水线作业:数据像流水一样源源不断地通过 ADC 涌入。如果不马上处理,新的数据就会覆盖旧的数据,导致信息丢失。

  • 不能等待:正如文中提到的,“我们不能等待所有消息样本被接收”。你不能跟 ADC 说:“嘿,等你把这一小时的声音都录完了,我再开始计算。”因为那样需要巨大的存储空间,而且会造成巨大的延迟(你说话,对方一小时后才听到)。

  • 结论DSP 必须“随到随处理”,来一个样本,算一个样本,送出一个样本。

第二层面:怎么实现“随到随处理”?(中断驱动与 ISR)

既然必须“随到随处理”,处理器怎么知道数据来了呢?这就引入了**“中断驱动(Interrupt-Driven)”**的概念。

你可以把 DSP 芯片想象成一个正在专心看书(执行主程序)的人,而 ADC 是门外的快递员。

  1. 中断(Interrupt):快递员(ADC)送来了一个包裹(数据样本),他按了一下门铃。这个“门铃”就是硬件中断信号。

  2. 中断服务例程(ISR):听到门铃,你必须暂停看书,放下书签,去开门拿包裹,并把它放到指定位置。这个“开门拿包裹”的一系列动作,就是代码中的ISR(Interrupt Service Routine)

  3. 异步性:文中强调“输入和输出 ISR 都是异步的”。这意味着你不知道门铃什么时候响,它完全取决于外部的采样率(比如每秒响 48000 次)。你不能在主程序里写死代码去“等”数据,因为那样效率极低。

  4. 程序员的责任:如果你的“拿包裹动作(ISR)”太慢,还没等你在架子上放好,下一个快递员又按门铃了,系统就会崩溃(数据溢出)。因此,DSP 程序员的核心任务是写出极高效率的 ISR 代码,确保在下一次采样到来前处理完当前数据。

  5. 必要的“搬运工”:文中最后提到“除非您用适当的接收和传输 ISR……否则任何东西都不会进出”。这意味着,如果不开门(没有写好 ISR),数据就烂在门口了,DSP 内部算法再强大也拿不到数据。

第三层面:数据长什么样?(整数表示与溢出风险)

当数据终于通过 ISR 进入 DSP 内部后,你需要理解它的数学形态。

  1. 电压变整数:现实世界是模拟电压(比如 -1V 到 +1V),但计算机只认识 0 和 1。ADC 把电压映射为整数

  2. 补码与范围:文中提到了16位二进制补码(Two's Complement)。

    • 在 16 位系统中,能表示的整数总数是= 65536$ 个。

    • 为了表示正负,这些数字被分为两半:范围是从-32,768+32,767

    • 注意:这里有一个不对称性,负数比正数多一个(因为 0 占用了正数的一位,或者说非负数的一位)。

  3. 偏置与包络失真(Clipping)

    • 这段话特别提到了AM(调幅)信号的生成场景。在 AM 中,我们通常需要给信号加一个直流偏置(Bias),把信号“抬”起来,使其主要位于正值区域,或者是为了控制载波的幅度。

    • 天花板与地板:DSP 的数字世界是有“天花板”(+32767)和“地板”(-32768)的。

    • 警告:如果你设置的偏置(Bias)加上信号本身的波动,超过了 +32767,数值无法继续变大,就会被强行“削顶”(Clipping),产生严重的失真。文中提到“偏置电平必须不超过 +32768”其实是一个简化的说法,准确地说是“偏置 + 信号峰值”不能越界。

    • 实验建议:作者最后建议你故意把偏置设得很大(比如大于 32768,虽然在 16 位里这本身就会发生溢出回绕),目的是让你通过实验去听或看,当数字系统发生**溢出(Overflow)**时,AM 信号的波形会变成什么样(通常会发生相位翻转或严重的杂音),以此来加深对数字范围限制的理解。

python运行代码

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ AM (DSB-LC) simulation and visualization script. Features: - Generate or read a baseband message signal (sine or WAV file). - Add one or more DC biases B and produce biased baseband signals. - Multiply (pointwise) biased baseband with a cosine carrier to form DSB-LC AM. - Compute analytic signal via FFT-based Hilbert transform and extract envelope. - Compute single-sided magnitude spectrum (dB). - Produce and save PNG plots for: baseband, biased baseband, AM time-domain, AM + envelope, and AM spectrum up to 24 kHz (configurable). - Save a README and zip the result folder. Dependencies: - numpy - matplotlib - optional: scipy (for wav reading). If scipy unavailable, script uses synthetic signal. Usage example: python am_dsb_lc_sim.py --outdir ./am_results --fs 48000 --duration 0.1 \ --fm 1000 --amplitude 0.5 --biases 0.005 0.02 --fc 12000 --ac 1.0 Author: ChatGPT (assistant) """ import argparse import os from pathlib import Path import numpy as np import matplotlib # Use a non-interactive backend for environments without display matplotlib.use("Agg") import matplotlib.pyplot as plt import zipfile # Optional: try to import scipy.io.wavfile for WAV reading try: from scipy.io import wavfile SCIPY_AVAILABLE = True except Exception: SCIPY_AVAILABLE = False # ------------------------- # Utility functions # ------------------------- def analytic_signal_fft(x): """ Compute analytic signal using FFT-based Hilbert transform. Returns complex analytic signal xa such that envelope = |xa|. """ X = np.fft.fft(x) N = len(X) H = np.zeros(N, dtype=float) # Construct frequency-domain multiplier H if N % 2 == 0: H[0] = 1 H[N // 2] = 1 H[1:N//2] = 2 else: H[0] = 1 H[1:(N+1)//2] = 2 xa = np.fft.ifft(X * H) return xa def single_sided_spectrum_db(x, fs, nfft=16384): """ Compute single-sided magnitude spectrum (dB) of signal x. Returns freqs (0..fs/2) and mag_db arrays. """ X = np.fft.fft(x, nfft) X = X[:nfft//2 + 1] mag = np.abs(X) / nfft # avoid log of zero mag[mag == 0] = 1e-20 mag_db = 20.0 * np.log10(mag) freqs = np.linspace(0, fs/2, nfft//2 + 1) return freqs, mag_db def ensure_outdir(path): p = Path(path) p.mkdir(parents=True, exist_ok=True) return p def save_png(fig, path, dpi=200): fig.tight_layout() fig.savefig(path, dpi=dpi) plt.close(fig) # ------------------------- # Main simulation function # ------------------------- def run_simulation( outdir, fs=48000, duration=0.1, message_type="sine", fm=1000.0, Am=0.5, wav_path=None, biases=(0.005, 0.02), fc=12000.0, Ac=1.0, nfft=16384, spectrum_max_khz=24.0 ): outdir = ensure_outdir(outdir) # Time vector t = np.arange(0, duration, 1.0/fs) N = len(t) # Message signal: either synthetic sine or WAV file (if provided and readable) if message_type == "wav" and wav_path is not None and SCIPY_AVAILABLE: wav_path = Path(wav_path) if not wav_path.exists(): raise FileNotFoundError(f"WAV file not found: {wav_path}") sr, data = wavfile.read(str(wav_path)) # If stereo, take first channel if data.ndim > 1: data = data[:, 0] # Convert to float in range -1..1 if integer if np.issubdtype(data.dtype, np.integer): maxint = float(2**(8*data.itemsize - 1)) data = data.astype(np.float64) / maxint # Resample if sampling rates differ (simple truncation/pad if needed) if sr != fs: # simple approach: resample via numpy interpolation orig_t = np.arange(len(data)) / sr new_t = np.arange(0, duration, 1.0/fs) from numpy import interp data = interp(new_t, orig_t, data[:min(len(data), int(duration*sr))]) t = new_t N = len(t) else: # use portion that fits duration data = data[:N] m = Am * (data / np.max(np.abs(data))) # scale to requested amplitude Am message_descr = f"WAV input: {wav_path.name} (rescaled to Am={Am} V)" else: # synthetic sine wave message m = Am * np.sin(2.0 * np.pi * fm * t) message_descr = f"Synthetic sine: fm={fm} Hz, Am={Am} V" # Save baseband (message) plot fig = plt.figure(figsize=(8,3)) plt.plot(t * 1000.0, m) plt.xlabel("时间 / ms") plt.ylabel("消息信号 / V") plt.title(f"基带消息信号 - 时域 ({duration*1000:.0f} ms)\n{message_descr}") plt.xlim(0, duration*1000.0) save_png(fig, outdir / "message.png") # Carrier carrier = np.cos(2.0 * np.pi * fc * t) # Process each bias saved_files = [] for B in biases: biased = B + m s = Ac * biased * carrier # DSB-LC AM signal # 1) save biased baseband fig = plt.figure(figsize=(8,3)) plt.plot(t * 1000.0, biased) plt.xlabel("时间 / ms") plt.ylabel("偏置后消息信号 / V") plt.title(f"偏置 B = {B*1e3:.1f} mV 的基带信号 - 时域") plt.xlim(0, duration*1000.0) fname_biased = outdir / f"biased_{int(B*1e6)}uV.png" save_png(fig, fname_biased) saved_files.append(fname_biased.name) # 2) save AM waveform (time domain) fig = plt.figure(figsize=(8,3)) plt.plot(t * 1000.0, s) plt.xlabel("时间 / ms") plt.ylabel("AM 信号 / V") plt.title(f"DSB-LC AM 信号 (B={B*1e3:.1f} mV, fc={fc/1000:.1f} kHz)") plt.xlim(0, duration*1000.0) fname_am = outdir / f"am_{int(B*1e6)}uV.png" save_png(fig, fname_am) saved_files.append(fname_am.name) # 3) envelope via analytic signal xa = analytic_signal_fft(s) envelope = np.abs(xa) fig = plt.figure(figsize=(8,3)) plt.plot(t * 1000.0, s, label="AM 波形") plt.plot(t * 1000.0, envelope, label="包络 (解析信号)") plt.plot(t * 1000.0, -envelope, label="_nolegend_") plt.xlabel("时间 / ms") plt.ylabel("电压 / V") plt.title(f"AM 信号与包络 (B = {B*1e3:.1f} mV)") plt.xlim(0, duration*1000.0) plt.legend(loc="upper right") fname_env = outdir / f"am_envelope_{int(B*1e6)}uV.png" save_png(fig, fname_env) saved_files.append(fname_env.name) # 4) spectrum (single-sided dB) up to spectrum_max_khz freqs, mag_db = single_sided_spectrum_db(s, fs, nfft=nfft) idx_max = np.searchsorted(freqs, spectrum_max_khz * 1000.0) fig = plt.figure(figsize=(8,3)) plt.plot(freqs[:idx_max] / 1000.0, mag_db[:idx_max]) plt.xlabel("频率 / kHz") plt.ylabel("幅度 / dB") plt.title(f"AM 信号功率谱幅度 (B={B*1e3:.1f} mV)") plt.xlim(0, spectrum_max_khz) # autoset ylim to show reasonable dynamic range ymin = np.min(mag_db[:idx_max]) ymax = np.max(mag_db[:idx_max]) plt.ylim(ymin - 5, ymax + 5) fname_spec = outdir / f"spectrum_am_{int(B*1e6)}uV.png" save_png(fig, fname_spec) saved_files.append(fname_spec.name) # Write README readme_path = outdir / "README.txt" with open(readme_path, "w", encoding="utf-8") as f: f.write("AM (DSB-LC) 仿真结果\n") f.write("=====================\n\n") f.write(f"采样率 (Fs): {fs} Hz\n") f.write(f"仿真时长: {duration} s\n") f.write(f"消息: {message_descr}\n") f.write(f"载波: fc = {fc} Hz, Ac = {Ac}\n") f.write("偏置值 (B): " + ", ".join([f"{b} V" for b in biases]) + "\n\n") f.write("文件列表:\n") for name in sorted(saved_files): f.write(f"- {name}\n") f.write("- message.png\n") f.write("\n说明:\n") f.write("1. 若要使用外部 WAV 文件, 请在命令行使用 --message-type wav --wav-path <file.wav> 并确保已安装 scipy.\n") f.write("2. 包络使用 FFT-based Hilbert transform 计算, 可用于演示包络检波的有效性或过调情况.\n") # Zip the results zip_path = Path(outdir.parent) / (outdir.name + ".zip") with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: for fpath in sorted(outdir.iterdir()): zf.write(fpath, arcname=fpath.name) print(f"Results saved to folder: {outdir}") print(f"ZIP archive: {zip_path}") print("Done.") # ------------------------- # Command-line interface # ------------------------- def parse_args(): p = argparse.ArgumentParser(description="AM (DSB-LC) simulation and visualization.") p.add_argument("--outdir", default="./am_results", help="Output directory (will be created).") p.add_argument("--fs", type=int, default=48000, help="Sampling frequency (Hz).") p.add_argument("--duration", type=float, default=0.1, help="Simulation duration (seconds).") p.add_argument("--message-type", choices=["sine", "wav"], default="sine", help="Message source: 'sine' for synthetic sine, 'wav' to read WAV file (requires scipy).") p.add_argument("--fm", type=float, default=1000.0, help="Message frequency (Hz) for synthetic sine.") p.add_argument("--amplitude", type=float, default=0.5, help="Message amplitude (peak, V) for synthetic sine.") p.add_argument("--wav-path", default=None, help="Path to WAV file if message-type==wav.") p.add_argument("--biases", type=float, nargs="+", default=[0.005, 0.02], help="List of DC biases (V). E.g. --biases 0.005 0.02") p.add_argument("--fc", type=float, default=12000.0, help="Carrier frequency (Hz).") p.add_argument("--ac", type=float, default=1.0, help="Carrier amplitude (Ac).") p.add_argument("--nfft", type=int, default=16384, help="FFT length for spectrum.") p.add_argument("--spectrum-max-khz", type=float, default=24.0, help="Max kHz to show in spectrum plot.") return p.parse_args() if __name__ == "__main__": args = parse_args() run_simulation( outdir=args.outdir, fs=args.fs, duration=args.duration, message_type=args.message_type, fm=args.fm, Am=args.amplitude, wav_path=args.wav_path, biases=tuple(args.biases), fc=args.fc, Ac=args.ac, nfft=args.nfft, spectrum_max_khz=args.spectrum_max_khz )

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询