目录
简介
本博客将介绍C#和HFSS联合仿真的框架和实现方法,并展示联合仿真的过程。我们将微带天线划分为18*22的网格,用二维数组表示,1代表是填充,即此方块覆铜,0代表的未填充,即此方块不覆铜,这样就能表示一个天线。同时,每个方块有两种可能,这样有一共有2的396次方种可能,如果用穷举法优化的话,是仿真不完的,这就需要用遗传算法来搜索一个最优解了。
天线模型演化
联合仿真的时候,每迭代5次(每迭代一次,即仿真完一个种群,12个天线模型,每60次仿真保存一次模型),保存一次模型天线,A,B,C,D,E,F,G为每五代种群中适应度最高的个体的模型,H为G天线整理一下的模型,I天线为最后在H天线上微调得到的模型。最终模型的驻波在要求频段上小于2.5
天线模型变换图示
模型演化如下所示:
天线驻波如下
适应度变化如下
适应度图示
适应度对数表示
方法简介
该方法通过使用C#-HFSS-API脚本来联合调用C#和HFSS对LTE微带天线进行建模,仿真,输出,计算,优化。
原理框图
遗传算法简介
选择(selection)
遗传算法中的选择操作就是用来确定如何从父代群体中按某种方法选取那些个体,以便遗传到下一代群体。选择操作用来确定重组或交叉个体,以及被选个体将产生多少个子代个体。
轮盘赌选择: 是一种回放式随机采样方法。每个个体进入下一代的概率等于它的适应度值与整个种群中个体适应度值和的比例。选择误差较大。
随机竞争选择: 每次按轮盘赌选择一对个体,然后让这两个个体进行竞争,适应度高的被选中,如此反复,直到选满为止。
最佳保留选择: 首先按轮盘赌选择方法执行遗传算法的选择操作,然后将当前群体中适应度最高的个体结构完整地复制到下一代群体中。
无回放余数随机选择: 可确保适应度比平均适应度大的一些个体能够被遗传到下一代群体中,因而选择误差比较小。
均匀排序: 对群体中的所有个体按期适应度大小进行排序,基于这个排序来分配各个个体被选中的概率。
最佳保存策略: 当前群体中适应度最高的个体不参与交叉运算和变异运算,而是用它来代替掉本代群体中经过交叉、变异等操作后所产生的适应度最低的个体。
下面以轮盘赌选择为例给大家讲解一下:
假如有5条染色体,他们的适应度分别为6、3、2、8、1、5。
那么总的适应度为:F = 6 + 3 + 2 + 8 + 1+5 = 25。
那么各个个体的被选中的概率为:0.24、0.12、0.08、0.32、0.04、0.20。
交叉(crossover)
遗传算法的交叉操作,是指对两个相互配对的染色体按某种方式相互交换其部分基因,从而形成两个新的个体。
单点交叉:指在个体编码串中只随机设置一个交叉点,然后再该点相互交换两个配对个体的部分染色体。
两点交叉:在个体编码串中随机设置了两个交叉点,然后再进行部分基因交换。
均匀交叉:两个配对个体的每个基因座上的基因都以相同的交叉概率进行交换,从而形成两个新个体。
下面以简单的单点交叉为例给大家讲解一下:
交换前
染色体A 0010 1101 1001 1100
染色体B 1011 1001 0101 0001
交换后
染色体A* 0010 1101 0101 1100
染色体B* 1011 1001 1001 0001
变异(Mutation)
遗传算法中的变异运算,是指将个体染色体编码串中的某些基因座上的基因值用该基因座上的其它等位基因来替换,从而形成新的个体。
基本位变异:对个体编码串中以变异概率、随机指定的某一位或某几位仅因座上的值做变异运算。
均匀变异:分别用符合某一范围内均匀分布的随机数,以某一较小的概率来替换个体编码串中各个基因座上的原有基因值。
非均匀变异:对原有的基因值做一随机扰动,以扰动后的结果作为变异后的新基因值。对每个基因座都以相同的概率进行变异运算之后,相当于整个解向量在解空间中作了一次轻微的变动。
高斯近似变异:进行变异操作时用符号均值为P的平均值,方差为P**2的正态分布的一个随机数来替换原有的基因值。
下面以简单的基本位编译为例给大家讲解一下:
变异前
染色体A 0010 1101 1001 1100
变异后
染色体A* 0010 1101 1011 1100
C#–HFSS模型建立
首先,我们将微带天线划分成N* M的网格,其中覆铜区域设置为1,未覆铜区域设置为0,这样就能用一个长度N* M的二维数组表示一个微带天线了,或者将每一列转为十进制,这样就能用一个长度N的十进制表示一个微带天线了。
如图所示:
如图所示,用一个12*20的二维数组表示了一个微带天线。
C#程序实现
初始设置
static int Population_size = 12; //种群规模
static int child_size = 6; //子种群规模
static int best_size = 2; //精英个体
static int val = 21; //染色体个数21
static int vaw = 16; //染色体维数16
static int Chromosome_length = val * vaw; //染色体网格数
static double rate_crossover = 0.9; //交叉率
static double rate_mutation = 0.1; //变异率
static int iteration_num = 70; //迭代次数
static ChooseType chooseType = ChooseType.Roulette;//选择方法,Bubble,冒泡; Roulette,轮盘赌;
static double rate_roulette=0.6; //轮盘选择率
种群规模:每次参与演化的个体数量
子种群规模:每次演化后迭代进入下一次的个体数量
精英个体:种群中适应度最高的个体,进入下次演化,加快收敛
染色体条数和维数:基因组的大小,对应微带天线的大小
交叉率:基因组产生交叉的概率
变异率:基因组产生变异的概率
选择方法:在种群中选择进入下次演化的个体的方法
轮盘选择率:提高精英个体在轮盘选择中存活的概率
算法主体
public MainWindow()
{
InitializeComponent();
//初始化种群
Init();
//迭代次数累计器
int i = 0;
//适应度
double cost = 0;
List<double> cost_list = new List<double>();
while (i <iteration_num || cost < 780)
{
i++;
//重新计算fit值
UpdateFitValue();
//适应度排序
ChooseChromosome();
//选择方法,轮盘赌
UpdateNext();
//交叉得到新个体
CrossOperate();
//变异操作
VariationOperate();
//插入新的种群,保留子种群
Initchild()
//记录适应度值
cost = chromosomes[0].fitValue;
cost_list.Add(cost);
}
//打印结果
double maxfit = chromosomes[0].fitValue;
Console.WriteLine("最大值为: " + maxfit);
Print();
//控制台打印适应度值
foreach (double cs in cost_list)
Console.WriteLine("cost:"+cs);
Console.ReadLine();
}
定义个体类
包含个体的编码,适应值,选择概率和累计概率
class chromosome
{
// 对染色体进行编码;
public int[] bits = new int[val * vaw];
// 适应值;
public double fitValue;
// 选择概率;
public double fitValuePercent;
// 累积概率;
public double probability;
}
选择方法
采用改进的轮盘选择方法,提高适应度高的个体的存活概率,减小选择误差
private void UpdateNext()
{
// 获取总的fit;
double totalFitValue = 0;
for (int i = best_size ; i < chromosomes.Count; i++)
{
//适应度为负数的取0;
if (chromosomes[i].fitValue <= 0)
{
totalFitValue += 0;
}
else
{
totalFitValue += chromosomes[i].fitValue;
}
}
//算出每个的fit percent;
for (int i = best_size ; i < chromosomes.Count; i++)
{
if (chromosomes[i].fitValue <= 0)
{
chromosomes[i].fitValuePercent = 0;
}
else
{
chromosomes[i].fitValuePercent = chromosomes[i].fitValue / totalFitValue;
}
}
//计算累积概率;
//第一个的累计概率就是自己的概率;
chromosomes[best_size].probability = chromosomes[best_size].fitValuePercent;
for (int i = best_size +1; i < chromosomes.Count; i++)
{
// 上一个的累计概率加上自己的概率,得到自己的累计概率;
chromosomes[i].probability = chromosomes[i - 1].probability + chromosomes[i].fitValuePercent;
}
//轮盘赌选择方法
for (int i = best_size ; i < chromosomes.Count; i++)
{
//产生随机的选择概率
string uuid2 = Guid.NewGuid().ToString("N");
char []c_array = uuid2.ToArray();
Random random = new Random(c_array [i%30]*best_size+i*i+c_array [best_size%30]*i);
double rand = (random.Next(1, 10000)/10000.00000)*rate_roulette;
if (rand <= chromosomes[best_size].probability)
{
break;
}
else
{
for (int j = best_size ; j < chromosomes.Count - 1; j++)
{
if (chromosomes[j].probability < rand && rand <= chromosomes[j + 1].probability)
{
int[] bits_aa = new int[val * vaw];
int[] bits_bb = new int[val * vaw];
bits_aa = chromosomes[j + 1].bits ;
bits_bb = chromosomes[best_size].bits ;
chromosomes[best_size].bits =bits_aa;
chromosomes[j + 1].bits = bits_bb;
break;
}
}
}
}
}
交叉方法
采用改进的均匀交叉方法,同一纬度上的基因片段进行交叉,且交叉概率和交叉位置不定
private void CrossOperate()
{
for (int k = 0; k < child_size /2; k++)
{
for (int j = 0; j < val; j++)
{
//每一维度产生不同的交叉机率
string uuid_c = Guid.NewGuid().ToString("N");
char[] c_ac = uuid_c.ToArray();
int seed_c =c_ac[j % 31] + c_ac[12]+j+j*j+c_ac[j % 31]*c_ac[j % 31]*c_ac[k % 31];
Random random_c = new Random(seed_c);
double rate_rand = random_c.Next(1, 10000) / 10000.00000;
int seed_j =c_ac[k % 31] + c_ac[23]+k+j*k+c_ac[k % 31]*c_ac[k % 31]*c_ac[k % 31];
//每一维度产生不同的交叉位置
Random random_j = new Random(seed_j);
int rand_j = random_j.Next(3, vaw-2);
int a = child_size -1-k;
int b = child_size -1-k;
//如果大于交叉概率就进行交叉操作
if (rate_rand <= rate_crossover)
{
for (int i = 0; i < rand_j; i++)
{
int bit_a = 0;
bit_a= chromosomes[b].bits[j * vaw + i];
chromosomes[a].bits[j * vaw + i] =bit_a;
}
for (int i = rand_j; i < vaw; i++)
{
int bit_b = 0;
bit_b = chromosomes[(b+1)%(child_size /2)].bits[j * vaw + i];
chromosomes[a].bits[j * vaw + i] = bit_b;
}
}
}
}
}
变异方法
采用均匀变异的方法,对每一维度上不定位置进行随机变异。
private void VariationOperate()
{
for (int k =1; k < Population_size; k++)
{
for (int j = 0; j < val; j++)
{
//每一维度上的变异概率
string uuid_d = Guid.NewGuid().ToString("N");
char[] c_ad = uuid_d.ToArray();
int seed_d =c_ad[j % 31] + c_ad[16]*k+k*j+c_ad[j % 31]*c_ad[j % 21]*c_ad[j % 11];
Random random_d= new Random(seed_d);
double rate_rand_d = random_d.Next(1, 10000)/10000.00000;
if (rate_rand_d < rate_mutation)
{
string uuid_e = Guid.NewGuid().ToString("N");
char[] c_ae = uuid_e.ToArray();
int seed_e =c_ae[j % 21] + c_ae[12]*k+k*j+c_ae[j % 31]*c_ae[k % 21]*c_ae[j % 31];
Random random_e= new Random(seed_e);
//每一维度上基因变异的位置
int col = random_e.Next(1, vaw);
// 0变为1,1变为0;
if (chromosomes[k].bits[j * vaw + col] == 0)
{
chromosomes[k].bits[j * vaw + col] = 1;
}
else
{
chromosomes[k].bits[j * vaw + col] = 0;
}
}
}
}
}
获取适应度
将hfss仿真得到的驻波转换为cost值,其中,在范围内达到要求的值记为0,将范围内超出要求的驻波值乘2,将频带范围内的值相加记为总的cost值。
private double GetFitValue(int []x)
{
//目标函数,将cost变为正值,方便计算
return (hfss_runandgetdata(x));
}