如何成为坐标测量的专家?你离三坐标专家还有多远?

根据ISO/TC213,起草人提出了专家的几项标准,翻译如下(不是我翻译的):

CMM-专家能在一套常无法预测结果的不同环境中运用一系列的基本原理和复杂技术,具有很大的自主权,并能在活动中发展其他能力。

CMM-操作者应该掌握的专业知识有:

——几何学,数据,几何公差和CNC编程

并且应具备的知识有:

——要点-CAD的制造要点

——数字的过滤和评估

——随机的

——测量不确定度的评估和对CMM的监控

——自由形体表面的数字化

——质量管理,质量管理的方面和方法,TQM,CAQ和质量成本

——良好的坐标测量实践

并且应该能够:

——编写并优化测试计划

——对测量和使用者资格进行监控

——对测量不确定度进行评估

——自由形体表面的数字化

——质量管理的实施方法

然后我尝试着翻译成易懂的语言。

CMM专家应该了解通用的基础知识,以及很多领域的专业知识,以及在没有过往经验的条件下,自主分析并辅导他人的能力。

需要拥有如下知识:

——几何学,数据,几何公差和CNC编程
俗称的GDT,结合到日常工作中,可以简单的理解为机械制图和工艺,以前的教材叫互换性测量,现在是精密机械设计,另外就是如何操作三坐标了。
这是最基础也最容易被忽略的一点,我面试过一些自称会编程,会操作三坐标的人,有些基础概念都无法掌握,基准,最大实体,公差,配合什么的。

——要点-CAD的制造要点
翻译的好烂,原文应该是基本的制造业知识和基本的CAD知识。
CAD是计算机辅助设计的缩写,在这里的意思是要有相关的课外知识,三坐标是一种检测设备,对应着质量部门,和质量部门有关的一般是设计部门和制造加工部门。
一个是工作的基础,检测的目的是为了验证产品是否符合设计,那么设计部门的要求就是标准。
另外一个是客户,客户送来产品,需要的是检测结果是否合格。
所以作为专家,必须要了解这些知识以便和这两个部门打交道。

——数字的过滤和评估
数字滤波和评价。这也是我经常遇到的问题,最小二乘法和最小条件法哪个测得准(应该选哪个),滤波是否应该一直选中?
真正明白这些内容需要一定的数学基础和实际的经验。

——随机的
我的理解这里随机指的的概率论里的随机,另外一个可能性是随机过程。
在处理一些数据和情况时,需要了解并排除一些特殊情况,而这些情况往往是随机出现的。不太好解释。

——测量不确定度的评估和对CMM的监控
测量不确定度一直是这一行的难点,通常除了三坐标厂家和一些科研机构,大部分用户并不了解这些。
相当一部分原因是为了商业原因刻意地模糊这一概念,测量不确定度本身是个单独的概念,大学里还有专门的课程,往往和实验课结合在一起。
三坐标的测量不确定度有标准定义ISO10360,对于具体检测,需要将三坐标的既有不确定度与实测尺寸做转换。

——自由形体表面的数字化
数字化就是逆向,将不规则表面逆向为计算机可识别的格式,在大多数人看来只是用一个高科技设备晃一晃就完成了。
实际上这是一个比较综合的题目,根据材料,精度要求等有不同的设备和方法,软件上也有很多的算法。
不过这个要求是比较早之前的文档,现在由于计算机辅助的超高速发展,对于这一块的理论要求已经非常低了。

——质量管理,质量管理的方面和方法,TQM,CAQ和质量成本
这个也是比较好笑的一方面,看到很多简历写我掌握质量七大手法,面试一问就是往已经做好的表格里填数据,怎么算的?不知道。
还有就是一些花了5000块钱外面上了个培训班,就号称自己熟悉ISO9001管理认证体系什么什么的。
这几种情况是纯管理者作的,不能说不对,但是如果是技术人员,这么做完全是本未倒置。

——良好的坐标测量实践
这个就是堆经验了,我有一些客户非常看重自己的工作年限,但是这样不全面,你只测几吨重的铸件,就无法理解模具行业对于效率的要求;
只在模具行业,就无法理解为什么测量大型工件时为什么要考虑温度,材料等等等等。
对专家的要求当然是越广越深越好。

并且应该能够:

——编写并优化测试计划
大白话就是看图纸来编程,问题在于,你能否保证你的方案能保证正确性和完备性么?
干测量是很战战競競的工作,合格放出去的会想是否会有未发现的缺陷,不合格的会想是工件本身的问题还是我的检测有问题。

