感谢学长在他的博客无私分享的高质量代码,才让我能够顺利地完成这次实验
在此融入些鄙人粗浅的理解分享出来供更多人学习
一. 引言
-
移动通信中的数字信号往往是复数信号a+bi,储存时分开储存复数的实部和虚部a、b也称Q(quotient)、I(imaginary number)。
-
终端在每个地点收到的是多个基站信号的叠加,需要依据强度,判断选择接入哪个基站。而这种判断是随着终端位置的改变需要不断进行的。
-
信号强度的计算(N为数据组数):
-
信号强度的排序:可以采用冒泡排序、插入排序、希尔排序等方法。
-
当基站信号均较弱时,信号强度排序可能会在几个网络之间不断跳动,故加上门限的限定能够避免网络在多个基站间反复切换。
二. 系统设计要求
总体要求:计算12个候选小区的强度,找出大于强度门限的小区,并进行从强到弱的排序。强度门限自行设定。
- 输出中间过程的信息。
- 打印各小区强度以及小区排序的结果(小区ID即文件名)。
- 打印设置的强度门限。
三. 设计思路与方案
1. 流程图
2.全局变量及结构体
#define NUM 12//数据组数
#define MAX 30000 //data中存放信号强度的实部和虚部Q和I共30000个数据
struct Area//小区结构体
{
char ID[15];//小区名称——文件名称
double avg_strength;//小区信号平均强度
};
struct Area area[NUM];//小区结构体数组
3.算法设计
整体代码
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NUM 12//数据组数
#define MAX 30000 //data中存放信号强度的实部和虚部Q和I共30000个数据
struct Area//小区结构体
{
char ID[15];//小区名称——文件名称
double avg_strength;//小区信号平均强度
};
struct Area area[NUM];//小区结构体数组
void ID_init()//初始化小区名称
{
strcpy(area[0].ID,"data24.txt");
strcpy(area[1].ID,"data25.txt");
strcpy(area[2].ID,"data26.txt");
strcpy(area[3].ID,"data27.txt");
strcpy(area[4].ID,"data28.txt");
strcpy(area[5].ID,"data29.txt");
strcpy(area[6].ID,"data30.txt");
strcpy(area[7].ID,"data31.txt");
strcpy(area[8].ID,"data32.txt");
strcpy(area[9].ID,"data33.txt");
strcpy(area[10].ID,"data34.txt");
strcpy(area[11].ID,"data35.txt");
}
int calculate(struct Area *area,double Q,double I)//求平均强度函数
{
static double sum; //利用static对数据进行累加
static int i = 0; //利用static对计算次数进行统计
sum = sum + sqrt(Q * Q + I * I); //信号强度计算公式并对结果求和
i++;//计算次数累加
if (i == MAX/2)//当执行到MAX/2次时执行以下代码
{
area->avg_strength = sum / (MAX/2);//求平均信号强度并写入结构体
sum = 0;//总和清零
i = 0;//次数清零
return 0;//返回0表示计算完成
}
return 1;//返回1表示计算未完成
}
void fileop(int num)//读取文件
{
FILE* fp;
int flag;//设置旗标flag用于检测calculate()的返回值,从而判断是否计算完所有数据
double Q,I;//定义双精度浮点数存放信号强度的实部和虚部
if((fp = fopen(area[num].ID,"r")) == NULL)
{
printf("打开文件错误");
}
else
{
for(int i=0;i<MAX/2;i++)//边读取文件边进行计算
{
fscanf(fp,"%lf %lf",&Q,&I);//读取文件,并将数值存储到Q和I中
calculate(&area[num],Q,I);
flag = calculate(&area[num],Q,I);
if(flag == 0)
{
fclose(fp);
break;
}
}
}
}
void sort()//冒泡算法排序
{
struct Area temp;
for (int i=0; i<=NUM-1; i++)
{
for (int j=0; j<=NUM-1-i; j++)
{
if (area[j].avg_strength < area[j+1].avg_strength)
{
temp = area[j] ;
area[j] = area[j+1];
area[j+1] = temp;
}
}
}
}
int main()
{
double threshold;//定义强度门限
ID_init();//初始化小区名称
for(int i=0; i<NUM; i++)
{
fileop(i);
printf("小区%s信号平均强度为:%lf\n",area[i].ID,area[i].avg_strength);
}
sort();
printf("\n排序结果为:\n");
for(int i=0; i<NUM; i++)
{
fileop(i);
printf("小区%s信号平均强度为:%lf\n",area[i].ID,area[i].avg_strength);
}
printf("请输入强度门限:\n");
scanf("%lf",&threshold);
printf("\n满足门限条件的小区:\n");
for (int i = 0; i < NUM; i++)
{
if(area[i].avg_strength>=threshold)//如果满足门限条件打印相关信息
printf("ID:%s \t信号平均强度:%lf\n", area[i].ID, area[i].avg_strength);
}
}
3.1初始化小区名称
void ID_init()//初始化小区名称
{
strcpy(area[0].ID,"data24.txt");
strcpy(area[1].ID,"data25.txt");
strcpy(area[2].ID,"data26.txt");
strcpy(area[3].ID,"data27.txt");
strcpy(area[4].ID,"data28.txt");
strcpy(area[5].ID,"data29.txt");
strcpy(area[6].ID,"data30.txt");
strcpy(area[7].ID,"data31.txt");
strcpy(area[8].ID,"data32.txt");
strcpy(area[9].ID,"data33.txt");
strcpy(area[10].ID,"data34.txt");
strcpy(area[11].ID,"data35.txt");
}
3.2 平均强度计算
int calculate(struct Area *area,double Q,double I)//求平均强度函数
{
static double sum; //利用static对数据进行累加
static int i = 0; //利用static对计算次数进行统计
sum = sum + sqrt(Q * Q + I * I); //信号强度计算公式并对结果求和
i++;//计算次数累加
if (i == MAX/2)//当执行到MAX/2次时执行以下代码
{
area->avg_strength = sum / (MAX/2);//求平均信号强度并写入结构体
sum = 0;//总和清零
i = 0;//次数清零
return 0;//返回0表示计算完成
}
return 1;//返回1表示计算未完成
}
3.3读文件传递参数
void fileop(int num)//读取文件
{
FILE* fp;
int flag;//设置旗标flag用于检测calculate()的返回值,从而判断是否计算完所有数据
double Q,I;//定义双精度浮点数存放信号强度的实部和虚部
if((fp = fopen(area[num].ID,"r")) == NULL)
{
printf("打开文件错误");
}
else
{
for(int i=0;i<MAX/2;i++)//边读取文件边进行计算
{
fscanf(fp,"%lf %lf",&Q,&I);//读取文件,并将数值存储到Q和I中
calculate(&area[num],Q,I);
flag = calculate(&area[num],Q,I);
if(flag == 0)
{
fclose(fp);
break;
}
}
}
}
3.4冒泡排序
void sort()//冒泡算法排序
{
struct Area temp;
for (int i=0; i<=NUM-1; i++)
{
for (int j=0; j<=NUM-1-i; j++)
{
if (area[j].avg_strength < area[j+1].avg_strength)
{
temp = area[j] ;
area[j] = area[j+1];
area[j+1] = temp;
}
}
}
}
3.5主函数
int main()
{
double threshold;//定义强度门限
ID_init();//初始化小区名称
for(int i=0; i<NUM; i++)
{
fileop(i);
printf("ID:%s信号平均强度为:%lf\n",area[i].ID,area[i].avg_strength);
}
sort();
printf("\n排序结果为:\n");
for(int i=0; i<NUM; i++)
{
fileop(i);
printf("ID;%s信号平均强度为:%lf\n",area[i].ID,area[i].avg_strength);
}
printf("\n请输入强度门限:\n");
scanf("%lf",&threshold);
printf("\n满足门限条件的小区有:\n");
for (int i = 0; i < NUM; i++)
{
if(area[i].avg_strength>=threshold)//如果满足门限条件打印相关信息
printf("ID:%s \t信号平均强度:%lf\n", area[i].ID, area[i].avg_strength);
}
if(area[0].avg_strength<threshold)
printf("没有满足门限条件的小区");
}
四. 调试
对比单精度和双精度浮点数存放数据,单精度浮点数在小数点后六位便会存在误差,而双精度浮点型存储的数到小数点后16位才会出现误差,故采用双精度浮点型存储数据所得的精度比单精度浮点型高12个数量级。
本次代码的实现难点在于,读文件以及数据计算的操作。遇到的第一个问题:如何确保从单个文件中30000个数据按照Q和I的顺序读取并存储到程序中。倘若使用数组将Q和I分别存储,那么还需要一个循环语句对它们进行求和,故采用一边读取一边传递参数给计算函数,可以很大程度上简化代码量。第二个问题是:12个小区对应了12组文件一个一个打开无疑使代码显得十分冗长。故采用结构体分别存放这12组文件的ID和平均强度,用for循环对结构体进行操作。
五.心得体会
在实际工程中C语言的基本操作——如指针,结构体,文件的运用是必须掌握的,我的基础尚且薄弱仍需进一步学习。
六.意见
七.附录
结果展示
这里是一些写报告时可以用到的网站
流程图绘制:https://app.diagrams.net/?libs=general;flowchart
C代码美化:https://highlightcode.com/