ns-3上への全二重通信の実装について †
ns-3上で無線全二重通信の検証ができるようにfdwifiモジュールを実装しました。
fdwifiモジュールとはns-3のwifiモジュールを拡張したモジュールです。
fdwifiモジュールでは、中継しながら全二重通信可能なRFD(Relay Full-Duplex)-MACを実装しています。
fdwifiモジュールを編集することで、ns-3を用いて全二重通信のシミュレーションをすることが可能です。
fdwifiの使用方法 †
fdwifiはns-3.20のwifiモジュールを改良して作成したため、ns-3.20のみ動作が保証されています。ここではホームディレクトリにns-3.20がインストールされていると仮定してfdwifiの使用方法を記載します。ns-3.20のインストールは、↓を参考にして下さい。
ns-3.20のインストール
プログラムのダウンロード †
まず、git(ns3-fdwifi)からソースコードをダウンロードします。https://github.com/yusuke-sugiyama/ns-3-fdwifiを開くと↓のページが表示されます。
右下のDownload ZIPをクリックすると「ns-3-fdwifi-master.zip」がダウンロードできます。
プログラムの配置方法 †
ダウンロードした「ns-3-fdwifi-master.zip」をhomeディレクトリに置いたと仮定して話を進めます。まず、以下のコマンドを利用してzipを解凍します。
unzip ns-3-fdwifi-master.zip
すると、「ns-3-fdwifi-master」ディレクトリが生成されるのでcdコマンドでそのディレクトリに移動します。
cd ns-3-fdwifi-master
次に、「ns-3-fdwifi-master/src」の中身をns-3.20の「src」に上書き、「ns-3-fdwifi-master/scratch」の中身ををns-3.20の「scratch」に追加します。
ns-3.20の「scratch」に「fdwifi」フォルダが追加されます。
ns-3.20の「src/wifi」と「src/energy」と「src/dsr」の一部のソースファイルが上書きされますのでご注意ください。
cp -r src/* ../ns-allinone-3.20/ns-3.20/src/
cp -r scratch/* ../ns-allinone-3.20/ns-3.20/scratch/
最後にns-3.20のディレクトリに移動して、「waf」を用いてビルドします。
cd ~/ns-allinone-3.20/ns-3.20/
./waf
これで、プログラムの配置は完了です。
サンプルプログラムの説明 †
サンプルプログラムは、ライントポロジのシミュレーションをすることが可能です。
コマンドライン上から、ノード数、データの発生間隔,ノード間の距離等のパラメータを変更することが可能です。
パラメータのデフォルト設定は以下の通りです。
- ノード数:3
- データの発生間隔:0.002 [s]
- ノード間の距離:90 [m]
固定設定は以下の通りです。
- 伝送レート: 6 [Mbps]
- ルーティングプロトコル:AODV
↑の図に示したように、シミュレーションを開始するとノード1がノードnに向けてパケットを送信します。
シミュレーションの終了タイミングは次の2つです。
1つ目は、ノードnが1100回パケットを受信した時です。
2つ目は、シミュレーションが開始されてから1000 [s] 経過した時です。
シミュレーション終了後、シミュレーションの実行結果が「data-run-xxxxxxxxxx.sca」(xは実行した日付と時間によって変動します)に書き込まれます。
実行結果として、「data-run-xxxxxxxxxx.sca」には、シミュレーションの開始から、ノードnが1000パケット目を受信し終えるまでの時間、ACKのタイムアウト回数、プライマリ・セカンダリ・Busytone・ACK・その他のパケットの送信回数が出力されます。
サンプルプログラムの実行方法 †
fdwifiモジュールの
ダウンロードからプログラムの配置
が終了していることとしてサンプルプログラムの実行方法を説明します。
まず、ns-3.20の「scratch/fdwifi」ディレクトリに移動します。
cd ~/ns-allinone-3.20/ns-3.20/scratch/fdwifi/
以下のコマンドを実行することでデフォルト値でシミュレーションを実行することが可能です。
catコマンドを利用してシミュレーションの実行結果を見れます。
./waf --run "fdwifi"
cat ../../data-run-xxxxxxxxxx.sca ※ xxxxxxxxxx には数字が入ります
↓の図は実行結果を示します。
fdwifiのチュートリアル †
fdwifiモジュールの
ダウンロードからプログラムの配置
を行っていない場合はそちらを先にして下さい。チュートリアルでは、fdwifiモジュール
が使用可能であること、ホームディレクトリにns-3.20がインストールされていることとして話を進めていきます。
ns-3.20のインストールは、↓を参考にして下さい。
ns-3.20のインストール
パラメータを変更してシミュレーションを実行 †
パラメータを変更してシミュレーションを実行する方法と
変更可能なパラメータの表示方法を記載します。
まず、cdコマンドでns-3.20の「scratch/fdwifi」ディレクトリに移動します。
cd ~/ns-allinone-3.20/ns-3.20/scratch/fdwifi/
パラメータを指定してシミュレーションを実行するためには引数にパラメータを指定します。例えば、ノード数を4にしてシミュレーションを実行するためには以下のコマンドを実行します。
./waf --run "fdwifi --nodeAmount=4"
"--"の後に変更したいパラメータを設定します。
変更可能なシミュレーションパラメータは以下のコマンドで表示することができます。
./waf --run "fdwifi --help"
↓の図は上記コマンドの実行結果です。
スクリプトを利用してシミュレーションを実行 †
スクリプトを利用してシミュレーションを実行する方法を記載します。
※ sqlite3がインストールされていない場合は動作しませんのでご注意ください。
まず、cdコマンドでns-3.20の「scratch/fdwifi」ディレクトリに移動します。
cd ~/ns-allinone-3.20/ns-3.20/scratch/fdwifi/
fdwifiディレクトリの中に「script-sim.sh」と「script-db.sh」の2つのスクリプトを用意しました。「script-sim.sh」はノード数、データの発生間隔、乱数シードを組み合わせてシミュレーションプログラムを実行するスクリプトです。
シミュレーションの結果はSQLiteで読み込み可能なフォーマットでdata.dbに書き込まれます。
「script-db.sh」はdata.dbから、スループット、衝突率、セカンダリ送信の発生率、遅延時間の平均値を算出して平均値を所定のファイルに書き込むスクリプトです。以下のコマンドを実行することでスクリプトを用いてシミュレーションを実行することが可能です。
sh script-sim.sh
sh script-db.sh
スクリプトの実行後、4つのファイルが生成されます。生成される4つのファイルは
- throughput.data:1500 [Byte]のデータを1000 回送信した際のスループット
- collision.data:プライマリ・セカンダリ送信の衝突率
- fullduplex.data:プライマリ送信に対するセカンダリ送信の発生率
- delay.data:パケットが生成されてから最終宛先ノードが受信するまでの時間
です。
↓の図は上記スクリプトの実行結果です。
fdwifiの詳細 †
仕様説明 †
実装した全二重通信のプロトコルであるRFD-MACに関する論文と実装したプログラムを解説したPDFを載せます。
[英語論文]
Kenta Tamaki, Yusuke Sugiyama, Ari Raptino H., Masaki Bandai , Shunsuke Saruwatari, Takashi Watanabe, Full Duplex Media Access Control for Wireless Multi-hop Networks, Proceedings of the IEEE 77th Vehicular Technology Conference (IEEE VTC2013-Spring), 2013
[日本語論文]
玉置 健太,Ari Raptino H.,杉山 佑介,猿渡 俊介,渡辺 尚,無線全二重通信を利用した中継MACプロトコルの評価,電子情報通信学会技術研究報告, vol. 112, no. 405, AN2012-50, pp. 37-42, 2013
新規に追加したファイル †
busytone-tag.cc (h) †
BusytoneTag
図1: BusytoneTagクラス
図1にBusytoneTagのクラス図を示します。
BusytoneTagはTagクラスを継承しています。
BusytoneTagはプライマリ送信・セカンダリ送信時に付与されるBusytoneの長さを表すために利用されます。
具体的にはm_dataSizeにBusytoneの長さが格納されます。
secondary-tag.cc (h) †
SecondaryTag
図2: SecondaryTagクラス
図2にSecondaryTagのクラス図を示します。
SecondaryTagはTagクラスを継承しています。
SecondaryTagはセカンダリ送信のパケットに付与されます。
source-tag.cc (h) †
SourceTag
図3: SourceTagクラス
図3にSourceTagのクラス図を示します。
SourceTagはTagクラスを継承しています。
SourceTagは送信元ノードを保存して干渉のアドレス情報として利用されます。
surrounding-node-table.cc (h) †
SurroundingNodeTable, SurroundingNodeItem
図4: SurroundingNodeTable, SurroundingNodeItemクラス
図4にSurroundingNodeTableとSurroundingNodeItemのクラス図を示します。
SurroundingNodeTableクラスは隣接ノードテーブルを管理するクラスです。
SurroundingNodeTableクラスはSurroundingNodeItemとPRIORITESを持ちます。
SurroundingNodeItemクラスは、テーブルのタプルをモデル化したクラスです。
SurroundingNodeItemクラスは、addressとしてm_adderss、NextHopとしてm_nextHop、
HasFramesとしてm_hasFreamesをメンバ変数に持ちます。
PRIORITESは4つのプライオリティーを示す為に用います。
FIRSTは最もプライオリティーが高く0が割り当てられます。
SECONDがFIRSTの次にプライオリティが高く1が割り当てられます。
THIRDがSECONDの次にプライオリティが高く2が割り当てられます。
FORTHが最もプライオリティが低く3が割り当てられます。
変更したファイル †
wifi-mac-header.cc †
変更点
- DATA送信時にaddress4を利用するように変更
- moreDataビットに値を設定・取得できるように変更
- Busytoneを示すため、WifiMacTypeにWIFI_MAC_CTL_BUSYを追加
- Busytoneを示すため、サブタイプとしてSUBTYPE_CTL_BUSYを追加
追加関数
変更関数
dcf-manager.cc (h) †
変更点
- 送受信の終了時間を変更可能な関数を追加
- セカンダリ送信が送信可能となる時間を返す関数を追加
追加関数
- void NotifyTxPostponeNow (Time endTime)
endTimeからm_lastTxStartを減算した値をm_txDurationに代入する。
- void NotifyRxPostponeNow (Time endTime)
endTimeからm_lastRxStartを減算した値をm_rxDurationに代入する。
- void CancelAccessRequested()
次の送信ができるように準備をする。
m_accessRequestedがtrue状態のDcfStateを探索。
探索されたDcfStateのm_accessRequestedをfalseにして、m_BackoffSlotsを0にする。
- bool IsBusyForFullDuplex (void)
セカンダリ送信が可能な状態が判定する。
送信終了時間が現在時間よりも遅い場合、またはNAV時間が現在時間よりも遅い場合trueを返す。
それ以外の場合はfalseを返す。
- Time GetSecondaryGrantedTime ()
セカンダリ送信が送信可能となる時間にAifs * スロット時間を足した時間を返す。
- Time GetAccessGrantStartForSecondary (void) const
セカンダリ送信が送信可能となる時間を返す。
dca-txop.cc (h) †
変更点
追加関数
- bool IsQueueEmpty (void)
キューにパケットが存在する場合はtrue、そうでない場合はfalseを返す。
- bool IsCurrentPacket (void)
CurrentPacketにPacketがある場合はtrue、そうでない場合はfalseを返す。
- bool IsSecondaryTransmissionGranted (void)
セカンダリ送信の送信条件を満たしている場合にtrue、そうでない場合はfalseを返す。
- bool IsSendBusytoneGranted (void)
Busytoneの送信条件を満たしている場合はtrue、そうでない場合はfalseを返す。
- void SecondaryTransmissionGranted (void)
セカンダリ送信をMAC層に通知する。
- void NotifySecondaryTransmissionRequested ()
送信可能なパケットが存在する場合にセカンダリ送信を開始する。
MAC層のヘッダのaddress4にセカンダリ送信の送信元ノードのアドレスを追加する。
MAC層のヘッダのMoreDataビットにキューにデータがある場合は1を、そうでない場合は0を代入する。
mac-low.cc (h) †
変更点
- DcaTxopへのポインタを付与
- SurroundingNodeTableへのポインタを付与
- セカンダリ送信の送信関数を追加
追加変数
追加関数
- void SetDcaTxop (Ptr<DcaTxop> dcaTxop)
DcaTxopへのポインタを設定する。
- void ReScheduleNormalAckTimeoutEvent(Time time)
time時間後にNormalAckTimeoutEventを呼び出すように再スケジューリングする。
- void StartSecondaryTransmission (Ptr<const Packet> packet, const WifiMacHeader* hdr, MacLowTransmissionParameters parameters, MacLowTransmissionListener *listener)
セカンダリ送信を開始する。
- void SendSecondaryDataPacket (void)
セカンダリ送信を物理層に渡す。
プライマリ送信の送信終了時間とセカンダリ送信の送信終了時間を比較して、プライマリ送信の送信終了時間の方が遅い場合に、パケットにBusytoneを付与する。
- void StartSecondaryDataTxTimers (WifiTxVector dataTxVector)
Busytoneのサイズを考慮して、セカンダリ送信のACKがタイムアウトする時間を設定する。
変更関数
wifi-phy.cc (h) †
変更点
- 受信終了イベントの再スケジューリングのために、受信中のパラメータを保存する変数を追加
- ヘッダ受信時にTraceできるように変数と関数を追加
- Stateに送信中かつ受信中を表すFD状態を追加
追加変数
追加関数
- virtual void NotifyTxPostpone (Time endTime) = 0
送信時間の遅延をDcfManagerに通知する。
- virtual void NotifyRxPostpone (Time endTime) = 0
受信時間の遅延をDcfManagerに通知する。
- static Time CalculatePlcpDuration (WifiTxVector txvector, WifiPreamble preamble)
txvectorとpreambleからPLCPのみのDurationを算出してバイト数を返す。
- static uint32_t GetPacketSizeFromDuration (Time time, WifiTxVector txvector)
txvectorからtime時間内で送ることが可能なパケットのサイズを返す。
- virtual Time GetPrimaryTransmissionEndTime() = 0
MAC層から物理層で取得されるプライマリ送信の終了時間を参照する。
- void SetReceivingTxVector (WifiTxVector txVector)
m_receivingTxVectorにtxVectorを設定する。
- void SetReceivingPreamble (WifiPreamble preamble)
m_receivingPreambleにpreambleを設定する。
- void SetReceivingAddress4 (Mac48Address addr4)
m_receivingAddress4にaddr4を設定する。
- WifiTxVector GetReceivingTxVector ()
m_receivingTxVectorを返す。
- WifiPreamble GetReceivingPreamble ()
m_receivingPreambleを返す。
- Mac48Address GetReceivingAddress4 ()
m_receivingAddress4を返す。
変更関数
wifi-phy-state-helper.cc (h) †
変更点
- 送受信の終了時間を変更するための関数を追加
- 送信中かつ受信中を表すFD状態を適応
追加関数
- void PostponeRx(Time rxEndTime)
m_endRxにrxEndTimeを設定する。
受信終了時間の変更を通知するためNotifyRxPostpone関数を呼び出す。
- void PostponeTx(Time txEndTime)
m_endTxにtxEndTimeを設定する。
送信終了時間の変更を通知するためNotifyTxPostpone関数を呼び出す。
- bool IsStateFd (void)
状態がFD状態の場合true、そうでない場合falseを返す。
- Time GetLastRxEndTime() const
受信終了時間を返す。
- Time GetLastTxEndTime() const
送信終了時間を返す。
- void NotifyRxPostpone (Time endTime)
Listenerを用いて受信終了時間を通知する.
- void NotifyTxPostpone (Time endTime)
Listenerを用いて送信終了時間を通知する。
変更関数
- Time WifiPhyStateHelper::GetDelayUntilIdle (void)
状態がFD状態の場合のIDLE状態に遷移するまでの時間を返す処理を追加。
- enum WifiPhy::State WifiPhyStateHelper::GetState (void)
送信終了時間がシミュレータの現在時刻よりも遅い、かつ受信状態の場合にWifiPhy::FDを返すように変更。
- void WifiPhyStateHelper::SwitchToTx (Time txDuration)
受信状態から送信状態に遷移する際に、受信イベントをキャンセルしないように変更。
- void WifiPhyStateHelper::SwitchToRx (Time rxDuration)
送信状態からでも受信状態に状態遷移できるように変更。
- void WifiPhyStateHelper::SwitchMaybeToCcaBusy (Time duration)
状態がFD状態の場合を追加(特になにもしない)。
yans-wifi-phy.cc (h) †
変更点
- ヘッダとPayloadを分けて受信できるように変更
- 送信と受信が同時に行えるように変更
追加変数
追加関数
変更関数
- YansWifiPhy ()
初期化処理を追加。
m_headerErrorFlgにfalseを代入する。
m_eventにNULLを代入する。
- void SetChannelNumber (uint16_t nch)
状態がFD状態の場合を追加(特になにもしない)する。
- void StartReceivePacket (Ptr<Packet> packet, double rxPowerDbm, WifiTxVector txVector, enum WifiPreamble preamble)
送信状態でも受信できるように変更。
Preambleの始まりからMAC層のヘッダまでと残りのPayloadを別々に受信できるように変更。
- void EndReceive (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event)
SNR・PERの算出をパケット全体からではなくPayloadから算出するように変更。
yans-wifi-channel.cc (h) †
追加関数
interference-helper.cc (h) †
変更点
- 干渉情報をMACアドレスと紐づけして、干渉の終了時間を変えられるように変更
- PreambleからMAC層のヘッダまでと残りのPayloadを分離してPERとSNRを計算できるように変更
- busytoneを考慮してPERとSNRを計算できるように変更
追加変数
変更変数
- std::vector<Ptr<Event> > Events;
vectorで取り扱えるように変更。
追加関数
- Event (uint32_t size, WifiMode payloadMode, enum WifiPreamble preamble, Time startTime, Time endTime, double rxPower, WifiTxVector txvector)
デフォルトのEvent関数を変更してstartTimeとendToimeを指定して設定できるように変更。
- void ChangeEventEndTime(Ptr<InterferenceHelper::Event> event, Time endTime)
eventが終了時間を迎えていない場合eventの終了時間をendTimeに変更。
- void ChangeEventEndTime(Mac48Address address, Time endTime)
MACアドレスがaddressであるノードの干渉の終了時間を変更する。
- void UpdateEvent(Ptr<InterferenceHelper::Event> event)
Eventsをevent情報を基に更新する。
- void AddEvent(Ptr<InterferenceHelper::Event> event)
eventをEventsに追加する
- int GetEventIndexByAddress (Mac48Address address)
addressがEvents内に存在するか確認する。存在する場合はEvents内のaddressに対応する添え字を返す。存在しない場合は-1を返す。
- void SetAddress (Mac48Address address)
m_addressにaddressを設定する。
- void Add (uint32_t size, WifiMode payloadMode, enum WifiPreamble preamble, Time startTime, Time endTime, double rxPowerW, WifiTxVector txVector, Mac48Address address)
Add関数の拡張。
干渉時間をDurationではなく、干渉開始時間と干渉終了時間を追加できるように変更する。
- void AppendEventForFutureEvent (Ptr<InterferenceHelper::Event> event)
AppendEvent関数の拡張。
eventのm_startTimeがシミュレーションの現在時刻よりも遅い場合に対応させる。
- double CalculatePerPayload (Ptr<const InterferenceHelper::Event> event, NiChanges *ni, uint32_t busytoneSize) const
busytoneSizeを考慮して、Payload部分のPERを返す。
- struct InterferenceHelper::SnrPer CalculateSnrPerPayload (Ptr<InterferenceHelper::Event> event, uint32_t busytoneSize)
busytoneSizeを考慮して、Payload部分のSNRを返す。
変更関数