资源描述
n
目录
一、目录 ----------------------------1
二、序言 ---------------------------- 2
三、设计思绪 ------------------------ 3
四、程序流程图 ---------------------- 4
五、程序及说明 ---------------------- 5
六、计算结果 -----------------------12
七、总结 --------------------------- 15
第二部分 序言
1、 课程设计的性质、目的和任务
误差理论与测量平差是一门理论与实践并重的课程,其课程设计是测量数据解决理论学习的一个重要的实践环节,它是在我们学习了专业基础课“误差理论与测量平差基础”课程后进行的一门实践课程。其目的是增强我们对误差理论与测量平差基础理论的理解,牢固掌握测量平差的基本原理和基本公式,熟悉测量数据解决的基本技能和计算方法,灵活准确地应用于解决各类数据解决的实际问题,并能用所学的计算机理论知识,编制简朴的计算程序。
2、误差理论与测量平差课程和其它课程的联系和分工
这次课程设计中所用的数学模型和计算方法是我们在误差理论与测量平差课程中所学的内容,所使用的C程序语言使我们在计算机基础课程中所学知识。误差理论与测量平差课程设计是测量平差和计算机程序设计等课程的综合实践与应用,同时也为我们此后步入工作岗位打下了一定基础。
3、 课程设计重点及内容
本次课程设计重点是培养我们对的应用公式、综合分析和解决问题的能力,以及计算机编程能力。此外它规定我们完毕1-2个综合性的结合生产实践的题目。如目前生产实践中经常用到的水准网严密平差及精度评估,边角网(导线)严密平差及精度评估等。本次我所选的课程设计课题是水准网严密平差及精度评估,其具体内容如下:
根据题目规定,对的应用平差模型列出观测值条件方程、误差方程和法方程;解算法方程,得出平差后的平差值及各待定点的高程平差值;评估各平差值的精度和各高程平差值的精度。
具体算例为:
如图所示水准网,有2个已知点,3个未知点,7个测段。各已知数据及观测值见下表
(1) 已知点高程H1=5.016m , H2=6.016m (2)高差观测值(m)
端点号
高差观测值m
测段距离km
序号
1-3
1.359
1.1
1
1-4
2.009
1.7
2
2-3
0.363
2.3
3
2-4
1.012
2.7
4
3-4
0.657
2.4
5
3-5
0.238
1.4
6
5-2
-0.595
2.6
7
(3)求各待定点的高程;3-4点的高差中误差;3号点、4号点的高程中误差。
第三部分 设计思绪
一、解题环节
(1)本次设计我所采用的模型为间接平差模型,根据已知条件我们可知观测总数n=7,必要观测数t=3(则多余观测数r=n-t=4),因此我需先选定三个参数,即3、4、5点的最或然高程X3、X4、X5(X=X0+x,X30=6.375、X40=7.025、X50=6.611;其中X0为参数的近似值,x为其改正值)为参数。
(2)列出条件方程,即将每一个观测量的平差值分别表达成所选参数的函数,H1+h1=X3、H1+h2=X4、H2+h3=X3、H2+h4=X4、X3+h5=X4、X3+h6=X5、X5+h7=H2;整理后得出误差方程,v1=x3、v2=x4、v3=x3-4、v4=x4-3、v5=-x3+x4-7、v6=-x3+x5-2、v7=-x5,即v=Bx-l的形式。
(3)定权,令每千米的观测高差为单位权观测,即Pi=1/Si,从而可写出权阵P;根据误差方程式又可得其系数矩阵B和自由项l,并由它们组成法方程NBBx-W=0(其中NBB=BTPB,W=BTPl),法方程的个数等于所选参数的个数。
(4)解算法方程,求出参数改正值x并计算参数的平差值X=X0+x。
(5)由误差方程计算V,并求出观测量的平差值。为了检查平差计算的对的性,将所求的值代入条件方程,看其是否满足方程。
(6)精度评估,计算单位权中误差,按照题设规定列出权函数式,再根据平差参数的协方差阵求出协因数,最后求出某段高差中误差,某些点的高程中误差。
二、程序设计思想
考虑到在解题过程中一些计算的复杂性,我们需借助一些技术将计算简朴化,快捷化,因此在课程设计过程中,我们把一些C语言程序设计引入其中;通过一些简朴、明了的程序及子函数调用,我们就可以很方便快捷的求出用笔算比较繁琐、费时的矩阵乘积、矩阵的逆(如BTPB、BTPl)等运算。
第四部分 程序流程图
根据题目列出条件方程并写成误差方程的形式V=Bx-l
↓
拟定权阵,根据误差方程得到矩阵B、l进而写出BT
↓
运用C程序语言求出BTP,进一步得到NBB=BTPB、W=BTPl并求出NBB-1
↓
用C程序求出参数的改正数x=NBB-1W
↓
根据C程序语言求Bx,进而由V=Bx-l写出各观测值的改正数
↓
根据L=L+V求出各观测值的平差值
↓
检查所求各值是否对的,若无误则往下进行,反之检查各环节查犯错误并改正
↓
由程序计算VTP进而求出VTPV,求单位权中误差,再根据权函数式、协因数传播定律评估各观测值及所求高程的精度
第五部分 程序及说明
一、矩阵相乘计算函数
#include “stdio.h”
void Matrix(a,b,m,n,k,c)
int m,n,k;
double a[],b[],c[];
{
int i,j,l,u;
for(i=0;i<=m-1;i++)
for(j=0;j<=k-1;j++)
{
u=i*k+j;c[u]=0.0;
for(l=0;l<=n-1;l++)
c[u]=c[u]+a[i*n+l]*b[l*k+j];
}
return;
}
1.计算BTP
main()
{
int i,j;
static double a[3][7]=BT;
static double c[3][7],b[7][7]=P;
Matrixmul(a,b,3,7,7,c);
printf(“\n”);
for(i=0;i<=2;i++)
{
for(j=0;j<=6;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
2.计算BTPB,即NBB
main()
{
int i,j;
static double a[3][7]=BTP;
static double c[3][3],b[7][3]=B;
Matrixmul(a,b,3,7,3,c);
printf(“\n”);
for(i=0;i<=2;i++)
{
for(j=0;j<=2;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
3.计算BTPl,即W
main()
{
int i,j;
static double a[3][7]=BTP;
static double c[3][1],b[7][1]=l;
Matrixmul(a,b,3,7,1,c);
printf(“\n”);
for(i=0;i<=2;i++)
{
for(j=0;j<=0;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
二、矩阵的逆计算函数(求NBB-1)
#include "stdio.h"
#define M 3
void main()
{
float MAT[M][2*M];
float MAT1[M][M];
float t;
int i,j,k,l;
/***********************************************/
/*对矩阵进行初始化*/
for(i=0;i<M;i++)
for(j=0;j<2*M;j++)
MAT1[j]='\0';
/*对MAT1矩阵赋初值 */
for(i=0;i<M;i++)
for (j=0;j<M;j++)
scanf("%f",&MAT1[j]);
/*打印目的矩阵?*/
printf("原矩阵为:\n");
for (i=0;i<M;i++)
{
for (j=0;j<M;j++)
printf("%13.7f",MAT1[j]);
printf("\n");
} /********************************************/
/*对MAT1矩阵进行扩展,MAT1矩阵添加单位阵,由M*M变成2M*2M矩阵 */
for(i=0;i<M;i++)
for(j=0;j<2*M;j++)
if (j<M) MAT[j]=MAT1[j];
else if (j==M+i) MAT[j]=1;
else MAT[j]=0;
/*对M矩阵进行变换,使得前半部分矩阵成为单位阵,则 */
/*后半部分矩阵即为所求矩阵逆阵 */
for(i=0;i<M;i++)
{
/*对第i行进行归一化 */
for (j=0;j<2*M;j++)
for(k=i+1;k<M;k++)
MAT[j]=MAT[j]+MAT[k][j];
t=MAT;
for(j=i;j<2*M;j++)
MAT[j]=MAT[j]/t;
/*对矩阵进行行变换,使得第i 列只有一个元素不为零,且为1*/
for(k=0;k<M;k++)
if(k!=i)
{
t=MAT[k];
for (l=i;l<2*M;l++)
MAT[k][l]=MAT[k][l]-MAT[l]*t;
}
}
/*将后半部分矩阵即所求矩阵逆阵存入MAT2矩阵。*/
for(i=0;i<M;i++)
{
for(j=0;j<M;j++)
MAT1[j]=MAT[j+M];
printf("\n");
}
/*********************************************/
/*输出所求的逆阵*/
printf("逆阵为:\n");
for(i=0;i<M;i++)
{
for(j=0;j<M;j++)
printf("%8.4f",MAT1[j]);
printf("\n");
}
}
4.求NBB-1W,即改正数x
main()
{
int i,j;
static double a[3][3]=NBB-1;
static double c[3][1],b[3][1]=W;
Matrixmul(a,b,3,3,1,c);
printf(“\n”);
for(i=0;i<=2;i++)
{
for(j=0;j<=0;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
5.计算Bx
main()
{
int i,j;
static double a[7][3]=B;
static double c[7][1],b[3][1]=x;
Matrixmul(a,b,7,3,1,c);
printf(“\n”);
for(i=0;i<=6;i++)
{
for(j=0;j<=0;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
6.计算VTP
main()
{
int i,j;
static double a[1][7]=VT;
static double c[1][7],b[7][7]=P;
Matrixmul(a,b,1,7,7,c);
printf(“\n”);
for(i=0;i<=0;i++)
{
for(j=0;j<=6;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
}
7.计算VTPV
main()
{
int i,j;
static double a[1][7]=VTP;
static double c[1][1],b[7][1]=V;
Matrixmul(a,b,1,7,1,c);
printf(“\n”);
for(i=0;i<=0;i++)
{
for(j=0;j<=0;j++)
printf(“%8.4f\t”,c[i][j];
printf(“\n”);
}
printf(“\n”);
return0;
注:程序中有下划线部分在C语言环境中运营时,需根据已知条件及所求结果进行替换!
第六部分 计算结果
根据条件方程及定权原则写出B、l、P及BT
B={{1.0,0.0,0.0},
{0.0,1.0,0.0},
{1.0,0.0,0.0},
{0.0,1.0,0.0},
{-1.0,1.0,0.0},
{-1.0,0.0,1.0},
{0.0,0.0,-1.0}}
l={{0.0},
{0.0},
{4.0},
{3.0},
{7.0},
{2.0},
{0.0}}
P={{0.9091,0.0,0.0,0.0,0.0,0.0,0.0},
{0.0,0.5882,0.0,0.0,0.0,0.0,0.0},
{0.0,0.0,0.4348,0.0,0.0,0.0,0.0},
{0.0,0.0,0.0,0.3704,0.0,0.0,0.0},
{0.0,0.0,0.0,0.0,0.4167,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0,0.7143,0.0},
{0.0,0.0,0.0,0.0,0.0,0.0,0.3846}}
BT={{1.0,0.0,1.0,0.0,-1.0,-1.0,0.0},
{0.0,1.0,0.0,1.0,1.0,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0,1.0,-1.0}}
一、在矩阵相乘计算函数的程序前提下,进行以下子程序的调用
1.替换第1个程序中的BT 、P并运营程序得到BTP
BTP={{0.9091,0.0,0.4348,0.0,-0.4167,-0.7143,0.0},
{0.0,0.5882,0.0,0.374,0.4167,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0,0.7143,-0.3846}}
2.替换第2个程序中的BTP、B并运营程序得到BTPB,即NBB
NBB={{2.4748,-0.4167,-0.7143},
{-0.4167,1.3753,0.0},
{-0.7143,0.0,1.0989}}
3.替换第3个程序中的BTP、l并运营程序得到BTPl,即W
W={{-2.6063},
{4.0281},
{1.4286}}
二、在矩阵的逆计算函数程序中进行以下操作
运营程序,按照提醒及以上运算得到的矩阵NBB输入其元素,运营的结果即为NBB-1 NBB-1={{0.5307,0.1608,0.3450},
{0.1608,0.7758,0.1045},
{0.3450,0.1045,1.1342}}
三、再次在矩阵相乘计算函数的程序前提下,进行以下子程序的调用
1.替换第4个程序中的NBB-1、W并运营程序得到NBB-1W,即所选参数的改正数x
x={{-0.2426},
{2.8552},
{1.1421}}
2.替换第5个程序中的B、x并运营程序得到Bx
Bx={{-0.2426},
{2.8552},
{-0.2464},
{2.8552},
{3.0978},
{1.3847},
{-1.1421}}
3.根据V=Bx-l求出各观测值的改正数V,并写出VT,然后替换第6个程序中的VT、P并运营程序得到VTP
V={{-0.2426},
{2.8552},
{-4.2426},
{-0.1448},
{-3.9022},
{-0.6153},
{-1.1421}}
VT={{-0.2426,2.8552,-4.2426,-0.1448,-3.9022,-0.6153,-1.1421}}
VTP={{-0.2205,1.6794,-1.8447,-0.0536,1.6260,-0.4395,-0.4393}}
4.替换第7个程序中的VTP、V并运营程序得到VTPV
VTPV=19.7997
四、求出各个观测值平差值并按规定平定精度
X3=6.3748 m X4=7.0279 m X5=6.6122 m
h1=1.3588m h2=2.0119m h3=0.3588m h4=1.0119m h5=0.6531m h6=0.2374m h7=-0.5961m
根据公式可求得单位权中误差为 2.225mm
h34= X3- X4 Q34=[1 -1 0] NBB-1[1 -1 0]T=0.9849
H3=X3 Q34=[1 0 0] NBB-1[1 0 0]T=0.5307
H4= X4 Q34=[0 1 0] NBB-1[0 1 0]T=0.7758
3、4点高差中误差为 2.208mm
3号点高程中误差为 1.621mm
4号点高程中误差为 1.96mm
第七部分 总结
通过这次误差理论与测量平差的课程设计,我又对整本书有了一个更深的理解。其实课程设计就是将我们所学的理论知识应用于实践的过程,在这一过程中,进一步掌握测量平差的基本原理和基本公式,并熟悉测量数据解决的基本技能和计算方法。
或许我们已对《误差理论与测量平差》这本书的理论知识有了一定了解,但将它应用于实践仍然是我们的一个难点,特别是将这门课程与计算机程序完美地结合。这便规定我们在原有的解题思绪中加入C语言程序,并让它来帮助我们解决矩阵的复杂运算。既然用到了程序,我们就必须保证其运算的简洁性、对的性,特别是在编写过程中要认真检查,为程序顺利运营打下基础。此外在各个子程序调用过程中,我们要充足考虑其顺序性并反复调试,以便得到抱负结果。
尽管在这次课程设计中碰到了很多困难,但我却得到了不少收获,并培养了自己对的应用公式、综合分析和解决问题的能力,同时也为此后步入社会打下了一定的基础。此外,我们还要学会综合运用自身所学的知识,并将它们联系起来帮助自己有效地解决实际中的问题。
总之,在这次课程设计中我不仅过了比较充实的一周,还收获了不少知识。
#include<iostream>
#include<fstream>
#include<stdlib.h>
#include<math.h>
#include<iomanip>
#include<string.h>
using namespace std;
class SZWPC
{
private:
int gcz_zs; //高差总数
int szd_zs; //总点数
int yz_szd_zs; //已知点数
double s0;//单位权水准路线长度
double m_pvv; //[pvv]
int *qsd_dh; //高差起点号
int *zd_dh; //高差终点号
char **dm; //点名地址数组
double *gcz; //观测值数组
double *szd_gc; //高程值数组
double *P; //观测值的权
double *BTPB,*BTPL; //法方程系数矩阵与自由项
double *dX; //高程改正数、平差值
double *V; //残差
double zwc; //单位权中误差
public:
SZWPC();
~SZWPC();
int ij(int i,int j);//对称矩阵下标计算函数
bool inverse(double a[],int n);//对称正定矩阵求逆(仅存下三角元素)(参考别人)
void inputdata(char *datafile);//输入原始数据函数
int dm_dh(char *name); //点名转点号
void ca_H0(); //近似高程计算函数
void ca_BTPB(); //法方程组成函数
void ca_dX(); //高程平差值计算函数
void printresult(char *resultfile); //精度估计与平差值输出函数
double ca_V(); //残差计算函数
void zxecpc(char *resultfile);//最小二乘平差函数
};
//////// // 构造函数
SZWPC::SZWPC()
{
gcz_zs=0;
szd_zs=0;
yz_szd_zs=0;
}
//// // 析构函数
SZWPC::~SZWPC()
{
if(gcz_zs>0)
{
delete []qsd_dh;
delete []zd_dh;
delete []gcz;
delete []P;
delete []V;
}
if(szd_zs>0)
{
delete []szd_gc;
delete []BTPB;
delete []BTPL;
delete []dX;
for(int i=0; i<szd_zs;i++)
if(dm[i]!=NULL)delete[](dm[i]);
delete []dm;
}
}
////// // 对称矩阵下标计算函数
int SZWPC::ij(int i,int j)
{
return (i>=j)? i*(i+1)/2+j :j*(j+1)/2+i;
}
// 对称正定矩阵求逆(仅存下三角元素)
bool SZWPC::inverse(double a[],int n)
{
double *a0=new double[n];
for(int k=0;k<n;k++)
{
double a00=a[0];
if(a00+1.0==1.0)
{
delete []a0;
return false;
}
for(int i=1;i<n;i++)
{
double ai0 = a[i*(i+1)/2];
if(i<=n-k-1)a0[i]=-ai0/a00;
else a0[i]=ai0/a00;
for(int j=1;j<=i;j++)
{
a[(i-1)*i/2+j-1]=a[i*(i+1)/2+j]+ai0*a0[j];
}
}
for(int i=1;i<n;i++)
{
a[(n-1)*n/2+i-1]=a0[i];
}
a[n*(n+1)/2-1]=1.0/a00;
}
delete []a0;
return true;
}
////////// 原始数据输入函数
void SZWPC::inputdata(char *datafile)
{
ifstream infile(datafile,ios::in);//声明输入句柄infile打开地址为datafile的文献并
if(!infile)
{
cerr<<" Open error!"<<endl;
}
infile>>gcz_zs>>szd_zs>>yz_szd_zs;
infile>>s0;
szd_gc=new double [szd_zs];
dX=new double [szd_zs];
BTPB=new double [szd_zs*(szd_zs+1)/2];
BTPL=new double [szd_zs];
qsd_dh=new int [gcz_zs];
zd_dh=new int [gcz_zs];
gcz=new double [gcz_zs];
V=new double [gcz_zs];
P=new double [gcz_zs];
dm=new char* [szd_zs];
for(int i=0;i<szd_zs;i++)
{
dm[i] = NULL;// dm_dh函数根据dm[i]是否为NULL拟定dm[i]是否为点名地址
}
char buffer[128]; //临时数组,保存从文献中读到的点名
for(int i=0;i<=yz_szd_zs-1;i++)// 读取已知高程数据
{
infile>>buffer;
int c=dm_dh(buffer);
infile>>szd_gc[i];
}
for(int i=0;i<gcz_zs;i++)// 读取观测数据
{
infile>>buffer; //读取高程起点名
qsd_dh[i]=dm_dh(buffer);
infile>>buffer;//读取高程终点
zd_dh[i]=dm_dh(buffer);
infile>>gcz[i]>>P[i]; //读取高差值与路线长度
P[i]=s0/P[i];//线路长转化为观测值的权
}
infile.close();
}
////////// 点名转点号,返回点名相应的点号
int SZWPC::dm_dh(char *name)
{
for(int i=0;i<szd_zs;i++)
{
if(dm[i]!=NULL)
{
if(strcmp(name,dm[i])==0)return i;//将待查点名与已经存入点名数组的点名比较,若存在返回点号
}
else
{
int len=strlen(name);//判断点名长度
dm[i]=new char[len+1];//为点名申请存储空间
strcpy(dm[i], name);//待查点名是一个新的点名,将新点名的地址放到dm数组中
return i;//返回点号
}
}
return -1; //dm数组已经存满,且没有待查点名
}
//////////高程近似值计算
void SZWPC::ca_H0()
{
for(int i=yz_szd_zs;i<szd_zs;i++)szd_gc[i]=-10000.9;//为计算机设立辨别未知高程点的标志
for(int j=1;;j++)
{
int k=0; //计算出近似高程的点数
for(int i=0;i<gcz_zs;i++)
{
int k1=qsd_dh[i]; //高差起点号
int k2=zd_dh[i]; //高差终点号
if(szd_gc[k1]>-10000.0 && szd_gc[k2]<-10000.0)//k1点高程或高程近似值已知,k2点高程或高程近似值未知
{
szd_gc[k2]=szd_gc[k1]+gcz[i];//计算近似高程
k++;
}
else
if(szd_gc[k1]<-10000.0 && szd_gc[k2]>-10000.0)//k2点高程或高程近似值已知,k1点高程或高程近似值未知
{
szd_gc[k1]=szd_gc[k2]-gcz[i];//计算近似高程
k++;
}
}
if(k==(szd_zs-yz_szd_zs))break;//所有的近似高程计算完毕,退出
}
}
//////////////////////////////
// 组成法方程
void SZWPC::ca_BTPB()
{
int t=szd_zs;
for(int i=0; i<szd_zs*(szd_zs+1)/2; i++) BTPB[i]=0.0;//赋初值
for(int i=0; i<szd_zs; i++) BTPL[i]=0.0;//赋初值
for(int k=0; k<gcz_zs; k++)
{
int i=qsd_dh[k];//获取点号
int j=zd_dh[k];//获取点号
double Pk=P[k];//获取权值
double lk=gcz[k]-(szd_gc[j]-szd_gc[i]);//获得第k个自由项
BTPL[i]-=Pk*lk;//获得法方程自由项
BTPL[j]+=Pk*lk;
BTPB[ij(i,i)]+=Pk;//获得法方程系数矩阵
BTPB[ij(j,j)]+=Pk;
BTPB[ij(i,j)]-=Pk;
}
}
/////////////////////////
// 高程平差值计算
void SZWPC::ca_dX()
{
for(int i=0;i<yz_szd_zs;i++) BTPB[ij(i,i)]=1.0e30;//解决已知点
if(!inverse(BTPB,szd_zs))//矩阵求逆
{
cerr<<"法方程系数矩阵降秩!"<<endl;//矩阵为奇异矩阵,无法求逆
exit(0);//退出程序
}
for(int i=0; i<szd_zs; i++)//计算高程改正数
{
double xi=0.0;
for(int j=0; j<szd_zs; j++)
{
xi+=BTPB[ij(i,j)]*BTPL[j];
}
dX[i]=xi;
szd_gc[i]+=xi;//计算高程平差值
}
}
/////////////////////
// 残差计算
double SZWPC::ca_V()
{
double pvv=0.0;
for(int i=0;i<=gcz_zs-1;i++)
{
int k1=qsd_dh[i];
int k2=zd_dh[i];
V[i]=(sz
展开阅读全文