GNSS网平差之间接平差(C语言)

本文介绍使用C语言实现GNSS网间接平差的过程。针对等精度观测数据,通过读取基线文件、计算各点坐标初值、构建并求解误差方程,最终输出平差结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GNSS网间接平差(等精度观测,P=1)

  1. 摘要
    误差理论于测量平差基础。对GPS网测得的基线数据进行间接平差。工具:C语言。

  2. .实习流程
    (1)读取数据文件
    (2)间接平差理论基础:
    观测值的平差值=计算出的观测值初值+改正值
    观测值初值=观测值计算出的各个点坐标之差
    X^i是平差值,Xi0是初值
    在这里插入图片描述
    列出误差方程:
    在这里插入图片描述
    其中红色画圈的记为 “l”,绿色系数为B
    则误差方程为:
    在这里插入图片描述
    计算出V后与观测值求和,得到最终的平差值。
    假设有m条基线,n个点,每条基线有3个观测值,给定一个已知点:则
    V矩阵的形式:3m行,1列
    B矩阵的形式:3
    m行,3*(n-1)列
    L矩阵的形式:3*(n-1)行,1列

  3. 代码实现C语言

#include"stdafx.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
using namespace std;
typedef struct {
	int seq;
	int begin;
	int end;
	double  dx = 0, dy = 0, dz = 0;
}BaseLine;//基线的结构体,存储基线的起点,终点序号,和基线序号,以及基线的观测值dx,dy,dz
typedef struct {
	double  x = 0;
	double  y = 0, z = 0;
	bool flag = 0;
}Pt;//点的结构体,存储每个点的坐标,flag用来判断此点是否已经计算过初值
typedef struct {
	double  x = 0;
	double  y = 0, z = 0;
	bool flag = 0;
}W;//误差项,存储l矩阵的
#define N 39
void getMatrix(BaseLine *line);//用来读取基线文件
void getInitial_Value(BaseLine *line, Pt *pt);//计算各个点的初值
float getL(Pt *pt, BaseLine *line);//计算L矩阵
void TransMatrix(int Mat[24 * 3][3 * 13], int newMat[3 * 13][3 * 24]);//矩阵转置
void Gauss(int A[][N], float B[][N], int n);//矩阵求逆

