如何使用C++绘制正弦/余弦/方波并实现波形傅里叶变换
C++ 波形生成与傅里叶变换实现指南
核心实现思路
优先用标准库完成核心逻辑,无需引入复杂第三方依赖,跑通流程后再扩展绘图功能。
1. 基础概念定义
先统一需要用到的参数:
- 采样率:每秒采集的波形点数,常用值44100/48000
- 采样点数:单次处理的总点数,建议取2的整数次幂方便后续优化为FFT
- 信号频率:生成波形的频率,比如100Hz
- 振幅:波形的最大幅值,常用值1.0
2. 波形生成实现
三类基础波形的生成逻辑都可以用循环遍历每个采样点计算对应值实现:
核心公式
- 正弦波:
amplitude * sin(2 * M_PI * signal_freq * i / sample_rate) - 余弦波:
amplitude * cos(2 * M_PI * signal_freq * i / sample_rate) - 方波:
amplitude * (sin(2 * M_PI * signal_freq * i / sample_rate) >= 0 ? 1 : -1)(50%占空比)
示例代码
#include <iostream> #include <vector> #include <cmath> #include <fstream> // 全局参数 const double SAMPLE_RATE = 44100.0; const int SAMPLE_COUNT = 1024; const double SIGNAL_FREQ = 100.0; const double AMPLITUDE = 1.0; // 生成正弦波 std::vector<double> generate_sine() { std::vector<double> res(SAMPLE_COUNT); for (int i = 0; i < SAMPLE_COUNT; i++) { res[i] = AMPLITUDE * sin(2 * M_PI * SIGNAL_FREQ * i / SAMPLE_RATE); } return res; } // 生成方波 std::vector<double> generate_square() { std::vector<double> res(SAMPLE_COUNT); for (int i = 0; i < SAMPLE_COUNT; i++) { double sin_val = sin(2 * M_PI * SIGNAL_FREQ * i / SAMPLE_RATE); res[i] = AMPLITUDE * (sin_val >= 0 ? 1 : -1); } return res; }
3. 离散傅里叶变换(DFT)实现
新手优先实现逻辑简单的DFT,理解原理后再替换为效率更高的快速傅里叶变换(FFT):
// DFT实现,输入时域信号,输出频域幅值 std::vector<double> dft(const std::vector<double>& time_domain) { int n = time_domain.size(); std::vector<double> freq_mag(n/2); // 只保留正频率部分 for (int k = 0; k < n/2; k++) { double real = 0.0; double imag = 0.0; for (int t = 0; t < n; t++) { double angle = 2 * M_PI * k * t / n; real += time_domain[t] * cos(angle); imag -= time_domain[t] * sin(angle); } // 计算幅值并归一化 freq_mag[k] = sqrt(real*real + imag*imag) / n; } return freq_mag; }
4. 结果输出与可视化
无需引入C++绘图库,直接输出为CSV文件,用Excel/WPS表格即可直接生成波形图:
void output_to_csv(const std::vector<double>& time_domain, const std::vector<double>& freq_domain) { std::ofstream file("wave_result.csv"); file << "采样点,时域值,频域幅值\n"; for (int i = 0; i < time_domain.size(); i++) { double freq_val = i < freq_domain.size() ? freq_domain[i] : 0; file << i << "," << time_domain[i] << "," << freq_val << "\n"; } file.close(); } int main() { // 生成正弦波,可替换为generate_square()生成方波 std::vector<double> time_signal = generate_sine(); // 执行傅里叶变换 std::vector<double> freq_signal = dft(time_signal); // 输出结果 output_to_csv(time_signal, freq_signal); return 0; }
常见问题修复
- 编译提示
M_PI未定义:在包含<cmath>前添加#define _USE_MATH_DEFINES(MSVC编译器),或手动定义const double M_PI = 3.141592653589793; - 方波傅里叶变换结果出现毛刺:属于正常的吉布斯效应,不是代码错误
- 频域幅值过小:检查是否做了除以采样点数的归一化操作
内容的提问来源于stack exchange,提问作者Ong Shi Quan
相关产品推荐
相关产品推荐

