在FPGA中实现DDS方案详解(频率,幅度,波形可调)

在FPGA中实现DDS方案详解(频率,幅度,波形可调)

目录

1. DDS原理简介

2. 代码实现

2.1 控制模块

2.2 DDS实现模块

2.3 ip核ROM的实现

3. 实验结果

3.1 仿真结果

3.2 实际输出结果

3.2.1波形选择

3.2.2 频率控制:

3.2.3 幅度控制


1. DDS原理简介

        DDS技术是从波形相位概念出发,直接对相应的波形数据进行抽样,得到不同的相位,通过DAC转换成模拟波形,最后通过低通滤波器平滑输出所需频率的波形。下图为DDS的示意流程图。


两个重要参数解释:      

         频率控制字FTW:一般为整数,数值大小控制输出信号的频率大小,数值越大输出信号频率越高,实际输出的信号的频率与频率控制字关系为:

频率控制字 = 脉冲频率 * 2^N / 时钟频率

        相位控制字P_WORD:一般为整数,数值大小控制输出信号的相位偏移,主要用于相位的信号调制


一个普通的DDS设计应该由:相位累加器,相位调制器,波形数据表,DAC转换组成。

        相位累加器:是整个DDS的核心,用于控制波形的相位累加,组成完整的波形显示。

相位累加器的输入为频率控制字,表示相位增量,其位宽为N。

        相位调制器:接收相位累加器输出的相位码,在这里加上一个相位偏移值P,主要用于信号的相位调制。

        波形数据表:波形数据表ROM中存有一个完整周期的正弦波信号。举个例子:假设波形数据ROM的地址位宽为12位,储存数据位宽为8位,即ROM有

2^{12}=4096

个存储空间,每个存储空间可以存储1字节数据。将一个周期的正弦波信号,沿横轴等间隔采样4096次,每次采集的信号幅度用1字节数据表示,最大值为255,最小值为0。将4096次采样结果按顺序写入ROM的4096个存储单元,一个完整周期正弦波的数字幅度信号就写入了波形数据表ROM中。波形数据表ROM以相位调制器传入的相位码为ROM读地址,将地址对应存储单元的电压幅值数字量进行输出。

        DAC转换:将输入的电压幅值数字量转换为模拟量输出。由上个公式可得,当频率控制字FTW为1时,此时输出信号频率最低。根据奈奎斯特采样定理,频率控制字的最大值应小于 2^N / 2 

运行流程为:


相位累加器得到的相位码是如何实现ROM寻址的呢?

        对于N位的相位累加器,其对应的相位累加值为2^N,如果正弦ROM中存储单元的个数也是2^N的话,那这个问题就很容易解决,但是这对ROM的存储容量要求较高。

        那么在实际中,我们使用相位累加器的高几位来对ROM进行寻址,也就是说并不是每个系统时钟都对ROM进行数据读取,而是多个时钟读取一次,因为这样能保证相位累加器溢出时,从正弦ROM表中取出正好一个正弦周期的样点。

        因此,相位累加器每计数2^N次,对应一个正弦周期。而相位累加器1秒钟计数fclk次(工作时钟频率),当频率控制字FTW为1时,DDS输出的时钟频率就是频率分辨率。当FTW增加时,相位累加器溢出的频率增加,对应DDS输出信号频率就变成了FTW倍的DDS频率分辨率。

        举个例子:

        假设ROM的存储单元个数为4096,每个存储数据用8位二进制表示。即ROM地址线宽为12,数据线宽为8;相位累加器位宽设置为N=32。

        由于ROM地址线位宽为12,所以相位调制器的输出位宽也应该为12。(因为DDS原理就是通过相位调制器的输出去ROM寻址)在相位调制器中与相位控制字进行累加时,用相位累加器的高12位累加,而低位只与频率控制字累加

        以频率控制字FTW=1为例,相位累加器的低20位一直加1,直到低20位溢出而向高12位进位,此时ROM为0,也就是说,ROM的0地址中的数据被读了2^20次,继续往下,ROM的4096个点全部都会读2^20次,最终输出的波形频率应该是参考时钟频率的1/2^20,周期被扩大了2^20倍。同样当频率控制字为100时,所以最终输出频率是上述的100倍。


