音频(八)——C语言生成正弦波并用 I2S 输出
文章目录 固定采样率下的正弦波数组 I2S 输出 USB 麦克风 AP 仪器测试
I2S 输出正弦波 PC 端 C 语言生成正弦波数组 原理
三角函数的公式 y = A s i n w x y = y=
代码实现 源码
#include
#include
#include #define SAMPLE_POINT_NUM (64) /* 需要生成的点的个数 */
#define SINE_MAX (512) /* sin 函数幅值 */
#define PI (3.1415926) /* 数学中的常量:Π */
#define POINT_BUFFER_LEN (128)int generate_data[POINT_BUFFER_LEN]; /* 生成的数据放在此数组中 */void get_sin_data(unsigned int point)
{unsigned int i = 0;float step = 0.0;float data = 0.0;int tem = 0;step = 2 * PI / point; /* 将 sin 函数从 [0-2Π] 等分为 N 个点,则每个点的步长为 2Π/point_num */for (i = 0; i < point; i++){data = SINE_MAX * sin(step * i);tem = (int)data;generate_data[i] = tem;}
}int main(int argc, char *argv[])
{get_sin_data(SAMPLE_POINT_NUM);for (int i = 0; i < SAMPLE_POINT_NUM; i++){printf("%d ", generate_data[i]);}printf("\r\n");return 0;
}
编译
gcc generate_sin_data.c -lm
需要用到数学库中的函数 sin ,所以链接的时候需要加上 lm 参数
运行结果
0 50 99 148 195 241 284 324 362 395 425 451 473 489 502 509 512 509 502 489 473 451 425 395 362 324 284 241 195 148 99 50 0 -50 -99 -148 -195 -241 -284 -324 -362 -395 -425 -451 -473 -489 -502 -509 -512 -509 -502 -489 -473 -451 -425 -395 -362 -324 -284 -241 -195 -148 -99 -50
从生成的数据中可以看出,数据的最大最小值分别为 512 和 -512
波形
将上述数据用散点图绘制出来如下图
固定采样率下的正弦波数组
上一节生成的正弦波数组 幅值 及 step 步长并没有考虑实际频率
实际音频输出是需要考虑:采样位数,采样频率,声道数详见音频(一)——基本概念及硬件拓扑
采样位数对应到正弦波中即为幅值
采样频率对应到正弦波中即为频率
基本思路:
源码实现
#include
#include
#include #define SAMPLE_POINT_NUM (48) /* 需要生成的点的个数,即每 ms 有多少个点,48000Hz - 48个点/ms; 16000 - 16个点/ms*/
#define SAMPLE_BIT (16) /* 采样位数 决定幅值 */
#define PI (3.1415926) /* 数学中的常量:Π */int generate_data[512]; /* 生成的数据放在此数组中 */int get_sin_max(int sample_bit)
{int value = 2;for (int i = 0; i < sample_bit - 1; i++){value = value * 2;}return value - 1;
}void get_sin_data(unsigned int point)
{float data = 0.0;int sin_max_data;float step = 0.0;sin_max_data = get_sin_max(SAMPLE_BIT - 1);step = 2 * PI / SAMPLE_POINT_NUM;for (int i = 0; i < point; i++){data = sin_max_data * sin(step * i);generate_data[i] = (int)data;}
}int main(int argc, char *argv[])
{get_sin_data(SAMPLE_POINT_NUM);for (int i = 0; i < SAMPLE_POINT_NUM; i++){printf("%d, ", generate_data[i]);}printf("\r\n");return 0;
}
编译
gcc generate_sin_data.c -lm
需要用到数学库中的函数 sin ,所以链接的时候需要加上 lm 参数
运行结果
0, 4276, 8480, 12539, 16383, 19947, 23169, 25995, 28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272, 28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276, 0, -4276, -8480, -12539, -16383, -19947, -23169, -25995, -28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272, -28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276,
从生成的数据中可以看出,数据的最大最小值分别为 32767 和 -32767,16 位音频数据的取值范围为 − 2 31 —— 2 31 − 1 -2^{31}——2^{31}-1 −231——231−1
波形
将上述数据用散点图绘制出来如下图
I2S 输出 数据通路
sram/flash -> I2S master SDATAO -> AP SDATAI
USB 麦克风
对于 USB 麦克风,如果采样率为 16KHz,那么 1s 内有 16000 个点,1ms 内有 16 个点,其他采样率类似,如果是双声道,数据量需要乘以 2 。
对于全速设备的等时端点来说,1ms 来一次中断,所以将对应采样率的点数通过 USB 等时端点发送给主机即可。
short buf_mono_16KHz[] = {0, 12539, 23169, 30272, 32767, 30272, 23169, 12539, 0, -12539, -23169, -30272, -32767, -30272, -23169, -12539};
short buf_mono_32KHz[] = {0, 6392, 12539, 18204, 23169, 27244, 30272, 32137, 32767, 32137, 30272, 27244, 23169, 18204, 12539, 6392, 0, -6392, -12539, -18204, -23169, -27244, -30272, -32137, -32767, -32137, -30272, -27244, -23169, -18204, -12539, -6392, };
short buf_mono_48KHz[] = {0, 4276, 8480, 12539, 16383, 19947, 23169, 25995, 28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272, 28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276, 0, -4276, -8480, -12539, -16383, -19947, -23169, -25995, -28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272, -28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276,};
short buf_mono_96KHz[] = {0, 2143, 4276, 6392, 8480, 10532, 12539, 14492, 16383, 18204, 19947, 21604, 23169, 24635, 25995, 27244, 28377, 29387, 30272, 31028, 31650, 32137, 32486, 32696, 32767, 32696, 32486, 32137, 31650, 31028, 30272, 29387, 28377, 27244, 25995, 24635, 23169, 21604, 19947, 18204, 16383, 14492, 12539, 10532, 8480, 6392, 4276, 2143, 0, -2143, -4276, -6392, -8480, -10532, -12539, -14492, -16383, -18204, -19947, -21604, -23169, -24635, -25995, -27244, -28377, -29387, -30272, -31028, -31650, -32137, -32486, -32696, -32767, -32696, -32486, -32137, -31650, -31028, -30272, -29387, -28377, -27244, -25995, -24635, -23169, -21604, -19947, -18204, -16383, -14492, -12539, -10532, -8480, -6392, -4276, -2143, };
软件测试 波形测试
频谱分析
上述代码中,将数组的幅值修改为 − 2 15 -2^{15} −215
得到的正弦波数组为
short test_buf_96_1db[] = {0, 1071, 2138, 3196, 4240, 5266, 6269, 7246, 8191, 9101, 9973, 10802, 11584, 12317, 12997, 13621, 14188, 14693, 15135, 15513, 15824, 16068, 16242, 16347, 16383, 16347, 16242, 16068, 15824, 15513, 15135, 14693, 14188, 13621, 12997, 12317, 11584, 10802, 9973, 9101, 8191, 7246, 6269, 5266, 4240, 3196, 2138, 1071, 0, -1071, -2138, -3196, -4240, -5266, -6269, -7246, -8191, -9101, -9973, -10802, -11584, -12317, -12997, -13621, -14188, -14693, -15135, -15513, -15824, -16068, -16242, -16347, -16383, -16347, -16242, -16068, -15824, -15513, -15135, -14693, -14188, -13621, -12997, -12317, -11584, -10802, -9973, -9101, -8191, -7246, -6269, -5266, -4240, -3196, -2138, -1071, };
该正弦波数组对应的 FFT 为
对于数字音频,根据 dBFS 的计算公式为:理解dB
d B = 20 ∗ l o g 10 s a m p l e 65535 dB = 20 * log_{10}{\frac{}{65535}} dB=20∗log10
由上公式可以算出两者相差 6dB。
对比两次频谱分析,差值也为 6dB( − 8 − − 2 {-8 - -2} −8−−2)。
通过测量二者的 RMS 也可以看出二者相差 6dB。
AP 仪器测试
AP 一起测试时,输入源选择数字音频接口即 I2S,并配置 AP 端 I2S 格式和 MCU 端格式一致
波形测试
FFT 测试
THD+N 测试
测试数据
频率测试
测试数据