相关检测方法实验
相关检测方法
相关检测技术是信号检测领域里一种重要工具,常用于从噪声背景中检测出有用得确定性信号。它利用确定信号在不同时刻得取值一般都具有较强的相关性,而干扰噪声因为随机性较强,不同时刻取值相关性较差的特性,把确定性信号和干扰噪声区分开来。
实验背景
拥有12个基站信号(即12个data文件,文件按实部+虚部进行交替存储,共30000行),计算各个基站的信号强度,并得出信号最强的三个基站,将其信号作为确定信号,即前文提到的确定信号序列;
具有噪声背景的实际信号序列为从已知的三组数据中任选其一的PSS文件(共4096行);
将data文件与PSS做滑动相关计算,需要注意的是此处为先复数计算再取模,
最终再根据得到的序列比较,PSS与哪一个基站的信号最相关。
基本流图
信号强度计算
序号为的点,,其信号强度:
信号强度(N为序列个数):
复数相乘
已知两复数分别为,,
则计算有:
由复数的特性可知,乘积的模等于模的乘积,所以可以在读取文件时便提前取模再存入数组;
滑动相关检测计算
具体算法见前篇文章;
此处将其封装并稍微调整便于调用,注意为复数计算;
因原为计算两数的乘积,前文提到,在复数运算中,两复数的乘积的模等于两复数模的乘积(并且可以推导到个复数相乘),所以可以先将数据处理为复数的模后相乘再求和;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
int slide(double x[],double y[],int S) { int i = 0; int j = 0; int kz = 0; double max[3] = { 0 }; int maxpos = 0;
for (kz = 0; kz < k; kz++) { for (i = 0; i < m ; i++) { Z[S][kz] += x[i] * y[i + j]; } j++; if (Z[S][kz] >= max[S]) { max[S] = Z[S][kz]; maxpos = kz; } } return maxpos; }
|
读文件
使用 fopen() 函数来打开已有文件,
1
| FILE *fopen( const char *filename, const char *mode );
|
filename 是字符串,用来命名文件,mode的值如下表:
模式 |
描述 |
r |
打开一个已有的文本文件(只读模式) |
w |
打开一个文本文件,允许写入文件。若文件不存在,则会创建一个新文件。在这里程序会从文件的开头写入内容。如果文件存在,则会被截断为零长度,重新写入(只写模式) |
a |
打开一个文本文件,以追加模式写入文件。若文件不存在,则会创建一个新文件。在这里程序会在已有的文件内容中追加内容(追加写入模式) |
r+ |
打开一个文本文件,允许读写文件(读写模式) |
w+ |
打开一个文本文件,允许读写文件。若文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件 |
a+ |
打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式 |
如需处理二进制文件,在启动模式后添加 b
文件使用完毕后,务必关闭文件,使用如下函数:
若成功关闭文件, fclose() 函数返回零,如果关闭文件时发生错误,函数返回 EOF ,此函数会清空缓冲区中的数据并关闭文件,释放用于该文件的所有内存。
此实验中使用 fread 函数来读文件,其原型如下:
1
| size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
ptr 指向带有最小尺寸 字节的内存块的指针;
size 是要读取的每个元素的大小,以字节为单位;
nmemb 是元素的个数,每个元素的大小为 字节;
stream 指向 对象的指针;
成功读取的元素总数会以 对象返回,该对象是一个整型数据类型,若总数与 参数不同,则可能发生了一个错误或者达到了文件末尾。
在VSCode中使用fopen和sprintf会产生报错,可以使用以下方式关闭此报错:
1
| #pragma warning(disable:4996);
|
由于需要打开的data文件与PSS文件长度,返回值,需要存入的对象以及文件个数均不一致,为了简便(就是想偷懒不想写成一个函数…)为data文件与PSS文件分别写了一个函数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
double OpData(int i, FILE *fp[12]) { char sBuffer[100]; double Q = 0, R = 0; double Sum = 0; sprintf(sBuffer, "E:\\datas\\data%d.txt", i); if ((fp[i] = fopen(sBuffer, "r")) == NULL) { printf("Cannot open file data%d.txt\r\n",i); return -1; } fseek(fp[i], 0, SEEK_SET); for (int j = 0; j < n; j++) { fscanf(fp[i], "%lf %lf", &Q,&R); Y[i][j] = sqrt(pow(Q, 2) + pow(R, 2)); Sum += Y[i][j]; } fclose(fp[i]); return Sum; }
int OpPSS(int i, FILE* fp) { char sBuffer[100]; double Q = 0, R = 0; sprintf(sBuffer, "E:\\datas\\PSS%d.txt", i); if ((fp = fopen(sBuffer, "r")) == NULL) { printf("Cannot open file data%d.txt\r\n", i); return -1; } fseek(fp, 0, SEEK_SET); for (int j = 0; j < 2 * m; j += 2) { fscanf(fp, "%lf %lf", &Q, &R); X[j / 2] = sqrt(pow(Q, 2) + pow(R, 2)); } fclose(fp); return 0; }
|
其中的作用就是临时存储读出的实部与虚部,求模后再存入数组;
获取信号最强的三个基站
由于直接进行排序无法同时记录三个基站的位序,如果使用结构体直接进行排序应该会更加简单,并提升运算速度;
但在此处我们用一个长度为3的数组几下三次的最大值,便可轻易地得出三个最大值及其下标,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
int GetStations() { double Intensity[12] = { 0 }; int i = 0; int j = 0; FILE* fp[12] = { NULL }; double max[3] = { 0 }; for (i = 0; i < 12; i++) { Intensity[i] = OpData(i, fp); } for (j = 0; j < 3; j++) { for (i = 0; i < 12; i++) { switch (j) { case 0: { if (Intensity[i] >= max[j]) { max[j] = Intensity[i]; Station[j] = i; } break; } default: { if(Intensity[i] >= max[j] && Intensity[i] < max[j - 1]) { max[j] = Intensity[i]; Station[j] = i; } break; } } } } return 0; }
|
得出相关性最强的基站
将数组拓展为二维数组以存储三个基站分别进行相关检测计算后的结果,再根据每一次相关检测的结果,比较他们最大确定信号(也就是序列中模值的最大值),得出这一个基站对应的标号(预先已经存储在了Station这一个全局变量内),具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
int MaxIntensity() { int maxpos[3]; double max = 0; int pos = 0; int j = 0; for (int i = 0; i < 3; i++) { maxpos[i] = slide(X, Y[Station[i]], i); if (Z[i][maxpos[i]] >= max) { max = Z[i][maxpos[i]]; pos = Station[i]; j = i; } } printf("相关性最强的基站确定信号的起始位置为%d\r\n", maxpos[j]); return pos; }
|
主函数及宏定义等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
#include <stdio.h> #include <math.h> #include <string.h>
#define n 30000/2 #define m 4096/2 #define k n-m+1
#pragma warning(disable:4996) #pragma warning(disable:6031)
int slide(double x[], double y[]); double OpData(int i, FILE* fp[12]); int OpPSS(int i, FILE* fp); int GetStations(); int MaxIntensity();
double Z[3][k] = { 0 }; double X[m] = { 0 }; double Y[12][n] = { 0 }; int Station[3] = { 0 };
int main(void) { int pos = 0; FILE* fp1[12] = { NULL }; FILE* fp = NULL; OpPSS(0, fp); GetStations(); pos = MaxIntensity(); printf("相关性最强的基站为%d号基站\r\n", pos); return 0; }
|
参考网站
C 文件读写 | 菜鸟教程 (runoob.com)
附.实验数据