——对测量和使用者资格进行监控
如果你没有直接操作设备,你能否发现他人的问题并作出指导?
这个就是我们国内经常看到的审核,客户派到供应商现场一些人,审核有问题的环节。

——对测量不确定度进行评估
如果谁说我的测量是准确的,那么这个人肯定不懂测量,测量永远是测不准的(不是量子力学里的概念-_-b),但是作为专家,你需要知道我测得有多接近于真实的情况。

——自由形体表面的数字化
不规则曲面的逆向(见上文)

——质量管理的实施方法
将质量管理方法同实际工作相结合,生般硬套也不是不行,不过用上了,出了结果,只是看个数是没有意义的,需要将这个工具同上下环节联系起来。

根据这些要求,需要有相当系统的知识,还要有相当多的实际经验,个人感觉在国内这种不太重视质量的环境下很难培养出这类的专家来。

全文结束,你离三坐标专家还有多远?如果您觉得您符合其中60%以上,欢迎来我司应聘。

两件小事的感想——人际关系对日常工作的影响

第一件事比较简单,大约两年前给一个客户做了些单独的解决方案,前天一个同事说在给另外一个客户现场使用的时候有很多问题,发邮件和截图问我原因。

最后我不高兴的原因有两点,一是用之前没有和我商量或询问,由于我有些严苛的版权意识,有些被冒犯的感觉。

二是我针对他的问题和情况,前后回复了四封邮件,包括BUG的原因,参考资料,替代解决方案等。然后——就没有然后了,一点回音都没有。

第二件事细节稍复杂,某销售需要特殊软件,要德国这面的开发部门支持,报价,安装等等等等。

把技术协议(虽然在技术部门看来毫无帮助)往我这一扔,让我去弄。我稀里湖涂帮他翻译了一下就去找人咨询了,从此这件事就成我的了。

但是我跟这件事唯一的关系是,我是中国人,我人在德国……简直无语了。

这两件事对我的直接影响是,这两位同事以后就在我的信任黑名单里了,对于第一位技术同事,那么以后所有他的咨询邮件我都会直接转给他的领导,在经过他的领导确认并确定这件事需要我的支持的情况下,再投入精力去解决。对于第二位销售同事,在没有经过正常流程(他的领导的领导找我的领导,再给我下命令)的情况下,我不会做任何份外的事情,哪怕是转发一封邮件,而且也不会回复,直接无视或放到回收站。

然后反思我的做法,我其实在这两件事中损失的只是一些时间,但换个思路损失的就是资源,根本的问题是这种损失无法量化,可能很少可能很大。

我在这两件事中用处理私人关系的方法来处理了工作,处理私人关系的时候我可以付出资源,来判断一个人是否可交,因为人需要朋友,而得到真正的朋友相当不易,值得去付出资源。对于工作,期望的回报并不是交朋友,而是付出尽可能少的资源,完成任务(获得更多的资源)。

未来应该修正的是投入资源的量吧,先判断做这件事需要投入多少资源,然后再根据回报来判断是否投入这些资源。

最后一条感想,跨部门指挥是能力的体现,但是结果很难理想,还是尽量避免展示这种能力吧。

根据凸轮升程值求轮廓线

通常此类工作由设计人员完成,根据需求计算出合适的轮廓。

但由于国内质量部门地位低下,以及CAD在设计环节上的缺失,经常拿不到CAD Model或者轮廓的数据,只能拿到升程值。
当然另外一个原因就是专门的凸轮检测仪是模拟测量,可以直接得到对应的升程值。

但是对于坐标检测,就需要将升程值转化为轮廓坐标,通过坐标检测出轮廓线,再转化回升程值。

已知基圆半径\(r_0\),滚子半径\(r_r\),对应角度\(n\)的升程值为\(s_n\),从动件与凸轮偏心量为\(e\),则滚子圆心轨迹坐标\(P_n\left(x_n,y_n\right)\)为\[x_n=(r_0+r_r+s_n)\sin(n)+e\cos(n)\]\[y_n=(r_0+r_r+s_n)\cos(n)+e\sin(n)\]

凸轮轮廓是滚子圆心轨迹的包络曲线,只要求得对应点的法向方向,沿法向方向减去滚子半径即可。如果知道升程的解析式,直接求导数即得,通常情况下,用相邻点近似求得该点切向。

对应点\(P_n\left(x_n,y_n\right)\)的切向矢量表示为

\[\begin{bmatrix}i_n\\j_n\end{bmatrix}=\vec{\begin{bmatrix}\Delta x\\\Delta y\end{bmatrix}}=\vec{\begin{bmatrix}x_{n+1}-x_n\\y_{n+1}-y_n\end{bmatrix}}\]

