FC2カウンター FPGAの部屋

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vivado HLS 2016.4 における assert() 文の効果5(AXI4-Stream版での比較)

Vivado HLS 2016.4 における assert() 文の効果4(自分定義した固定小数点)”の続き。

前回は、アンシャープマスキング・フィルタ単体では、任意精度固定小数点型の方が自分で定義した固定小数点型に比べてリソース使用量が少なくなったという結果だったが、AXI4-Stream インターフェースを被せた状態ではどうなるか?をやってみた。

まずは、変数の変域を指定するために、pow() を使用して、定義値からの生成を行うようにコードを変更した。
それを利用してassert() を書いた。
まずは、任意精度固定小数点型を試してみた。ピンクの枠で示した assert() を追加した。
assert_35_170216.png

C コードの合成結果を示す。
assert_36_170216.png

Analysis 結果を示す。
assert_37_170216.png

37ステートだった。

Analysis 結果で、unsharp_masking() の使用リソースとステート見てみよう。
右上のModule Hierarchy で unsharp_masking をクリックした。
assert_38_170216.png

unsharp_masking() の使用リソースは、FF が 1313 個、LUT が 1331 個だそうだ。ステートは 31 ステートだった。

次に、assert() 文をコメントアウトしてみた。
合成結果を示す。
assert_39_170216.png

LUT が 2244 個から、2262 個に増えていた。FF も 1995 個から 2021 個に増えていた。Latency は同じだった。

Analysis 結果を示す。
assert_40_170216.png

ステートは 38 ステートで変更はない。

Analysis 結果で、unsharp_masking() の使用リソースとステートを見た。
assert_41_170216.png

31ステートで変化はない。FF が 1331 個、LUT が 1357 個だった。assert() が入っているときは、FF が 1313 個、LUT が 1331 個なので、明らかに assert() が無いほうが増えている。

次に、自分で定義した固定小数点型をやってやってみよう。このようにassert() が入っている。
assert_42_170216.png

合成結果を示す。
assert_43_170216.png

FF が 1986 個 、LUT が 1895 個だった。任意精度固定小数点型では、FF が 2244 個、LUT が 1995 なので、明らかに自分で定義した固定小数点型の方がリソース使用量が少ない。単体でテストしたのとは逆の結果になった。
Latency も 3104 クロックに対して、任意精度固定小数点型では 3108 クロックとなっている。

Analysis 結果を示す。
assert_44_170216.png

ステートも 33 ステートだった。こちらも任意精度固定小数点型では、37 ステートだったので、自分で定義した固定小数点型のほうがステートが少ない。

Analysis 結果で、unsharp_masking() の使用リソースとステートを見た。
assert_45_170216.png

FF は 1083 個、LUT は 1245 個だった。任意精度固定小数点型ではFF が 1313 個、LUT が 1331 個だった。

次に、自分で定義した固定小数点型で、assert() をすべてコメントアウトした。
assert_46_170217.png

合成結果を示す。
assert_47_170217.png

FF 、LUT 共に、assert() を入れてあるときと変化が無かった。assert() は効いていない。

AXI4-Stream インターフェースを被せた状態でアンシャープマスキング・フィルタの任意精度固定小数点型と自分で定義した固定小数点型はどっちが使用量が少ないか比べてみたが、自分で定義した固定小数点型の方が少ないという結果になった。これは、アンシャープマスキング・フィルタ単体とは逆の結果だ。

前回は、自分で定義した固定小数点型の方がリソース使用量が少ないという結果になって、自分で定義した固定小数点型を使おうという話になったが、assert() でリソース使用量を減らすことができるし、演算の間違いも少なくなるので、積極的に任意精度固定小数点型を使っていこうと思う。
  1. 2017年02月17日 04:28 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果4(自分で定義した固定小数点)

Vivado HLS 2016.4 における assert() 文の効果3”の続き。

これまでは、任意精度固定小数点型で assert() 文で変数の変域を指定するリソース使用量の低減効果を見てきたが、今回は、任意精度固定小数点型を使用しない自分で定義した固定小数点演算との比較をしてみた。

最初にC ソースコードを示す。これは、int 型を使用して、PRECISION の 6 ビット左シフトを行って小数桁を確保している。最後には 6 ビット右シフトして整数に戻す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// assertテスト用

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "unsharp_mask_axis.h"

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
// 2015/09/27 : 演算の小数部は num_adec_k*2 ビットとする。
//