int main()
{
	
	Pt  pt[14];
	BaseLine line[24];
	//读取基线观测值文件,注意,文件中的顶点P1,P2什么的都改成1,2,3...,不然运行就会Error。
	getMatrix(line);

	//printf("序号 |    起点 |    终点  | △X | △Y  | △Z \n");
	/*for (int i=0;i<24;i++)
	printf("%d   |    P%d  |    P%d   | %f  | %f   |  %f\n", line[i].seq, line[i].begin, line[i].end, line[i].dx, line[i].dy, line[i].dz);*/

	//以P4为起点,计算其他点坐标初值
	getInitial_Value(line, pt);
	//输出点坐标
	/*for (int j = 0; j < 14; j++)
	printf("%f  %f  %f\n", pt[j].x, pt[j].y, pt[j].z);*/
	/*int i = 0, j = 0;
	int arr1[2][2] = { { 10,20 },{ 30,40 } };
	for (i = 0; i < 2; i++)
	{
	for (j = 0; j < 2; j++)
	{
	arr1[i][j] = i + j;
	printf("%3d", arr1[i][j]);
	}
	printf("\n");
	}*/

	//计算L 矩阵****************************************************************
	float l[24 * 3];
	W L[24];
	for (int i = 0; i < 24; i++)
	{
		L[i].x = line[i].dx - (pt[line[i].end - 1].x - pt[line[i].begin - 1].x);
		L[i].y = line[i].dy - (pt[line[i].end - 1].y - pt[line[i].begin - 1].y);
		L[i].z = line[i].dz - (pt[line[i].end - 1].z - pt[line[i].begin - 1].z);
	}
	//for (int i = 0; i < 24; i++)
	//{//输出L矩阵
	//printf("%f |  %f |  %f\n", L[i].x, L[i].y, L[i].z);
	//}
	int i = 0;
	for (int j = 0; i<24; j += 3, i++)
	{
		l[j] = L[i].x;
		l[j + 1] = L[i].y;
		l[j + 2] = L[i].z;

	}
	//输出l矩阵
	/*for (int i = 0; i < 72; i++)
	{
	printf("%f\n", l[i]);
	}*/
	/*********************************************************************/
	//计算B矩阵
	int t = 0;
	int B[3 * 24][3 * 13] = { 0 };
	for (int i = 0; i <24 * 3;)
	{
		if ((line[t].end == 1))
		{
			B[i][(line[t].begin - 1) * 3 - 3] = -1;
			B[i + 1][(line[t].begin - 1) * 3 - 2] = -1;
			B[i + 2][(line[t].begin - 1) * 3 - 1] = -1;

		}
		else if ((line[t].begin == 1))
		{
			B[i][(line[t].end - 1) * 3 - 3] = 1;
			B[i + 1][(line[t].end - 1) * 3 - 2] = 1;
			B[i + 2][(line[t].end - 1) * 3 - 1] = 1;
		}
		else
		{
			B[i][(line[t].begin - 1) * 3 - 3] = -1;
			B[i + 1][(line[t].begin - 1) * 3 - 2] = -1;
			B[i + 2][(line[t].begin - 1) * 3 - 1] = -1;
			B[i][(line[t].end - 1) * 3 - 3] = 1;
			B[i + 1][(line[t].end - 1) * 3 - 2] = 1;
			B[i + 2][(line[t].end - 1) * 3 - 1] = 1;
		}
		t++;
		i += 3;


	}
	//输出B矩阵
	//for (int i = 0; i < 3 * 24; i++)
	//	for (int j = 0; j < 3 * 13; j++)
	//	{
	//		
	//		if (j == 3 * 13 - 1)
	//		{
	//			printf("%d", B[i][j]);
	//			printf("\n");
	//		}
	//		else
	//		{
	//			if (j == 0&&(i%3==0||i==0))
	//				printf("Line%d:   ", i/3 + 1);
	//			printf("%d ,", B[i][j]);
	//		}
	//	}
	求B的转置矩阵BT
	int BT[39][72];
	TransMatrix(B, BT);
	/*for (int i = 0; i < 13*3; i++)
	{
	for (int j = 0; j < 3*24; j++)
	{
	printf("%d,", BT[i][j]);
	if (j == 3 * 24 - 1)
	printf("\n");
	}
	}*/
	int NBB[3 * 13][3 * 13] = { 0 };
	for (int i = 0; i < 13 * 3; i++)
	{
		for (int j = 0; j < 13 * 3; j++)
		{
			int sum = 0;
			for (int k = 0; k < 24 * 3; k++)
			{
				sum += BT[i][k] * B[k][j];
			}
			NBB[i][j] = sum;
		}
	}
	/*for (int i = 0; i < 39; i++)
	{
		
		for (int j = 0; j < 39; j++)
		{
			
			if (j == 38)
			{
				printf("%d", NBB[i][j]);
				printf("\n");
			}
			else
				printf("%d,", NBB[i][j]);
		}
	}*/
	//求NBB的逆           公式:x=inv(NBB)*B'*l
   float invNBB[39][39];
   Gauss(NBB, invNBB, 39);
  /* for (int i = 0; i<39; i++)
   {//输出invNBB
	   for (int j = 0; j<39; j++)
	   {
		   printf("%.3lf ", (double)invNBB[i][j] );
	   }
	   printf("\n");
   }*/

   //求x,待解参数的误差
   float temp1[3 * 13][3 * 24] = { 0 };
   for (int i = 0; i < 13 * 3; i++)
   {
	   for (int j = 0; j < 24 * 3; j++)
	   {
		   float sum = 0;
		   for (int k = 0; k < 13 * 3; k++)
		   {
			   sum += invNBB[i][k] * BT[k][j];
		   }
		   temp1[i][j] = sum;
	   }
   }
  /* for (int i = 0; i < 39; i++)
   {

       for (int j = 0; j < 72; j++)
      {
  
             if (j == 71)
            {
			   printf("%f", temp1[i][j]);
                printf("\n");
             }
             else
                printf("%f,", temp1[i][j]);
       }
   }*/
   //解得待解参数x改正值,39*1
   float x[39] = { 0 };
   for (int i = 0; i < 13 * 3; i++)
   {
	   float sum = 0;
	   for (int k = 0; k < 24 * 3; k++)
	   {
		   sum += temp1[i][k] * l[k];
	   }
	   x[i] = sum;
   }
   float V[72];
   for (int i = 0; i < 24 * 3; i++)
   {
	   float sum = 0;
	   for (int k = 0; k < 13 * 3; k++)
	   {
		   sum += B[i][k] * x[k]-l[k];
	   }
	   V[i] = sum;
   }
   //输出每个观测值的改正值:
   printf("每个观测值的改正值:\n");
   const char *pFileName = "间接平差result.txt";
   FILE * pFile;
   pFile = fopen(pFileName, "w");
   if (NULL == pFile)
   {
	   printf("error");
	   return 0;
   }
    for (int i = 0; i < 72; i++)
    {
		printf("%d :   %.4f  \n",i+1,V[i]);
		fprintf(pFile, "V[%d] :   %.4f  \n", i + 1, V[i]);
    }
	fclose(pFile);
	int vv = 0;
	for (int i = 0; i < 72; i += 3)
	{
		line[vv].dx = line[vv].dx + V[i];
		line[vv].dy = line[vv].dy + V[i+1];
		line[vv].dz = line[vv].dz + V[i+2];
		vv++;
	}
	//输出最终平差值
	printf("最终平差结果为:\n");
	pFile = fopen(pFileName, "a");
	if (NULL == pFile)
	{
		printf("error ");
		return 0;
	}	for (int i = 0; i < 24; i++)
	{
		printf("%.3f  |   %.3f    |   %.3f    \n", line[i].dx, line[i].dy, line[i].dz);
		fprintf(pFile, "%.3f  |    %.3f    |    %.3f\n", line[i].dx, line[i].dy, line[i].dz);

	}
	fclose(pFile);
	printf("名为:‘间接平差result.txt’的文件已经存入本目录\n");
   system("pause");
	return 0;
	
}
void getMatrix(BaseLine *line)
{
	FILE* fp;
	fp = fopen("GNSS.txt", "r");//读取文件,改成自己的路径
	if (!fp)
	{//报错
		printf("ERROR!");
		exit(0);
	}
	int t = 0;
	int i = 0;
	float f = 0;
	while (!feof(fp))
	{
		fscanf_s(fp, "%d,", &t);
		line[i].seq = t;
		fscanf_s(fp, "%d,", &t);
		line[i].begin = t;
		fscanf_s(fp, "%d,", &t);
		line[i].end = t;
		fscanf_s(fp, "%f,", &f);
		line[i].dx = f;
		fscanf_s(fp, "%f,", &f);
		line[i].dy = f;
		fscanf_s(fp, "%f\n", &f);
		line[i].dz = f;
		i++;
	}
	fclose(fp);//关闭文件
}
void getInitial_Value(BaseLine *line, Pt *pt)
{
	float X0 = 0, Y0 = 0, Z0 = 0;
	printf("请输入P1的(X,Y,Z)坐标,作为起算点\n");
	scanf_s("%f ,%f, %f", &X0, &Y0, &Z0);
	pt[0].x = X0;
	pt[0].y = Y0;
	pt[0].z = Z0;
	pt[0].flag = 1;
	//计算其他点坐标初值x0,y0,z0;
	for (int j = 0; j < 24;)
	{
		if ((pt[line[j].end - 1].flag == 0) && (pt[line[j].begin - 1].flag == 1))
		{//终点没有算过初值,起点有初值
			pt[line[j].end - 1].x = pt[line[j].begin - 1].x + line[j].dx;
			pt[line[j].end - 1].y = pt[line[j].begin - 1].y + line[j].dy;
			pt[line[j].end - 1].z = pt[line[j].begin - 1].z + line[j].dz;
			pt[line[j].end - 1].flag = 1;
			j++;

		}
		else if ((pt[line[j].end - 1].flag == 1) && (pt[line[j].begin - 1].flag == 0))
		{//终点算过初值,起点没初值
			pt[line[j].begin - 1].x = pt[line[j].end - 1].x - line[j].dx;
			pt[line[j].begin - 1].y = pt[line[j].end - 1].y - line[j].dy;
			pt[line[j].begin - 1].z = pt[line[j].end - 1].z - line[j].dz;
			pt[line[j].begin - 1].flag = 1;
			j++;

		}
		else if ((pt[line[j].end - 1].flag == 1) && (pt[line[j].begin - 1].flag == 1))
		{//都算过了
			j++;

		}

	}
}
void TransMatrix(int Mat[24 * 3][3 * 13], int newMat[3 * 13][3 * 24])
{//B矩阵转置
	for (int i = 0; i < 72; i++)
	{
		for (int j = 0; j < 3 * 13; j++)
		{
			newMat[j][i] = Mat[i][j];
		}
	}

	//for (int i = 0; i < 3 * 24; i++)
	//	for (int j = 0; j < 3 * 13; j++)
	//	{
	//		
	//		if (j == 3 * 13 - 1)
	//		{
	//			printf("%d", Mat[i][j]);
	//			printf("\n");
	//		}
	//		else
	//		{
	//			/*if (j == 0&&(i%3==0||i==0))
	//				printf("Line%d:   ", i/3 + 1);*/
	//			printf("%d ,",Mat[i][j]);
	//		}
	//	}
}


