【CCS仿真系列教程】手把手教你纯软件仿真实现音频滤波
如果你的CCS还没有配置仿真条件,不能纯软件仿真打印出HelloWorld,请先看这篇文章【致CCS仿真失败的你】CCS(Code Composer)V6.0以上版本仿真教程
事先说明
- 在CCS纯软件仿真时,可以使用C语言的文件系统,读取Debug目录下的文件,或把数据保存到文件中。
- 此时,CCS不支持以浮点型或者长整型的方式读取文件中的数据或者存储数据到文件。
- 正是由于CCS的简化版文件系统只能对整型数据进行读写,所以使用Matlab把音频数据从双精度浮点型转换为整形,在DSP仿真处理结束后,把处理结果读进Matlab中,重新处理为双精度浮点型后,用sound函数播放。
- 因为本例子中要处理的音频数据比较长,所以先把音频存到文件中,在程序运行时,动态加载该文件。
- 为了减少时间复杂度,本例中音频缓冲方式是直接以新数据覆盖旧数据,没有使用数组移位来加载新数据。
- CCS仿真时,printf到命令行的东西需要加回车符\n,遇到\n后才会一次性显示到命令行。
- 由于F28335性能比较低下,而仿真软件在仿真的时候真实度过高,仿真了F28335的低处理速度,所以程序运行有点慢,大约需要20分钟,在命令行会输出当前进度。
示例项目下载
无法下载请私信或评论,看到马上修复
尽量使用Giuhub版本
GitHub:https://github.com/highskyno1/CCS_music_filter
链接: https://pan.baidu.com/s/103x1j4S4x5Y0kwvmnTlXJw?pwd=4y3d
提取码:4y3d
示例使用说明
首先用Matlab生成加了噪声的音频
- 注意把被调戏音乐放到F盘,或修改audioread的参数,改为被调戏音乐的地址。
- 运行下载下来的音频滤波项目文件中的Matlab部分的Filter.m。
- 代码运行后,会在Matlab安装目录的bin文件夹中生成_input文件,这个文件是加了噪声后,根据设定的采样率生成的经过处理的整形音频数据文件,把它拷贝到CCS仿真的工程目录中的Debug文件中。
- 代码运行后,会显示加噪声后以及滤波后的频谱,用于做可行性检验,以确定滤波器设计正确,同时,还会显示滤波器的幅频特征曲线图以及相频特征曲线。
- 代码运行后,会通过电脑音频播放滤波后的音乐。
代码如下
Frequency_in = 1000; %需要引入的干扰正弦波的频率
size_cut = 100000; %截断到多少点
is_Filte = 1; %为零时播放假如干扰后的音频,为一时播放滤波后的音频
[data,fs] = audioread('C:\Users\high_sky\Desktop\音频滤波项目\样品2.wav'); %要调戏的音频,改成你自己的路径
result_Fs = 8000; %结果的采样率
%[size_raw,~] = size(data);
%注意,如果是两个或者以上声道的音频数据,以下代码只取读进来的第一个声道
temp = data(1:size_cut,1); %由于DSP处理速度过低,可能要压缩数据
temp2 = resample(temp,result_Fs,fs); %对原音频的再次采样
[size_data,~] = size(temp2); %求取音频长度
%给音频人为地添加干扰,干扰的频率由Frequency_in给定
noise = sin(2*pi*Frequency_in*size_data/result_Fs*linspace(0,1,size_data));
temp2 = temp2 + noise'; %加入噪声
temp3 = int32(temp2*10^4); %把数据处理成整形,方便DSP读入
temp4 = double(temp3)/10^4; %尝试把整形数据恢复成浮点型数据
Hn = getFilter(result_Fs); %获取滤波器的时域数据
if is_Filte
temp4 = conv(temp4,Hn); %对加入了干扰的音频数据进行滤波
end
sound(temp4,result_Fs); %播放处理结果
%把加了噪声并且做了整形转换的结果写入到文件,方便DSP分析
fp = fopen('_input','w');
for i = 1:size(temp3)
fprintf(fp,'%d ',temp3(i));
end
fclose(fp);
%画出加干扰后的频谱图
figure(1);
plot(abs(fft(temp2)));
%画出滤波后的频谱图
figure(2);
plot(abs(fft(temp4)));
%画出滤波器的分析图
figure(3);
freqz(Hn);
%格式化输出滤波器数据,方便写入DSP
fprintf("{");
for i = 1:length(Hn)
fprintf("%e,",Hn(i));
end
fprintf("};\n");
%获得滤波器的方法
function result = getFilter(result_Fs)
fcuts = [200 900 1100 2000]; %定义通带和阻带的频率
mags = [1 0 1]; %定义通带和阻带
devs = [0.1 0.01 0.1]; %定义通带或阻带的纹波系数
[n,Wn,beta,ftype] = kaiserord(fcuts,mags,devs,result_Fs); %计算出凯塞窗N,beta的值
result = fir1(n,Wn,ftype,kaiser(n+1,beta),'noscale'); %生成滤波器
end
将我的项目弄你的CCS的WorkSpace中
- 解压下载的文件
- 点击CCS中的Import
- 选择Import类型为CCS Projects,然后选择Next
- 开始导入,按下Brows,选择项目解压的目录,点击确定,然后点击Finish,注意勾上Copy projects into WorkSpace的选项
把Matlab生成后的_input文件拷贝到CCS仿真的工程目录中的Debug文件中
- 我的CCS工程已经放好,如果你使用自己的音频文件,就需要这一步。
把Matlab生成的滤波器数据加载到DSP
- 把Matlab生成的滤波器数据复制到CCS代码中
- 更改滤波器长度标志
运行CCS仿真
- 代码运行需要比较长,请耐心等待,命令行中会显示进度。
- 仿真结束后,在项目Debug文件夹下会有一个_output文件,这个文件就是仿真的对输入音频滤波后的输出,该文件需要使用Matlab播放。
- 运行请使用Debug方式运行,操作方法如下图所示:
- 进入Debug界面后,等待程序编译完成,点击Resume按钮,开始程序的运行:
仿真代码如下
#include <stdio.h>
#include <stdlib.h>
#define N 27 //滤波器的长度
/**
* hello.c
*/
//滤波器数据
const static double filter[] = {-1.817133e-03,-1.030943e-02,-1.486092e-02,-6.554923e-03,5.310618e-03,-3.484461e-17,-1.961028e-02,-1.277302e-02,5.264802e-02,1.370936e-01,1.426501e-01,1.707388e-02,-1.639884e-01,7.500000e-01,-1.639884e-01,1.707388e-02,1.426501e-01,1.370936e-01,5.264802e-02,-1.277302e-02,-1.961028e-02,-3.484461e-17,5.310618e-03,-6.554923e-03,-1.486092e-02,-1.030943e-02,-1.817133e-03,};
int temp_Music[N]; //音频缓冲器
//循环保存数据时,取音频缓冲器的值
//为了减少时间复杂度,直接以新数据覆盖最旧的数据
//减少了移位的环节
/**
* 循环保存数据时,取音频缓冲器的值
* @param index 需要取得数据的相对索引
* @param bias 索引偏置,即当前最新数据的直接索引
* @return 取出的数据
*/
int getValue(int index,int bias){
int temp = bias + index;
if(temp < N)
return temp_Music[temp];
else
return temp_Music[temp - N];
}
//此函数用于计算滤波结果,每次输出一个值
//index为当前最新时域数据在音频缓冲器中的位置
/**
* 实现单个数据的卷积并输出结果
* @param index 最新的数据的直接索引
* @return 卷积结果
*/
int output(int index){
int i;
double sum = 0;
for(i = 0;i < N;i++)
sum += getValue(N-i-1,index) * filter[i];
return (int)sum;
}
int main(void)
{
int i; //我就是一个移位计数器
int out_Count = 0; //在输出百分比时,用户换行以方便观看
unsigned long Conter = 0; //用于统计进行了多少次结果输出
int index_new = 0; //用于记录新数据插入的位置
int out_temp; //乘积缓冲
long input_length; //用于统计程序进行了百分之多小,计算时用作分母
double input_size = 0; //保存输入数据的长度,如果超出了,我也没办法,哈哈哈
char temp; //缓存器
printf("Hello World!\n");
FILE *fp_input,*fp_output; //输入和输出的音频信号的文件
if((fp_input = fopen("_input","r")) == NULL){ //尝试打开文件
printf("The file can not be opened\n"); //文件打开失败
return 1; //退出程序
}
printf("OK0!\n");
if((fp_output = fopen("_output","w")) == NULL){ //创建结果输出文件
printf("The file can not be created\n"); //输出文件无法创建
return 2; //退出程序
}
printf("OK1!\n");
//统计输入文件有多大,基于输入文件的空格字符数
while((temp = fgetc(fp_input)) != EOF){
if(temp == ' ')
input_size++;
}
input_length = (long)(input_size/1000); //计算输出进度统计的分母
//使文件指针回到文件初位置
fseek(fp_input,0L,SEEK_SET);
//用数据来喂饱饥饿已久的缓冲数组
for(i = 0;i < N;i++){
fscanf(fp_input,"%d",&out_temp);
temp_Music[i] = out_temp;
}
printf("OK2!\n");
fprintf(fp_output,"%d ",output(index_new)); //写入第一个卷积输出结果
printf("OK3!\n");
while(fscanf(fp_input,"%d",&out_temp) != EOF){ //不断地往循环数据添加新数据
temp_Music[index_new] = out_temp;
index_new++;
if(index_new >= N) //触及输入缓冲数组最大索引(即数组顶)
index_new = 0; //回到输入缓冲数组的底部
fflush(fp_output); //因为写入是异步的,为防止漏写,添加此步
fprintf(fp_output,"%d ",output(index_new));
Conter++; //输出结果的计数器+1
if(Conter % input_length == 0){ //更新进度条
printf("%d/1000 \0",(int)(Conter/input_length));
out_Count++;
if(out_Count >= 15){
printf("\n");
out_Count = 0;
}
}
}
printf("OK4!\n"); //滤波完成
//关闭文件IO
fclose(fp_input);
fclose(fp_output);
return 0;
}
Matlab播放DSP滤波结果
- Matlab运行OpenOutput_Filter.m,注意把fopen的参数改为你的CCS项目的Debug下的_output的路径。
- 播放时,切记把sound的第二个参数设置成音频文件生成的采样率,也就是Filter.m文件中的result_Fs的值。
- 戴上耳机,聆听滤波后的结果,享受成功的喜悦。
播放代码
Id = fopen('E:\CCS_prj_new\MyFilter\Debug\_output','r');
data = fscanf(Id,'%d ');
data = data/10^4;
sound(data,8000); %播放时,注意采样率需要与生成时一致
fclose(Id);
教程结束,点个赞再走嘛!