压力角\(\theta_n=\arctan (\Delta y/\Delta x)\)

凸轮轮廓线上的点\({P’}\left({x’}_n,{y’}_n\right)\)为\[{x’}_n=x_n\mp r_r\cos\theta_n\]\[{y’}_n=y_n\mp r_r\sin\theta_n\]

最小二乘法拟合一些基本空间元素的C#实现 —— (四)C#实例

包含之前几篇文章提到的算法的C#实现。

界面很简单,点按钮选择数据文件,一行一个点的xyz坐标。选择类型,然后计算。

可执行文件同目录下有两个测试用数据文件。

二进制包下载LSQ_Feature_binary

源码及二进制包下载(VS2012 Express)

最小二乘法拟合一些基本空间元素的C#实现 —— (三)圆柱

同前一篇文章相同,算法主要根据这篇文章,修改了其中一些笔误并微调以适合C#代码。

首先是将圆柱参数化并简化该模型。

圆柱的轴线为一空间直线,由一点\(P\)和一空间向量\(V\)定义。

如果经过坐标变换,新坐标系零点为\(P\)且坐标z轴为\(V\),那么该轴线的未知量就由\(x_0,y_0,z_0,a,b,c\)减少为4个。

参数化

圆柱的轴线表示为经过点\(P\left(x_0,y_0,z_0\right)\)向量为\(V\left(a,b,c\right)\)的直线,半径为R

求初始值

我个人觉得这种求法偏繁琐,不过的确相当接近最后拟合值,迭代次数相当少。

\(a,b,c\)的初始值

对于圆柱面上任一点\(P_i\left(x_i,y_i,z_i\right)\)有\[A^2+B^2+C^2=R^2\]其中\[A=c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\]\[B=a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\]\[C=b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\]

将上面的等式代入展开\[\left[c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\right]^2+\left[a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\right]^2+\left[b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\right]^2=R^2\]这个等式很简单(不得不吐槽,当时看到这里我都疯了,现在手打这些公式更疯了),它等价于\[Ax_i^2+By_i^2+Cz_i^2+Dx_iy_i+Ex_iz_i+Fy_iz_i+Gx_i+Hy_i+Iz_i+J=0\]其中\begin{array}{lclp{12}}
A&=&\left(b^2+c^2\right)\\
B&=&\left(a^2+c^2\right)\\
C&=&\left(a^2+b^2\right)\\
D&=&-2ab\\
E&=&-2ac\\
F&=&-2bc\\
G&=&-2\left(b^2+c^2\right)x_0+2aby_0+2acz_0\\
H&=&2abx_0-2\left(a^2+c^2\right)y_0+2bcz_0\\
I&=&2acx_0+2bcy_0-2\left(a^2+b^2\right)z_0\\
J&=&\left(b^2+c^2\right)x_0^2+\left(a^2+c^2\right)y_0^2+\left(a^2+b^2\right)z_0^2-2bcy_0z_0-2acz_0x_0-2abx_0y_0-R^2
\end{array}

两边同除以\(A\)并将\(x\)二次项移到等式右边得
\[\frac{B}{A}y_i^2+\frac{C}{A}z_i^2+\frac{D}{A}x_iy_i+\frac{E}{A}x_iz_i+\frac{F}{A}y_iz_i+\frac{G}{A}x_i+\frac{G}{A}y_i+\frac{I}{A}z_i+\frac{J}{A}=-x^2\]

这是一个线性方程组
\[\begin{bmatrix}y_1^2 &z_1^2 & x_1y_1 & x_1z_1 & y_1z_1 & x_1 & y_1 & z_1 & 1 \\y_2^2 & z_2^2 & x_2y_2 & x_2z_2 & y_2z_2 & x_2 & y_2 & z_2 & 1 \\\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots \\y_n^2 &z_n^2 & x_ny_n & x_nz_n & y_nz_n & x_n & y_n & z_n & 1 \end{bmatrix}\begin{bmatrix}B/A\\C/A\\D/A\\E/A\\F/A\\G/A\\H/A\\I/A\\J/A\end{bmatrix}=\begin{bmatrix}-x_1^2\\-x_2^2\\\vdots\\-x_n^2\end{bmatrix}\]

求解:

令\(B’=B/A,C’=C/A,D’=D/A,E’=E/A,F’=F/A,G’=G/A,H’=H/A,I’=I/A,J’=J/A\)
如果\(|D’|\),\(|E’|\)和\(|F’|\)近似等于0(意味着abc中有两个近似于0,向量与某坐标轴平行),如果\(B’\)近似于1向量为\(\left(0,0,1\right)\),如果\(C’\)近似于1向量为\(\left(0,1,0\right)\)

