IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> CCS中C语言应用开发实例 -> 正文阅读

[人工智能]CCS中C语言应用开发实例

山东大学信息学院DSP课程实验二

【实验目的】 ??

1. 熟练掌握DSP开发流程

2. 掌握运用C语言基于CCS的项目设计思路及过程

【实验要求】 ?

1. 利用MATLAB的滤波器设计软件,生成低通滤波器、高通滤波器,分别给出滤波器系数。

2. 利用MATLAB产生由不同的正弦波合成的波形文件,送入CCS。

3. 编写C程序,分别实现低通、高通滤波,用CCS画出波形,给出结果分析

4. 利用编译器的op选项,对实验二的C语言程序按照级别进行优化,给出耗时的变化的分析。

5. 应用CCS的内联函数实现低通、高通滤波,与步骤1中的耗时进行比较

【实验具体内容】

1. 利用MATLAB的滤波器设计软件,生成低通滤波器、高通滤波器,分别给出滤波器系数。

采用开发环境为:Win 10 Matlab2020a版本

  1. 在Matlab命令窗口输入:filterDesigner命令,打开FilterDesigner设计工具

uploading.4e448015.gif

正在上传…重新上传取消

图1.1 ?打开FilterDesigner

或直接选择Matlab中APP选择中的:FilterDesigner

图1.2 ?FilterDesigner设计工具

  1. 调整FIR低通滤波器的参数

选择FIR等波纹型、滤波器阶数200阶,采样频率4096、=200Hz/=300Hz

图1.3 ?FIR低通滤波器设计

设置好参数后点击“设计滤波器”,可通过观察“幅值响应”波形图直观的看出滤波效果。接下来需要将生成的滤波系数导出以便后续加载到CCS中。

图1.4 ?点击目标生成头文件

图1.5 生成C头文件界面

生成C头文件如下:

图1.6 ?生成低通滤波器系数头文件

  1. 调整FIR高通滤波器的参数

选择FIR等波纹型、滤波器阶数200阶,采样频率4096、=800Hz/=100Hz

图1.7 ?高通滤波器设计

同上述步骤生成C头文件:

图1.8 ?生成高通滤波器系数头文件

2. 利用MATLAB产生由不同的正弦波合成的波形文件,送入CCS。

在进行DSP算法设计时,我们通常会在Matlab上验证一下算法是否正确,然后再把算法移植到DSP当中,然而在移植的过程中会不可避免的出现各种问题,这时就需要将DSP内存中的数据导出来传到Matlab中进行分析处理,同时我们也需要从Matlab传递一些数据到DSP当中,比如我们想生成某种比较复杂的数据(例如各种类型的噪声),如果用C语言来写的话将会非常的麻烦,而这些用matlab能够亲而易举的完成,这时我们只需要将matlab生成的数据导入到DSP中就可以了

首先需要利用Matlab生成若干个数据,然后存储为dat格式的文件,然后通过CCS将dat格式的文件导入到DSP中。

dat文件时CCS能够识别的文件之一、CCS支持的dat文件格式为:

文件头为:

定数 ??数据格式 起始地址 页类型 ??数据块大小

1651 ????????1 ???????80000000 ????????0 ??????????10

固定标识???数据格式?????基地址???????页类型 ??????长度

固定标识:它的值固定为1651

数据格式:1-十六进制 ?2-十进制 ?3-十进制长整型 ?4-十进制浮点型

基地址: ?就是要存入到DSP一段内存空间的首地址

页类型: ?0-数据 ??1-程序 ?

长度: ???装入数据的长度

1)首先给出Matlab源代码:

f1=100;

f2=1500;

fs=4096;

N=1024;

T=1/fs;

n=0:N;

y1=1024*sin(2*pi*f1*n*T);

y2=1024*sin(2*pi*f2*n*T);

y=y1+y2;

xto_ccs=round(y);

fid=fopen('input1.dat','w');%将文件头写入文件,将生成的y信号写入到文件,格式四位小数

fprintf(fid,'%d\n',xto_ccs);

fclose(fid);

采用=100Hz和两种频率(高频、低频)组成噪声信号波形

