0%

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

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

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

[TOC]

问题是这样的

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

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

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

MATLAB生成1/4的ROM表

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

这并不是很重要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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状态机控制地址和加减

这里直接上图看一个周期:
bb
至于为什么是这样,大家可以从导数的角度自己理解一下,所以写出来的状态机是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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操作端

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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

仿真结果

CC

结语

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

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

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

如果你觉得有丶收获的话