I2S 输出正弦波
- PC 端:先生成一个正弦波数组
- MCU 端:将正弦波数组使用 I2S 输出
- AP 端:接受从 MCU I2S 端口出来的正弦波数据并测量 THD+N 等数据
PC 端生成正弦波数组
原理
三角函数的公式 y = A s i n x y = Asinx y=Asinx
- A 表示幅值
代码实现
源码
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#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
步长并没有考虑实际频率
实际音频输出是需要考虑:采样位数,采样频率,声道数详见音频(一)——基本概念及硬件拓扑
采样位数对应到正弦波中即为幅值
采样频率对应到正弦波中即为频率
基本思路:
- 采样频率和需要的采样点控制步长
- 采样位数控制幅值
- char 型数据,即 8 位采样位数的取值范围 − 2 7 —— 2 7 − 1 -2^7——2^7-1 −27——27−1
- short 型数据,即 16 位采样位数的取值范围 − 2 15 —— 2 15 − 1 -2^{15}——2^{15}-1 −215——215−1
- int 型数据, 即 32 位采样位数的取值范围 − 2 31 —— 2 31 − 1 -2^{31}——2^{31}-1 −231——231−1
源码实现
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#define SAMPLE_POINT_NUM (64) /* 需要生成的点的个数 */
#define SAMPLE_RATE (48000) /* 48KHz */
#define SAMPLE_BIT (16) /* 采样位数 */
#define SINE_CHANNEL (1) /* 采样声道数 */
#define PI (3.1415926) /* 数学中的常量:Π */
#define POINT_BUFFER_LEN (128)
int generate_data[POINT_BUFFER_LEN]; /* 生成的数据放在此数组中 */
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 step = 0.0;
float data = 0.0;
int sin_max_data;
sin_max_data = get_sin_max(SAMPLE_BIT - 1);
step = 2 * PI / SAMPLE_RATE; /* 采样频率表示采样数据之间的时间间隔 */
step *= SAMPLE_RATE / point; /* 只取 point 个点,所以真正的 step 需要乘 SAMPLE_RATE / point */
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 3211 6392 9511 12539 15446 18204 20787 23169 25329 27244 28897 30272 31356 32137 32609 32767 32609 32137 31356 30272 28897 27244 25329 23169 20787 18204 15446 12539 9511 6392 3211 0 -3211 -6392 -9511 -12539 -15446 -18204 -20787 -23169 -25329 -27244 -28897 -30272 -31356 -32137 -32609 -32767 -32609 -32137 -31356 -30272 -28897 -27244 -25329 -23169 -20787 -18204 -15446 -12539 -9511 -6392 -3211
从生成的数据中可以看出,数据的最大最小值分别为 32767
和 -32767
波形
将上述数据用散点图绘制出来如下图
I2S 输出
数据通路
flash -> I2S master SDATAO -> AP
AP 仪器测试
波形测试
图片待补充
FFT 测试
图片待补充
THD+N 测试
THD+N 理论值计算
图片待补充
SNR 测试
图片待补充
THD+N 理论值计算