You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QtCreator+C++正弦波生成器83.3Hz信号周期性clipping问题求助

问题分析与解决方案

问题根源

你遇到的83.3Hz信号周期性削波,本质是相位不连续导致的信号突变:

  • 83.3Hz实际是250/3 Hz,在44100采样率下,单个周期的样本数为44100/(250/3)=529.2,并非整数
  • 你每次生成100ms的buffer(固定4410个样本),都是从相位0开始计算正弦波,这意味着每个buffer的结尾相位和下一个buffer的开头相位完全断开(4410个样本对应8.333个周期,结尾相位不为0)
  • 前后buffer的信号值突变,在示波器上就表现为每100ms一次的类似削波的尖峰;而其他频率(如60Hz)刚好满足整数周期,相位连续,所以无异常

解决方案

核心是维护一个累积相位变量,让每次生成的buffer都从上一次结束的相位继续计算,保证信号连续性。

步骤1:添加相位成员变量

在MainWindow类的头文件中添加全局相位变量:

private:
    double m_currentPhase = 0.0;
    int m_targetFrequency = 0; // 保存当前要生成的频率

步骤2:修改频率生成函数

更新gerador_frequencia,保存目标频率并重置相位:

void MainWindow::gerador_frequencia(int frequency)
{
    stopSignal();

    qDebug() << "Gerando sinal de" << frequency << "Hz";

    m_targetFrequency = frequency;
    m_currentPhase = 0.0; // 切换频率时重置相位

    int sampleRate = 44100; 

    QAudioFormat format;
    format.setSampleRate(sampleRate);
    format.setChannelCount(1);
    format.setSampleFormat(QAudioFormat::Int16);

    QAudioDevice audioDevice = QMediaDevices::defaultAudioOutput();

    audioSink = new QAudioSink(audioDevice, format, this);
    audioIODevice = audioSink->start();

    audioTimer = new QTimer(this);
    connect(audioTimer, &QTimer::timeout, this, &MainWindow::onAudioNotify);
    audioTimer->start(100);

    stopTimer = new QTimer(this);
    connect(stopTimer, &QTimer::timeout, this, &MainWindow::stopSignal);
    stopTimer->setSingleShot(true);
    stopTimer->start(3600000);

    qDebug() << "Frequencia gerada com sucesso!!!";
}

步骤3:修改正弦波生成函数

让generateSineWave使用累积相位计算,保证连续:

QByteArray MainWindow::generateSineWave(int frequency, int sampleRate, int durationMs) 
{
    int sampleCount = static_cast<int>((static_cast<double>(sampleRate) * durationMs) / 1000.0);
    QByteArray buffer(sampleCount * sizeof(int16_t), 0);
    int16_t *data = reinterpret_cast<int16_t*>(buffer.data());

    double amplitude = 16000;
    double angleIncrement = (2.0 * M_PI * frequency) / sampleRate;

    for (int i = 0; i < sampleCount; ++i) {
        data[i] = static_cast<int16_t>(amplitude * sin(m_currentPhase));
        m_currentPhase += angleIncrement;
        // 防止相位无限增大,取模2π优化数值稳定性
        while (m_currentPhase >= 2.0 * M_PI) {
            m_currentPhase -= 2.0 * M_PI;
        }
    }
    return buffer;
}

步骤4:更新音频回调函数

每次定时器触发时生成新的连续相位buffer,而不是复用旧buffer:

void MainWindow::onAudioNotify()
{
    if (!audioIODevice || !audioSink) return;
    // 每次生成新的连续相位buffer
    QByteArray newBuffer = generateSineWave(m_targetFrequency, audioSink->format().sampleRate(), 100);
    audioIODevice->write(newBuffer);
}

额外注意事项

  • 确保stopSignal()函数正确清理audioTimer、stopTimer、audioSink等资源,避免内存泄漏
  • 若仍有削波,可小幅降低amplitude值(比如调整到15000),留足突变余量,但核心问题解决后大概率不需要

内容的提问来源于stack exchange,提问作者matheusbrl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:32:08