否则,令\[k=\frac{2}{1+B’+C’}\]则\[A=k,B=kB’,C=kC’,D=kD’,E=kE’,F=kF’,G=kG’,H=kH’,I=kI’,J=kJ’\]如果\(A,B\)近似于1,则\begin{array}{lcl}c’&=&\left(1-C\right)^{1/2}\\a’&=&E/-2c’\\b’&=&F/-2c’\end{array}
如果A近似1,B不近似1则\begin{array}{lcl}b’&=&\left(1-B\right)^{1/2}\\a’&=&D/-2b’\\c’&=&F/-2b’\end{array}
如果A不近似于1\begin{array}{lcl}a’&=&\left(1-A\right)^{1/2}\\b’&=&D/-2a’\\c’&=&E/-2a’\end{array}
将向量\(\left(a’,b’,c’\right)\)正规化得到单位向量\[\left(a,b,c\right)\]

注:近似于这个概念很模糊,由于我使用在机械测量中,通常设备采集原始点的精度为0.001左右,而点云本身的标准差在0.001~1,所以我在程序中将近似于定义为\(\Delta<0.001\)
上文两次提到近似于,第一次是\(DEF\),用来判断向量是否平行于某一轴。第二次是\(A,B\),实际上此时已经排除了向量平行于轴线的可能性,这里是用来判断向量更接近于哪个轴,从而避免近似0 的小数开平方造成的精度误差,所以在算法中我将这部分改为了比大小。
另外就是\(ABC\)三个值有可能略微大于1,用原文算法有可能出现负数开方造成无解。

\(x_0,y_0,z_0\)的初始值

根据\(x_0,y_0,z_0\)与\(G,H,I\)的关系,以及等式\(ax_0+by_0+cz_0=0\)(注:原文中使用原点到轴线的垂足作为起始点,因为个人需要,我将之替换为数据第一点投影到轴线的垂足\(ax_0+by_0+cz_0=ax_1+by_1+cz_1\)得到线性方程组

\[\begin{bmatrix}-2\left(b^2+c^2\right)&2ab&2ac\\2ab&-2\left(a^2+c^2\right)&2bc\\2ac&2bc&-2\left(a^2+b^2\right)\\a&b&c\end{bmatrix}\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}G\\H\\I\\ax_1+by_1+cz_1\end{bmatrix}\]

注:在实际使用中,这个初始值算法有一些问题,当圆柱的轴线非常接近于\((0,0,1)\)时(很常见,通常为了仪器测量方便都会先找正),该方程组变为了\[\begin{bmatrix}-2&0&0\\0&-2&0\\0&0&0\\0&0&1\end{bmatrix}\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}G\\H\\I\\z_1\end{bmatrix}\]这个一看就知道\(x_0=-\frac{G}{2},y_0=-\frac{H}{2},z_0=z_1\),但是由于第三行都是0的存在,使得矩阵的任何操作都有问题。

\(r\)的初始值

原文使用了前面\(J\)的等式。\[R^2=(b^2+c^2)x_0^2+(a^2+c^2)y_0^2+(a^2+b^2)z_0^2-2bcy_0z_0-2acx_0z_0-2abx_0y_0-J\]

注:依然是在我的实际使用中,发现J的解在特定情况下会是极大的正数(可能是由于圆柱的轴线长度小于直径的原因),于是又出现了负数开方无解的情况,例如这组数据,于是我用了所有测量点半径平均值来代替。

迭代算法

1.坐标变换

在\((x_0,y_0,z_0)\)处以\((a,b,c)\)为Z轴建立一个坐标系U并将所有实测点的一个副本变换到该坐标系下。

\[\begin{bmatrix}x_i\\y_i\\z_i\end{bmatrix}=\left(\begin{bmatrix}x_i\\y_i\\z_i\end{bmatrix}-\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}\right)U\]

其中\[U=\begin{bmatrix}1&0&0\\0&c_1&s_1\\0&-s1&c1\end{bmatrix}\begin{bmatrix}c_2&0&s2\\0&1&0\\-s2&0&c2\end{bmatrix}\]

当\((a,b,c)\)为\((1,0,0)\)时\(s_1=0,c_1=1,s_2=-1,c_2=0\)否则\[\begin{array}{lcl}c_1&=&\frac{c}{\sqrt{b^2+c^2}}\\s_1&=&\frac{-b}{\sqrt{b^2+c^2}}\\c_2&=&\frac{cc_1-b_s1}{\sqrt{a^2+(cc_1-bs_1)^2}}\\s_2&=&\frac{-a}{\sqrt{a^2+(cc_1-bs_1)^2}}\end{array}\]

