
简介面向武汉大学测绘学院平差课程设计这份 C#/WPF 导线网平差程序覆盖坐标近似值、平差值、坐标改正数等核心计算可输出验后单位权中误差、迭代次数、点位中误差、边角观测值改正数以及最后一次迭代的系数矩阵、常数矩阵与权阵并能绘制导线网图形。导入自有数据即可运行若需二次开发可将 Adjustment.cs 与 Data.cs 两个核心类移植到新 WPF 或 WinForm 工程按界面按钮逻辑调用函数快速完成课设要求。压缩包共80个文件以 C# 源码、txt 数据文件、xaml 界面、dll 依赖和 xlsx 测试数据为主另含 PDF 算法论文、可直接运行的 exe 程序及两组测标相对误差 1:2000、测角误差 12″ 的实例数据便于核验计算结果整体仅5.98MB。目前已有3790人浏览/学习适合正在完成平差编程实习、或需要可复用平差算法的测绘专业学生。1. 导线网平差程序一份能直接换数据跑课设的 C# 源码包这套资源是一份用 C# WPF 写成的导线网平差课设源代码核心实现了间接平差参数平差的完整计算链路。角度观测、边长观测、已知点坐标读进来以后程序会先算坐标近似值再迭代求出坐标改正数、平差值、验后单位权中误差、点位中误差连最后一次迭代的系数矩阵、常数矩阵和观测值权阵都可以导出来看最后还能把导线网画到界面上。对武汉大学测绘学院的平差课设来说它的价值很直接换成你自己的观测数据结果就能算想研究实现Adjustment.cs 和 Data.cs 两个类拆得干净整体拷进新的 WPF 或 WinForm 工程就能复用。如果你正卡在“算得出来但不知道矩阵怎么排”的阶段这份源代码能省下大半个课设。2. 间接平差算法与模块划分为什么选它Adjustment.cs 和 Data.cs 各管什么2.1 为什么课设和工程实测都默认选间接平差导线网平差是测量平差里最标准的间接平差应用场景。老一辈教材把平差分成两大派条件平差和间接平差。条件平差要人工列条件方程把所有观测值约束在几何关系里网形稍微复杂一点条件方程就容易漏列错列间接平差则相反直接设未知点坐标为参数每条边、每个角各写一个误差方程解出来就是坐标改正数后续精度指标全从法方程里拿。从课设答辩的角度也说得通老师要看到你一步步算出坐标近似值与平差值间接平差的成果和坐标直接挂钩表格、图形都直观条件平差输出的是改正数画图展示远不如间接平差友好。这份程序选择间接平差不是偶然是这个场景下最省事、最能展示完整成果的方案。误差方程标准形式是v B·x - lv 是观测值改正数B 是系数矩阵x 是坐标改正数参数l 是“观测值减近似计算值”的常数项。每轮迭代里近似坐标是固定的观测值也是固定的所以 l 作为常数出现在方程右边。观测总数 n 等于边观测数与角观测数之和必要观测数 t 等于未知点坐标数乘 2多余观测数 r n - t。一个 5 个未知点、9 条边、8 个角的小型边角网n 17、t 10、r 7。如果 r 接近 0法方程矩阵奇异求逆直接报错这一点后面避坑章节还要细说。2.2 系数矩阵、常数阵和权阵的形成逻辑B 矩阵的物理含义是每个观测对每个坐标参数的偏导。拿边长观测举例设未知点 A、B 的近似坐标已知反算近似边长 S0观测边长 L那么常数项就是 L - S0。误差方程里对四个坐标参数求偏导∂S/∂x_A -(x_B - x_A)/S0 ∂S/∂y_A -(y_B - y_A)/S0 ∂S/∂x_B (x_B - x_A)/S0 ∂S/∂y_B (y_B - y_A)/S0C# 里对应的方法大概是这样的public void BuildEdgeRow(int row, EdgeObs edge, Point pA, Point pB) { double dx pB.X - pA.X; double dy pB.Y - pA.Y; double S0 Math.Sqrt(dx * dx dy * dy); // 系数矩阵B边长观测对四个坐标参数的一阶偏导 B[row, colA_X] -dx / S0; B[row, colA_Y] -dy / S0; B[row, colB_X] dx / S0; B[row, colB_Y] dy / S0; // 常数矩阵l 观测边长 - 近似边长单位米 L[row] edge.Length - S0; }参数说明edge.Length是从 txt 或 xlsx 解析出的观测边长pA、pB是两端点的近似坐标对象colA_X这类索引是预先为未知参数分配的列号。赋值前必须有一层索引映射否则 B 的列顺序对不上未知数顺序结果全是错的。角度观测的系数是方位角对坐标的偏导表达式比边长复杂核心公式形如∂α/∂x dy / S², ∂α/∂y -dx / S²方向不同符号会变这里不逐项展开。你要理解的是B 的每一行对应一个观测每个元素表示该观测对哪个坐标参数敏感。角度观测对垂直于视线方向的坐标分量敏感边长观测对沿视线方向的坐标分量敏感两者的系数分布天然不同。权阵 P 是对角阵行列与 B 的行一致。工程习惯按仪器标称精度定权边长权 P_S 1/σ_S²角度权 P_angle 1/σ_angle²其中 σ_angle 必须统一转成弧度。代码里常见写法P[row, row] 1.0 / (sigma * sigma);如果你看到 P 被赋成一个大数或者 1通常是做了先验权归一化换数据时要按自己的精度重新算一遍不能照抄。2.3 法方程与迭代求解Adjustment.cs 的骨架有了 B、L、P平差核心就是解法方程// 法方程N B^T P Bt×t 对称方阵 Matrix N B.Transpose().Multiply(P).Multiply(B); // 自由项W B^T P Lt×1 Matrix W B.Transpose().Multiply(P).Multiply(L); // 参数解x N^-1 * W Matrix X N.Inverse().Multiply(W);注意实际项目里类名和方法不一定这么直白核心逻辑在 Adjustment.cs 里可能封装成Compute()或RunAdjust()但套路都是这三步。N 是 t×t 对称方阵已知点不够、网形不完整时对角线元素会异常求逆时就出现除零或奇异异常。这是平差代码最常见的翻车点。迭代是因为坐标改正数 x 会反过来影响 B 和 l——坐标变了边长偏导、方位角偏导也变了。程序用改正数更新坐标后要重新构造 B、L再解法方程直到 x 小于阈值通常 1e-3 或 1e-4 米或迭代次数达到上限。程序输出的“迭代次数”就是这个循环走了几轮一般 2 到 5 次就收敛。2.4 Adjustment.cs 与 Data.cs 的分工拷进新工程怎么调用这个程序的分层值得模仿。Data.cs 负责把观测文件变成点对象、边对象、角对象同时记录已知点坐标Adjustment.cs 负责拿这些对象构建误差方程、法方程、求解、迭代并输出中间矩阵。很多同学课设习惯把所有代码堆在一个文件里最后改一处崩全局。这套工程至少把解析和计算拆开了这件事本身比算法更值得学。如果你想在新工程里重写 UI只保留核心计算就把这两个类原样拷过去UI 这边按按钮事件调用// 新工程里的核心调用以下顺序不能颠倒 Data data new Data(); data.ReadKnownPoints(w已知值.txt); // 先读已知点 data.ReadAngles(w角数据_右.txt); // 再读角度观测 data.ReadSides(w边数据.txt); // 后读边长观测 Adjustment adj new Adjustment(data); adj.Compute(); // 执行平差迭代 double sigma0 adj.GetPosteriorSigma(); // 验后单位权中误差 Matrix N adj.GetNormalMatrix(); // 最后一次迭代的可执行矩阵其中GetPosteriorSigma()内部算的是σ0 sqrt( V^T P V / (n - t) )分子是所有观测改正数向量与权阵构成的二次型分母是自由度。这个 σ0 要和先验精度比测角误差 12″、测距相对误差 1:2000 是程序默认的先验参数。σ0 小于 1说明观测值比预想的更自洽大于 1说明网内有系统误差或先验权给粗了。这个对比是课设报告里最加分的一句话。3. 两组测试数据跑通全流程文件格式、结果字段和 Excel 交叉核对3.1 文件包里到底有哪些文件、哪个是干嘛的解压以后先别急着打开工程把文件分个类。这个包里的文件用途大致如下文件类型作用TriangulaterationAdjustment.sln解决方案Visual Studio 打开的项目入口TriangulaterationAdjustment/ 目录源码包含 Adjustment.cs、Data.cs、DisplayWindow.xamlpackages 目录依赖WPF 项目需要的 NuGet 包Readme.md说明项目用法和文件组织说明导线网间接平差算法分析与实现-郭辉.pdf参考论文给出算法推导和算例对照公式用w已知值.txt已知点数据固定点坐标作为强制约束w角数据_右.txt / w角数据_左.txt角度观测右角、左角两种记录方式w边数据.txt边长观测边长的原始观测值测标相对误差12000测角误差12″.txt精度实例把先验精度参数按固定格式写好的算例Side.txt、Known.txt、Angle.txt等价格式与上面数据同内容的另一种分文件写法边角网.xlsx / w边角网.xlsxExcel 数据带表头的观测表方便人工核对w角数据_右.txt和w角数据_左.txt不是重复文件是同一组导线按右角和左角两种外业记录习惯各存了一份。右角是从后视方向顺时针转到前视左角是逆时针。平差前要统一换算成方位角增量再列误差方程Data.cs 会判断是哪种角度文件。这里有个隐藏坑换算方向搞反改正数符号会整体反号但大小看起来依旧合理属于最隐蔽的一类错。3.2 在 Visual Studio 中跑起来的步骤用 Visual Studio 打开.sln首次加载会自动还原 packages 里的依赖包等右下角显示还原完成再编译。启动项目要确认是DisplayWindow不是类库工程然后直接 F5。程序起来以后主界面是DisplayWindow.xaml里面用 TextBox 或者 Canvas 展示计算结果。导入数据的入口可能写死在构造函数里也可能在按钮事件里让你选文件。如果不想走界面直接把某个 txt 的路径拼进Data.ReadSides(...)把结果输出到控制台也一样能看。调试顺序建议是先运行一次自带数据生成一组结果再对照边角网.xlsx里已有的成果表核对。很多同学一上来就换自己的数据结果矩阵规模一变行列索引全乱排查时间比写代码还长。先跑通自带数据就是给自己留一个能回溯的基准答案。3.3 计算结果里每个字段应该怎么看程序输出大概分这几组每一组的用处不同坐标近似值迭代前的起始坐标由导线推算或角度交会得到不经过平差工序。坐标改正数迭代收敛后的 x 向量单位米。正常情况应趋向 1e-3 以下如果偏大说明初值差或网形有问题。平差值近似坐标加上改正数这才是最终成果。验后单位权中误差σ0反映整网观测值的自洽程度是精度评定的核心指标。迭代次数法方程重复求解了几轮才收敛。坐标参数方差阵N 的逆矩阵对角线是坐标分量的方差开根号后是点位中误差。边角观测值改正数每条边、每个角对应的 v 向量边长单位是米、角度单位是秒。某个改正数明显偏大说明那个观测有问题。最后一次迭代的系数矩阵、常数矩阵和权阵调试用的关键数据把它和论文里的算例矩阵对照能直接定位 B 矩阵是否列反、权阵是否给错。3.4 用 Excel 数据做交叉核对包里的边角网.xlsx其实把 txt 数据转成了表格。我拿到 Excel 后通常会做一件事把程序输出的点位坐标写进 Excel反算边长再和w边数据.txt里的观测边长比较差值应当就是平差后的边长残差。一个可以直接抄进课设报告的小验证步骤残差 反算边长 - 观测边长 点位误差 sqrt( σ0² × 协因数阵对角线 )如果把残差按边号列成一列观察符号分布。正常平差残差应该有正有负大致围绕零对称如果边长残差全是正或全是负说明已知点坐标系存在整体偏移或者某条闭合导线没有闭合这个检查几乎每次都能抓到问题。4. 接入自己的测区数据数据格式、最少观测数和权比设置4.1 已知点、角度、边长的文本格式约定改数据前先搞清程序能吃什么格式。常见的约定是已知点坐标每行一个点号后跟 X、Y 坐标三位小数。角度观测每行“测站 后视 前视 度 分 秒”比如A B C 89 59 58.5含义是在 B 点照准 A 后转到 C 的水平角。边长观测每行两个点号加一个边长值单位米。如果你自己的数据是这种格式直接替换文件内容就能跑。差一行、多个逗号都会让解析错位。4.2 自由度检查先算 n 和 t换数据前先做算术n 角观测数 边观测数t 未知点数 × 2。比如 6 个未知点12 个角度观测、9 条边长观测n 21、t 12、r 9结构很健康。如果 r 只有 1 或 2整网对单个观测极度敏感结果没有实际意义。r 0 时 N 矩阵奇异求逆直接报错。这种情况常见于闭合导线且两个已知点都在同一端或者某个支点只有一条边连接进来。我多年来的习惯是把 r ≥ 4 作为底线低于这个数先考虑加观测而不是硬跑。4.3 修改 Data.cs 的解析逻辑如果你把自己的数据整理成与测试文件完全相同的列格式就不用改代码。换成 CSV 或 Excel 时需要在 Data.cs 里加一个解析入口。常见做法是先用 StreamReader 读 CSV再复用同一套构建对象的方法// 在 Data.cs 里增加一个 CSV 读取入口 public void ReadCSV(string path) { using (var reader new StreamReader(path)) { string line; while ((line reader.ReadLine()) ! null) { var parts line.Split(,); if (parts[0] Point) continue; // 表头跳过 // 假设列序点名, X, Y Point p new Point(parts[0], double.Parse(parts[1]), double.Parse(parts[2])); _knownPoints.Add(p); } } }参数说明parts[0]是点名parts[1]、parts[2]是坐标数字_knownPoints只是示意实际字段名要看 Data.cs 里的定义。加这段解析时顺手看一下原工程的字段命名风格保持统一后面维护省事。4.4 在 WPF 界面里挂上你自己的数据入口DisplayWindow.xaml里如果有“打开”“计算”“画图”按钮改按钮事件里的路径就行。新工程调用核心逻辑时依赖方向只有一个private void BtnCompute_Click(object sender, RoutedEventArgs e) { Data data new Data(); data.ReadKnownPoints(txtKnown.Text); data.ReadAngles(txtAngles.Text); data.ReadSides(txtSides.Text); Adjustment adj new Adjustment(data); adj.Compute(); txtResult.Text adj.GetReport(); // 拼好的结果字符串 DrawNetwork(adj.GetAdjustedPoints()); // 把平差后的点位画到 Canvas }参数说明txtKnown.Text是文件路径输入框的值adj.Compute()内部同时处理近似值计算和迭代调用前不需要手工算初值DrawNetwork需要自己实现坐标到屏幕坐标的变换具体做法看第 5 章避坑里的画布问题。4.5 权比设置误差 12″ 与相对 1:2000 怎么转成权这是最容易翻车的一步。常见错误是拿 12″ 直接当小数写成 0.0012权会大得离谱。正确顺序是先换算再定权σ角 12″ 转弧度 12 / 3600 × π / 180 ≈ 5.82e-5 rad P角 1 / σ角² ≈ 2.96e8 边长中误差按相对误差 1:2000 理解 某条 400m 边σ边 400/2000 0.2mP边 1/0.2² 25角度权和边长权大小差好几个数量级是正常的关键是比例关系要真实反映仪器精度。如果换成 5″ 全站仪观测σ 角变小角度权要相应调大好几倍。测试文件测标相对误差12000测角误差12″.txt表示程序默认用这两个参数做先验你换数据时务必重新考虑先验误差不能照抄。5. 平差程序避坑记录迭代不收敛、单位混乱和数据解析的五种典型翻车5.1 现象迭代几十次不收敛改正数越算越大原因坐标近似值太差误差方程线性化只在小邻域内有效迭代一跑就发散。常见于导线推算初值时角度闭合差处理错了或者已知点坐标给反。解决先检查已知点坐标的轴方向和符号再检查角度观测是左角还是右角。更稳妥的办法是自己先用两三长边手工推导出粗略坐标再把它作为初值喂给程序不依赖程序内部的自动初值计算。每次我遇到迭代发散先做这两步检查八成能定位。5.2 现象角度改正数全是几十秒到上百分秒边长改正数却看起来正常原因角度单位没有统一。输入文件里是度分秒但误差方程里的 B、l 必须是弧度制漏转弧度会导致残差被系统性放大。解决在进入误差方程前把角度全部转弧度同时确认 l 的单位和 B 的列单位一致。检查办法是打印第一行角度误差方程的 B 和 l手工验证偏导数值的量级是否在合理范围内。如果 B 是 0.0001 量级、l 却是 89 度这样的量级那单位一定没转。5.3 现象N 矩阵异常提示行列式为零或矩阵不可逆原因未知点数和参数列数不匹配网形里存在孤立点——某些未知点没有任何角度或边长观测连接到整体网络对应的参数列全是零。解决先算 t 未知点数 × 2再检查每个未知点是否至少被一条观测边或一个角度连接到其他点。孤立点要么删掉要么补测。边界条件是任何未知点都必须与已知网形成连通的整体这是平差的硬前提。5.4 现象计算正常但画布空白导线图没有画出来原因WPF Canvas 坐标系 Y 轴方向和测量坐标系相反而且测量坐标往往是几万米的大数直接往 Canvas 上画必然落到可视范围之外。解决对点位做平移和缩放映射公式如下// 坐标到屏幕的映射Canvas 顶部是 Y 更小的方向 double screenX (p.X - minX) * scale pad; double screenY (maxY - p.Y) * scale pad; // Y 轴反转参数说明minX、maxY是测区范围scale是缩放系数pad是边距。画之前打印几个 screenX、screenY 值确认落在 Canvas 宽高范围内再画线。这问题不影响计算但它会让课设演示环节非常尴尬。5.5 现象坐标改正数输出全为零但近似值和真实值差距明显原因B 矩阵的列顺序和参数排列不一致某些列在构建时全部赋值为零导致对应参数永远解不出改正数。这种情况通常发生在手工修改了未知点顺序却没有同步更新索引映射。解决把最后一次迭代的 B 矩阵打印出来看第一行数据。边长观测对应的那一行理论上应该能在 A 点和 B 点对应的四个列上看到非零偏导如果看到全零或者错位说明列索引映射错了。这是最容易自查的矩阵层问题。6. 验证平差结果的小技巧用残差分布和已知闭合差交叉把关拿到一组新数据我验证程序结果的顺序跟多数人不太一样先不看最终坐标先看残差分布。坐标可以通过各种方式调整到看起来正确但残差的符号和大小很难伪。道理很简单平差本质是在让观测值之间尽量自洽自洽良好时残差应该有正有负围绕零对称显著性检验也不会拒绝原假设。具体操作是从输出里把边长残差和角度残差分别拉出来按观测顺序排列。如果发现连续 5 个以上边长残差同为正值或者全部残差都集中在一侧那几乎可以断定已知点坐标存在系统偏差或者有一条边的方位角初值错了。这个检查不需要额外计算打印结果里直接看就能判断。第二个习惯是找完整闭合条件。小型导线网里只要有闭合导线就手算一个已知点间的坐标闭合差再和程序输出的已知点平差后坐标对比。比如一个三角网里已知点 A 和 B 之间本来就有高精度坐标你用平差后的其他点反算 A 到 B 的方位角和边长与已知值做差误差应该落在点位中误差的两倍范围以内。这个方法比任何理论推演都直接也是答辩时老师最爱问的一个点。第三个技巧是把结果对回郭辉那篇论文的算例。论文里有小网的手算过程和中间矩阵把这些矩阵值输入程序对比输出的系数矩阵。数值一致说明你的调用方式没问题不一致则要检查是不是权阵单位弄错了。这个方法适合在换数据之前先做一次确认程序本身没被动过手脚。还有一个更细的检查看验后单位权中误差和先验误差的比值。对那组带测标相对误差12000测角误差12″标识的测试数据σ0 应该接近 1。如果 σ0 明显偏大说明你的定权参数太乐观明显偏小说明观测条件比标称精度更好或自由度分配不合适。这个比值是全网精度的第一判断指标建议写进课设报告的结果分析里。从那以后我每次拿到陌生测量数据都强制自己先走一遍“残差正负分布 闭合差反算 σ0 对比”三连检查再决定要不要看坐标成果。过了这三关结果基本上就可以放心用了。希望帮到你。本文还有配套的精品资源点击获取