图2.1 ?源代码截图

  1. 运行一下程序得到一个名为input1的dat文件,其保存在当前Matlab活动的目录。

图2.2 ?生成.dat文件

用记事本的方式打开此文件里面的内容如下:

图2.3 ?生成.dat文件中内容

  1. 将生成的的input1.dat文件拷贝到在CCS中新创建的工程项目工作文件夹中

  1. 在CCS中编写程序实现波形导入

源程序如下:

#include "stdio.h"

#include "LPF1.h"

#include <math.h>

#include <stdlib.h>

#define Length 1024

#define pi 3.1415926

??

long yn; //保存滤波后结果,32位长整型

long input[Length]; //

long output[Length];

int i;

void main() {

int m,n;

for(n=0;n<Length+BL;n++) //卷积计算

{

yn=0;

for(m=0;(m<BL)&&(m<n);m++)

yn+=B[m]*input[n-m];

output[n]=yn;

}

while(1);

}

  1. 在while(1)处设置断点

图2.4 ?设置断点

接下来打开断点管理器Breakpoints,进行断点设置

图2.5 ?打开断点管理器

图2.6 ?断点管理器内容

图2.7 ?设置断点Action

进行如下选择:

File:选择所产生的.dat文件作为数据导入

Wrap Around:True

Start Address:input

Page:DATA

Length:1024

图2.8 ?Read Data from File 设置

点击OK后即可完成Matlab合成波形文件并送入CCS

3. 编写C程序,分别实现低通、高通滤波,用CCS画出波形,给出结果分析

建立工程添加文件。建立工程,工程结构如下图所示。将在matlab中生成的c语言头文件添加至CCS工程文件夹下面。在matlab生成的CCS头文件中,需要调用matlab的头文件。将头文件拷贝到工程路径下即可。

图3.1 ?工程结构框架

只拷贝生成的头文件后,运行可能会出错,提示缺失某个文件“tmwtypes.h”。该文件在matlab安装路径下。可以直接在安装路径下搜索该文件,直接拷贝到工程路径下即可。

输入信号生成,代码如下:

??????for(i=0;i<Length;i++)

???????????????????input[i]=1024*sin(w1*i)+1024*sin(w2*i);??

因为计算时,其他数据类型都为整数,因此需要将-1~+1的小数格式转换为整数,不然在-1~+1的小数数据绝对值不超过1,那么在内存中都将被视作0,会导致波形严重失真。所以在此处需要将小数数据转换为整数型,又因为最后输出数据类型设置为long型,为了保证在计算过程中不溢出,Q值不能设置过大。

卷积计算公式为:

在计算机中要处理的信号和处理完成后的信号都可以用数组来保存,并且信号都为因果信号,即下表没有负数项,下标可以从0开始计算

已知h(n)的长度为BL,x(n)的长度为Length,利用外层循环控制n,内层循环控制m,将卷积计算的公式可表示为如下代码。

for(n=0;n<Length+BL;n++) ?????????????

????{undefined

????????yn=0;

????????for(m=0;(m<BL)&&(m<n);m++)

????????????yn+=B[m]*input[n-m];

????????output[n]=yn;

????}

CCS仿真测试情况??

  1. 源代码如下:

#include "stdio.h"

#include "LPF1.h"

#include <math.h>

#include <stdlib.h>

#define Length 1024

#define pi 3.1415926

int fs=4096; //采样频率

int f1=100; //信号频率

int f2=1500; //噪声频率

#define w1 2*pi*f1/fs //信号角频率

#define w2 2*pi*f2/fs //噪声角频率

long yn; //保存滤波后结果,32位长整型

long input[Length];

long output[Length];

int i;

void main() {

int m,n;

for(i=0;i<Length;i++)

input[i]=1024*sin(w1*i)+1024*sin(w2*i); //待滤波信号,乘以1024转换为Q10格式(sin范围为-1~1,将其转换为整数格式)

for(n=0;n<Length+BL;n++) //卷积计算

{

yn=0;

for(m=0;(m<BL)&&(m<n);m++)

yn+=B[m]*input[n-m];

output[n]=yn;

}

while(1);

}

  1. 点击调试按钮,出现如下界面