#define PRECISION    6    // 小数点以下の桁数、精度(1以上)

int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
    int y;
    int xy[3][3];
    int result=0;
    int z;

    int x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -(xy[0][0]<<PRECISION) -(xy[0][1]<<PRECISION) -(xy[0][2]<<PRECISION)
            -(xy[1][0]<<PRECISION) +x1y1*xy[1][1]         -(xy[1][2]<<PRECISION)
            -(xy[2][0]<<PRECISION) -(xy[2][1]<<PRECISION) -(xy[2][2]<<PRECISION);

        y = ((k * y)/9) >> num_adec_k; // k は num_adc_k だけ左シフトされているので戻す

        z = y + (1<<(PRECISION-1)); // 四捨五入 +0.5
        z = z >> PRECISION; // 小数点以下切り捨て

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


プロジェクトを示す。
assert_26_170215.png

C コードの合成結果を示す。
assert_27_170215.png

任意精度固定小数点型で実装したときの assert() 無しに比べて、int 型を使用してシフトで小数を表した時のほうがリソース使用量が多い。それにLatency も長い。

Analysis 結果を示す。
assert_28_170215.png

こちらも、58 ステートで任意精度固定小数点型の38 ステートよりも多い。

次に assert.h をインクルードして、適当な assert() を入れてみた。
assert_29_170215.png

C コードlの合成を行った。
assert_30_170215.png

ものすごくリソース使用量が減った。やはり、assert() が効いているようだ。

Analysis 結果を示す。
assert_31_170215.png

4 ステートになってしまった。

最後に、まともに変域を考えて指定した。
assert_32_170215.png

C コードlの合成を行った。
assert_33_170215.png

元の合成結果と比べて、1353 個が 1291 個に減った。

Analysis 結果を示す。
assert_34_170215.png

58ステートになった。元と変化が無かった。

結果として、自分で定義した固定小数点演算をするよりも任意精度固定小数点型を使ったほうが、リソース使用量が少なかった。更に assert() を使うとリソース使用量が削減できるので、固定小数点を使うときは任意精度固定小数点型を使ったほうが良いと思う。
  1. 2017年02月15日 07:05 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果3

Vivado HLS 2016.4 における assert() 文の効果2”の続き。

前回も assert() 文を使用して、演算に使用する変数の変域を指定することにより、任意精度固定小数点型の飽和演算は必要ないとVivado HLS に認識してもらい、しかもビット長も制限されることでリソース使用量の低減を図ってきた。しかし、ループカウンタのカウント数の制限によってリソース使用量が低減はされたが、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

次に、assert() 文の変域の書き方は C や C++ の if() 文の中の様に C や C++ の結合規則によって記述するということを hiyuh さんに教えてもらった。それで書き直しても、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

もう一度、hiyuh さんに、assert() 文を入れる規則を教えてもらった。それを引用する。

assertの挿入箇所が適切ではありません.assertに与えられた条件式はその挿入箇所で評価されますので,被演算対象に対しては値が確定した演算前,代入対象については値が確定した代入後,可及的速やかに適用する必要があります.


ということで、下のソースコードで確かめてみたが、やはりリソース使用量には変化が無かった。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    temp = in0;
    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);

    //assert(limit <= 10);
    for (int i=0; i<limit; i++){
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
        temp = temp * (ap_xfix_def)2.0;
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    }

    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    *out = temp * in1;

    return(0);
}



次に、アンシャープ・マスキング・フィルタでもう一度、検証してみよう。ソースコードを示す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// ap_fixedバージョン 2015/10/04
//

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ap_int.h>
#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <iostream>

#include "unsharp_mask_axis.h"

using namespace std;

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
//

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88, AP_RND, AP_SAT> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1;
    y_fixed_td y;
    /*ap_ufixed<8, 8> xy[3][3];    int result=0;    ap_ufixed<8, 8, AP_RND, AP_SAT> z;    x1y1_fixed_td x1y1;    y_fixed_td y;*/

    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -xy[0][0]    -xy[0][1]        -xy[0][2]
            -xy[1][0]    +x1y1*xy[1][1]    -xy[1][2]
            -xy[2][0]    -xy[2][1]        -xy[2][2];
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = (k_fixed * y)/(y_fixed_td)9;
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = y+(y_fixed_td)0.5// 四捨五入
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));
        if (y < 0)
            z = 0;
        else if (y > 255)
            z = 255;
        else
            z = y;

        result += z.to_int()<<i; // i=0 : blue, i=8 : green, i=16 : red
    }
    return(result);
}