2.构造Jacobian矩阵

参考直线距离公式,并且将\(a=b=0,c=1,z=0\)代入得到\[\begin{bmatrix}-x_1/r_1&-y_1/r_1&-x_1z_1/r_1&-y_1z_1/r_1&-1\\-x_2/r_2&-y_2/r_2&-x_2z_2/r_2&-y_2z_2/r_2&-1\\\vdots&\vdots&\vdots&\vdots&\vdots\\-x_m/r_m&-y_m/r_m&-x_mz_m/r_m&-y_mz_m/r_m&-1\end{bmatrix}\begin{bmatrix}P_{x0}\\P_{y0}\\P_a\\P_b\\P_r\end{bmatrix}=-1\begin{bmatrix}r_1-r\\r_2-r\\\vdots\\r_m-r\end{bmatrix}\]

3.更新参数

\[\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}+\begin{bmatrix}P_{x_0}\\P_{y_0}\\-P_{x_0}P_a-P_{y_0}P_b\end{bmatrix}U^T\]

\[\begin{bmatrix}a\\b\\c\end{bmatrix}=\begin{bmatrix}P_a\\P_b\\1\end{bmatrix}U^T\]

\[r=r+P_r\]

4.确定迭代结束条件

重复1~3,直到满足终止条件。

终止条件3选1:

  • 新参数与旧参数对应相减,平方和小于退出值
  • 求所有点的偏差二乘和,新值与旧值相减,差小于退出值
  • 迭代次数超过退出值

包含直线、平面与圆柱算法的C#实例与说明

最小二乘法拟合一些基本空间元素的C#实现 —— (二)直线与平面

本文讨论并实现的算法主要(99%)基于这篇文章,更多参考请阅读这里

大部分能搜索到的关于直线最小二乘拟合的资料是基于2维空间的\[y=ax+ b\]

而从三维空间的角度上来看,这只是一种特例。本文主要讨论三维空间上的直线拟合。

参数化

三维直线的表示如下。\[\left(x,y,z\right)=\left(x_0,y_0,z_0\right) + t\left(a,b,c\right)\]

其中\(\left(x_0,y_0,z_0\right)\)为直线上任一已知点,\(\left(a,b,c\right)\)为向量,所以所有直线都可以使用一个点坐标及一个向量来表示。

对于测量点\(P_i\left(x_i,y_i,z_i\right)\)与直线的距离为\[d_i=\sqrt{{u_i}^2+{v_i}^2+{w_i}^2}\]

其中:\[u_i=c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\]\[v_i=a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\]\[w_i=b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\]

算法

根据原文:拟合的直线过所有点的平均值,没有证明……

所以未知量其实是3个,构建一个矩阵\[A=\begin{bmatrix}x_1-x_0&y_1-y_0&z_1-z_0\\x_2-x_0&y_2-y_0&z_2-z_0\\\vdots & \vdots & \vdots \\x_i-x_0&y_i-y_0&z_i-z_0\end{bmatrix}\]

将矩阵A做奇异值分解(SVD),令:\[A=U_1SV^T\]

矩阵\(V\)的第一列(Column)即是直线向量\(\left(a,b,c\right)\)。

代码实现:

 public override void Estimate(List<Point3D> datas)
        {
            double sum_x = 0;
            double sum_y = 0;
            double sum_z = 0;
            foreach (Point3D temp in datas)
            {
                sum_x += temp.x;
                sum_y += temp.y;
                sum_z += temp.z;
            }
            sum_x /= datas.Count;
            sum_y /= datas.Count;
            sum_z /= datas.Count;

            DenseMatrix jacobian = new DenseMatrix(datas.Count, 3);
            foreach (Point3D temp in datas)
            {
                Vector<double> gradient = new DenseVector(3);
                gradient[0] = temp.x - sum_x;
                gradient[1] = temp.y - sum_y;
                gradient[2] = temp.z - sum_z;
                jacobian.SetRow(datas.IndexOf(temp), gradient);
            }
            Svd svd = jacobian.Svd(true);
            // get matrix of left singular vectors with first n columns of U
            Matrix<double> U1 = svd.U().SubMatrix(0, datas.Count, 0, 3);
            // get matrix of singular values
            Matrix<double> S = new DiagonalMatrix(3, 3, svd.S().ToArray());
            // get matrix of right singular vectors
            Matrix<double> V = svd.VT().Transpose();

            Vector<double> parameters = new DenseVector(3);
            parameters = V.Column(0);
            x = sum_x;
            y = sum_y;
            z = sum_z;
            i = parameters[0];
            j = parameters[1];
            k = parameters[2];
        }

