【Audio】正弦波生成原理及C++代码

news2024/12/27 11:41:39

正弦波生成及频谱分析

正弦波公式

  • 诊断系统(Diag)会通过播放一段指定频率、采样率、时长及振幅的正弦音,以此对Audio测试。
  • 正弦波的公式如下,其中 A是振幅、x是时间、F是频率。
    y = A ∗ sin ⁡ ( 2 ∗ π ∗ x ∗ F ) y = A* \sin \lparen 2 * \pi * x * F \rparen y=Asin(2πxF)

当振幅是1.0 ,频率是1.0(频率指一秒钟震几次)。正弦波公式及其图像为
y = sin ⁡ ( 2 π x ) y = \sin \lparen 2 \pi x \rparen y=sin(2πx)
在这里插入图片描述

  • 考虑到相偏移和Y轴偏移量(比如为了方便计算振幅不存在负数,那么Y轴向上偏移),其公式为
    y = A ∗ sin ⁡ ( 2 ∗ π ∗ x ∗ F + θ ) + D y = A* \sin \lparen 2 * \pi * x * F + \theta \rparen + D y=Asin(2πxF+θ)+D

C++生成正弦波

  • WebRTC中提供了一段正弦波的生成函数,生成精度比较高。可以借鉴其代码,编写正弦波函数(改造后的实际应用代码不便放出)。这里分析一下WebRTC 正弦波生成源码。
// webrtc/modules/audio_mixer/sine_wave_generator.h
/*
 *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_
#define MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_

#include <stdint.h>

#include "api/audio/audio_frame.h"
#include "rtc_base/checks.h"

namespace webrtc {

class SineWaveGenerator {
 public:
  SineWaveGenerator(float wave_frequency_hz, int16_t amplitude)
      : wave_frequency_hz_(wave_frequency_hz), amplitude_(amplitude) {
    RTC_DCHECK_GT(wave_frequency_hz, 0);
  }

  // Produces appropriate output based on frame->num_channels_,
  // frame->sample_rate_hz_.
  // 通过这个函数生成正弦波
  void GenerateNextFrame(AudioFrame* frame);

 private:
  float phase_ = 0.f;
  // 正弦波频率
  const float wave_frequency_hz_;
  // 振幅
  const int16_t amplitude_;
};

}  // namespace webrtc

#endif  // MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_

// webrtc/modules/audio_mixer/sine_wave_generator.cc
/*
 *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_mixer/sine_wave_generator.h"

#include <math.h>
#include <stddef.h>

#include "rtc_base/numerics/safe_conversions.h"

namespace webrtc {

namespace {
constexpr float kPi = 3.14159265f;
}  // namespace

void SineWaveGenerator::GenerateNextFrame(AudioFrame* frame) {
  RTC_DCHECK(frame);
  // 获取用来保存数据的指针地址(一段Buffer)
  int16_t* frame_data = frame->mutable_data();
  // samples_per_channel_ 表示每个声道采样多少个样本
  for (size_t i = 0; i < frame->samples_per_channel_; ++i) {
  	// 计算每个声道(Channel)的样本值
    for (size_t ch = 0; ch < frame->num_channels_; ++ch) {
     // 比如双声道(两个Channel),i = 0时就是frame_data[0] 和frame_data[1]
     // frame_data[ 2 * 0 + 0 ] --> Frame_data[0]
     // frame_data[ 2 * 0 + 1 ] --> Frame_data[1]
     // amplitude_  指振幅,sinf(phase_) 是对 phase_ 其sin函数值
      frame_data[frame->num_channels_ * i + ch] =
          rtc::saturated_cast<int16_t>(amplitude_ * sinf(phase_));
    }

	// 这段是重点。 phase_ 就是正弦函数中的 变量值。
	// wave_frequency_hz_  表示采样频率
	// Kpi 为π
	// 2∗ Kpi * wave_frequency_hz_ 是一个完整点的采样周期。
	// frame->sample_rate_hz_ 这个参数表示采样率
	// 采样率理解为在一个采样周期内,采多少个点。
    // 所以每个点的步长,例如 [ 0 0.1 0.2 ... 1.0 ], 0.1就是步长。
    // 采样的步长应为  采样周期 / 采样率。
    phase_ += wave_frequency_hz_ * 2 * kPi / frame->sample_rate_hz_;
  }
}
}  // namespace webrtc
  • 上面的代码中,针对多通道、特定频率、特定采样率、特定时长(样本点),生成了一段正弦波数据。关于AudioFrame,实际上就是记录了一些设定项,以及保存数据的数组,其源码可以参考(webrtc/api/audio/audio_frame.h)
  • WebRTC中提供的Testsample
// The audio level ranges linearly [0,32767].
// audio_level 振幅
// duration_ms 时间
// sample_rate_hz 采样频率
// num_channels 通道数
std::unique_ptr<AudioFrame> CreateAudioFrame1kHzSineWave(int16_t audio_level,
                                                         int duration_ms,
                                                         int sample_rate_hz,
                                                         size_t num_channels) {
  // 根据采样频率,计算样本数
  size_t samples_per_channel = sample_rate_hz / (1000 / duration_ms);
  // 创建对象,保存样本数据
  std::vector<int16_t> audio_data(samples_per_channel * num_channels, 0);
  // 给audioFrame设置相关参数
  std::unique_ptr<AudioFrame> audio_frame = std::make_unique<AudioFrame>();
  audio_frame->UpdateFrame(0 /* RTP timestamp */, &audio_data[0],
                           samples_per_channel, sample_rate_hz,
                           AudioFrame::SpeechType::kNormalSpeech,
                           AudioFrame::VADActivity::kVadUnknown, num_channels);
						   
  // 生成频率是1000(1kHZ)的正弦波
  SineWaveGenerator wave_generator(1000.0, audio_level);
  wave_generator.GenerateNextFrame(audio_frame.get());
  return audio_frame;
}
  • 需要注意一点,正弦波频率 和 采样频率不是一个事情。正弦波频率是指正弦波一秒钟震几下,在人耳辨别的范围内,频率越高越刺耳。采样频率指的是将连续信号转化为离散信号时,采样周期的选择,也就是一秒钟采几次(一般为44.1kHz)