图3.2 ?调试结果

  1. 设置断点。在while(1)处设置断点。如下图所示:

图3.3 ?设置断点

  1. 装载项目

图3.4 ?装载项目

选择volume2.out文件,并点击打开

图3.5 ?选择volume2.out文件

  1. 运行程序。将光标置于断点处后,点击调试栏中的“Run to cursor”

图3.6 ?点击Run to cursor执行程序

  1. 波形生成。利用CCS软件自带的graph工具测试输入输出波形,并且可以对信号进行频谱分析。操作过程如下图所示:

图3.7 ?创建Graph图标窗口

  1. Graph显示参数设置

①时域显示参数设置,如下图,设置完成后点击OK即可显示曲线

图3.8 ?时域显示参数设置

参数说明:

Acquisition Buffer Size:表示通过仿真器从DSP的内存中读取的数据的大小。由于程序里用于存储信号的数组大小是1024,这里我们设置成1024,也可以设置成比他更小的值,这样就只能看到信号的部分图像。

Dsp Data Type:数据类型设置,因为在程序中使用的是long型数据,在这里需要设置成32位整形数据。

Index Increment:索引增量,表示每个数据点序号的相差值,这里是逐点显示的,因此默认设置为1,如果想要每隔一个点显示一个那么就应该设置成2。

Q_Value:Q值,一般这不常用,默认。

Sampling Rate Hz:以Hz为单位的采样率,在这里我们的采样率是4096,因此设置成4096。

Start Address:开始地址,表示要显示的数组的首地址,假设我们现在想要看的是数组input因此,设置这里设置成input。

Auto Scale:自动调整显示比例使其适应整个显示窗口,默认即可。

Axis Display :显示坐标轴,默认即可。

Data Plot Style:数据绘制类型,有Line和Bar两种,这里选择Line。

Display Data Size:显示数据大小,表示要将多少个点的数据进行显示,注意这个值一定要小于等于Acquisition Buffer Size,这里设置成1024。

Grid Style:网格类型,有 NoGrid, Minor Grid, Major Grid三种选项,默认即可。

Magnitude Display Scale:幅值显示类型,有Linear(线性的)Logarithmic(对数的),默认即可。

Time Display Unit:显示时间的单位有sample,s, ms, us几种可选,其中sample表示显示的点的序号,默认即可。

Use Dc Value For Graph:是否使用Dc值,一般不常用,默认即可。

②频谱显示参数设置,如下图

图3.9 ?FFT显示参数设置

参数说明:部分参数和时域显示时的参数相同,有部分不同如下:

Signal Type :信号类型,有Real,Complex这两种,此处信号数据均为实数据,因此我们选择Real,如果数据类型是Complex,选择Complex。

Frequency Display Unit :频率显示单位,有Hz,KHz,MHz三种,这里选择Hz。

FFT Order :FFT的阶数,由它来决定FFT Frame Size,例如 FFT Order 设置为5 那么FFT Frame Size 就为32 = 2^5。这里我们设置成12,那么FFT Frame Size就是4096。

FFT Frame Size :FFT做变换的点数,FFT Order决定,此处选择4096点FFT。

FFT Window Function :FFT窗函数,选择做FFT变换时采用什么窗函数,有Rectangular(矩形窗),Bartlett,Blackman,Hamming,Hanning,选择什么窗函数根据实际的需求来决定到底采用哪一个窗函数,默认即可。

  1. 波形显示

①按照上述操作实现的低通滤波

图3.10 ?低通显示图形

②将头文件中的LPF1.h文件更换成为HPF.h后,重复上述操作实现高通滤波

图3.11 ?高通显示图形

  1. 利用编译器的op选项,对实验二的C语言程序按照级别进行优化,给出耗时的变化的分析。

每个文件都可以设置编译器优化,右键.c文件->File Specific options>optimization level 设置成空的,即可在debug的时候避免出现异常。开编译器优化可能导致跟踪函数的变量时值是错的。编译优化的好处是加快代码运行速度,但缺点就是只能把函数当做黑盒,函数内部的bebug结果是不可靠的。所以一般将算法和流程编到不同的文件中去,因为算法文件一般都是验证完了的,不怎么需要调试,所以算法文件开适当的优化,流程文件不开优化。这样既能提高运行效率又可以不影响流程的调试