平面的最小二乘拟合

放在一起的原因是这两种元素的算法是完全一样的,直线拟合最后一步得到的矩阵V第一列是直线的向量,而第三列就是平面的向量。

参数化

平面同样可以用一个点\(\left(x_0,y_0,z_0\right)\)和一个向量\(\left(a,b,c\right)\)来表示,只是垂直与该向量。

平面的公式为\[a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)=0\)

对于测量点\(P_i\left(x_i,y_i,z_i\right)\)直接的距离为\[d_i=a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)\]

算法

与直线的算法完全相同。

包含直线、平面与圆柱算法的C#实例与说明

最小二乘法拟合一些基本空间元素的C#实现 —— (一)术语、基本算法与思路

本系列的主要目的是将拟合算法用C#实现,相关的操作用到了Math.NET数值运算库,所以将一些基本概念,算法和对应的C#代码放到前面。

对于线性模型,例如直线和平面,算法大约分三步:

  1. 参数化:将模型用参数化方式表达出来。
  2. 构造Design(非线性中的Jacobian)矩阵:根据参数公式求所有参数的偏导数作为列(Column),将实测值作为行(Row)。将偏差值作为等式右值。
  3. 求解。

对于非线性模型,例如圆柱,Gauss-Newton算法类似:

  1. 参数化:
  2. 求(或猜)初始解。
  3. 找到Jacobian矩阵及右值
  4. 求解
  5. 通过4计算逼近值,重复3和4
  6. 迭代结束

线性模型的解法是基础,详细的分析请看这篇文章,这里只解释代码部分。在Math.Net

对于矩阵\(A=\begin{bmatrix}A_{11} & A_{12}\\A_{21} & A_{22}\end{bmatrix}\)
A.Transpose() 代表A的转置矩阵\(A^T=\begin{bmatrix}A_{11} & A_{21}\\A_{12} & A_{22}\end{bmatrix}\)

这在坐标运算中是非常重要的,因为坐标运算中坐标系都表示为正交矩阵(抱歉,没找到证明),当计算一个点(用二维举例)\(P=\left(x,y\right)\)在新坐标系A中的坐标\(P^{‘}=\left(x^{‘},y^{‘}\right)\)时。\[P^{‘}=PA\]

而已知坐标系A中的坐标点\(P^{‘}\)求原坐标值可用\[P=P^{‘}A^T\]

一些类似的代码为:

A.Inverse()代表A的逆矩阵\(A^{-1}\)

A.Multiply(B)代表矩阵乘法\(A*B\)或者矩阵乘以向量\(A*b\)

对于常用的算法:

线性模型

已知Jacobian矩阵\(J\)及等式右值(偏差值向量)\(y\),另\[Ax=y\]求解向量x

  1. 正规方程(normal equations)
    \[A^TAx=A^Ty\]
    逆矩阵解法
    \[x=\left(A^TA\right)^{-1}A^Ty\]
    实现代码 
    x = A.Transpose().Multiply(A).Inverse().Multiply(A.Transpose().Multiply(y));

    更快和更稳定的方法将是对左侧的矩阵进行乔姆斯基分解(Cholesky decomposition),实现代码

    x = A.Transpose().Multiply(A).Cholesky().Solve(A.Transpose().Multiply(y));

    这两个在一些限定条件下是等价的,而这些限定条件在点数远大于参数的情况下是满足的。

  2. QR分解
    推论见原文,代码更简单: 
    x=A.QR().Solve(y);
  3. 奇异值分解(Singular Value Decomposition, SVD)
    A是方阵的情况下(即点数等于参数)代码为 
    x = A.Svd(true).Solve(y);

    A不是方阵的情况下代码为

// compute the SVD 
Svd svd = A.Svd(true);
// get matrix of left singular vectors with first n columns of U 
Matrix U1 = svd.U().SubMatrix(0, m,0, n); 
// get matrix of singular values 
Matrix S = new DiagonalMatrix(n, n, svd.S().ToArray()); 
// get matrix of right singular vectors 
Matrix V = svd.VT().Transpose(); 
x = V.Multiply(S.Inverse()).Multiply(U1.Transpose().Multiply(y));

非线性模型

这部分对于代码并没有什么区别,只是需要迭代(循环)及判断终止条件。

业余码农选择C#的理由

在网上看了太多又臭又长的类似文章,从方方面面夸或者黑某种语言,我选择C#的理由很简单,所以如果有和我类似情况的,我也推荐你选择C#作为开发语言。

我的情况:

