前提・実現したいこと:8PSKでの通信路容量の導出
Visual Studio 2019 でAWGM環境下で各変調ごとの通信路容量を導出するプログラムをC言語で書いています。BPSK,QPSKでの通信路容量は完璧に導出できたのですが、8PSKでの通信路容量のグラフの値がどれだけ多くの試行回数を重ねても収束しません。
BPSK,QPSKでは完璧にうまくいっているので、プログラムの内容自体はあっていると思うのですが、、、(つまり、私はこの問題は乱数が正規分布に収束していないという問題だと認識しています。)
どなたか助言いただける方がいたら、よろしくお願いします。
なお、エラーメッセージは一つも出ていません。
以下が、作りたいグラフです。
以下、出力時のグラフです。
C
1#include<stdio.h> 2#include<stdlib.h> 3#include<math.h> 4#include<time.h> 5#include<complex.h> 6#include"MT.h" 7#pragma warning(disable : 4996) 8#define modulation_level 8//BPSK:2 QPSK:4 8PSK:8 16QAM:16 変調多値数 9#define N 10000000 //受信信号の要素数 10#define EbN0db_max 20//プロットするEs/N0[db]の最大値[db] 11#define EbN0db_min -10 //プロットするEs/N0[db]の最小値[db] 12#define EbN0db_plot 31 //プロットする点数 13#define Ns 1//1シンボル当たりのサンプル数 14#define PI 3.1415926 15#define amplitude 1 //雑音と信号の比が重要なので、振幅は1で固定 16 17int genpulse() 18{ 19 return genrand_int32() & 1; 20} 21 22int generate_constellation_diagram()//コンスタレーション上のプロットを表す数値を出力 23{ 24 int pulse_number=0; 25 26 for (int i = 0; i < log2(modulation_level); i++) 27 { 28 int pulse = genpulse(); 29 pulse_number+=pow(2, i)* pulse; 30 } 31 32 return pulse_number; 33} 34 35_Dcomplex generate_noise(long double N0)//N0を引数にして雑音(noise_I+j*noise_Q)を返す関数 36{ 37 long double sigma = pow((long double)N0 / 2, 0.5); 38 long double u1 = genrand_real3(); //(0,1)乱数を作成 39 long double u2 = genrand_real3(); 40 long double noise_I = sigma* pow(-2 * log(u1), 0.5)* cos(2 * PI * u2); 41 long double noise_Q = sigma* pow(-2 * log(u1), 0.5)* sin(2 * PI * u2); 42 _Dcomplex noise = _Cbuild(noise_I, noise_Q); 43 44 return noise; 45} 46 47long double calc_entropy_function(long double N0,int constellation_number) 48{ 49 _Dcomplex constellation_point[modulation_level]; 50 if (modulation_level == 2) 51 { 52 constellation_point[0] = _Cbuild(amplitude, 0); 53 constellation_point[1] = _Cbuild(-amplitude, 0); 54 } 55 56 else if (modulation_level == 4) 57 { 58 constellation_point[0] = _Cbuild(pow(2, -1 * 0.5) * amplitude, pow(2, -1 * 0.5) * amplitude); 59 constellation_point[1] = _Cbuild(pow(2, -1 * 0.5) * amplitude, -pow(2, -1 * 0.5) * amplitude); 60 constellation_point[2] = _Cbuild(-pow(2, -1 * 0.5) * amplitude, pow(2, -1 * 0.5) * amplitude); 61 constellation_point[3] = _Cbuild(-pow(2, -1 * 0.5) * amplitude, -pow(2, -1 * 0.5) * amplitude); 62 } 63 64 else if (modulation_level == 8) 65 { 66 constellation_point[0] = _Cbuild(amplitude ,0); 67 constellation_point[1] = _Cbuild(amplitude/sqrt(2), amplitude / sqrt(2)); 68 constellation_point[2] = _Cbuild(0,amplitude); 69 constellation_point[3] = _Cbuild(amplitude / sqrt(2), -1 * amplitude / sqrt(2)); 70 constellation_point[4] = _Cbuild(0,-1*amplitude); 71 constellation_point[5] = _Cbuild( -1*amplitude / sqrt(2), -1*amplitude / sqrt(2)); 72 constellation_point[6] = _Cbuild(0, -1*amplitude); 73 constellation_point[7] = _Cbuild(amplitude/sqrt(2),-1*amplitude/sqrt(2)); 74 } 75 _Dcomplex noise=generate_noise(N0); 76 _Dcomplex constellation_noise = _Cbuild(creal(noise)+creal(constellation_point[constellation_number]), cimag(noise)+cimag(constellation_point[constellation_number]));//得られる点のコンスタレーション上の座標 77 long double tmp2=0; 78 for (int i = 0; i < modulation_level; i++)//分子の合計をtmp2に返す 79 { 80 if (i == constellation_number) 81 { 82 long double tmp = 0; 83 tmp = cabs(noise); 84 tmp2 += exp(-1 * tmp * tmp / N0); 85 86 } 87 88 else 89 { 90 long double tmp = 0; 91 tmp = cabs(_Cbuild(creal(constellation_noise) - creal(constellation_point[i]), cimag(constellation_noise) - cimag(constellation_point[i]))); 92 tmp2 += exp(-1 * tmp * tmp / N0); 93 } 94 95 } 96 97 long double tmp=0; 98 99 tmp = cabs(noise); 100 101 return (log2(tmp2)-log2( exp(-1 * tmp * tmp / N0))); 102} 103 104int main() 105{ 106 init_genrand((unsigned)time(NULL)); 107 long double channel_capacity=0;//C 108 long double entropy_function=0;//H(x|y) 109 int constellation_number; 110 111 FILE* fp; 112 113 if ((fp = fopen("d.txt","w")) == NULL) 114 { 115 printf("cannot open!"); 116 exit(1); 117 } 118 119 for (int i = 0; i < EbN0db_plot; i++) 120 { 121 122 long double EsN0db =i*((long double)EbN0db_max - EbN0db_min) / ((long double)EbN0db_plot -1)+ EbN0db_min;//-10~20まで31点プロット 123 124 long double N0 = pow(10, -1 * EsN0db / 10); 125 126 constellation_number=generate_constellation_diagram();//コンスタレーション上のプロットを表す整数を出力 127 128 entropy_function = 0;//(nI+j*nQ)の整数とN0を引数にしてH(x|y)を求める関数 129 for (int j = 0; j < N; j++) 130 { 131 entropy_function+= calc_entropy_function(N0, constellation_number); 132 } 133 entropy_function /= N; 134 135 channel_capacity = log2(modulation_level) - entropy_function;//チャネル容量 136 137 fprintf(fp, "%f,%lg\n", EsN0db, channel_capacity); 138 139 printf("finish Es/N0=%f\n", EsN0db); 140 } 141 142 fclose(fp); 143 144 return 0; 145 146}
試したこと
・乱数生成が一様分布でない
→乱数生成の関数をrand関数からメルセンヌツイスタへ変更
・計算結果がdouble型に収まっていない
→すべてのdouble型をlong double型に変更(complex.hに問題があるのかも?)
・測定回数が十分でない
→最大1000000000点で測定(終了まで15時間かかりました、、、)
補足情報(FW/ツールのバージョンなど)
実行環境:win10
visual studio 2019
回答2件
あなたの回答
tips
プレビュー