2. 代码实现

        本次实验的硬件平台为小梅哥AC101-EDA,开发软件为Quartus13.1。

        由上节对DDS原理的介绍,可以分为以下几个模块。        


2.1 控制模块

频率控制模块、相位控制模块、幅度控制模块这三个模块的逻辑一模一样,即:指定一个按键,通过按键的值将对应的参数进行改变。下面以幅度控制模块进行举例说明。

当系统检测到按键被按下后,将变量cnt进行计数:

即用cnt来表示按键的按下的次数,这里是当cnt按下5次后,被清零。其中key_flag表示按键按下,由按键消抖模块输出。

        amplitude的值由cnt的值决定,用一个case语句即可实现。

 其他两个模块几乎一模一样,这里不再赘述。


2.2 DDS实现模块

还需要设计一个波形选择的功能,可按如下实现。

其中dac_data0、dac_data1、dac_data2、dac_data3分别对应四个rom的输出。


2.3 ip核ROM的实现

在Quatrtus13.1中,rom使用ip核进行实现:由于实验所用的开发板的DAC为8位,所以ROM的数据位宽这里也设置为8。

总共使用4个ROM,分别对应正弦波、三角波、方波、锯齿波,ROM所需的.mif文件由matlab实现。如正弦波文件的matlab代码如下:

clc; %清除命令行命令 clear all; %清除工作区变量,释放内存空间 F1=1; %信号频率 Fs=2^12; %采样频率 P1=0; %信号初始相位 N=2^12; %采样点数 t=[0:1/Fs:(N-1)/Fs]; %采样时刻 ADC=2^7 - 1; %直流分量 A=2^7; %信号幅度 %生成正弦信号 s=A*sin(2*pi*F1*t + pi*P1/180) + ADC; plot(s); %绘制图形 %创建mif文件 fild = fopen('sin_wave_4096x8.mif','wt'); %写入mif文件头 fprintf(fild, '%s\n','WIDTH=8;'); %位宽 fprintf(fild, '%s\n\n','DEPTH=4096;'); %深度 fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;'); %地址格式 fprintf(fild, '%s\n\n','DATA_RADIX=UNS;'); %数据格式 fprintf(fild, '%s\t','CONTENT'); %地址 fprintf(fild, '%s\n','BEGIN'); %开始 for i = 1:N s0(i) = round(s(i)); %对小数四舍五入以取整 if s0(i) <0 %负1强制置零 s0(i) = 0 end fprintf(fild, '\t%g\t',i-1); %地址编码 fprintf(fild, '%s\t',':'); %冒号 fprintf(fild, '%d',s0(i)); %数据写入 fprintf(fild, '%s\n',';'); %分号,换行 end fprintf(fild, '%s\n','END;'); %结束 fclose(fild);

这里需要注意一点的是,如果在modelsim进行仿真时,rom输出一直为0,是因为没有把生成的.mif文件放在quartus的工程目录下。具体可以看一下我的这篇文章modelsim无法读取.mif文件

但是是否对实际输出波形有影响不知道,我没有实践过。

DAC驱动模块:

        开发板上的DAC是MCP4802,采用的SPI通信。代码部分参考这篇文章基于FPGA的目标反射回波检测算法及其实现(准备篇)

在Quartus中查看RTL视图:


3. 实验结果

3.1 仿真结果

3.2 实际输出结果

3.2.1波形选择

3.2.2 频率控制

3.2.3 幅度控制


若有不懂,不清楚的地方或有相关建议,欢迎留言!


Read more

Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

1.引言 随着大模型在各类智能应用中的广泛应用,高效的推理硬件成为关键瓶颈。昇腾 NPU(Ascend Neural Processing Unit)凭借其高算力、低能耗以及对 SGLang 的深度优化,能够显著提升大模型推理性能。本文以 Llama 3-8B-Instruct 为例,通过在昇腾 NPU 上的实测,展示其在吞吐量、延迟和资源利用方面的优势,并探索可行的优化策略,为开发者在今后的开发中提供可参考的案例。 在本篇文章中我们会使用到Gitcode的Notebook来进行实战,GitCode Notebook 提供了开箱即用的云端开发环境,支持 Python、SGLang 及昇腾 NPU 相关依赖,无需本地复杂环境配置即可直接运行代码和进行实验。对于没有硬件平台的小伙伴来说是非常便利的。 GitCode Notebook使用链接:https://gitcode.com/user/m0_49476241/notebook。 2.实验环境与准备 2.