1.公司提供的工作环境和客户的工作站全部是Windows环境。

2.开发程序的规模要求比较小:
比如:不会有大规模的客户端连接,也不需要数据量,负载等等,像我自己目前开发的小程序都是订制型的,客户的数量都是个位数的。

3.对C或C系列语言有些基础,比如(C,C++,JAVA等等)。

C#的优点:

1.免费,因为我写的程序虽然小,但是的确是以公司的名义提供给客户的,当然是收费的,所以选择免费的开发工具是很有必要的。而目前VS Express已经做到了完全免费,除了开发大型软件需要的功能,所有桌面级别的功能全部是免费的。

2.配置简单,千篇一律可能是专业开发人员的槽点,我上大学时也以自己搭建开发环境为兴趣,但是当我只想花一天写一个坐标转换的小程序时,VS Express这种高度集成的开发工具帮助极大,Express不支持绝大部分的插件和订制(专业版可以),但是好处是当你遇到一引起问题,你看到的问题解答中的界面和你永远是一样的,对于初学者这其实是很友好的。

3.语言的自解释,这本来是一种开发者写代码时需要注意的事项,但是我觉得.NET系列语言做得非常好,.NET库是不需要头文件的!刚开始我四处找头文件,后来发现当你引用一个库时,所有的函数及参数列表都是可见,而且所有.NET程序都可以非常简单的反编译,推荐ILSPY,这意味着你不用任何参考就可以直接使用函数,如果愿意还可以看到源码实现。(这叫强制开源吧。。。)

4.部署方便,Win7默认包含.NET 3.5,这意味着你开发的任何一个程序都可以在所有的Win7上运行,不用考虑环境设置,库的引用,而且程序非常小(我之前使用QT开发,最让人郁闷的一点就是任意带GUI的程序都要10M以上)。

缺点:

1.跨平台,很难在其他平台上使用,虽然有MONO,但是不免费。

2.库相对少,并不意味着没有,只不过当你 的需求非常专业,那么C++的历史在那摆着,库肯定多且专业,参考资料也多。
实际上C#的库比较多,但是因为自解释的原因吧,专业人员用起来肯本不需要文档,初学者就会很郁闷了。

2013年流水帐

12年没有写,补个13年吧。

首先是12年底把证领了,也算是裸婚,虽然我觉得这个词没什么意义。12年绝对是工作后最累的一年,时间管理相当差的我还为了工作牺牲了好多私人利益,教训是深刻的。结婚则是因为已经决定13年来德国,领了证才有可能申请签证。

13年1月老房东卖房想毁约,经历一些斗争,和平解决,新房东同意我们4月份才搬走。

然后就是开始折腾签证,雷声大雨点小的外派终于进入操作阶段,德国的中介开始操作所有事情,我也尽可能地在配合,预计开始的日期是4月1日,但是1月份才开始准备有点太紧了。

说是派两个人,老板也在春节公司一起吃饭时宣布了,然后另外一个一直不怎么积极的同事宣布不去了,然后闪电离职,虽然没有什么实际利益,但是对我还是好事情,至少不用给同事做饭了,我带老婆来德国还得帮同事做饭也不太爽啊。

后面的乏善可陈,德国的人事拖拖拉拉地一直不给合同,于是一直卡在这个坎上,最后4月终于把合同拿到手,我一是担心使馆耽误时间,二也是不想太赶,于是把日期改到了7月1日,没想到德国中介太NB,已经在德国拿到了移民局的批准,一周不到签证就下来了,不过还是照着我填的7月1号开始。

于是奸计得逞,虽然还是苦逼干活,但是走之前申请了两周婚假,虽然还是各种折腾行李,但是难得地休了长假。

国内的工作大撒把,话说的再好谁也不清楚一年后的事情。

7月来到德国,至现在半年了,一直在做工程师的工作,毕竟干工程师算是轻车熟路,所以还是很自在,压力也有,都是自己加的,避免自己太过放松。

德国同事比想像得热情,带我在开车能到的地方转了很多,其实也有机会自己玩,不过主要目的还是来工作,所以YY的欧洲游没有实现,德国都没出过。

德语是最大的问题,语言不能导致交流的不顺畅,工作的同事还好,大家都在国际化的环境中工作过,都能在适度的理解和宽容下工作,而且客观来说我表现得也不错。但是其他方面就没办法了,德国是单一民族的国家,Aalen还算国际化,要是去其他城市我估计我就直接挂了。

总的来说13年是调整的一年,来德国这一年休假的同时也充实了自己不少,虽然是技术上的,由于国内目前依然结构调整中,所以我的未来依然不明朗,不过14年是增长放缓甚至衰退的一年,挑战往往也是机会。

 