//高斯求逆
void Gauss(int A[][N], float B[][N], int n)
{
	int i, j, k;
	float max, temp;
	float t[N][N];                //临时矩阵
								  //将A矩阵存放在临时矩阵t[n][n]中
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			t[i][j] = A[i][j];
		}
	}
	//初始化B矩阵为单位阵
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			B[i][j] = (i == j) ? (float)1 : 0;
		}
	}
	for (i = 0; i < n; i++)
	{
		//寻找主元
		max = t[i][i];
		k = i;
		for (j = i + 1; j < n; j++)
		{
			if (fabs(t[j][i]) > fabs(max))
			{
				max = t[j][i];
				k = j;
			}
		}
		//如果主元所在行不是第i行,进行行交换
		if (k != i)
		{
			for (j = 0; j < n; j++)
			{
				temp = t[i][j];
				t[i][j] = t[k][j];
				t[k][j] = temp;
				//B伴随交换
				temp = B[i][j];
				B[i][j] = B[k][j];
				B[k][j] = temp;
			}
		}
		//判断主元是否为0, 若是, 则矩阵A不是满秩矩阵,不存在逆矩阵
		if (t[i][i] == 0)
		{
			printf("There is no inverse matrix!");
			system("pause");
			exit(0);
		}
		//消去A的第i列除去i行以外的各行元素
		temp = t[i][i];
		for (j = 0; j < n; j++)
		{
			t[i][j] = t[i][j] / temp;        //主对角线上的元素变为1
			B[i][j] = B[i][j] / temp;        //伴随计算
		}
		for (j = 0; j < n; j++)        //第0行->第n行
		{
			if (j != i)                //不是第i行
			{
				temp = t[j][i];
				for (k = 0; k < n; k++)        //第j行元素 - i行元素*j列i行元素
				{
					t[j][k] = t[j][k] - t[i][k] * temp;
					B[j][k] = B[j][k] - B[i][k] * temp;
				}
			}
		}
	}
}