GitHub Copilot:Python开发者的AI助手

GitHub Copilot:Python开发者的AI助手 前言 大家好,我是第一程序员(名字大,人很菜)。作为一个非科班转码、正在学习Rust和Python的萌新,最近我开始使用GitHub Copilot。今天我想分享一下GitHub Copilot如何成为Python开发者的AI助手。 一、GitHub Copilot简介 1.1 什么是GitHub Copilot * AI编程助手:由GitHub和OpenAI合作开发的AI编程助手 * 代码生成:根据上下文自动生成代码 * 智能建议:提供智能的代码建议 * 多语言支持:支持多种编程语言,包括Python 1.2 GitHub Copilot的工作原理 * 基于GPT模型:使用OpenAI的GPT模型 * 代码训练:在大量开源代码上训练 * 上下文理解:理解代码的上下文和意图 * 实时建议:在编写代码时实时提供建议 二、GitHub Copilot在Python开发中的应用 2.1 代码生成 示例1:生成函数

医疗送药机器人“空间拓扑优化+动态算法决策+多级容错控制”三重链式编程技术解析与应用

医疗送药机器人“空间拓扑优化+动态算法决策+多级容错控制”三重链式编程技术解析与应用

一、引言 1.1 研究背景与意义 在医疗体系中,高效精准的药品配送是保障医疗服务质量和患者安全的关键环节。随着医疗技术的不断进步和医疗需求的日益增长,传统的人工送药方式逐渐暴露出诸多弊端,如配送效率低下、易受人为因素干扰导致错误率上升、人力成本高昂等。特别是在大型综合医院,科室众多、布局复杂,药品配送路径长且需经过多个区域,这使得人工送药的难度和工作量大幅增加,进而影响医疗服务的及时性和准确性。 医疗送药机器人的出现为解决这些问题提供了新的途径。它能够在医院复杂的环境中自主导航,按照预设的路径和时间准确地将药品送达指定地点,极大地提高了药品配送的效率和准确性。通过自动化的配送流程,送药机器人可有效减少人为因素造成的错误,如拿错药、送错药等情况,从而保障患者的用药安全。同时,送药机器人的应用还能将药师和护士从繁琐的药品配送工作中解放出来,使其能够将更多的时间和精力投入到临床药学服务和患者护理工作中,提高医疗服务的整体质量。 “空间拓扑优化 + 动态算法决策 + 多级容错控制” 三重链式编程技术的提出,为医疗送药机器人性能的进一步提升带来了革命性的突破。空间拓扑优化技术能够对医院的

RTMP高清推流直播/视频转码EasyDSS在无人机RTMP直播场景中的应用技术解析

RTMP高清推流直播/视频转码EasyDSS在无人机RTMP直播场景中的应用技术解析

在无人机直播赛道竞争日趋激烈的当下,推流稳定性、画面清晰度、延迟控制与操作便捷性,成为衡量平台实力的核心指标。EasyDSS流媒体平台之所以能在众多解决方案中脱颖而出,关键在于其深度整合机巢、RTMP推流、高清直播、低延迟等几大核心能力,形成“全链路优化、全场景适配”的竞争优势,彻底解决传统无人机直播的痛点,为用户提供更优质的直播体验。 核心优势1:RTMP推流优化,筑牢低延迟传输防线。 RTMP协议作为直播推流的主流协议,其低延迟特性的发挥直接决定直播体验。EasyDSS对RTMP协议进行深度优化,优化数据包传输逻辑,减少网络波动对推流的影响,将端到端延迟控制在2-5秒,远低于行业平均的10秒以上延迟,完美满足应急调度、实时监控等对延迟敏感的场景需求。即便在野外复杂网络环境下,也能实现流畅推流。 核心优势2:高清编码加持,呈现极致视觉体验。 高清直播是无人机直播的核心需求,尤其是在巡检、安防等场景中,画面清晰度直接影响问题识别的准确性。 EasyDSS采用H.265高效编码技术,相较于传统H.264编码,在保持相同视觉质量的前提下,压缩效率提升一倍,可在低带宽环