美文网首页
关于DDS的正弦波ROM裁剪问题

关于DDS的正弦波ROM裁剪问题

作者: 今日你学左米啊 | 来源:发表于2019-07-23 17:17 被阅读0次

关于DDS的正弦波ROM裁剪问题

质疑著
在这里感谢电子森林的苏老师对上一篇博客提出的质疑

[TOC]

问题是这样的

在上一篇博客中我曾经写到:

打脸图
\frac18是在一个别人写的专利交底书的里面看到的,当时心理想了想觉得是可以的,没有实际地操作过

然后我把博客分享到朋友圈后收到了电子森林苏老师的一些质疑,其中一个便是这个应该是\frac14还是\frac18的问题,当时年少轻狂的我说着应该是\frac18,结果吃完饭想着实验一下,便发现,这错的离谱了。。。史称秒打脸,故作此篇实地操作一下这个\frac14的ROM表压缩,也算是对自己的一个小警示..

MATLAB生成1/4的ROM表

这里本来应该是8192个点的,因为我中途意识到自己的错误的时候,为了偷懒不重新配置ROM,所以就把这里改成了4096个点,其他的唯一改动就在于在文件写入操作的时候只写了前\frac14个点,和修复了以前mif文件没有自动加END;结尾的BUG.

这并不是很重要

depth = 4096;
width = 14;
x = 0 : 2*pi/(depth-1) :2*pi;
y = sin(x);

y=(y+1)/2*16383/16384;      %转正
disp(y);
y_qua = round(y*2^width);

%编写mif文件
fid = fopen('/home/heweibao/project_matlab/fpga_dds/sindiv8.mif','wt'); %将信号写入一个.mif文件中
fprintf(fid,'WIDTH=%d;\n',width);%写入存储位宽
fprintf(fid,'DEPTH=%d;\n',depth/4);%写入存储深度
fprintf(fid,'ADDRESS_RADIX=UNS;\n');%写入地址类型为无符号整型
fprintf(fid,'DATA_RADIX=UNS;\n');%写入数据类型为无符号整型
fprintf(fid,'CONTENT BEGIN\n');%起始内容
for num=0 : (depth-1)/4 
fprintf(fid,'%d:%14.0f;\n',num,y_qua(num+1));
end
fprintf(fid,'END;');
fclose(fid);

plot(x,y_qua);

FPGA状态机控制地址和加减

这里直接上图看一个周期:


自己画的图

至于为什么是这样,大家可以从导数的角度自己理解一下,所以写出来的状态机是这样的:

module fsm_control(
    input clk,rst_n,
    
    output reg oper_add_sub,    // 0 for add ,1 for sub 
    output reg [9:0] phase_address
);

parameter s0 = 2'b00,
             s1 = 2'b01,
             s2 = 2'b10,
             s3 = 2'b11;

reg [2:0] now_state;


always @(posedge clk or negedge rst_n)
begin 
    if(!rst_n)
        begin
            now_state <= s0;
            phase_address <= 10'd0;
            oper_add_sub <= 1'b0;
        end
    else
        case(now_state)
            
            s0:begin            
                    phase_address <= phase_address + 1'b1;
                    oper_add_sub  <= 1'b0;
                    
                    if(phase_address == 10'd1023) 
                        begin 
                           phase_address <= 10'd1023;
                            now_state   <= s1;
                        end
                    else    now_state <= s0;
                end
                
                
                
            s1:begin    
                    phase_address <= phase_address - 1'b1;
                    oper_add_sub  <= 1'b1;
                    
                    if(phase_address == 10'd0) 
                        begin 
                            phase_address <= 10'd0;
                            now_state   <= s2;
                        end
                    else    now_state <= s1;
                end
                
            s2:begin    
                    phase_address <= phase_address + 1'b1;
                    oper_add_sub  <= 1'b1;
                    
                    if(phase_address == 10'd1023 ) 
                        begin 
                           phase_address <= 10'd1023;
                            now_state   <= s3;
                        end
                    else    now_state <= s2;
                end
            s3:begin    
                    phase_address <= phase_address - 1'b1;
                    oper_add_sub  <= 1'b0;
                    
                    if(phase_address == 10'd0 ) 
                        begin 
                            phase_address <= 10'd0;
                            now_state   <= s0;
                        end
                    else    now_state <= s3;
                end
        endcase
end
endmodule

ROM操作端

这里要考虑就是我的数据是没有符号位的,所以取加减的时候需要求出变化量的绝对值,而且变化量要防止因为状态切换而突然变大导致波形失真,要做一个阈值判断.最后就是初始值给最大值的一半.

module data_process(
    input clk,rst_n,
    input oper_add_sub, // 0 for add ,1 for sub 
    input [9:0] phase_address,
    
    output wire [13:0] data_out
);

wire [13:0] rom_data_out;

rom_sin_8   rom_sin_8_inst (
    .address ( phase_address ),
    .clock ( clk ),
    .q ( rom_data_out )
    );



reg [13:0] data_shift ,data_shift_pre;
always @(posedge clk or negedge rst_n)
begin 
    if(!rst_n)
        begin
            data_shift <= 14'd0;
            data_shift_pre <= 14'd0;
        end
    else
        begin 
            data_shift <= data_shift_pre;
            data_shift_pre <= rom_data_out;
        end
end

wire [13:0] delta_data;
assign  delta_data_pre = data_shift<data_shift_pre ? (data_shift_pre - data_shift) :
                                                     (data_shift-data_shift_pre);


reg [13:0] out_data;
always @(posedge clk or negedge rst_n)
begin 
    if(!rst_n)
            out_data <= 14'd8192;
    else
    //  out_data <= oper_add_sub ? (out_data-delta_data<14'b0)? 14'b0  : (out_data-delta_data) : 
    //                        (out_data+delta_data>14'h3fff)? 14'h3fff : (out_data+delta_data);
        out_data <= oper_add_sub ? (out_data-delta_data) :(out_data+delta_data);
end

assign data_out = out_data;

endmodule

仿真结果

仿真

结语

这次确实是年少轻狂,没认真思考惹的问题. 不过错了就应该大大方方承认嘛.

自省年少显轻狂,俯首道歉表心怀

再一次谢谢电子森林苏老师的质疑.

如果你觉得有丶收获的话

相关文章

网友评论

      本文标题:关于DDS的正弦波ROM裁剪问题

      本文链接:https://www.haomeiwen.com/subject/dgualctx.html