4.输入文件与输出结果结果
输入文件格式:
这里把所有的顶点的字母"P"去掉了
在这里插入图片描述
结果:
在这里插入图片描述
C语言的一些矩阵运算

间接原理写的代码,绝对有用,真实可靠 Dim strFileName As String Dim nn%, un%, tn%, hn% '已知点个数,未知点个数,总点数,观测值个数 Dim Pname() As String '点名数组 Dim Hknown() As Double '已知高程数组,存放已知点高程和高程近似值 Dim be%(), en%() '观测值的起点和终点编号数组,存储的是点序号 Dim h#(), s#() '高观测值数组和距离观测值数组 Dim A#(), X#(), P#(), L#() '间接的系数阵、解向量、权阵和常数向量 '计算 Private Sub mnuAdj_Click() Dim i%, j% ReDim X(1 To un) InAdjust A, P, L, X '调用间接的通用过程求解 '计算并显示高程结果 txtShow.Text = txtShow.Text & "计算结果:" & vbCrLf txtShow.Text = txtShow.Text & "点号 初始高程(m) 高程改正数(m) 后高程(m)" & vbCrLf For i = 1 To un txtShow.Text = txtShow.Text & Pname(nn + i) & " " & Format(Hknown(nn + i), "0.0000") Hknown(nn + i) = Hknown(nn + i) + X(i) txtShow.Text = txtShow.Text & " " & Format(X(i), "0.0000") & " " & Format(Hknown(nn + i), "0.0000") & vbCrLf Next i txtShow.Text = txtShow.Text & vbCrLf '计算并显示单位权中误差--------->>精度评定部分应该也包含在间接模块里,一起来调用 ' Dim dblT As Double ' dblT = 0 ' For i = 1 To un ' ' Next i End Sub '列立误差方程:给A、P、L赋值 Private Sub mnuEqu_Click() Dim i%, j% ReDim A(1 To hn, 1 To un), L(1 To hn), P(1 To hn, 1 To hn) '对每个观测值列误差方程 For i = 1 To hn If en(i) > nn Then A(i, en(i) - nn) = 1 '若终点未知,则给终点对应的系数矩阵元素赋值 If be(i) > nn Then A(i, be(i) - nn) = -1 '若起点未知,则给起点对应的系数矩阵元素赋值 L(i) = -(Hknown(en(i)) - Hknown(be(i)) - h(i)) '根据起终点计算常数项 P(i, i) = 1 / s(i) '以距离的倒数为权 Next i '显示误差方程 txtShow.Text = txtShow.Text & " 列立的误差方程:" & vbCrLf For i = 1 To hn For j = 1 To un txtShow.Text = txtShow.Text & A(i, j) & " " Next j txtShow.Text = txtShow.Text & " " & Format(L(i), "0.0000") & vbCrLf Next i txtShow.Text = txtShow.Text & "权矩阵:" & vbCrLf For i = 1 To hn For j = 1 To hn txtShow.Text = txtShow.Text & P(i, j) & " " Next j txtShow.Text = txtShow.Text & vbCrLf Next i End Sub '计算近似高程 Private Sub mnuHeight_Click() Dim i%, j% For i = 1 To un For j = 1 To hn If be(j) = nn + i And en(j) < nn + i Then '找到一个起点相同且终点已知的观测值 Hknown(nn + i) = Hknown(en(j)) - h(j) Exit For End If If en(j) = nn + i And be(j) < nn + i Then '找到一个终点相同且起点已知的观测值 Hknown(nn + i) = Hknown(be(j)) + h(j) Exit For End If Next j Next i '显示近似高程计算结果 txtShow.Text = txtShow.Text & " 近似高程计算结果: " & vbCrLf For i = 1 To un txtShow.Text = txtShow.Text & Pname(i + nn) & ":" & Format(Hknown(i + nn), "0.000") & vbCrLf Next i End Sub '退出程序 Private Sub mnuExit_Click() End End Sub '打开文件 Private Sub mnuOpen_Click() Dim i As Integer '循环变量 Dim strT1 As String, strT2 As String CDg1.Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*" CDg1.ShowOpen '打开对话框 strFileName = CDg1.FileName '获得选中的文件名和路径 Open strFileName For Input As #1 '打开文件 Input #1, nn, un, hn '读入已知点个数,未知点个数,观测值个数 tn = nn + un ReDim Pname(1 To tn), Hknown(1 To tn) ReDim h(1 To hn), s(1 To hn), be(1 To hn), en(1 To hn) For i = 1 To tn '读入点名 Input #1, Pname(i) Next i For i = 1 To nn '读入已知高程 Input #1, Hknown(i) Next i For i = 1 To hn '读入各观测值 Input #1, strT1, strT2, h(i), s(i) be(i) = Order(strT1): en(i) = Order(strT2) '给起终点数组排序 Next i '显示读入的数据 txtShow.Text = txtShow.Text & "读入的水准数据:" & vbCrLf txtShow.Text = txtShow.Text & " 已知点" & nn & "个,未知点" & un & "个,观测值" & hn & "个。" & vbCrLf txtShow.Text = txtShow.Text & " 中涉及的点名有:" For i = 1 To tn txtShow.Text = txtShow.Text & Pname(i) & "," Next i txtShow.Text = txtShow.Text & vbCrLf txtShow.Text = txtShow.Text & " 已知点高程为:" & vbCrLf For i = 1 To nn txtShow.Text = txtShow.Text & Pname(i) & "的高程为:" & Hknown(i) & vbCrLf Next i txtShow.Text = txtShow.Text & " 各观测值分别为:" & vbCrLf txtShow.Text = txtShow.Text & "起点" & " " & "终点" & " " & "高观测值 " & " 距离观测值" & vbCrLf For i = 1 To hn txtShow.Text = txtShow.Text & Pname(be(i)) & " " & Pname(en(i)) & " " & Format(h(i), "0.000") & " " & Format(s(i), "0.000") & vbCrLf Next i Close #1 '不要忘记关闭文件 End Sub '点名-序号转换函数 Public Function Order(str As String) As Integer Dim i% For i = 1 To tn If str = Pname(i) Then Order = i Exit For End If Next i End Function '保存计算结果 Private Sub mnuSave_Click() CDg1.Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*" CDg1.ShowSave strFileName = CDg1.FileName Open strFileName For Output As #1 Print #1, txtShow.Text Close #1 End Sub
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值