ヘッダファイルを示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_ufixed<K_BITLEN, K_BITLEN-NUM_ADC_K> k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION> y_fixed_td;

#define K 2.5 // 鮮鋭化の強さ

#endif


最初に assert() をコメントアウトして合成を行った。(なお、assert() 文の変域は正しくない。結果を見るためにわざと厳しい値にしてある)
assert_17_170214.png

合成後の結果を示す。
assert_18_170214.png

Analysis 結果を示す。
assert_19_170214.png

37 ステートだった。

次に assert() のコメントを外して合成を行った。
assert_20_170214.png

合成後の結果を示す。
assert_21_170214.png

Latency が 146 クロックから 131 クロックに 15 クロック減った。DSP48E, FF, LUT もすべて減っている。

Analysis 結果を示す。
assert_22_170214.png

32ステートだった。assert() 文を入れないときは、37ステートだったので、5ステート減っている。

これで、assert() 文で変数の変域を指定することにより、リソース使用量を減らせることが分かった。

最後に実際に使用予定の変数の変域を入れてみよう。
assert_23_170214.png

合成後の結果を示す。
assert_24_170214.png

やはり、assert() 文が無いのに比べてリソース使用量が減っている。

Analysis 結果を示す。
assert_25_170214.png

36ステートで、assert() 文が無いのに比べて 1 ステート減少した。
  1. 2017年02月14日 05:14 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果2

Vivado HLS 2016.4 における assert() 文の効果”の続き。

前回は、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無いという結論になったが、hiyuh さんに再度教えてもらって、もう一度やってみた。

前回の引数の変域の指定方法が間違っていた。hiyuh さんに教えてもらった C /C++ の結合則に従うということだった。それに、値をキャストするのを忘れていた。更に ap_ufixed もやってみようということでソースコードを書き換えた。
新しい ap_fixed_test.cpp を示す。
assert_7_170213.png

ap_fixed_test.cpp のソースコードを示す。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    //assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    //assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    //assert(*out > (ap_xfix_def)(-50.0) && *out < (ap_xfix_def)50.0);
    //assert(in0 < (ap_xfix_def)1.0);
    //assert(in1 < (ap_xfix_def)2.0);
    //assert(*out < (ap_xfix_def)50.0);

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_xfix_def)2.0;

    *out = temp * in1;

    return(0);
}


最初にもう一度、このソースコードのまま合成を行った。
assert_8_170213.png

次に、最初の 3 行の assert() 文を活かしてみよう。これは、符号あり小数の場合だ。
assert_9_170213.png

これを合成した。
assert_10_170213.png

レポートを見ると、assert() 文を活かして無い時と変わらない。

次に、ap_ufixed にして、符号なし小数の場合をやってみた。assert() 文はすべてコメントアウトしてある。
assert_11_170213.png

これを合成した。
assert_12_170213.png

符号あり少数の場合よりも、レイテンシもリソース使用量も少ない。符号なし小数で良いのであれば、大分お得ということができると思う。

次に、下の 3 つの assert() 文を活かした。
assert_13_170213.png

合成を行った。
assert_14_170213.png

assert() 文を入れたときと、入れないときでは変化が無かった。

最後に変数の temp に asset() 文を試しに入れてみた。
assert_15_170213.png

合成を行った。
assert_16_170213.png

temp 変数に assert() 文で変域を指定すると合成されなくなるようだ。
  1. 2017年02月13日 04:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果

Vivado HLS 2016.4 で変域を指定することができる assert() 文の効果を確かめてみた。

まずは、assert() は、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.4) 2016 年 11 月 30 日”の 344 ページの”アサート”に書かれている。最初の1文を引用する。

C の assert マクロは、 範囲情報をアサートするのに使用される場合、 合成でサポートされます。 たとえば、 変数 とループ境界の上限を指定でき ます。