频谱分析

  • 利用一些音频软件,可以对生成的数据进行分析。比如通上述代码,生成300HZ的一段正弦波数据。通过频谱分析可以看出,其峰值为311。其误差值较小。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1063764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【考研数学】高等数学第七模块 —— 曲线积分与曲面积分 | 4. 对坐标的曲面积分(第二类曲面积分)与场论初步

文章目录 二、曲面积分2.2 对坐标的曲面积分&#xff08;第二类曲面积分&#xff09;1. 问题产生 —— 流量2. 对坐标的曲面积分的定义&#xff08;了解&#xff09;3. 对坐标的曲面积分的性质4. 对坐标的曲面积分的计算法&#xff08;1&#xff09; 二重积分法&#xff08;2&a…

properties文件和yaml文件的区别~

之前&#xff0c;关于数据库的连接信息&#xff0c;端口号的设置等&#xff0c;我们会将它分门别类的写在多个文件中&#xff0c;但SpringBoot&#xff0c;它讲究统一的配置管理&#xff0c;我们想设置的任何参数都集中在一个固定位置和命名的配置文件&#xff0c;而该配置文件…

10.4| QT实现TCP服务器客户端搭建的代码,现象

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>#include<QTcpServer> //服务器头文件 #include<QTcpSocket> //客户端头文件#include<QList> //链表容器 #include<QMessageBox> …

Error string: Could not load library

启动Rivz时&#xff0c;报错&#xff1a; Error string: Could not load library (Poco exception libg2o_csparse_extension.so.0.1: cannot open shared object file: No such file or directory) [ERROR] [1696572310.529059051]: Failed to load nodelet [/radar_graph_s…

破译滑块验证间距 破译sf顺丰滑块验证

废话不多说直接开干&#xff01; from selenium import webdriver # 导入配置 from selenium.webdriver.chrome.options import Options import time from PIL import Image # 导入动作链 from selenium.webdriver.common.action_chains import ActionChains import random, st…

如何获取高质量的微信私域客户?

在当今数字化时代&#xff0c;企业都在努力寻求创新的营销方式来获取更多的客户。微信私域流量作为一种精准的营销工具&#xff0c;越来越受到企业的青睐。那么&#xff0c;如何获取高质量的微信私域客户呢&#xff1f;本文将为你揭示这一难题的答案&#xff0c;让你轻松Get高转…

STM32--MQ2烟雾传感器

本文主要介绍STM32F103C8T6和烟雾传感器模块的控制算法 简介 烟雾模块选用MQ-2气体传感器&#xff0c;根据传感器的电导率随空气中可燃气体浓度的增加而增大的特性检测空气中可燃气体&#xff0c;然后将电导率的变化转换成对应的电信号 MQ系列烟雾传感分类如下&#xff1a; 该…