最小二乘法拟合一些基本空间元素的C#实现 —— (零)前言和参考资料

写这些(为了避免单个过长)文章的目的有两个,一是记录下最近工作的过程和参考的档案,避免以后忘记。二是万一有人和我有一样的问题,也许能搜到这篇文章,避免像我一样走这么多的歪路。

最近半因为工作,半因为兴趣,想实现一些笛卡尔三维坐标内的点云拟合基本元素(直线、平面、圆柱等),虽然很多软件都有非常强的功能,但是基本上都是重量级的收费工业软件,我买不起,而像我们公司的虽然我不用付费,API又几乎没有,所以也借这个机会来学习一下。

先要吐一下槽,中文的资料几乎找不到,不是一些算法课的作业和解答,就是论文数据库中付费才能看,而且不知道质量好坏的论文。不过也是这些论文拯救了我,虽然论文不免费,但是参考文档直接列在那,看参考文档往往比看这些翻译+“优化”的论文要好。

另外一个比较有用的工具是google 学术搜索,可以看到一个论文被引用的次数,后面附的一篇论文被引用了150多次,基本上是这个话题里最早的几篇论文,也是讲的最基础的论文。

另外还要感谢维基百科,一些基本已经忘记的数学概念都是通过这个想起来的,还可以当专业词典用,一篇文章切换中英文,可以极大的帮助理解。

以下是参考资料,会不断更新。

C#类:

math.net库是一个C#实现的数值计算库,在算法实现中大量实用了这个库提供的线代矩阵操作。如果使用C++,一个更有名的库是boost

msdn有任何问题和错误来msdn肯定能查到,比csdn要靠谱太多了。

stackoverflow无数次把我从绝望深渊拯救上来的人,什么问题都可以问,什么问题都有人问,几乎都会得到正确的解释和参考信息。

算法及原理类:

使用Math.NET进行线性与非线性最小二乘拟合,我最早找到的文章之一,我几乎以为单凭这篇文章就可以帮助我搞定问题。
这篇文章的优点是罗列了从基本到常用的几种线性与非线性算法,提供了比较详细的推导过程(不包括线代的定理),和所有的C#代码实现。(下载二进制源代码
不过这篇文章里只有单变量二维空间上的拟合。
使用这篇文章及代码可以了解如何使用Math.NET进行矩阵操作,帮助极大,因为其他的文章偏向于论文,往往推导出解法后连计算步骤都不给,使用这里提供的算法可以得到最后一步的结果。
我在代码中找到了一个小BUG,于是给作者写了信,作者很热心的回复并且告诉我有个中国朋友进行了翻译,这是赵毅力同学的翻译。更推荐先阅读这个版本,因为所有的基本概念都做了介绍,不用自己去查教材或者维基百科了。

无名文章,这是我正在使用而且帮助排名第二的文章,看格式像论文或者会议上的技术报告,但是没找到标题,这篇文章提供了笛卡尔空间上的线,圆柱,圆锥,球等的拟合算法,由于没找到引用信息,无法判断这篇文章的正确或者权威性,我目前看到空间直线部分,和我们公司的软件的计算结果取得一致,未来两天会继续验证。(1月23日添加,已验证直线平面和圆柱,算法正确)
缺点是这篇文章里只有基本数据的计算方法,和算法思路,稍微具体点的推导都没有。例如——矩阵A是每个点减平均算出来的,然后使用SVD对A进行计算就可以得到空间向量的解。
如果没有线代基础或者相关的算法概念会觉得莫名其妙,结合第一篇文章看就好很多了。

更原理性的一篇,这篇文章有两个版本,这篇稍老,新的没仔细看,和这个几乎一样Faithful版本,要赞一下这个Prof.论文都放到了个人网站上,省得去各个黑心网站上付费,我觉得论文这种东西写出来就是为了让大家看的,卖几十刀实在是太黑了啊。
不过对应用层面帮助不大,不过如果想对算法实现改进(例如从最小二乘至最小元素法),应该会有帮助的,等我有需求时再看吧。

另外还有几篇是针对圆柱的,因为我个人工作的需求主要针对圆柱的拟合,所以也列在这里了。

5点计算圆柱的算法,给出了详细的推导和分析,产生多种结果的原因,以及Mathematica下的代码实现。

圆柱拟合的代数算法实现

最小误差(条件)及最小二乘拟合圆柱的实现应该是一个图形库的文档,应该是基于C++和OpenGL的库,也提供了代码实现。而且库中直接实现了基本元素的最小二乘拟合实现,圆柱C++实现