そこで、任意精度固定小数点型を使う際の問題点の変数の変域が飽和演算が必要ない状態で、飽和演算回路を入れないようにできるかを探ってみた。
任意精度型固定小数点型を使用したアンシャープマスキング・フィルタの例については下のリンクを参照のこと。
Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)
Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)
Vivado HLS によるアンシャープマスクキング・フィルタの作製9(C++ の任意精度固定小数点型3)

ap_fixed_test というVivado HLS 2016.4 のプロジェクトを生成した。
assert_1_170212.png

ap_fixed_test.cpp を貼っておく。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

int ap_fixed_test(ap_fixed<16,8, AP_RND, AP_SAT> in0, ap_fixed<16,8, AP_RND, AP_SAT> in1, int limit,
        ap_fixed<16,8, AP_RND, AP_SAT> *out){

    ap_fixed<16,8, AP_RND, AP_SAT> temp;

    /*assert(-1 <= in0 <= 1);    assert(-2 <= in1 <= 2);    assert(-10 <= temp <= 10);    assert(-100 <= *out <= 100); */

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_fixed<16,8, AP_RND, AP_SAT>)2.0;

    *out = temp * in1;

    return(0);
}


まずはC コードの合成を行った。結果を示す。
assert_2_170212.png

Latency のmin は 4、max は 13 だった。これは、LOOP_TRIPCOUNT に設定した値が元になっている。LOOP_TRIPCOUNTのカウントにその他のレイテンシを加えたものが Latency として示されている。だが、LOOP_TRIPCOUNT は合成には影響しない。
そこで、合成に変数の変域を反映させるのが assert() だ。
まずは、引数と変数の変域を指定する assert() のコメントを外した。
assert_3_170212.png

これで合成してみよう。
assert_4_170212.png

前回と同じだ。この assert() は効かないようだ。

次に、今コメントを外した部分をコメントにして、LOOP_TRIPCOUNT の max と同じ値を assert() で指定した文のコメントを外す。
assert_5_170212.png

合成結果を示す。
assert_6_170212.png

FF は 137 個が 110 個に、LUT が 243 個が 189 個に減った。

この結果から、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無い様だ。

Vivado HLS 2016.4 における assert() 文の効果2”に続く。
  1. 2017年02月12日 07:16 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

バイキュービック法のFPGAへの適用

演算処理をFPGA へ適用するにはどうすれば良いかを検討している。私も先は長くないと思うので、少し公開してみようと思う。そのうちにVivaodo HLS で実装してみよう。

今回はバイキュービック(BiCubic)法をFPGA に適用できるように固定小数点に直して演算する方法だ。
具体的には、バイキュービック法を用いて画像を横2倍、縦2倍にするときの演算である。

参考したのは、「画像の拡大「Bicubic法」」と「分かる!画像補間 ~基本から応用まで~」だ。

このうちの「分かる!画像補間 ~基本から応用まで~」からバイキュービック(BiCubic)法の部分をそのまま引用させて頂いて、最初の式を式(1)、次の式を式(2)とした。
BiCubic_1_170210.png

中間値Mnの式を式3に示す。中間値 Mn は、ピクセル値 xmk に x の重み wxm と y の重み wyk を掛けて合計し、それを xmk に x の重み wxm と y の重み wyk を掛けた値の合計で割ることで求められる。
BiCubic_2_170210.png

今、図2に示す画像のピクセル4x4点を使用して、x11に3点(M0, M1, M2)を追加する。
BiCubic_3_170210.png

M0の値の導出
M0はy方向がyと一致しているので、y=0の時の値のみとなる。y=1の時はy軸方向の重みwy1が0となる。(y=0の時はwy0 = 1)
・M0からx11、x21へのx方向の重み
式(1)から
w(0.5) = (a+2)(0.5)3 – (a+3)(0.5)2 + 1 = 0.125(a+2) – (0.25)(a+3) + 1
= 0.125a + 0.25 – 0.25a + 1 = 0.5 – 0.125a
  ・a = -0.5の場合 w(0.5) = 0.5625
  ・a = -1の場合 w(0.5) = 0.625

・M0からx01、x31へのx方向の重み
式(1)から
w(1.5) = a(1.5)3 – 5a(1.5)2 + 8a(1.5) – 4a = 3.375a – 11.25a + 12a -4a
= 0.125a
  ・a = -0.5の場合 w(1.5) = -0.0625
  ・a = -1の場合 w(1.5) = -0.125