基于SSM的校园二手物品交易平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Python之字符串构造

Python之字符串构造 字符串str 一个个字符组成的有序的序列&#xff0c;是字符的集合使用单引号、双引号、三引号引住的字符序列字符串是不可变对象&#xff0c;是字面常量 Python3起&#xff0c;字符串都是Unicode类型 x abcde使用for循环遍历x的值&#xff0c;打印并查看…

九小场所消防安全检查安全码系统

九小场所安全码&#xff0c;实现消防安全监督管理&#xff0c;落实消防安全责任&#xff0c;形成九小场所网格化监控、动态化管理&#xff1b; 安全码流程化管理 监管部门日常检查&#xff0c;微信扫码即可填写检查记录&#xff0c;现场可拍照、视频、文字、记录检查情况&…

1200*C. Challenging Cliffs(模拟构造贪心)

Problem - 1537C - Codeforces Challenging Cliffs - 洛谷 解析&#xff1a; 排序数组&#xff0c;然后找出间隔最短的两个相邻的数 a&#xff0c;b&#xff0c;c&#xff0c;d&#xff0c;e&#xff0c;f &#xff08;假设b&#xff0c;c为差最小的两个数&#xff09;。 然后…

虫情测报灯如何实现自动化测报?

一、KH-CQPest虫情测报灯的工作过程 虫情测报灯是新一代的图像式虫情测报智能设备&#xff0c;在农业虫害防治领域拥有独特魅力&#xff0c;它内置高像素的摄像头&#xff0c;能够精准记录并将照片上传至智慧农业平台识别害虫的形态、种类。虫情测报灯运用现代光电数控集成技术…

【深蓝学院】手写VIO第2章--IMU传感器--作业

这次作业坑很多&#xff0c;作业说明的不清楚&#xff0c;摸索了很长时间才将此次作业完成&#xff0c;在这里进行记录。 1. T1 1.1 题干 1.2 解答 1.2.1 法1&#xff0c;ros related方法 不知道为什么我的launch不了&#xff0c;在imu_utils目录下面建立build后&#xff0…

剑指offer——JZ7 重建二叉树 解题思路与具体代码【C++】

一、题目描述与要求 重建二叉树_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出…

[Spring] @Bean 修饰方法时如何注入参数

目录 一、Bean 的简单使用 1、正常情况 2、问题提出 二、解决方案 1、Qualifier 2、直接写方法名 三、特殊情况 1、DataSource 一、Bean 的简单使用 在开发中&#xff0c;基于 XML 文件配置 Bean 对象的做法非常繁琐且不好维护&#xff0c;因此绝大部分情况下都是使用…

计算机竞赛 题目:基于卷积神经网络的手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

分析“由于找不到msvcp120.dll无法继续执行代码”的原因及解决方法

在计算机使用过程中&#xff0c;我们可能会遇到一些莫名其妙的错误提示&#xff0c;其中“由于找不到 msvcp120.dll 无法继续执行代码”就是一种常见的困扰。这种错误提示的出现往往会给用户带来一定的烦恼&#xff0c;因为不清楚究竟是什么原因导致了这个错误&#xff0c;也不…

Zabbix自定义脚本监控MySQL数据库

一、MySQL数据库配置 1.1 创建Mysql数据库用户 [rootmysql ~]# mysql -uroot -p create user zabbix127.0.0.1 identified by 123456; flush privileges; 1.2 添加用户密码到mysql client的配置文件中 [rootmysql ~]# vim /etc/my.cnf.d/client.cnf [client] host127.0.0.1 u…

【Python基础】字典和函数拓展

文章目录 前言一、字典1.1 字典是什么&#xff1f;1.2 字典的定义和操作字典的定义访问字典元素修改字典元素添加新键值对删除键值对 二、函数的拓展2.1 多返回值的函数2.2 调用函数并接收多个返回值2.3 多参数的函数2.4 函数作为参数传递2.5 示例代码 总结 前言 Python作为一…

信看课堂-厘米GNSS定位

我们常常说GPS 定位&#xff0c;不过定位远不止GPS定位&#xff0c;通过本节课程&#xff0c;我们将会了解到&#xff0c;原来GPS只是定位的一种&#xff1a; GNSS概述 不同的GNSS系统使用不同的频段来传输导航信号。以下是一些主要的GNSS系统及其相应的频段&#xff0c;用表…