图4.1 ?选择File Specific options

图4.2 ?Opt Level选择

进行代码优化,先要找出程序的瓶颈,即占用CPU时间较多的代码,然后对其进行有针对性的优化。使用CCS提供的代码剖析工具Profile可以统计显示出程序中各个重要段和函数的运行时间,找出运算量较大的程序段,优化这些程序段,对于提高算法的性能有巨大影响。
??①联合使用-pm和-03编译选项,对代码进行项目级的优化:CCS提供了强大功能的编译选项,从-O0到-O3共四级优化。-O3编译选项使能软件流水和其他优化方法,-pm选项从程序代码角度,把整个项目的所有源程序联合起来,作为一个模块来处理。-pm和-03两个选项联合使用,能进行一系列的优化,并且代码尺寸变小很多。 

②使用const、restrict 关键字修饰指针:const指示编译器其修饰的指针所指向的内容不能修改;restrict指示编译器其修饰的指针与其他指针指向的内容不会覆盖,这些信息使两个指针不会访问同一存储器地址,可以消除存储器之间的相关性,这样可以并行执行多个数据的读取和运算,使代码运行达到昀大效率。
③对短字长数据使用宽长度的存储器访问(数据打包处理):即当CPU执行一连串短型数据(如16bit数据)操作时,可将数据类型设置为32bit长度的int型,这样可以一次性访问2个短型数据,然后使用C6000指令,同时进行两个数据的操作,减少了对内存的访问,这比采用16bit长度short型节约一半的时间。
??④循环展开,把C语言中的循环打开,把多循环变为少循环,减少循环嵌套,使得可能并行的指令增加,从而改进软件流水编排,改善代码性能。
⑤减少C函数的调用,尽量使用系统提供的内联函数(intrinsics函数)代替C函数,C6000编译器提供了许多intrinsics,是直接与C6000汇编指令映射的在线函数,可以快速优化C代码,这样减少许多不必要的操作,提高代码运算速度。
?⑥使用软件流水技术,软件流水是一种对循环中的指令进行调度优化的技术,利用软件流水可生成非常紧凑的循环代码。当编译时采用-O2或-O3级别的优化选项时,编译器将对程序中的循环进行软件流水。通过软件流水的优化,可以大大提高循环代码的效率,极大地实现指令的并行性。

  1. 打开耗时计数时钟

图4.3 ?打开Clock视图

  1. 观察不同优化级别耗时情况

图4.4 ?优化级别为NONE

图4.5 ?优化级别为o0

图4.5 ?优化级别为o1

图4.5 ?优化级别为o2

图4.5 ?优化级别为o3

  1. 应用CCS的内联函数实现低通、高通滤波,与步骤1中的耗时进行比较

????在使用fir函数之前首先要把相关的头文件和一些库文件加入到工程中,在如图的安装路径下找到并打开此头文件和一个库文件,复制到工程所在文件夹中

图5.1 ?复制相关头文件库文件

接着在工程右键打开build option选项里把头文件的路径加进去即可,最后还要把54xdsp.lib这个库文件导入工程的library中,不然会有报错

?????????

图5.2 ?添加头文件

接着编写C文件的程序和cmd文件,核心程序如下:

#include <stdio.h>

#include <math.h>

#include "dsplib.h"

#define pi 3.1415926

//采样频率,单位Hz

int fs=4096;

//产生正弦波频率,单位为Hz

int f1=100,f2=1500;

//定义信号角频率

#define w1 2*pi*f1/fs

#define w2 2*pi*f2/fs

//输入波形数组大小

DATA In[1024];

/*------------等波纹设计法(Equiripple),阶数64,通带幅值衰减 Wpass=1dB,阻带幅值衰减 Wstop1=80dB---------------*/

/*通带频率 Fpass=100Hz,截止频率 Fstop=150Hz,采样频率 Fs=4096Hz*/