M0の値
よって、a = -0.5の場合(但しwy0 = 1)式3から
M0 = (0.5625x11 + 0.5625x21 - 0.0625x01 - 0.0625x31)/(0.5625×2 - 0.0625×2)
M0 = 0.5625x11 + 0.5625x21 - 0.0625x01 - 0.0625x31
a = -1の場合(但しwy0 = 1)式3から
M0 = (0.625x11 + 0.625x21 - 0.125x01 - 0.125x31)/(0.625×2 - 0.125x01×2)
M0 = 0.625x11 + 0.625x21 - 0.125x01 - 0.125x31

M1の値の導出
M1はx方向がxと一致しているのでx=0の時の値のみとなる。x=1の時はx軸方向の重みwx1が0となる。(x=0の時はwx0 = 1)
・M1からx11、x21へのy方向の重み
式(1)から
w(0.5) = (a+2)(0.5)3 – (a+3)(0.5)2 + 1 = 0.125(a+2) – (0.25)(a+3) + 1
= 0.125a + 0.25 – 0.25a + 1 = 0.5 – 0.125a
  ・a = -0.5の場合 w(0.5) = 0.5625
  ・a = -1の場合 w(0.5) = 0.625
  ・M1からx10、x13へのy方向の重み
式(1)から
w(1.5) = a(1.5)3 – 5a(1.5)2 + 8a(1.5) – 4a = 3.375a – 11.25a + 12a -4a
= 0.125a
  ・a = -0.5の場合 w(1.5) = -0.0625
  ・a = -1の場合 w(1.5) = -0.125

M1の値
よって、a = -0.5の場合(但しwy0 = 1)式3から
M1 = (0.5625x11 + 0.5625x21 - 0.0625x10 - 0.0625x13)/(0.5625×2 - 0.0625×2)
M1 = 0.5625x11 + 0.5625x21 - 0.0625x10 - 0.0625x13
a = -1の場合(但しwy0 = 1)式3から
M1 = (0.625x11 + 0.625x21 - 0.125x10 - 0.125x13)/(0.625×2 - 0.125x10×2)
M1 = 0.625x11 + 0.625x21 - 0.125x10 - 0.125x13

M2の値の導出

・M2からx11, x12, x21, x22へのx方向y方向の重み
式(1)から
w(0.5) = (a+2)(0.5)3 – (a+3)(0.5)2 + 1 = 0.125(a+2) – (0.25)(a+3) + 1
= 0.125a + 0.25 – 0.25a + 1 = 0.5 – 0.125a
  ・a = -0.5の場合 w(0.5) = 0.5625
  ・a = -1の場合 w(0.5) = 0.625
・M2からx00, x10, x20, x30, x01, x31, x02, x32, x03, x13, x23, x33へのx方向y方向の重み
式(1)から
w(1.5) = a(1.5)3 – 5a(1.5)2 + 8a(1.5) – 4a = 3.375a – 11.25a + 12a -4a
= 0.125a
  ・a = -0.5の場合 w(1.5) = -0.0625
  ・a = -1の場合 w(1.5) = -0.125

M2の値
a = -0.5の場合、式3から
M2 = {(0.5625)2x11 + (0.5625)2x21 + (0.5625)2x12 + (0.5625)2x22
+ (-0.0625)2x00 + (0.5625)(-0.0625)x10 + (0.5625)(-0.0625)x20 +(-0.0625)2x30
+ (-0.0625)(0.5625)x01 + (-0.0625)(0.5625)x31
+ (-0.0625)(0.5625)x02 + (-0.0625)(0.5625)x32
+ (-0.0625)2x03 + (0.5625)(-0.0625)x13 + (0.5625)(-0.0625)x23 +(-0.0625)2x33} /
{(0.5625)2 + (0.5625)2 + (0.5625)2 + (0.5625)2
+ (-0.0625)2 + (0.5625)(-0.0625) + (0.5625)(-0.0625) +(-0.0625)2
+ (-0.0625)(0.5625) + (-0.0625)(0.5625)
+ (-0.0625)(0.5625) + (-0.0625)(0.5625)
+ (-0.0625)2 + (0.5625)(-0.0625) + (0.5625)(-0.0625) +(-0.0625)2}
= {0.3164x11 + 0.3164x21 + 0.3164x12 + 0.3164x22
+ 0.0039x00 + (-0.0352)x10 + (-0.0352)x20 +0.0039x30
+ (-0.0352)x01 + (-0.0352)x31 + (-0.0352)x02 + (-0.0352)x32
+ 0.0039x03 + (-0.0352)x13 + (-0.0352)x23 +0.0039x33} /
{0.3164 + 0.3164 + 0.3164 + 0.3164
+ 0.0039 + (-0.0352) + (-0.0352) +0.0039
+ (-0.0352) + (-0.0352) + (-0.0352) + (-0.0352)
+ 0.0039 + (-0.0352) + (-0.0352) +0.0039}
M2 = 0.3164x11 + 0.3164x21 + 0.3164x12 + 0.3164x22
+ 0.0039x00 + (-0.0352)x10 + (-0.0352)x20 +0.0039x30
+ (-0.0352)x01 + (-0.0352)x31 + (-0.0352)x02 + (-0.0352)x32
+ 0.0039x03 + (-0.0352)x13 + (-0.0352)x23 +0.0039x33

