在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 3615|回复: 1

[原创] FPGA实现排序(中值滤波器设计)

[复制链接]
发表于 2017-1-24 15:19:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x

本文所用的算法很简单,以升序来说,有一数列[A0…..An],分别比较相邻的两两个元素,如果A(n) > A(n+1),则交换两个数的位置

举个例子:排序 序列[ 4 3 2 1]第一次比较分组{A0–A1};{A2–A3}: {4 > 3};{2>1}第一次交换位置后[ 3 4 1 2]第二次比较分组{A0};{A1-A2};{A3}:{3};{4>1};{2}
当然不能和第一次一样分组,那样就是原地踏步第二次交换位置后[ 3 1 4 2 ]第三次比较分组{A0–A1};{A2–A3}:{3 > 1};{4 > 2}
其实是和第一次一样,这个很重要,意味着可以用迭代的方法第三次交换位置后[1 3 2 4]第四次比较分组{A0};{A1-A2};{A3}:{1};{3>2};{4}
和第二次一样第四次交换位置后[ 1 2 3 4 ]排序完成算法需要4个clock,对4个,不是8个
此算法处理N长度的序列就需要N个clock,序列元素可以同值。
上面所有的“两两“交换也是http://opencores.org/的实现方式。
我要用更激进的方法~~”四四“分组,组内一次排4个数。序列[A0,A1,A2,A3…….A(n-2),A(n-1),A(n)]第一次分组{A1,A2,A3,A4};{A5->A8}…..{A(n-3),A(n-2),A(n-1),A(n)};第二次分组{A1-A2};{A3,A4,A5,A6}…..{A(n-5)->A(n-2};{A(n-1),A(n)};循环第一第二次。

此方法有个缺点,会有冗余的比较,例如第二次分组的时候A3,A4顺序是已经排过的,但是没关系,并不影响结果。
实现思路:

4个数分组排序是核心,如何实现4个数分组排序呢,且要在尽可能少的clock内完成,最好只用一个clock,如果用4个clock,就和上面的方式一样了。
假设排序前的序列是[A0,A1,A2,A3] ,排好序后的序列是[B0,B1,B2,B3]
A序列两两比较( >= :大于或等于),共有6种结果,我们把结果用一个的向量wire[5:0] C表示便是 6‘bXXX_XXX(本人使用的是verilog)





  1. C[5] = A0>=A1;
  2. C[4] = A0>=A2;
  3. C[3] = A0>=A3;
  4. C[2] = A1>=A2;
  5. C[1] = A1>=A3;
  6. C[0] = A2>=A3;


复制代码

那么,B的排序应该就是由C决定的 B=F(C);
B的值又是怎么决定的呢?
1、B[0]

如果A种的某个元素Ax不小于其他3个,那么我们就可以把它存入B[0]中。如果A0>{A1,A2,A3},那么就把A0赋予B0,
verilog实现:





  1. always@(posedge clock)begin
  2. casex(C)
  3. 6’b111_xxx: B[0]<= A[0];
  4. 6’b0xx_11x: B[0]<= A[1];
  5. 6’bx0x_0x1: B[0]<= A[2];
  6. 6’bxx0_x00: B[0]<= A[3];
  7. default: B[0]<= A[0];
  8. endcase
  9. end


复制代码

为什么case 有些状态有0?
对于A[0]来说 它比其他三个数大即 6‘b111_xxxx:
但是对于A[1] ,他要是最大必须是 6’b0xx_11x; C[5] 对于的是A[0] >= A[1], “0” 表示此式子不成立!
2、B[3]

和B[0] 类似,就不细说了
3、B[1],B[2]

B[1]:Ax对其他3个数中,比一个小,比两个大
B[2]:Ax对其他3个数中,比两个小,比一个大
情况比上两种复杂





  1. always@(posedge clock)begin
  2. casex(C)
  3. 6’b011_xxx,6’b101_xxx,6’b110_xxx: B[1]<= A[0]; //D0-01-d1 D0-01-d2 D0-01-d3
  4. 6’b1xx_11x,6’b0xx_01x,6’b0xx_10x: B[1]<= A[1]; //d0-01-D1 D1-01-d2 D1-01-d3
  5. 6’bx1x_0x1,6’bx0x_1x1,6’bx0x_0x0: B[1]<= A[2]; //d0-01-D2 d1-01-D2 D2-01-d3
  6. 6’bxx1_x00,6’bxx0_x10,6’bxx0_x01: B[1]<= A[3]; //d0-01-D3 d1-01-D3 d2-01-D3
  7. default: B[1]<= A[0];
  8. endcase
  9. end

  10. always@(posedge clock)begin
  11. casex(C)
  12. 6’b001_xxx,6’b100_xxx,6’b010_xxx: B[2]<= A[0]; //D0-01-d1 D0-01-d2 D0-01-d3
  13. 6’b1xx_01x,6’b0xx_00x,6’b1xx_10x: B[2]<= A[1]; //d0-01-D1 D1-01-d2 D1-01-d3
  14. 6’bx1x_1x1,6’bx0x_1x0,6’bx1x_0x0: B[2]<= A[2]; //d0-01-D2 d1-01-D2 D2-01-d3
  15. 6’bxx1_x10,6’bxx0_x11,6’bxx1_x01: B[2]<= A[3]; //d0-01-D3 d1-01-D3 d2-01-D3
  16. default: B[2]<= A[0];
  17. endcase
  18. end


复制代码

OK,”四四说完了“

组装N个序列了

组装一个25的看看,为什么是25,25不仅不是偶数,更不是4的倍数。haha~,25是5x5,排序25,就是直接做了一个5x5的中值滤波器!
25的分组,用6个“四”的排序,余1就不比较了,github上我是有用“三”的排序。

奇数次分组{A0->A3} {A4->A7} {A8->A11} {A12-A15} {A16->A19} {A20->A23} {A24}偶数次分组{A0} {A1} {A2->A5} {A6->A9} {A10->A13} {A14->A17} {A18->A21} {A22-A24}

只要迭代6次(github上的可不是迭代,纯流水实现),共排序13次(因为不够4除)就能实现25的排序,比传统方法快一倍,流水资源自然少一半。

FINISH:

既然多个数分组排序能提高速度和资源,为什么选4个而不是8个,16个呢,这样不是更快吗?
是的,组内数越多,迭代次数越少
如果把[A0…An] 只做成一个组,那么只要一个clock就行了。
时序,数越多,路径延时越长

排4的时候是
case((3_+2+1)’bxxxxxx)

排8的时候就是
case((7+6+5+4+2+1)’dx)=(case(sum(#8))= case(25’dx)
2^6 = 64种情况

排25的时候
2^25 = 33554432 放弃吧

源代码下载链接

发表于 2017-2-9 11:10:59 | 显示全部楼层
不错的中值排序方法。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-23 17:41 , Processed in 0.041785 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表