#pragma DATA_SECTION(lowpass,".lowpass")//定义一个数据段,需要在cmd文件中有相应的段定义

DATA lowpass[64] = {

?????-129, ?????4, ????11, ????24, ????43, ????67, ????98, ???136, ???180,

??????232, ???291, ???357, ???430, ???510, ???596, ???686, ???782, ???880,

??????981, ??1083, ??1185, ??1285, ??1381, ??1474, ??1560, ??1638, ??1708,

?????1769, ??1818, ??1856, ??1882, ??1895, ??1895, ??1882, ??1856, ??1818,

?????1769, ??1708, ??1638, ??1560, ??1474, ??1381, ??1285, ??1185, ??1083,

??????981, ???880, ???782, ???686, ???596, ???510, ???430, ???357, ???291,

??????232, ???180, ???136, ????98, ????67, ????43, ????24, ????11, ?????4,

?????-129

};

/*------------------------------------------------------------------------------------------------------*/

/*低通滤波数据缓存*/

#pragma DATA_SECTION(buf1,".buffer1")//定义一个数据段,需要在cmd文件中有相应的段定义

DATA buf1[64] ;

DATA ?*buf1ptr = &buf1[0];

DATA ff1[1024];//低通滤波输出数组

void main()

{

??? int i;

? printf("HelloWorld!\n");

for(i=0;i<1024;i++) //产生波形

In[i]=1024*sin(w1*i)+1024*sin(w2*i)

/*fir(DATA *x, DATA *h, DATA *r,DATA **d, ushort nh, ushort nx);

????*x:待滤波信号输入 ????????

????*h:滤波系数,即一个数组

????*r:滤波输出

????*d:滤波输出缓存

????*nh:滤波器的阶数

????*nx:待滤波信号输入的大小,即数组的大小

*/

fir(In, lowpass, ff1, &buf1ptr, 64, 1024); // ?调用函数,低通滤波

while(1);

}

MEMORY {

???PAGE 0: ??VECT: ????? origin = 0x80, ????????len = 0x80

???PAGE 0: ??PROG: ????? origin = 0x100, ???????len = 0x3f00 ?

???PAGE 1: ??DATA: ????? origin = 0x4000, ??????len = 0x3c00 ??

???PAGE 1: ??f1aDATA: ??? origin = 0x8000, ??????len = 0x80

???PAGE 1: ??f1bDATA: ??? origin = 0x8080, ??????len = 0x80

} /* MEMORY */

SECTIONS {

???.text ???> PROG PAGE 0 ??????????????/* code ????????????????????*/

???.switch ?> PROG PAGE 0 ??????????????/* switch table info ???????*/

???.cinit ??> PROG PAGE 0

???.vectors > VECT PAGE 0 ???????????????/* interrupt vectors ????????*/

???

???.cio ????> DATA PAGE 1 ??????????????/* C I/O ????????????????????*/ ?

???.data ???> DATA PAGE 1 ??????/* initialized data ?????????*/

???.bss ????> DATA PAGE 1 ??????/* global & static variables */

???.const ??> DATA PAGE 1 ??????????????/* constant data ????????????*/

???.sysmem ?> DATA PAGE 1 ??????????????/* heap ?????????????????????*/

???.stack ??> DATA PAGE 1 ??????????????/* stack ????????????????????*/

???.buffer1: ?{} align =64, ?load = f1aDATA PAGE 1 ??

???.lowpass: ?{} align =64, ?load = f1bDATA PAGE 1 ?????

} ??/*SECTIONS */

由于在程序中定义了数据段,所以要在cmd文件中定义使用的数据段大小

图5.3 ?定义cmd文字内容

再次编译一下,如果没有问题的话应该是没有错误和警告的,然后就可以查看频谱了,操作跟上面看输入信号频谱一样,需要修改的是开始的地址,改为滤波输出的数组的名称即可

图5.4 ?修改滤波输出数组名

图 5.5 ?运用内联函数实现低通滤波

图5.6 ?运用内联函数实现高通滤波

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-11-26 08:51:52  更:2021-11-26 08:53:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 4:37:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码