a = -1.0の場合、式3から
M2 = {(0.625)2x11 + (0.625)2x21 + (0.625)2x12 + (0.625)2x22
+ (-0.125)2x00 + (0.625)(-0.125)x10 + (0.625)(-0.125)x20 +(-0.125)2x30
+ (-0.125)(0.625)x01 + (-0.125)(0.625)x31
+ (-0.125)(0.625)x02 + (-0.125)(0.625)x32
+ (-0.125)2x03 + (0.625)(-0.125)x13 + (0.625)(-0.125)x23 +(-0.125)2x33} /
{(0.625)2 + (0.625)2 + (0.625)2 + (0.625)2
+ (-0.125)2 + (0.625)(-0.125) + (0.625)(-0.125) +(-0.125)2
+ (-0.125)(0.625) + (-0.125)(0.625)
+ (-0.125)(0.625) + (-0.125)(0.625)
+ (-0.125)2 + (0.625)(-0.125) + (0.625)(-0.125) +(-0.125)2}
= {0.3906x11 + 0.3906x21 + 0.3906x12 + 0.3906x22
+ 0.0156x00 + (-0.0781)x10 + (-0.0781)x20 +0.0156x30
+ (-0.0781)x01 + (-0.0781)x31 + (-0.0781)x02 + (-0.0781)x32
+ 0.0156x03 + (-0.0781)x13 + (-0.0781)x23 +0.0156x33} /
{0.3906 + 0.3906 + 0.3906 + 0.3906
+ 0.0156 + (-0.0781) + (-0.0781) +0.0156
+ (-0.0781) + (-0.0781) + (-0.0781) + (-0.0781)
+ 0.0156 + (-0.0781) + (-0.0781) +0.0156}
M2 = 0.3906x11 + 0.3906x21 + 0.3906x12 + 0.3906x22
+ 0.0156x00 + (-0.0781)x10 + (-0.0781)x20 +0.0156x30
+ (-0.0781)x01 + (-0.0781)x31 + (-0.0781)x02 + (-0.0781)x32
+ 0.0156x03 + (-0.0781)x13 + (-0.0781)x23 +0.0156x33


式は小数点数なので、FPGAに実装するに重みを整数とする必要がある。整数にするために重みを256倍して、演算してから8ビット右シフト(1/256)する必要がある。
256倍した時のバイキュービック法のM0, M1, M2の式を示す。
 ・a = -0.5の場合
M0 = 144x11 + 144x21 - 16x01 - 16x31
M1 = 144x11 + 144x21 - 16x10 - 16x13
M2 = 81x11 + 81x21 + 81x12 + 81x22 + x00 + (-9)x10 + (-9)x20 +x30
+ (-9)x01 + (-9)x31 + (-9)x02 + (-9)x32 + x03 + (-9)x13 + (-9)x23 +x33

 ・a = -1.0の場合
M0 = 160x11 + 160x21 - 32x01 - 32x31
M1 = 160x11 + 160x21 - 32x10 - 32x13
M2 = 81x11 + 81x21 + 81x12 + 81x22 + x00 + (-9)x10 + (-9)x20 +x30
+ (-9)x01 + (-9)x31 + (-9)x02 + (-9)x32 + x03 + (-9)x13 + (-9)x23 +x33
  1. 2017年02月10日 05:14 |
  2. 演算処理のFPGAへの適用方法
  3. | トラックバック:0
  4. | コメント:0

PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出2

PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出1”の続き。

前回、ブロックデザインが完成したので、今回は、ビットストリームまで生成して、SDKを立ち上げてアプリケーションソフトを作り、PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出してみよう。

まずは、前回からの続きでHDL のラッパーファイル(pynq_fastx_wrapper)を生成した。
pynq_de_fastx_18_170207.png

次に制約を書いた。
pynq_de_fastx_19_170207.png

set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports href]
set_property IOSTANDARD LVCMOS33 [get_ports pclk]
set_property IOSTANDARD LVCMOS33 [get_ports standby]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports xck]

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF_BUFG]

create_clock -period 55.560 -name pclk -waveform {0.000 27.780} [get_ports pclk]
set_input_delay -clock [get_clocks pclk] 10.800 [get_ports {{cam_data[0]} {cam_data[1]} {cam_data[2]} {cam_data[3]} {cam_data[4]} {cam_data[5]} {cam_data[6]} {cam_data[7]} href pclk vsync}]

set_property PULLUP true [get_ports mt9d111_iic_scl_io]
set_property PULLUP true [get_ports mt9d111_iic_sda_io]

set_property PACKAGE_PIN W14 [get_ports {cam_data[7]}]
set_property PACKAGE_PIN V16 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN Y14 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN W16 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN T11 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN V12 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN T10 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN W13 [get_ports {cam_data[0]}]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_tx_0_B_p]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_tx_1_R_p]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_tx_2_G_p]
set_property IOSTANDARD TMDS_33 [get_ports TMDS_tx_clk_p]
set_property PACKAGE_PIN U19 [get_ports href]
set_property PACKAGE_PIN Y16 [get_ports standby]
set_property PACKAGE_PIN K17 [get_ports TMDS_tx_0_B_p]
set_property PACKAGE_PIN K19 [get_ports TMDS_tx_1_R_p]
set_property PACKAGE_PIN J18 [get_ports TMDS_tx_2_G_p]
set_property PACKAGE_PIN L16 [get_ports TMDS_tx_clk_p]
set_property PACKAGE_PIN Y19 [get_ports vsync]
set_property PACKAGE_PIN W19 [get_ports xck]
set_property PACKAGE_PIN Y18 [get_ports mt9d111_iic_scl_io]
set_property PACKAGE_PIN U18 [get_ports mt9d111_iic_sda_io]
set_property PACKAGE_PIN Y17 [get_ports pclk]

set_false_path -from [get_clocks pclk] -to [get_clocks clk_fpga_0]
set_false_path -from [get_clocks clk_fpga_0] -to [get_clocks pclk]
set_false_path -from [get_clocks [get_clocks -of_objects [get_pins pynq_fastx_i/bitmap_disp_cntrler_axi_master_0/inst/dvi_disp_i/BUFR_pixel_clk_io/O]]] -to [get_clocks clk_fpga_0]


論理合成、インプリメント、ビットストリームを生成した。と書いているが、何度か制約を修正しながらコンパイルしている。
pynq_de_fastx_20_170208.png

成功した。Clock Domain Closing のレポートを示す。
まずは、clk_fpga_0 から pclk
pynq_de_fastx_26_170209.png

次に、pclk から clk_fpga_0
pynq_de_fastx_27_170209.png

pclk_buf から clk_fpga_0
pynq_de_fastx_28_170209.png

ハードウェアをエクスポートして、SDK を立ち上げ、アプリケーションソフトを書いた。
pynq_de_fastx_21_170208.png

fastx_on_serial.elf を起動した。

threshold = 5 の時の FASTXコーナー検出の結果を示す。
pynq_de_fastx_22_170208.png

pynq_de_fastx_23_170208.jpg

threshold = 10 の時の FASTXコーナー検出の結果を示す。
pynq_de_fastx_24_170208.png

pynq_de_fastx_25_170208.jpg

うまく行った。PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出できた。。。うれしい。。。

PYNQボードの写真を示す。脇はZYBO だ。
pynq_de_fastx_29_170209.jpg

pynq_de_fastx_30_170209.jpg
  1. 2017年02月09日 04:18 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0