first commit
This commit is contained in:
		
						commit
						fd57c4cc62
					
				
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| study/eskf156/dataset/**/*.mat filter=lfs diff=lfs merge=lfs -text | ||||
							
								
								
									
										55
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| # Prerequisites | ||||
| *.d | ||||
| *.asv | ||||
| *.bag | ||||
| # *.csv | ||||
| 
 | ||||
| # Object files | ||||
| *.o | ||||
| *.ko | ||||
| *.obj | ||||
| *.elf | ||||
| 
 | ||||
| # Linker output | ||||
| *.ilk | ||||
| *.map | ||||
| *.exp | ||||
| 
 | ||||
| # Precompiled Headers | ||||
| *.gch | ||||
| *.pch | ||||
| 
 | ||||
| # Libraries | ||||
| *.lib | ||||
| *.a | ||||
| *.la | ||||
| *.lo | ||||
| 
 | ||||
| # Shared objects (inc. Windows DLLs) | ||||
| *.dll | ||||
| *.so | ||||
| *.so.* | ||||
| *.dylib | ||||
| 
 | ||||
| # Executables | ||||
| *.exe | ||||
| *.out | ||||
| *.app | ||||
| *.i*86 | ||||
| *.x86_64 | ||||
| *.hex | ||||
| 
 | ||||
| # Debug files | ||||
| *.dSYM/ | ||||
| *.su | ||||
| *.idb | ||||
| *.pdb | ||||
| 
 | ||||
| # Kernel Module Compile Results | ||||
| *.mod* | ||||
| *.cmd | ||||
| .tmp_versions/ | ||||
| modules.order | ||||
| Module.symvers | ||||
| Mkfile.old | ||||
| dkms.conf | ||||
							
								
								
									
										38
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| # 基于超宽带(UWB)技术的扩展卡尔曼滤波(EKF)算法的 MATLAB 实现仓库 | ||||
| 
 | ||||
| 教学性质的: | ||||
| 
 | ||||
| * GPS IMU经典15维ESKF松组合 | ||||
| * VRU/AHRS姿态融合算法 | ||||
| * 捷联惯导速度位置姿态解算例子 | ||||
| * UWB IMU紧组合融合 | ||||
| * 每个例子自带数据集 | ||||
| 
 | ||||
| 运行环境: | ||||
| 
 | ||||
| * 最低版本: MATLAB R2022a,  必须安装sensor fusion toolbox和navigation tool box | ||||
| 
 | ||||
| * 需要将`\lib`及其子目录加入MATLAB预设目录, 或者运行一下根目录下的`init.m` | ||||
| 
 | ||||
| 其中UWB+IMU融合和GPS+IMU融合就是经典的15维误差卡尔曼滤波(EKSF),没有什么论文参考,就是一直用的经典的框架(就是松组合),见参考部分。 | ||||
| 
 | ||||
| 更多内容请访问: | ||||
| 
 | ||||
| - 知乎:https://www.zhihu.com/people/yang-xi-97-90 | ||||
| - 网站:www.hipnuc.com | ||||
| 
 | ||||
| 参考: | ||||
| 
 | ||||
| 1. 书:捷联惯导算法与组合导航原理 严恭敏及PSINS工具箱官方网站:http://www.psins.org.cn/sy | ||||
| 2. 书:GNSS与惯性及多传感器组合导航系统原理 第二版 | ||||
| 3. 书:GPS原理与接收机设计 谢刚 | ||||
| 4. 深蓝学院-多传感器融合课程(理论推导及code) | ||||
| 5. 武汉大学牛小骥惯性导航课程(非常好,非常适合入门) https://www.bilibili.com/video/BV1nR4y1E7Yj | ||||
| 6. GPS IMU 松组合 https://kth.instructure.com/files/677996/download?download_frd=1 | ||||
| 7. Coursera课程 https://www.coursera.org/learn/state-estimation-localization-self-driving-cars  | ||||
| 
 | ||||
| 推荐的学习路线: | ||||
| 
 | ||||
| 1. 先看武汉大学惯性导航课程(牛小骥老师),入门非常推荐,也不需要什么教材,做笔记 | ||||
| 2. 看严恭敏老师的书籍,视频及code | ||||
| 3. 然后再入组合导航知识 | ||||
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas1.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas1.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas2.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas2.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas3.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas3.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas4.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas4.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas5.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas5.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas6.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas6.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas7.mat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UWBInsFusion/Datasets/NTV/TWR-4A1T/datas7.mat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										25
									
								
								UWBInsFusion/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								UWBInsFusion/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| 数据集说明: | ||||
| 
 | ||||
| 所有数据集均为实测机器人跑车数据,无仿真数据。 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| | 数据集 | 基站数 | 平面or3D | 说明                                                         | | ||||
| | ------ | ------ | -------- | ------------------------------------------------------------ | | ||||
| | datas1 | 4      | 2D       | 机器人U型跑车数据,机器人走走停停,速度不稳定                | | ||||
| | datas2 | 4      | 2D       | 机器人圆形轨迹跑车数据,机器人匀速运动,运动形状简单规则,可以用来初步验证算法 | | ||||
| | datas3 | 4      | 2D       | 机器人走一个典型赛道轨迹, 基本匀速,比较典型的实测数据      | | ||||
| | datas4 | 4      | 2D       | 相较于datas3 运动更复杂,场地更大. 机动更剧烈                | | ||||
| | datas5 | 4      | 2D       | 类似datas4                                                   | | ||||
| | datas5 | 4      | 2D       | 类似datas4                                                   | | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 数据集采集指导: | ||||
| 
 | ||||
| 如果您自己第一次采集数据做实验,建议: | ||||
| 
 | ||||
| 1. 建议IMU 100Hz, UWB 1-10Hz左右 | ||||
| 2. 用小车或者汽车,不要用手拿着,避免很多随机机动。 | ||||
| 3. 开始静止至少30s, 然后绕大8子,每个8子绕完不少于30s。 可以走走停停。做完一个比较标准(好识别)的动作后 静止几秒,再做下一个,比较典型的有八字,L型, 绕圈等 | ||||
| 4. 运动结束后最好也停止30s。 | ||||
							
								
								
									
										107
									
								
								UWBInsFusion/demo_plot.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								UWBInsFusion/demo_plot.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | ||||
| 
 | ||||
| 
 | ||||
| %% 说明 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| function demo_plot(dataset, out_data) | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', '原始数据'); | ||||
| subplot(2, 2, 1); | ||||
| plot(dataset.imu.acc'); | ||||
| legend("X", "Y", "Z"); | ||||
| title("加速度测量值"); | ||||
| subplot(2, 2, 2); | ||||
| plot(dataset.imu.gyr'); | ||||
| legend("X", "Y", "Z"); | ||||
| title("陀螺测量值"); | ||||
| subplot(2, 2, 3); | ||||
| plot(dataset.uwb.tof'); | ||||
| title("UWB测量值(伪距)"); | ||||
| subplot(2,2,4); | ||||
| plot(diff(dataset.uwb.tof')); | ||||
| title("伪距的差分(diff(tof))"); | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', '滤波器估计零偏'); | ||||
| subplot(2,1,1); | ||||
| plot(out_data.delta_u(:,1:3)); | ||||
| legend("X", "Y", "Z"); | ||||
| title("加速度零偏"); | ||||
| subplot(2,1,2); | ||||
| plot(rad2deg(out_data.delta_u(:,4:6))); | ||||
| legend("X", "Y", "Z"); | ||||
| title("陀螺仪零偏"); | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', '量测滤波信息'); | ||||
| subplot(2,1,1); | ||||
| plot(out_data.L); | ||||
| title("量测置信度S"); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', 'PVT'); | ||||
| subplot(2,2,1); | ||||
| plot(out_data.x(:,1:3)); | ||||
| legend("X", "Y", "Z"); | ||||
| title("位置"); | ||||
| subplot(2,2,2); | ||||
| plot(out_data.x(:,4:6)); | ||||
| legend("X", "Y", "Z"); | ||||
| title("速度"); | ||||
| subplot(2,2,3); | ||||
| plot(out_data.eul); | ||||
| legend("X", "Y", "Z"); | ||||
| title("欧拉角(姿态)"); | ||||
| 
 | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', '硬件给出的UWB解算位置'); | ||||
| subplot(1,2,1); | ||||
| plot3(out_data.uwb.pos(1,:), out_data.uwb.pos(2,:), out_data.uwb.pos(3,:), '.'); | ||||
| axis equal | ||||
| title("UWB 伪距解算位置"); | ||||
| 
 | ||||
| if(isfield(dataset, "pos")) | ||||
|     subplot(1,2,2); | ||||
|     plot3(dataset.pos(1,:), dataset.pos(2,:), dataset.pos(3,:), '.'); | ||||
|     hold on; | ||||
|     plot3(out_data.x(:,1), out_data.x(:,2), out_data.x(:,3), '.-'); | ||||
|     axis equal | ||||
|     title("硬件给出轨迹"); | ||||
| end | ||||
| 
 | ||||
| figure('NumberTitle', 'off', 'Name', '纯UWB伪距解算的位置和融合轨迹'); | ||||
| plot(out_data.uwb.pos(1,:), out_data.uwb.pos(2,:), '.'); | ||||
| hold on; | ||||
| plot(out_data.uwb.fusion_pos(1,:), out_data.uwb.fusion_pos(2,:), '.-'); | ||||
| 
 | ||||
| anch = out_data.uwb.anchor; | ||||
| hold all; | ||||
| scatter(anch(1, :),anch(2, :),'k'); | ||||
| for i=1:size(anch,2) | ||||
|     text(anch(1, i),anch(2, i),"A"+(i-1)) | ||||
| end | ||||
| hold off; | ||||
| 
 | ||||
| 
 | ||||
| legend("伪距解算UWB轨迹", "融合轨迹"); | ||||
| 
 | ||||
| %  | ||||
| % if(isfield(dataset, "pos")) | ||||
| %      figure('NumberTitle', 'off', 'Name', '硬件给出的位置和融合轨迹'); | ||||
| %     plot(dataset.pos(1,:), dataset.pos(2,:), '.'); | ||||
| %     hold on; | ||||
| %     plot(out_data.uwb.fusion_pos(1,:), out_data.uwb.fusion_pos(2,:), '.-'); | ||||
| %     legend("硬件给出轨迹", "融合轨迹"); | ||||
| %     anch = out_data.uwb.anchor; | ||||
| %     hold all; | ||||
| %     scatter(anch(1, :),anch(2, :),'k'); | ||||
| %     for i=1:size(anch,2) | ||||
| %         text(anch(1, i),anch(2, i),"A"+(i-1)) | ||||
| %     end | ||||
| %     hold off; | ||||
| % end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										355
									
								
								UWBInsFusion/eskf_uwb_imu.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								UWBInsFusion/eskf_uwb_imu.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,355 @@ | ||||
| clc | ||||
| clear | ||||
| close all | ||||
| 
 | ||||
| addpath './lib'; | ||||
| addpath './lib/gnss'; | ||||
| addpath './lib/calbiration'; | ||||
| addpath './lib/plot'; | ||||
| addpath './lib/rotation'; | ||||
| addpath './lib/geo'; | ||||
| savepath | ||||
| 
 | ||||
| %% 说明 | ||||
| % UWB IMU 融合算法,采用误差卡尔曼15维经典模型,伪距组合 | ||||
| % PR(TOF) 伪距:        UWB硬件给出的原始测量距离值 | ||||
| % IMU:                 加速度(3) 3轴陀螺(3) 共6维,, | ||||
| % noimal_state:        名义状态: 导航方程状态: 位置(3) 速度(3) 四元数(4) 共10维 | ||||
| % err_state:           KF误差状态: 位置误差(3) 速度误差(3) 失准角(3) 加速度计零偏(3) 陀螺零偏(3) 共15维 | ||||
| % du:                  零偏反馈: 加速度计零偏(3) 陀螺零偏(3), 共6维 | ||||
| 
 | ||||
| % 单位说明: | ||||
| % 加速度,加速度零偏: m/s^(2) | ||||
| % 角速度, 角速度(陀螺)零偏: rad/s | ||||
| % 角度 rad | ||||
| % 速度: m/s | ||||
| 
 | ||||
| %% 读取数据集 | ||||
| load datas2 | ||||
| dataset = datas; | ||||
| % dataset的数据结构如下 | ||||
| % dataset | ||||
| % ├── imu | ||||
| % |   ├── acc    加速度计三维数据 | ||||
| % |   ├── gyr    陀螺仪三维数据 | ||||
| % |   └── time   时间戳数组 | ||||
| % ├── uwb | ||||
| % |   ├── time   时间戳数组 1*17200 | ||||
| % |   ├── anchor 四个标签的坐标矩阵,x,y,z | ||||
| % |   ├── tof    飞行时间,4*17200,表示4个基站在连续时间点上对同一移动标签的测距时间 | ||||
| % |   └── cnt    基站个数 | ||||
| % └── pos | ||||
| 
 | ||||
| N = length(dataset.imu.time);                               % 时间序列的长度 | ||||
| dt = mean(diff(dataset.imu.time));                          % dt:IMU数据的平均采样周期。通过diff方法计算相邻时间戳的差值,并求平均值得到dt | ||||
| 
 | ||||
| % 故意删除一些基站及数据,看看算法在基站数量很少的时候能否有什么奇迹。。 | ||||
| % dataset.uwb.anchor(:,1) = []; | ||||
| % dataset.uwb.tof(1,:) = []; | ||||
| 
 | ||||
| 
 | ||||
| % EKF融合使用的基站个数,融合算法最少2个基站就可以2D定位 | ||||
| %dataset.uwb.cnt = size(dataset.uwb.anchor, 2); | ||||
| 
 | ||||
| 
 | ||||
| m_div_cntr = 0;                                              % 量测分频器:计数器,用于记录已累计的IMU更新次数。当计数器达到 m_div 时,触发UWB量测更新,并重置计数器。 | ||||
| m_div = 1;                                                   % 量测分频系数,每m_div次量测,才更新一次EKF量测(UWB更新),  可以节约计算量 或者 做实验看效果 | ||||
|                                                              % UWB的采样率通常远低于IMU(例如IMU 100Hz,UWB 10Hz),直接每次融合会导致冗余计算。通过分频系数可以匹配两者的实际更新频率,避免不必要的计算。 | ||||
| UWB_LS_MODE = 3;                                             % 2 纯UWB解算采用2D模式, 3:纯UWB解算采用3D模式 | ||||
| UWB_EKF_UPDATE_MODE = 3;                                     % EKF 融合采用2D模式,   3: EKF融合采用3D模式 | ||||
| 
 | ||||
| %% 数据初始化 | ||||
| out_data.uwb = [];                                           % 初始化输出数据结构 | ||||
| out_data.uwb.time = dataset.uwb.time;                        % 存储UWB时间戳 | ||||
| out_data.imu.time = dataset.imu.time;                        % 存储IMU时间戳 | ||||
| out_data.uwb.anchor = dataset.uwb.anchor;                    % 存储基站坐标 | ||||
| % pr = 0; | ||||
| % last_pr = 0; | ||||
| 
 | ||||
| %% 滤波参数初始化 | ||||
| settings = uwb_imu_example_settings();                       % 获取滤波器设置参数,使用uwb_imu_example_settings()函数获取滤波器的配置参数 | ||||
|                                                              % 返回值是一个结构体settings,包含滤波器的各种参数 | ||||
| R = diag(ones(dataset.uwb.cnt, 1)*settings.sigma_uwb^(2));   % 量测噪声协方差矩阵 | ||||
| noimal_state = init_navigation_state(settings) ;             % 初始化名义状态,10维:位置:(x,y,z);速度(vx,vy,vz);姿态四元数(q0,q1,q2,q3) | ||||
|                                                              % 名义状态:系统在理想条件下的理论状态,忽略噪声、扰动和模型误差 | ||||
| err_state = zeros(15, 1);                                    % 初始化误差状态,15维:位置误差(3维);速度误差(3维);姿态误差(3维);加速度计零偏(3维);陀螺仪零偏(3维) | ||||
|                                                              % 误差状态:实际状态与名义状态之间的偏差,由噪声、外部干扰或模型不确定性导致 | ||||
| 
 | ||||
| %使用第一帧伪距作为初始状态 | ||||
| pr = dataset.uwb.tof(:, 1);                                  % 获取第一帧UWB测量数据 | ||||
| % 初始位置解算 | ||||
| % 测量值=真实值+零偏+噪声 | ||||
| % 零偏是传感器在无输入信号时输出的非零偏移量,反应其基准点的系统性偏差 | ||||
| % 伪距是UWB(超宽带)等无线定位系统中,通过信号传播时间计算出的等效距离测量值 | ||||
| % noimal_state前三项:位置坐标,使用最小二乘法解算 | ||||
| noimal_state(1:3) = multilateration(dataset.uwb.anchor, [ 1 1 0.99]',  pr', UWB_LS_MODE); | ||||
| 
 | ||||
| du = zeros(6, 1);                                            % 初始化零偏反馈 | ||||
| [P, Q1, Q2, ~, ~] = init_filter(settings);                   % 初始化滤波器参数,此处初始化时使用~占位符,因为这个地方这两个参数没有意义,这样占位可以不占用内存 | ||||
| 
 | ||||
| % 输出提示 | ||||
| fprintf("共%d帧数据, IMU采样频率:%d Hz 共运行时间 %d s\n", N,  1 / dt, N * dt); | ||||
| fprintf("UWB基站个数:%d\n", dataset.uwb.cnt); | ||||
| fprintf("UWB量测更新频率为:%d Hz\n", (1 / dt) / m_div); | ||||
| fprintf("UWB EKF量测更新模式: %dD模式\n", UWB_EKF_UPDATE_MODE); | ||||
| fprintf("纯UWB最小二乘解算: %dD模式\n", UWB_LS_MODE); | ||||
| fprintf("EKF 滤波参数:\n"); | ||||
| settings | ||||
| fprintf("开始滤波...\n"); | ||||
| 
 | ||||
| 
 | ||||
| for k=1:N | ||||
|      | ||||
|     acc = dataset.imu.acc(:,k); | ||||
|     gyr = dataset.imu.gyr(:,k); | ||||
|      | ||||
|     % 反馈 加速度bias, 陀螺bias | ||||
|     % 测量值 = 真实值 + 零偏 + 噪声 | ||||
|     acc = acc - du(1:3);                                     % du是零偏,(1:3)和(4:6)分别代表加速度和陀螺仪的零偏 | ||||
|     gyr = gyr - du(4:6);                                     % 陀螺仪 | ||||
|      | ||||
|     % 捷联惯导解算 | ||||
|     p = noimal_state(1:3);                                   % 位置坐标 [x; y; z](单位:米) | ||||
|     v = noimal_state(4:6);                                   % 速度 [vx; vy; vz](单位:m/s) | ||||
|     q =  noimal_state(7:10);                                 % 姿态四元数 [q0; q1; q2; q3] | ||||
|     % 捷联惯导解算:输入当前状态和IMU测量值,输出更新后的位置、速度和姿态 | ||||
|     % pvq是当前的状态,acc、gyr是加速度和陀螺仪的测量值,dt为时间步长,后面为重力向量 | ||||
|     [p, v, q] = nav_equ_local_tan(p, v, q, acc, gyr, dt, [0, 0, -9.8]');  % 东北天坐标系,重力简化为-9.8 | ||||
|      | ||||
|     %   小车假设:基本做平面运动,N系下Z轴速度基本为0,直接给0 | ||||
|     v(3) = 0; | ||||
|      | ||||
|     % 更新数值 | ||||
|     noimal_state(1:3) = p; | ||||
|     noimal_state(4:6) = v; | ||||
|     noimal_state(7:10) = q; | ||||
|     out_data.eul(k,:) = q2eul(q);                            % 四元数转欧拉角并存入数据表  | ||||
|      | ||||
|     % 生成F阵   G阵 | ||||
|     % 看函数注释,根据当前的状态、加速度测量值 acc 和采样时间 dt,生成状态转移矩阵 F 和过程噪声耦合矩阵 G | ||||
|     [F, G] = state_space_model(noimal_state, acc, dt); | ||||
|      | ||||
|     % 卡尔曼P阵预测公式 | ||||
|     P = F*P*F' + G*blkdiag(Q1, Q2)*G'; | ||||
|      | ||||
|     % log数据 | ||||
|     out_data.x(k,:)  = noimal_state; | ||||
|     out_data.delta_u(k,:) = du';                             % 位置方差   | ||||
|     out_data.diag_P(k,:) = trace(P);                         % 姿态四元数方差  | ||||
|      | ||||
|      | ||||
|     %% EKF UWB量测更新 | ||||
|     m_div_cntr = m_div_cntr+1;                               %量测分频器 | ||||
|     % 每m_div次量测,才更新一次EKF量测(UWB更新),此时m_div设置为1 | ||||
|     if m_div_cntr == m_div | ||||
|         m_div_cntr = 0; | ||||
|          | ||||
|         pr = dataset.uwb.tof(1:dataset.uwb.cnt, k);          % pr是当前时刻(第k帧)所有UWB基站的TOF | ||||
|          | ||||
|         %判断两次PR 差,如果差太大,则认为这个基站PR比较烂,不要了。相当于GNSS里的挑星 | ||||
|         %                         arr = find(abs(pr - last_pr) < 0.05); | ||||
|         %                         last_pr = pr; | ||||
|         %                         out_data.good_anchor_cnt(k,:) = length(arr); %记录挑出来的基站数 | ||||
|         % | ||||
|         %                         if(isempty(arr)) | ||||
|         %                             continue; | ||||
|         %                         end | ||||
|         % | ||||
|         %                         %构建 剔除不好的基站之后的基站位置矩阵和R矩阵 | ||||
|         %                         pr = pr(arr); | ||||
|         %                         anch = dataset.uwb.anchor(:, arr); | ||||
|         %                         R1 = R(arr, arr); | ||||
|          | ||||
|         % 算了不挑基站了,所有基站直接参与定位,其实也差不太多 | ||||
|         anch = dataset.uwb.anchor; | ||||
|         R1 = R;                                               % 测量噪声协方差矩阵 | ||||
|          | ||||
|         % 量测方程 | ||||
|         % Y是根据当前状态 noimal_state 预测出来的各个基站到目标的距离 | ||||
|         % H是观测矩阵,表示距离对状态的偏导 | ||||
|         [Y, H]  = uwb_hx(noimal_state, anch, UWB_EKF_UPDATE_MODE); | ||||
|          | ||||
|         % 卡尔曼公式,计算K | ||||
|         S = H*P*H'+R1;                                       % system uncertainty 系统不确定度,用于衡量测量是否可信 | ||||
|         residual = pr - Y;                                   % residual 或者叫新息 测量与预测的差值 | ||||
|          | ||||
|         %% 根据量测置信度给R一些增益   Self-Calibrating Multi-Sensor Fusion with Probabilistic | ||||
|         %Measurement Validation for Seamless Sensor Switching on a UAV, 计算量测可靠性 | ||||
|         % 衡量量测可信度,L越大代表当前量测越不可信(Mahalanobis 距离L) | ||||
|         L = (residual'*S^(-1)*residual); | ||||
|         out_data.L(k,:) = L; | ||||
|          | ||||
|         %         if(L > 20 ) %如果量测置信度比较大,则更不相信量测 | ||||
|         %             S = H*P*H'+R1*5; | ||||
|         %         end | ||||
|          | ||||
|         K = (P*H')/(S);                                      % 卡尔曼增益K | ||||
|         err_state = [zeros(9,1); du] + K*(residual);         % 状态误差向量 | ||||
|          | ||||
|         % 反馈速度位置 | ||||
|         noimal_state(1:6) = noimal_state(1:6) + err_state(1:6); | ||||
|          | ||||
|         % 反馈姿态 | ||||
|         q = noimal_state(7:10);                              % 提取姿态四元数 | ||||
|         q = qmul(rv2q(err_state(7:9)), q); | ||||
|         noimal_state(7:10) = q;                              % 姿态反馈(使用小角度修正旋转) | ||||
|          | ||||
|         %存储加速度计零偏,陀螺零偏 | ||||
|         du = err_state(10:15); | ||||
|          | ||||
|         % P阵后验更新 | ||||
|         P = (eye(15)-K*H)*P; | ||||
|     end | ||||
|      | ||||
|      | ||||
|     %% 车载约束:Z轴速度约束: B系下 Z轴速度必须为0(不能钻地).. 可以有效防止Z轴位置跳动 参考https://kth.instructure.com/files/677996/download?download_frd=1 和 https://academic.csuohio.edu/simond/pubs/IETKalman.pdf | ||||
|     %% 车辆在 B系Z轴上不应该有速度,如果估计有,就认为估计错了,通过观测去修正 | ||||
|     R2 = eye(1)*0.5; | ||||
|     Cn2b = q2m(qconj(noimal_state(7:10)));                   % 计算四元数的共轭,得到从导航系到机体系的旋转;再转换成方向余弦矩阵 | ||||
|      | ||||
|     H = [zeros(1,3), [0 0 1]* Cn2b, zeros(1,9)];             % 构造观测矩阵H,用于观测当前状态中的速度 | ||||
|      | ||||
|     K = (P*H')/(H*P*H'+R2); | ||||
|     z = Cn2b*noimal_state(4:6);                              % 当前估计的B系Z轴速度 | ||||
|      | ||||
|     err_state = [zeros(9,1); du] + K*(0-z(3:3));             % 目标观测值是0(因为车不能在B系Z轴上移动),当前估计值是z(3),差值为残差 | ||||
|      | ||||
|     % 反馈速度位置 更新状态 | ||||
|     noimal_state(1:6) = noimal_state(1:6) + err_state(1:6); | ||||
|      | ||||
|     % 反馈姿态 | ||||
|     q = noimal_state(7:10); | ||||
|     q = qmul(ch_rv2q(err_state(7:9)), q);                    % 更新原始四元数 | ||||
|     noimal_state(7:10) = q; | ||||
|      | ||||
|     %存储加速度计零偏,陀螺零偏 | ||||
|     % du = err_state(10:15); | ||||
|      | ||||
|     % P阵后验更新 | ||||
|     P = (eye(15)-K*H)*P; | ||||
|      | ||||
|      | ||||
| end | ||||
| 
 | ||||
| fprintf("开始纯UWB最小二乘位置解算...\n"); | ||||
| %% 纯 UWB 位置解算 | ||||
| j = 1; | ||||
| uwb_pos = [1 1 1]'; | ||||
| N = length(dataset.uwb.time); | ||||
| 
 | ||||
| for i=1:N | ||||
|     pr = dataset.uwb.tof(:, i); | ||||
|     % 去除NaN点 | ||||
|     %if all(~isnan(pr)) == true | ||||
|      | ||||
|     uwb_pos = multilateration(dataset.uwb.anchor, uwb_pos,  pr', UWB_LS_MODE); | ||||
|     out_data.uwb.pos(:,j) = uwb_pos; | ||||
|     j = j+1; | ||||
|     %end | ||||
| end | ||||
| fprintf("计算完成...\n"); | ||||
| 
 | ||||
| %% plot 数据 | ||||
| out_data.uwb.tof = dataset.uwb.tof; | ||||
| out_data.uwb.fusion_pos = out_data.x(:,1:3)'; | ||||
| demo_plot(dataset, out_data); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| %%  初始化nomial state | ||||
| function x = init_navigation_state(~) | ||||
| 
 | ||||
| % 简单点, 全部给 0 。10维:位置:(x,y,z);速度(vx,vy,vz);姿态四元数(q0,q1,q2,q3) | ||||
| q = eul2q(deg2rad([0 0 0]));                         % eul2q函数用于将欧拉角转换为四元数 | ||||
| x = [zeros(6,1); q];                                 % 拼接6维零向量与四元数 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| %% 初始化滤波器参数 | ||||
| function [P, Q1, Q2, R, H] = init_filter(settings) | ||||
| 
 | ||||
| % Kalman filter state matrix | ||||
| P = zeros(15); | ||||
| P(1:3,1:3) = settings.factp(1)^2*eye(3); | ||||
| P(4:6,4:6) = settings.factp(2)^2*eye(3); | ||||
| P(7:9,7:9) = diag(settings.factp(3:5)).^2; | ||||
| P(10:12,10:12) = settings.factp(6)^2*eye(3); | ||||
| P(13:15,13:15) = settings.factp(7)^2*eye(3); | ||||
| 
 | ||||
| % Process noise covariance | ||||
| Q1 = zeros(6); | ||||
| Q1(1:3,1:3) = diag(settings.sigma_acc).^2*eye(3); | ||||
| Q1(4:6,4:6) = diag(settings.sigma_gyro).^2*eye(3); | ||||
| 
 | ||||
| Q2 = zeros(6); | ||||
| Q2(1:3,1:3) = settings.sigma_acc_bias^2*eye(3); | ||||
| Q2(4:6,4:6) = settings.sigma_gyro_bias^2*eye(3); | ||||
| 
 | ||||
| R =0; | ||||
| H = 0; | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| %%  生成F阵,G阵 | ||||
| % 根据当前的状态 x、加速度测量值 acc 和采样时间 dt,生成状态转移矩阵 F 和过程噪声耦合矩阵 G | ||||
| function [F,G] = state_space_model(x, acc, dt) | ||||
| Cb2n = q2m(x(7:10));                                     % 把四元数转换成方向余弦矩阵,从机体坐标系(body)转到导航系(nav)  | ||||
| 
 | ||||
| sk = askew(Cb2n * acc);                                  % 对一个向量v构造出反对称矩阵,用于表示向量叉乘的线性化形式 | ||||
| 
 | ||||
| O = zeros(3); | ||||
| I = eye(3); | ||||
| % P V theta 加计零偏  陀螺零偏 | ||||
| F = [ | ||||
|     O I   O O       O; | ||||
|     O O -sk -Cb2n O; | ||||
|     O O O O       -Cb2n; | ||||
|     O O O O       O; | ||||
|     O O O O       O]; | ||||
| 
 | ||||
| % Approximation of the discret  time state transition matrix | ||||
| % 将连续时间的状态转移矩阵做一次一阶近似离散化 | ||||
| F = eye(15) + dt*F; | ||||
| 
 | ||||
| % Noise gain matrix | ||||
| G=dt*[ | ||||
|     O       O         O  O; | ||||
|     Cb2n  O         O  O; | ||||
|     O        -Cb2n O  O; | ||||
|     O        O         I   O; | ||||
|     O        O        O   I]; | ||||
| end | ||||
| 
 | ||||
| %% UWB量测过程 | ||||
| % Y 根据当前状态和UWB基站坐标预测出来的伪距 | ||||
| % H 量测矩阵 | ||||
| % anchor: 基站坐标  M x N: M:3(三维坐标),  N:基站个数 | ||||
| % dim:  2: 二维  3:三维 | ||||
| function [Y, H] = uwb_hx(x, anchor, dim) | ||||
| N = size(anchor,2);                                      % 基站个数 | ||||
| 
 | ||||
| % 三维取xyz,二维取xy | ||||
| position = x(1:3); | ||||
| if(dim)== 2 | ||||
|     position = position(1:2); | ||||
|     anchor = anchor(1:2, 1:N); | ||||
|     %  uwb.anchor | ||||
| end | ||||
| 
 | ||||
| Y = [];                                                  % Y是伪距预测,即目标位置到每个锚点的欧几里得距离 | ||||
| H = [];                                                  % 雅可比矩阵的每一行 | ||||
| % 计算预测的伪距s,所有预测的位置与各个锚点的向量差 | ||||
| perd_pr = repmat(position,1,N) - anchor(:,1:N); | ||||
| for i=1:N | ||||
|      | ||||
|     if(dim)== 2 | ||||
|         H = [H ;perd_pr(:,i)'/norm(perd_pr(:,i)),zeros(1,13)]; | ||||
|     else | ||||
|         H = [H ;perd_pr(:,i)'/norm(perd_pr(:,i)),zeros(1,12)]; | ||||
|     end | ||||
|     Y = [Y ;norm(perd_pr(:,i))]; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										25
									
								
								UWBInsFusion/uwb_imu_example_settings.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								UWBInsFusion/uwb_imu_example_settings.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| 
 | ||||
| function settings = uwb_imu_example_settings() | ||||
| 
 | ||||
| settings.sigma_uwb = 0.5; % UWB测距噪声 | ||||
| 
 | ||||
| settings.sigma_acc = 0.02;                   %加速度计噪声 | ||||
| settings.sigma_gyro = deg2rad(0.3);      %陀螺仪噪声 | ||||
| settings.sigma_acc_bias = 0.00;              %加速度计零偏随机游走噪声  | ||||
| settings.sigma_gyro_bias = deg2rad(0.0);  %陀螺仪零偏随机游走噪声 | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| % Initial Kalman filter uncertainties (standard deviations) | ||||
| settings.factp(1) = 20;                                 % 初值位置方差(置信度)(m),越大代表对初始位置越不信任 | ||||
| settings.factp(2) = 1;                                   % 初值速度方差( [m/s] | ||||
| settings.factp(3:5) = deg2rad([1 1 20]);     % 初始i姿态方差 (roll,pitch,yaw) [rad] | ||||
| settings.factp(6) = 0.01;                               % 初始加速度零偏方差 [m/s^2] | ||||
| settings.factp(7) = deg2rad(0.01);                     % 初始角速度零偏方差 [rad/s] | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										25
									
								
								lib/ENU2LLA.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/ENU2LLA.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| function [lat, lon, h] = ENU2LLA(E, N, U, lat0, lon0, h0) | ||||
| 
 | ||||
| % ENU 转  经纬高  | ||||
| % lat0, lon0, h0: 起始点经纬高, 经纬度为rad, 高度为m | ||||
| % lat, lon, h 终点经纬度为rad, 高度为m | ||||
| % E, N ,U 系下增量,单位为m | ||||
| 
 | ||||
| %精确算法 | ||||
| % XYZ0 = ch_LLA2ECEF(lat0, lon0, h0); | ||||
| % XYZ1 = ch_LLA2ECEF(lat, lon, h); | ||||
| % dXYZ = XYZ1 - XYZ0; | ||||
| %  | ||||
| %  [~, ~, C_ECEF2ENU, ~]= ch_earth(lat0, lon0, h0); | ||||
| %  dENU = C_ECEF2ENU * dXYZ; | ||||
| %  E = dENU(1); | ||||
| %  N= dENU(2); | ||||
| %  U = dENU(3); | ||||
|   | ||||
|  %近似算法 | ||||
| R_0 = 6378137; %WGS84 Equatorial radius in meters | ||||
| clat = cos(lat0); | ||||
| h = h0 + U; | ||||
| lon = lon0 + E/clat/R_0; | ||||
| lat = lat0 + N/R_0 ; | ||||
| end | ||||
							
								
								
									
										108
									
								
								lib/allan.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/allan.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| 
 | ||||
| %%  ('NoiseDensity(角度随机游走)', N, 'RandomWalk(角速率随机游走)', K,'BiasInstability(零偏稳定性)', B); | ||||
| % omega 必须为 rad/s(陀螺), 加速度计: m/s^(2) | ||||
| % see Freescale AN: Allan Variance: Noise Analysis for Gyroscopes | ||||
| function [avar, tau, N, K, B] = allan(omega, Fs) | ||||
| 
 | ||||
| % t0 = 1/Fs; | ||||
| % theta = cumsum(omega, 1)*t0; | ||||
| %  | ||||
| % maxNumM = 200; | ||||
| % L = size(theta, 1); | ||||
| % maxM = 2.^floor(log2(L/2)); | ||||
| % m = logspace(log10(10), log10(maxM), maxNumM).'; | ||||
| % m = ceil(m); % m must be an integer. | ||||
| % m = unique(m); % Remove duplicates. | ||||
| %  | ||||
| % tau = m*t0; | ||||
| %  | ||||
| % avar = zeros(numel(m), 1); | ||||
| % for i = 1:numel(m) | ||||
| %     mi = m(i); | ||||
| %     avar(i,:) = sum( ... | ||||
| %         (theta(1+2*mi:L) - 2*theta(1+mi:L-mi) + theta(1:L-2*mi)).^2, 1); | ||||
| % end | ||||
| % avar = avar ./ (2*tau.^2 .* (L - 2*m)); | ||||
| 
 | ||||
| [avar,tau] = allanvar(omega, 'octave', Fs); | ||||
| adev  = sqrt(avar); | ||||
| 
 | ||||
| 
 | ||||
| %% Angle Random Walk | ||||
| slope = -0.5; | ||||
| logtau = log10(tau); | ||||
| logadev = log10(adev); | ||||
| dlogadev = diff(logadev) ./ diff(logtau); | ||||
| [~, i] = min(abs(dlogadev - slope)); | ||||
| 
 | ||||
| % Find the y-intercept of the line. | ||||
| b = logadev(i) - slope*logtau(i); | ||||
| 
 | ||||
| % Determine the angle random walk coefficient from the line. | ||||
| logN = slope*log10(1) + b; | ||||
| N = 10^logN; | ||||
| 
 | ||||
| % Plot the results. | ||||
| tauN = 1; | ||||
| lineN = N ./ sqrt(tau); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| %% Rate Random Walk | ||||
| slope = 0.5; | ||||
| logtau = log10(tau); | ||||
| logadev = log10(adev); | ||||
| dlogadev = diff(logadev) ./ diff(logtau); | ||||
| [~, i] = min(abs(dlogadev - slope)); | ||||
| 
 | ||||
| % Find the y-intercept of the line. | ||||
| b = logadev(i) - slope*logtau(i); | ||||
| 
 | ||||
| % Determine the rate random walk coefficient from the line. | ||||
| logK = slope*log10(3) + b; | ||||
| K = 10^logK; | ||||
| 
 | ||||
| % Plot the results. | ||||
| tauK = 3; | ||||
| lineK = K .* sqrt(tau/3); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| %% Bias Instability | ||||
| slope = 0; | ||||
| logtau = log10(tau); | ||||
| logadev = log10(adev); | ||||
| dlogadev = diff(logadev) ./ diff(logtau); | ||||
| 
 | ||||
| [~, i] = min(abs(dlogadev - slope)); | ||||
| [~, i] = min(adev); %yandld added | ||||
| 
 | ||||
| % Find the y-intercept of the line. | ||||
| b = logadev(i) - slope*logtau(i); | ||||
| 
 | ||||
| % Determine the bias instability coefficient from the line. | ||||
| scfB = sqrt(2*log(2)/pi); | ||||
| logB = b - log10(scfB); | ||||
| B = 10^logB; | ||||
| 
 | ||||
| % Plot the results. | ||||
| tauB = tau(i); | ||||
| lineB = B * scfB * ones(size(tau)); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| tauParams = [tauN, tauK, tauB]; | ||||
| params = [N, K, scfB*B]; | ||||
| figure; | ||||
| loglog(tau, adev, '-*', tau, [lineN, lineK, lineB], '--',  tauParams, params, 'o'); | ||||
| 
 | ||||
| title('Allan Deviation with Noise Parameters') | ||||
| xlabel('\tau') | ||||
| ylabel('\sigma(\tau)') | ||||
| legend('\sigma', '\sigma_N', '\sigma_K', '\sigma_B') | ||||
| text(tauParams, params, {'N', 'K', '0.664B'}) | ||||
| grid on | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										12
									
								
								lib/askew.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/askew.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| function m = askew(v)  | ||||
| % 生成反对称矩阵 | ||||
| % | ||||
| % Input: v - 3x1 vector | ||||
| % Output: m - v的反对称阵 | ||||
| %                    |  0   -v(3)  v(2) | | ||||
| %             m = | v(3)  0    -v(1) | | ||||
| %                    |-v(2)  v(1)  0    | | ||||
|     m = [ 0,     -v(3),   v(2);  | ||||
|           v(3),   0,     -v(1);  | ||||
|          -v(2),   v(1),   0     ]; | ||||
|        | ||||
							
								
								
									
										44
									
								
								lib/att_upt.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								lib/att_upt.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| 
 | ||||
| function out = att_upt(in, gyr, dt) | ||||
| % 输入当前姿态四元数和陀螺仪角速度,输出更新后的姿态四元数 | ||||
| % in为当前姿态四元数 | ||||
| % gyr是陀螺仪测量值 | ||||
| % dt 时间步长 | ||||
| 
 | ||||
| %% 单子样旋转矢量 | ||||
|  rv = gyr*dt;       % 旋转矢量 = 角速度 × 时间步长 | ||||
|  dq = rv2q(rv);  % 调用函数将旋转矢量转为四元数  | ||||
| 
 | ||||
| %% 不专业的做法 | ||||
| %                  dq(1) = 1; | ||||
| %                  dq(2) = rv(1)*0.5; | ||||
| %                  dq(3) = rv(2)*0.5; | ||||
| %                  dq(4) = rv(3)*0.5; | ||||
| 
 | ||||
|  out = qmul(in, dq); % 四元数相乘 当前姿态 × 增量 = 新姿态 | ||||
|  out = qnormlz(out); % 归一化 归一化防止数值漂移 | ||||
| 
 | ||||
|  %% 使用旋转矩阵更新 | ||||
| %  | ||||
| %  Cb2n = ch_q2m(in); | ||||
| %  theta = gyr*dt; | ||||
| %  | ||||
| % %C = eye(3) + ch_askew(theta); | ||||
| % C = ch_rv2m(theta); | ||||
| %  | ||||
| % Cb2n = Cb2n * C; | ||||
| %  | ||||
| % % 截断误差,保持正交化 GNSS与惯性及多传感器组合导航系统原理-第二版.pdf 公式 5.80 | ||||
| % c1 = Cb2n(1,:); | ||||
| % c2 = Cb2n(2,:); | ||||
| % c3 = Cb2n(3,:); | ||||
| % c1 = 2 / (1 + dot(c1,c1))*c1; | ||||
| % c2 = 2 / (1 + dot(c2,c2))*c2; | ||||
| % c3 = 2 / (1 + dot(c3,c3))*c3; | ||||
| % Cb2n = [c1; c2; c3]; | ||||
| %  | ||||
| % out = ch_m2q(Cb2n); | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										34
									
								
								lib/calbiration/acc_calibration.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/calbiration/acc_calibration.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| %% ACC Calibraiton | ||||
| 
 | ||||
| function [C, B] = acc_calibration(input) | ||||
| 
 | ||||
| 
 | ||||
| %% OPTION1: ST mehold AN4508 Application note Parameters and calibration of a low-g 3-axis accelerometer | ||||
| B = [1 0 0; 0 1 0; 0 0 1; -1 0 0; 0 -1 0; 0 0 -1]; | ||||
| A= [input -[ones(length(input), 1)]]; | ||||
| X = inv(A'*A) * A'*B; | ||||
| C = X(1:3,:)'; | ||||
| B = X(4,:)'; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| %% OPTION2: Time- and Computation-Efficient Calibration of MEMS 3D Accelerometers and Gyroscopes | ||||
| % Data: M x N  M: sample set(6),  N:acc X,Y,Z (3) | ||||
| % row1 = 1, 0, 0 case | ||||
| % row2 = 0, 1, 0 case | ||||
| % row3 = 0, 0, 1 case | ||||
| % row4 = -1, 0, 0 case | ||||
| % row5 = 0, -1, 0 case | ||||
| % row6 = 0, 0, -1 case | ||||
| 
 | ||||
| 
 | ||||
| % input = input'; | ||||
| % Asp = input(:,1:3); | ||||
| % Asn = input(:,4:6); | ||||
| %  | ||||
| % B = ((Asp + Asn)*[1 1 1]' / 6); | ||||
| % C = 2*(Asp - Asn)^(-1); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										112
									
								
								lib/calbiration/ch_magcal2d.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/calbiration/ch_magcal2d.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| clear; | ||||
| clc; | ||||
| close all; | ||||
| 
 | ||||
| % %% http://ztrw.mchtr.pw.edu.pl/en/least-squares-circle-fit/ | ||||
| %  | ||||
| %  | ||||
| % input = [ | ||||
| %   9.1667   0.5000   1.0000  | ||||
| %   0.3333   1.8750   1.0000  | ||||
| %  -7.8083   7.4167   1.0000  | ||||
| % -10.0167  11.2500   1.0000  | ||||
| % -15.5583  21.3750   1.0000  | ||||
| % -16.7500  31.6250   1.0000  | ||||
| % -13.4333  40.8333   1.0000  | ||||
| %   4.3917  53.0000   1.0000  | ||||
| %  15.3500  54.8750   1.0000  | ||||
| %  21.3083  54.6250   1.0000  | ||||
| %  32.5417  49.2083   1.0000  | ||||
| %  33.0417  38.8333   1.0000  | ||||
| %  32.8750  31.5417   1.0000  | ||||
| %  34.3083  19.3750   1.0000  | ||||
| %  25.2917  11.0417   1.0000  | ||||
| %  16.2500   5.0000   1.0000  | ||||
| %  11.2083   4.0000   1.0000  | ||||
| %     ]; | ||||
| %  | ||||
| %  | ||||
| % P = input(:,1:2)'; | ||||
| % n = length(P); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| clear; | ||||
| clc; | ||||
| close all; | ||||
| 
 | ||||
| 
 | ||||
| P = [1 7; 2 6; 5 8; 7 7; 9 5; 3 7]'; | ||||
| n= length(P); | ||||
| 
 | ||||
| 
 | ||||
| plot(P(1,:), P(2,:), '*'); | ||||
| 
 | ||||
| %build deisgn matrix | ||||
| A = [ P(1,:); P(2,:); ones(1,n)]'; | ||||
| b = sum(P.*P, 1)'; | ||||
| 
 | ||||
| % ls solution | ||||
| a= (A'*A)^(-1)*A'*b; | ||||
| 
 | ||||
| xc = 0.5*a(1); | ||||
| yc = 0.5*a(2); | ||||
| R  =  sqrt((a(1)^2+a(2)^2)/4+a(3)); | ||||
| R | ||||
| 
 | ||||
| viscircles([xc, yc],R); | ||||
| axis equal | ||||
| 
 | ||||
| 
 | ||||
| % max_min_ofs = max(P,[],2) + min(P, [], 2) ; | ||||
| % max_min_ofs = max_min_ofs / 2; | ||||
| % max_min_ofs | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| % %¸ø¶¨³õÖµ | ||||
| % xc = 5.3794; | ||||
| % yc = 7.2532; | ||||
| % r = 3.0370; | ||||
| % res = [xc; yc; r]; | ||||
| %  | ||||
| % max_iters = 20; | ||||
| %  | ||||
| % max_dif = 10^(-6); % max difference between consecutive results | ||||
| % for i = 1 : max_iters | ||||
| %     J = Jacobian(res(1), res(2), P); | ||||
| %     R = Residual(res(1), res(2), res(3), P); | ||||
| %     prev = res; | ||||
| %     res = res - (J'*J)^(-1)*J'*R; | ||||
| %     dif = abs((prev - res)./res);  | ||||
| %     if dif < max_dif | ||||
| %         fprintf('Convergence met after %d iterations\n', i); | ||||
| %         break; | ||||
| %     end | ||||
| % end | ||||
| % if i == max_iters | ||||
| %     fprintf('Convergence not reached after %d iterations\n', i); | ||||
| % end | ||||
| %  | ||||
| % xc = res(1); | ||||
| % yc = res(2); | ||||
| % r = res(3); | ||||
| %  | ||||
| % plot(P(:,1), P(:,2), '*') | ||||
| %  viscircles([xc, yc],r); | ||||
| %  axis equal | ||||
| %   | ||||
| % function J = Jacobian(xc, yc, P)  | ||||
| %     len = size(P); | ||||
| %     r = sqrt((xc - P(:,1)).^2 + (yc - P(:,2)).^2); | ||||
| %     J = [(xc - P(:,1))./r, (yc - P(:,2))./r, -ones(len(1), 1)]; | ||||
| % end | ||||
| 
 | ||||
| 
 | ||||
| function R = Residual(xc, yc, r, P) | ||||
|     R = sqrt((xc - P(:,1)).^2 + (yc - P(:,2)).^2) - r; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
|   | ||||
| %  | ||||
							
								
								
									
										185
									
								
								lib/calbiration/ellipsoid_fit.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								lib/calbiration/ellipsoid_fit.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,185 @@ | ||||
| function [A, b, magB, er]=ellipsoid_fit(XYZ,varargin) | ||||
| % Fit an (non)rotated ellipsoid or sphere to a set of xyz data points | ||||
| % XYZ: N(rows) x 3(cols), matrix of N data points (x,y,z) | ||||
| % optional flag f, default to 0 (fitting of rotated ellipsoid) | ||||
| 
 | ||||
| A = eye(3); | ||||
| 
 | ||||
|  x=XYZ(:,1); y=XYZ(:,2); z=XYZ(:,3);  | ||||
|  if nargin>1 | ||||
|      f=varargin{1}; | ||||
|  else f=0; | ||||
|  end | ||||
| 
 | ||||
|  if( f == 5) | ||||
| [A, b, magB, er, ispd] = correctEllipsoid4(x,y,z); | ||||
|  end | ||||
| 
 | ||||
| 
 | ||||
|  if( f == 1) | ||||
| [A, b, magB, er, ispd] = correctEllipsoid7(x,y,z); | ||||
|  end | ||||
| 
 | ||||
|  if( f == 0) | ||||
| [A, b, magB, er, ispd] = correctEllipsoid10(x,y,z); | ||||
|  end | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| function [Winv, V, B, er, ispd] = correctEllipsoid4(x,y,z) | ||||
| % R is the identity | ||||
| 
 | ||||
|     b = x.*x + y.*y + z.*z; | ||||
| 
 | ||||
|     A = [x,y,z]; | ||||
|     A = [A ones(numel(x),1)]; | ||||
| 
 | ||||
|     soln = (A'*A)^(-1)*A'*b; | ||||
|     Winv = eye(3); | ||||
|     V = 0.5*soln(1:3); | ||||
|     B = sqrt(soln(4) + sum(V.*V)); | ||||
|      | ||||
| %      res = residual(Winv, V, B,  [x,y,z]) | ||||
| %       er = (1/(2*B*B))*sqrt(res.'*res/numel(x)); | ||||
|     if nargout > 3 | ||||
|         res = A*soln - b; | ||||
|         er = (1/(2*B*B) * sqrt( res.'*res / numel(x))); | ||||
|         ispd = 1; | ||||
|     else | ||||
|         er = -ones(1); | ||||
|         ispd = -1; | ||||
|     end | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| function [Winv, V, B, er, ispd] = correctEllipsoid7(x,y,z) | ||||
| 
 | ||||
|     d =  [x.*x,  y.*y,  z.*z, x, y, z, ones(size(x))]; | ||||
| 
 | ||||
|     dtd = d.' * d; | ||||
| 
 | ||||
|     [evc, evlmtx] = eig(dtd); | ||||
| 
 | ||||
|     eigvals = diag(evlmtx); | ||||
|     [~, idx] = min(eigvals); | ||||
| 
 | ||||
|     beta = evc(:,idx); %solution has smallest eigenvalue | ||||
|     A = diag(beta(1:3)); | ||||
|     dA = det(A); | ||||
| 
 | ||||
|     if dA < 0 | ||||
|         A = -A; | ||||
|         beta = -beta; | ||||
|         dA = -dA; %Compensate for -A. | ||||
|     end | ||||
|     V = -0.5*(beta(4:6)./beta(1:3)); %hard iron offset | ||||
| 
 | ||||
|     B = sqrt(abs(sum([... | ||||
|         A(1,1)*V(1)*V(1), ... | ||||
|         A(2,2)*V(2)*V(2), ... | ||||
|         A(3,3)*V(3)*V(3), ... | ||||
|         -beta(end)] ... | ||||
|     ))); | ||||
|    | ||||
| 
 | ||||
|     % We correct Winv and B by det(A) because we don't know which has the | ||||
|     % gain. By convention, normalize A. | ||||
| 
 | ||||
|     det3root = nthroot(dA,3); | ||||
|     det6root = sqrt(det3root); | ||||
|     Winv = sqrtm(A./det3root); | ||||
|     B = B./det6root; | ||||
|      | ||||
|     if nargout > 3 | ||||
|         res = residual(Winv,V,B, [x,y,z]); | ||||
|         er = (1/(2*B*B))*sqrt(res.'*res/numel(x)); | ||||
|         [~,p] = chol(A); | ||||
|         ispd = (p == 0); | ||||
|     else | ||||
|         er = -ones(1, 'like',x); | ||||
|         ispd = -1; | ||||
|     end | ||||
| 
 | ||||
|      | ||||
|      | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| function [Winv, V,B,er, ispd] = correctEllipsoid10(x,y,z) | ||||
| 
 | ||||
|     d = [... | ||||
|         x.*x, ... | ||||
|         2*x.*y, ... | ||||
|         2*x.*z, ... | ||||
|         y.*y, ... | ||||
|         2*y.*z, ... | ||||
|         z.*z, ... | ||||
|         x, ... | ||||
|         y, ... | ||||
|         z, ... | ||||
|         ones(size(x))]; | ||||
| 
 | ||||
|     dtd = d.' * d; | ||||
| 
 | ||||
|     [evc, evlmtx] = eig(dtd); | ||||
| 
 | ||||
|     eigvals = diag(evlmtx); | ||||
|     [~, idx] = min(eigvals); | ||||
| 
 | ||||
|     beta = evc(:,idx); %solution has smallest eigenvalue | ||||
| 
 | ||||
|     A = beta([1 2 3; 2 4 5; 3 5 6]); %make symmetric | ||||
|     dA = det(A); | ||||
| 
 | ||||
|     if dA < 0 | ||||
|         A = -A; | ||||
|         beta = -beta; | ||||
|         dA = -dA; %Compensate for -A. | ||||
|     end | ||||
| 
 | ||||
|     V = -0.5*(A^(-1)*beta(7:9)); %hard iron offset | ||||
| 
 | ||||
|     B = sqrt(abs(sum([... | ||||
|         A(1,1)*V(1)*V(1), ... | ||||
|         2*A(2,1)*V(2)*V(1), ... | ||||
|         2*A(3,1)*V(3)*V(1), ... | ||||
|         A(2,2)*V(2)*V(2), ... | ||||
|         2*A(3,2)*V(2)*V(3), ... | ||||
|         A(3,3)*V(3)*V(3), ... | ||||
|         -beta(end)] ... | ||||
|     ))); | ||||
|    | ||||
|     % We correct Winv and B by det(A) because we don't know which has the | ||||
|     % gain. By convention, normalize A. | ||||
| 
 | ||||
|     det3root = nthroot(dA,3); | ||||
|     det6root = sqrt(det3root); | ||||
|     Winv = sqrtm(A./det3root); | ||||
|     B = B./det6root; | ||||
|      | ||||
|     if nargout > 3  | ||||
|         res = residual(Winv,V,B, [x,y,z]); | ||||
|         er = (1/(2*B*B))*sqrt(res.'*res/numel(x)); | ||||
|         [~,p] = chol(A); | ||||
|         ispd = (p == 0); | ||||
|     else | ||||
|         er = -ones(1, 'like',x); | ||||
|         ispd = -1; | ||||
|     end | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| function r = residual(Winv, V, B, data) | ||||
| % Residual error after correction | ||||
| 
 | ||||
| spherept = (Winv * (data.' - V)).'; % a point on the unit sphere | ||||
| radsq = sum(spherept.^2,2); | ||||
| 
 | ||||
| r = radsq - B.^2; | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										207
									
								
								lib/calbiration/ellipsoid_fit_new.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								lib/calbiration/ellipsoid_fit_new.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,207 @@ | ||||
| function [ center, radii, evecs, v, chi2 ] = ellipsoid_fit_new( X, equals ) | ||||
| % | ||||
| % Fit an ellispoid/sphere/paraboloid/hyperboloid to a set of xyz data points: | ||||
| % | ||||
| %   [center, radii, evecs, pars ] = ellipsoid_fit( X ) | ||||
| %   [center, radii, evecs, pars ] = ellipsoid_fit( [x y z] ); | ||||
| %   [center, radii, evecs, pars ] = ellipsoid_fit( X, 1 ); | ||||
| %   [center, radii, evecs, pars ] = ellipsoid_fit( X, 2, 'xz' ); | ||||
| %   [center, radii, evecs, pars ] = ellipsoid_fit( X, 3 ); | ||||
| % | ||||
| % Parameters: | ||||
| % * X, [x y z]   - Cartesian data, n x 3 matrix or three n x 1 vectors | ||||
| % * flag         - '' or empty fits an arbitrary ellipsoid (default), | ||||
| %                - 'xy' fits a spheroid with x- and y- radii equal | ||||
| %                - 'xz' fits a spheroid with x- and z- radii equal | ||||
| %                - 'xyz' fits a sphere | ||||
| %                - '0' fits an ellipsoid with its axes aligned along [x y z] axes | ||||
| %                - '0xy' the same with x- and y- radii equal | ||||
| %                - '0xz' the same with x- and z- radii equal | ||||
| % | ||||
| % Output: | ||||
| % * center    -  ellispoid or other conic center coordinates [xc; yc; zc] | ||||
| % * radii     -  ellipsoid or other conic radii [a; b; c] | ||||
| % * evecs     -  the radii directions as columns of the 3x3 matrix | ||||
| % * v         -  the 10 parameters describing the ellipsoid / conic algebraically:  | ||||
| %                Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + 2Hy + 2Iz + J = 0 | ||||
| % * chi2      -  residual sum of squared errors (chi^2), this chi2 is in the  | ||||
| %                coordinate frame in which the ellipsoid is a unit sphere. | ||||
| % | ||||
| % Author: | ||||
| % Yury Petrov, Oculus VR | ||||
| % Date: | ||||
| % September, 2015 | ||||
| % | ||||
| 
 | ||||
| %reference  | ||||
| narginchk( 1, 3 ) ;  % check input arguments | ||||
| if nargin == 1 | ||||
|     equals = ''; % no constraints by default | ||||
| end | ||||
|      | ||||
| if size( X, 2 ) ~= 3 | ||||
|     error( 'Input data must have three columns!' ); | ||||
| else | ||||
|     x = X( :, 1 ); | ||||
|     y = X( :, 2 ); | ||||
|     z = X( :, 3 ); | ||||
| end | ||||
| 
 | ||||
| % need nine or more data points | ||||
| if length( x ) < 9 && strcmp( equals, '' )  | ||||
|    error( 'Must have at least 9 points to fit a unique ellipsoid' ); | ||||
| end | ||||
| if length( x ) < 8 && ( strcmp( equals, 'xy' ) || strcmp( equals, 'xz' ) ) | ||||
|    error( 'Must have at least 8 points to fit a unique ellipsoid with two equal radii' ); | ||||
| end | ||||
| if length( x ) < 6 && strcmp( equals, '0' ) | ||||
|    error( 'Must have at least 6 points to fit a unique oriented ellipsoid' ); | ||||
| end | ||||
| if length( x ) < 5 && ( strcmp( equals, '0xy' ) || strcmp( equals, '0xz' ) ) | ||||
|    error( 'Must have at least 5 points to fit a unique oriented ellipsoid with two equal radii' ); | ||||
| end | ||||
| if length( x ) < 4 && strcmp( equals, 'xyz' ); | ||||
|    error( 'Must have at least 4 points to fit a unique sphere' ); | ||||
| end | ||||
| 
 | ||||
| % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + | ||||
| % 2Hy + 2Iz + J = 0 and A + B + C = 3 constraint removing one extra | ||||
| % parameter | ||||
| if strcmp( equals, '' ) | ||||
|     D = [ x .* x + y .* y - 2 * z .* z, ... | ||||
|         x .* x + z .* z - 2 * y .* y, ... | ||||
|         2 * x .* y, ... | ||||
|         2 * x .* z, ... | ||||
|         2 * y .* z, ... | ||||
|         2 * x, ... | ||||
|         2 * y, ... | ||||
|         2 * z, ... | ||||
|         1 + 0 * x ];  % ndatapoints x 9 ellipsoid parameters | ||||
| elseif strcmp( equals, 'xy' ) | ||||
|     D = [ x .* x + y .* y - 2 * z .* z, ... | ||||
|         2 * x .* y, ... | ||||
|         2 * x .* z, ... | ||||
|         2 * y .* z, ... | ||||
|         2 * x, ... | ||||
|         2 * y, ... | ||||
|         2 * z, ... | ||||
|         1 + 0 * x ];  % ndatapoints x 8 ellipsoid parameters | ||||
| elseif strcmp( equals, 'xz' ) | ||||
|     D = [ x .* x + z .* z - 2 * y .* y, ... | ||||
|         2 * x .* y, ... | ||||
|         2 * x .* z, ... | ||||
|         2 * y .* z, ... | ||||
|         2 * x, ... | ||||
|         2 * y, ... | ||||
|         2 * z, ... | ||||
|         1 + 0 * x ];  % ndatapoints x 8 ellipsoid parameters | ||||
|     % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Gx + 2Hy + 2Iz = 1 | ||||
| elseif strcmp( equals, '0' ) | ||||
|     D = [ x .* x + y .* y - 2 * z .* z, ... | ||||
|           x .* x + z .* z - 2 * y .* y, ... | ||||
|           2 * x, ... | ||||
|           2 * y, ...  | ||||
|           2 * z, ...  | ||||
|           1 + 0 * x ];  % ndatapoints x 6 ellipsoid parameters | ||||
|     % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Gx + 2Hy + 2Iz = 1, | ||||
|     % where A = B or B = C or A = C | ||||
| elseif strcmp( equals, '0xy' ) | ||||
|     D = [ x .* x + y .* y - 2 * z .* z, ... | ||||
|           2 * x, ... | ||||
|           2 * y, ...  | ||||
|           2 * z, ...  | ||||
|           1 + 0 * x ];  % ndatapoints x 5 ellipsoid parameters | ||||
| elseif strcmp( equals, '0xz' ) | ||||
|     D = [ x .* x + z .* z - 2 * y .* y, ... | ||||
|           2 * x, ... | ||||
|           2 * y, ...  | ||||
|           2 * z, ...  | ||||
|           1 + 0 * x ];  % ndatapoints x 5 ellipsoid parameters | ||||
|      % fit sphere in the form A(x^2 + y^2 + z^2) + 2Gx + 2Hy + 2Iz = 1 | ||||
| elseif strcmp( equals, 'xyz' ) | ||||
|     D = [ 2 * x, ... | ||||
|           2 * y, ...  | ||||
|           2 * z, ...  | ||||
|           1 + 0 * x ];  % ndatapoints x 4 ellipsoid parameters | ||||
| else | ||||
|     error( [ 'Unknown parameter value ' equals '!' ] ); | ||||
| end | ||||
| 
 | ||||
| % solve the normal system of equations | ||||
| d2 = x .* x + y .* y + z .* z; % the RHS of the llsq problem (y's) | ||||
| u = ( D' * D ) \ ( D' * d2 );  % solution to the normal equations | ||||
| 
 | ||||
| % find the residual sum of errors | ||||
| % chi2 = sum( ( 1 - ( D * u ) ./ d2 ).^2 ); % this chi2 is in the coordinate frame in which the ellipsoid is a unit sphere. | ||||
| 
 | ||||
| % find the ellipsoid parameters | ||||
| % convert back to the conventional algebraic form | ||||
| if strcmp( equals, '' ) | ||||
|     v(1) = u(1) +     u(2) - 1; | ||||
|     v(2) = u(1) - 2 * u(2) - 1; | ||||
|     v(3) = u(2) - 2 * u(1) - 1; | ||||
|     v( 4 : 10 ) = u( 3 : 9 ); | ||||
| elseif strcmp( equals, 'xy' ) | ||||
|     v(1) = u(1) - 1; | ||||
|     v(2) = u(1) - 1; | ||||
|     v(3) = -2 * u(1) - 1; | ||||
|     v( 4 : 10 ) = u( 2 : 8 ); | ||||
| elseif strcmp( equals, 'xz' ) | ||||
|     v(1) = u(1) - 1; | ||||
|     v(2) = -2 * u(1) - 1; | ||||
|     v(3) = u(1) - 1; | ||||
|     v( 4 : 10 ) = u( 2 : 8 ); | ||||
| elseif strcmp( equals, '0' ) | ||||
|     v(1) = u(1) +     u(2) - 1; | ||||
|     v(2) = u(1) - 2 * u(2) - 1; | ||||
|     v(3) = u(2) - 2 * u(1) - 1; | ||||
|     v = [ v(1) v(2) v(3) 0 0 0 u( 3 : 6 )' ]; | ||||
| 
 | ||||
| elseif strcmp( equals, '0xy' ) | ||||
|     v(1) = u(1) - 1; | ||||
|     v(2) = u(1) - 1; | ||||
|     v(3) = -2 * u(1) - 1; | ||||
|     v = [ v(1) v(2) v(3) 0 0 0 u( 2 : 5 )' ]; | ||||
| elseif strcmp( equals, '0xz' ) | ||||
|     v(1) = u(1) - 1; | ||||
|     v(2) = -2 * u(1) - 1; | ||||
|     v(3) = u(1) - 1; | ||||
|     v = [ v(1) v(2) v(3) 0 0 0 u( 2 : 5 )' ]; | ||||
| elseif strcmp( equals, 'xyz' ) | ||||
|     v = [ -1 -1 -1 0 0 0 u( 1 : 4 )' ]; | ||||
| end | ||||
| v = v'; | ||||
| 
 | ||||
| % form the algebraic form of the ellipsoid | ||||
| A = [ v(1) v(4) v(5) v(7); ... | ||||
|       v(4) v(2) v(6) v(8); ... | ||||
|       v(5) v(6) v(3) v(9); ... | ||||
|       v(7) v(8) v(9) v(10) ]; | ||||
| % find the center of the ellipsoid | ||||
| center = -A( 1:3, 1:3 ) \ v( 7:9 ); | ||||
| % form the corresponding translation matrix | ||||
| T = eye( 4 ); | ||||
| T( 4, 1:3 ) = center'; | ||||
| % translate to the center | ||||
| R = T * A * T'; | ||||
| % solve the eigenproblem | ||||
| [ evecs, evals ] = eig( R( 1:3, 1:3 ) / -R( 4, 4 ) ); | ||||
| radii = sqrt( 1 ./ diag( abs( evals ) ) ); | ||||
| sgns = sign( diag( evals ) ); | ||||
| radii = radii .* sgns; | ||||
| 
 | ||||
| % calculate difference of the fitted points from the actual data normalized by the conic radii | ||||
| d = [ x - center(1), y - center(2), z - center(3) ]; % shift data to origin | ||||
| d = d * evecs; % rotate to cardinal axes of the conic; | ||||
| d = [ d(:,1) / radii(1), d(:,2) / radii(2), d(:,3) / radii(3) ]; % normalize to the conic radii | ||||
| chi2 = sum( abs( 1+0*x - sum( d.^2, 2 ) ) ); | ||||
|   | ||||
| if abs( v(end) ) > 1e-6 | ||||
|     v = -v / v(end); % normalize to the more conventional form with constant term = -1 | ||||
| else | ||||
|     v = -sign( v(end) ) * v; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										29
									
								
								lib/calbiration/gyr_calibration.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/calbiration/gyr_calibration.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| %% GYR Calibraiton | ||||
| % example: | ||||
| % input = [ | ||||
| %     65.2191    0.1712    0.4618 | ||||
| %    -0.0901   71.9079   -0.0728 | ||||
| %    -0.5425   -0.1436   71.7273 | ||||
| %   -65.0873   -0.1008   -0.4814 | ||||
| %     0.1573  -71.9432    0.0436 | ||||
| %     0.6128    0.2009  -71.7076 | ||||
| %     ]; | ||||
| %  | ||||
| %  theory = [65.5618  0 0; 0 72.0649  0; 0 0 72.1298 ; -65.5081 0 0; 0 -72.1298 0; 0 0 -72.0649]; | ||||
| % gyr_calibration(input, theory) | ||||
| function [C, B] = gyr_calibration(input, ref) | ||||
| 
 | ||||
| %%  ST mehold AN4508 Application note Parameters and calibration of a low-g 3-axis accelerometer | ||||
| A= [input -[ones(length(input), 1)]]; | ||||
| B = ref; | ||||
| 
 | ||||
| X = inv(A'*A) * A'*B; | ||||
| C = X(1:3,:)'; | ||||
| B = X(4,:)'; | ||||
| 
 | ||||
| 
 | ||||
| %% Time- and Computation-Efficient Calibration of MEMS 3D Accelerometers and Gyroscopes  | ||||
| % TBD | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										53
									
								
								lib/data_import.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								lib/data_import.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| function dataset = data_import(path) | ||||
| 
 | ||||
| tbl = readtable(path); | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'AccX')) | ||||
|     dataset.imu.acc(1,:) = tbl.AccX'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'AccY')) | ||||
|     dataset.imu.acc(2,:) = tbl.AccY'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'AccZ')) | ||||
|     dataset.imu.acc(3,:) = tbl.AccZ'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'GyrX')) | ||||
|     dataset.imu.gyr(1,:) = tbl.GyrX'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'GyrY')) | ||||
|     dataset.imu.gyr(2,:) = tbl.GyrY'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'GyrZ')) | ||||
|     dataset.imu.gyr(3,:) = tbl.GyrZ'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'MagX')) | ||||
|     dataset.imu.mag(1,:) = tbl.MagX'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'MagY')) | ||||
|     dataset.imu.mag(2,:) = tbl.MagY'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'MagZ')) | ||||
|     dataset.imu.mag(3,:) = tbl.MagZ'; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'Roll')) | ||||
|     dataset.eul.roll = tbl.Roll'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'Pitch')) | ||||
|     dataset.eul.pitch = tbl.Pitch'; | ||||
| end | ||||
| 
 | ||||
| if sum(ismember(tbl.Properties.VariableNames,'Yaw')) | ||||
|     dataset.eul.yaw = tbl.Yaw'; | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										138
									
								
								lib/dip13.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								lib/dip13.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | ||||
| % syms  b1 b2 b3 real | ||||
| % syms  g1 g2 g3 real | ||||
| % syms  v1 v2 v3 real | ||||
| % syms  lambda real | ||||
| % syms h | ||||
| % syms  l11 l12 l13 l21 l22 l23 l31 l32 l33 real | ||||
| % L = [l11 l23 l13; l21 l22 l23; l31 l32 l33]; | ||||
| % B = [b1 b2 b3]'; | ||||
| % V = [v1 v2 v3]'; | ||||
| % G = [g1 g2 g3]'; | ||||
| %  | ||||
| % f = V'*L'*L*V - 2*V'*L'*L*B + B'*L'*L*B - h^2  | ||||
| % j = jacobian(f, [l11 l12 l13 l21 l22 l23 l31 l32 l33 b1 b2 b3 lamda]); | ||||
| % collect(j(1,1), [l11])  | ||||
| %  | ||||
| % alp = L*(V - B); | ||||
| % beta = V-B; | ||||
| % 2*alp(1)*beta(1); | ||||
| % collect(ans,[l11]) | ||||
| 
 | ||||
|  function [mis, bias, lamda, inter, residual] = dip13 (acc, mag, mag_norm, epsilon) | ||||
| %函数的功能:using DIP(dual inner product mehold to caluate mag) | ||||
| %函数的描述:  Calibration of tri-axial magnetometer using vector observations and  inner products    or       Calibration and Alignment of Tri-Axial Magnetometers for Attitude Determination | ||||
| %函数的使用:[mis, bias, lamda, inter, J] = dip (acc, mag, mag_norm, epsilon) | ||||
| %输入: | ||||
| %     input1: acc: raw acc | ||||
| %     input2: mag: raw mag | ||||
| 
 | ||||
| %输出: | ||||
| %     mis: misalign matrix | ||||
| %     bias: bias | ||||
| %     lamda: |reference_vector| * |mag_vector| * cos(theta) | ||||
| %     inter: interation | ||||
| %    J: cost function array | ||||
| 
 | ||||
|     mis = eye(3); | ||||
|     bias = zeros(1,3); | ||||
|     lamda = cos(deg2rad(60)); | ||||
|      | ||||
|     mu = 0.001; % damp | ||||
|     inter = 100; | ||||
|     last_e = 100; | ||||
|     last_J = 100; | ||||
|     | ||||
|     % [l11 l12 l13 l21 l22 l23 l31 l32 l33 b1 b2 b3 lamda], lamba = cos(inclincation) | ||||
|     x = [1 0 0 0 1 0 0 0 1 0 0 0 1]; | ||||
|      | ||||
|     % using max-min mehold to get a inital bias | ||||
|    x(10:12) =  (max(mag) + min(mag)) / 2; | ||||
|      | ||||
|      [last_J, ~, ~] = lm_dip(x, mag, acc, mag_norm); | ||||
|       | ||||
|     for i = 1:inter | ||||
|         [residual(i), Jacobi, e] = lm_dip(x, mag, acc, mag_norm); | ||||
|          x = x - (inv((Jacobi' * Jacobi + mu * eye(length(x)))) * Jacobi' * e)'; | ||||
|         %x = x - mu*(Jacobi' * e)'; | ||||
| 
 | ||||
|         if(residual(i) <= last_J) | ||||
|             mu = 0.1 * mu; | ||||
|         else | ||||
|             mu = 10 * mu; | ||||
|         end | ||||
|          | ||||
|        if((abs(norm(e) - norm(last_e))) < epsilon) | ||||
|              mis =[x(1:3); x(4:6); x(7:9)]; | ||||
|              bias = x(10:12)'; | ||||
|              lamda = x(13); | ||||
|              inter = i; | ||||
|            break; | ||||
|        end | ||||
|         | ||||
|        last_e  = e; | ||||
|        last_J = residual(i); | ||||
|     end | ||||
|      | ||||
| end | ||||
|   | ||||
| %% Function | ||||
| % Jval:  error | ||||
| % gradient :  gradient of cost func | ||||
| % e:  Fx | ||||
| 
 | ||||
| function[residual, gradient, e]=lm_dip(x, mB, gB, h) | ||||
| n = length(mB); | ||||
| e = zeros(n*2, 1); | ||||
| gradient = zeros(n*2, 13); | ||||
|  L =[x(1:3); x(4:6); x(7:9)]; | ||||
|  b = x(10:12)'; | ||||
|     for i = 1:n | ||||
| 
 | ||||
|         v = mB(i, :)'; | ||||
|         g = gB(i , :)'; | ||||
| 
 | ||||
|         % caluate e  | ||||
|         e(i , :) = v'*L'*L*v -2*v'*L'*L*b + b'*L'*L*b - h^2; | ||||
|      %   e(i , :) = (L*(v - b))' * (L*(v - b)) - h^2; | ||||
|       %  e(n+ i, :) = g'*L*v - g'*L*b - h*norm(g)*x(13); | ||||
|         e(n+ i, :) = g'*L*(v-b) -  h*norm(g)*x(13); | ||||
| 
 | ||||
|         alpa = L * (v - b); | ||||
|         beta = v - b; | ||||
| 
 | ||||
|         % caluate J  1- r | ||||
|         gradient(i, 1) = 2 * alpa(1) * beta(1); | ||||
|         gradient(i, 2) = 2 * alpa(1) * beta(2); | ||||
|         gradient(i, 3) = 2 * alpa(1) * beta(3); | ||||
|         gradient(i, 4) = 2 * alpa(2) * beta(1); | ||||
|         gradient(i, 5) = 2 * alpa(2) * beta(2); | ||||
|         gradient(i, 6) = 2 * alpa(2) * beta(3); | ||||
|         gradient(i, 7) = 2 * alpa(3) * beta(1); | ||||
|         gradient(i, 8) = 2 * alpa(3) * beta(2); | ||||
|         gradient(i, 9) = 2 * alpa(3) * beta(3); | ||||
| 
 | ||||
|         gradient(i, 10) = -2 * (alpa(1) * L(1,1) + alpa(2) * L(2,1) + alpa(3) * L(3,1));  | ||||
|         gradient(i, 11) = -2 * (alpa(1) * L(1,2) + alpa(2) * L(2,2) + alpa(3) * L(3,2));  | ||||
|         gradient(i, 12) = -2 * (alpa(1) * L(1,3) + alpa(2) * L(2,3) + alpa(3) * L(3,3));  | ||||
|         gradient(i, 13) = 0; | ||||
| 
 | ||||
|         % caluate J  r- 2r | ||||
|         gradient(n + i, 1) =  g(1) * beta(1); | ||||
|         gradient(n + i, 2) =  g(1) * beta(2); | ||||
|         gradient(n + i, 3) =  g(1) * beta(3); | ||||
|         gradient(n + i, 4) =  g(2) * beta(1); | ||||
|         gradient(n + i, 5) =  g(2) * beta(2); | ||||
|         gradient(n + i, 6) =  g(2) * beta(3); | ||||
|         gradient(n + i, 7) =  g(3) * beta(1); | ||||
|         gradient(n + i, 8) =  g(3) * beta(2); | ||||
|         gradient(n + i, 9) =  g(3) * beta(3); | ||||
|         gradient(n + i, 10) = - (g(1) * L(1,1) + g(2) * L(2,1) + g(3) * L(3,1));  | ||||
|         gradient(n + i, 11) = - (g(1) * L(1,2) + g(2) * L(2,2) + g(3) * L(3,2));  | ||||
|         gradient(n + i, 12) = - (g(1) * L(1,3) + g(2) * L(2,3) + g(3) * L(3,3));  | ||||
|         gradient(n + i, 13) = -norm(v) * norm(g); | ||||
|     end  | ||||
| 
 | ||||
|     residual = e' * e; | ||||
| end | ||||
| 
 | ||||
|   | ||||
							
								
								
									
										98
									
								
								lib/dip5.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/dip5.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| % using DIP mehold, only compute bias, norm_h, lamda(cos(inclination)), | ||||
| % modifed from DIP13 | ||||
| 
 | ||||
| % %% moudle DIP5 | ||||
| % syms  b1 b2 b3 real | ||||
| % syms  g1 g2 g3 real | ||||
| % syms  v1 v2 v3 real | ||||
| % syms  lambda real | ||||
| % syms norm_h norm_g real | ||||
| % B = [b1 b2 b3]'; | ||||
| % V = [v1 v2 v3]'; | ||||
| % G = [g1 g2 g3]'; | ||||
| % % %G'*(V - B) - CONST | ||||
| %  | ||||
| %  f1= (V - B)' * (V - B) - norm_h^2; | ||||
| %  j1 = jacobian(f1, [B' norm_h lambda]); | ||||
| %  collect(j1, B) ; | ||||
| %   | ||||
| %  f2 = G' * (V - B) - norm_g * norm_h * lambda; | ||||
| %   | ||||
| %  f = f1 + f2; | ||||
| %  j2 = jacobian(f2, [B' norm_h lambda]); | ||||
| %  collect(j2, B); | ||||
| %  | ||||
| %  | ||||
| % f1 | ||||
| % j1 | ||||
| %  | ||||
| % f2  | ||||
| % j2 | ||||
| 
 | ||||
|  function [mis, bias, norm_h, lamda, inter, J] = dip5 (acc, mag, x, epsilon) | ||||
|     % initalize value | ||||
|     mis = eye(3); | ||||
|     bias = zeros(1,3); | ||||
|     lamda = cos(deg2rad(60)); | ||||
|      | ||||
|     mu = 0.000; % damp | ||||
|     inter = 100; | ||||
|     last_e = 100; | ||||
|   | ||||
|     for i = 1:inter | ||||
|         [J(i), Jacobi, e] = compute_cost_and_jacob (x, mag, acc); | ||||
|          x = x - (inv((Jacobi' * Jacobi + mu * eye(length(x)))) * Jacobi' * e)'; | ||||
|          | ||||
|        if((abs(norm(e) - norm(last_e))) < epsilon) | ||||
|              bias = x(1:3)'; | ||||
|              lamda = x(5); | ||||
|              inter = i; | ||||
|              norm_h = x(4); | ||||
|            break; | ||||
|        end | ||||
|        last_e  = e; | ||||
|     end | ||||
|      | ||||
| end | ||||
|   | ||||
| %% Function | ||||
| % residual:  error | ||||
| % J :  gradient of cost func | ||||
| % e:  bx by bz lamada | ||||
| % X: [Bx By Bz norm_h lambada] | ||||
| 
 | ||||
| function[residual, J, e]=compute_cost_and_jacob(x, mB, gB) | ||||
|     n = length(mB); | ||||
|     e = zeros(n * 2, 1); | ||||
|     J = zeros(n * 2, 5); | ||||
|     b = x(1:3)'; | ||||
|     norm_h = x(4); | ||||
|     lamda = x(5); | ||||
|      | ||||
|     for i = 1:n | ||||
|         v = mB(i, :)'; | ||||
|         g = gB(i , :)'; | ||||
|          | ||||
|         % caluate e | ||||
|         e(i , :) = (v - b)' * (v - b) - norm_h^2; | ||||
|          e(n+ i, :) = g' * (v - b) - (norm_h * norm(g) * lamda); | ||||
| 
 | ||||
|         % caluate J  1- r | ||||
|         J(i, 1) = 2 * (b(1) - v(1)); | ||||
|         J(i, 2) = 2 * (b(2) - v(2)); | ||||
|         J(i, 3) = 2 * (b(3) - v(3)); | ||||
|         J(i, 4) = -2 * norm_h; | ||||
|         J(i, 5) = 0; | ||||
| 
 | ||||
|         % caluate J  r- 2r | ||||
|         J(n + i, 1) =  -g(1); | ||||
|         J(n + i, 2) =  -g(2); | ||||
|         J(n + i, 3) =  -g(3);  | ||||
|         J(n + i, 4) =  -lamda * norm(g); | ||||
|         J(n + i, 5) =  -norm_h * norm(g); | ||||
|     end  | ||||
| 
 | ||||
|     residual = e' * e; | ||||
| end | ||||
| 
 | ||||
|   | ||||
							
								
								
									
										57
									
								
								lib/dpi.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/dpi.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| %% A new calibration method for tri-axial field sensors in strap-down navigation systems   µã»ý²»±ä·¨ | ||||
| % Accelerometer: acc is sensor frame, n= number of obs,   m = 3(x y z) | ||||
| % Magnetometer: raw mag in sensor frame | ||||
| % A: mag misalignment matrix | ||||
| % b: mag bias | ||||
| 
 | ||||
|  function [mis bias] = dpi (acc, mag, dot_product) | ||||
| 
 | ||||
|     nbos = length(acc); | ||||
|      | ||||
|     % x = l11 l12 l13 l21 l22 l23 l31 l32 l33 b1 b2 b3 | ||||
|     A(:,1) = acc(:,1).* mag(:,1); | ||||
|     A(:,2) = acc(:,1).* mag(:,2); | ||||
|     A(:,3) = acc(:,1).* mag(:,3); | ||||
|     A(:,4) = acc(:,2).* mag(:,1); | ||||
|     A(:,5) = acc(:,2).* mag(:,2); | ||||
|     A(:,6) = acc(:,2).* mag(:,3); | ||||
|     A(:,7) = acc(:,3).* mag(:,1); | ||||
|     A(:,8) = acc(:,3).* mag(:,2); | ||||
|     A(:,9) = acc(:,3).* mag(:,3); | ||||
|     A(:,10) = -acc(:,1); | ||||
|     A(:,11) = -acc(:,2); | ||||
|     A(:,12) = -acc(:,3); | ||||
| 
 | ||||
|     %Y = ones(length(gB),1) * dot(gmOb, gReference); | ||||
|     Y = ones(nbos,1) * dot_product; | ||||
|     B = inv(A'*A)*A'*Y;  | ||||
|     % or you can use lsqlin(A,Y) | ||||
|      | ||||
|     mis = [B(1:3)'; B(4:6)'; B(7:9)']; | ||||
|     bias = [B(10) B(11) B(12)]; | ||||
|  end | ||||
|   | ||||
| %% DPI module | ||||
| % syms  l11 l12 l13 l21 l22 l23 l31 l32 l33 real | ||||
| % syms  b1 b2 b3 real | ||||
| % syms  g1 g2 g3 real | ||||
| % syms  v1 v2 v3 real | ||||
| % syms  CONST real | ||||
| 
 | ||||
| % b: bias | ||||
| % l11 - l33: mis align | ||||
| % v magnormetor reading | ||||
| % g graivity | ||||
| 
 | ||||
| % model | ||||
| % L = sym('l%d%d', [3 3]); | ||||
| % B = [b1 b2 b3]'; | ||||
| % V = [v1 v2 v3]'; | ||||
| % G = [g1 g2 g3]'; | ||||
| % G'*(L*V - B) - CONST | ||||
| % %G'*(V - B) - CONST | ||||
| %  | ||||
| % collect(ans, [L B])  | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										8
									
								
								lib/dv2atti.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/dv2atti.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| function [Cb2n] = dv2atti(vn1, vn2, vb1, vb2) | ||||
| 
 | ||||
|     vntmp1 = cross(vn1,vn2); vntmp2 = cross(vntmp1,vn1); | ||||
|     vbtmp1 = cross(vb1,vb2); vbtmp2 = cross(vbtmp1,vb1); | ||||
|     Cb2n = [vn1/norm(vn1), vntmp1/norm(vntmp1), vntmp2/norm(vntmp2)]*... | ||||
|           [vb1/norm(vb1), vbtmp1/norm(vbtmp1), vbtmp2/norm(vbtmp2)]'; | ||||
| 
 | ||||
|        | ||||
							
								
								
									
										11
									
								
								lib/geo/ch_ECEF2ENU.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/geo/ch_ECEF2ENU.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| function [E, N, U] = ch_ECEF2ENU(XYZ, lat0, lon0, h0) | ||||
| 
 | ||||
| % ECEF坐标转ENU | ||||
| % lat0, lon0, h0: 起始点经纬高, 经纬度为rad, 高度为m | ||||
| % XYZ ECEF坐标  单位为m | ||||
| % ENU距离 单位为m | ||||
| [lat, lon, h] = ch_ECEF2LLA(XYZ); | ||||
| 
 | ||||
| [E, N, U] =  ch_LLA2ENU(lat, lon, h,  lat0, lon0, h0); | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										46
									
								
								lib/geo/ch_ECEF2LLA.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/geo/ch_ECEF2LLA.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| function [lat, lon, h] = ch_ECEF2LLA(XYZ) | ||||
| 
 | ||||
| % ECEF坐标转经纬高 | ||||
| % lat:纬度(rad) | ||||
| % lon:经度(rad) | ||||
| % h高度(m) | ||||
| 
 | ||||
| R_0 = 6378137; %WGS84 Equatorial radius in meters | ||||
| e = 0.0818191908425; %WGS84 eccentricity | ||||
| 
 | ||||
| 
 | ||||
| lon = atan2(XYZ(2),XYZ(1)); | ||||
| 
 | ||||
| % From (C.29) and (C.30) | ||||
| k1 = sqrt(1 - e^2) * abs (XYZ(3)); | ||||
| k2 = e^2 * R_0; | ||||
| beta = sqrt(XYZ(1)^2 + XYZ(2)^2); | ||||
| E = (k1 - k2) / beta; | ||||
| F = (k1 + k2) / beta; | ||||
| 
 | ||||
| % From (C.31) | ||||
| P = 4/3 * (E*F + 1); | ||||
| 
 | ||||
| % From (C.32) | ||||
| Q = 2 * (E^2 - F^2); | ||||
| 
 | ||||
| % From (C.33) | ||||
| D = P^3 + Q^2; | ||||
| 
 | ||||
| % From (C.34) | ||||
| V = (sqrt(D) - Q)^(1/3) - (sqrt(D) + Q)^(1/3); | ||||
| 
 | ||||
| % From (C.35) | ||||
| G = 0.5 * (sqrt(E^2 + V) + E); | ||||
| 
 | ||||
| % From (C.36) | ||||
| T = sqrt(G^2 + (F - V * G) / (2 * G - E)) - G; | ||||
| 
 | ||||
| % From (C.37) | ||||
| lat = sign(XYZ(3)) * atan((1 - T^2) / (2 * T * sqrt (1 - e^2))); | ||||
| 
 | ||||
| % From (C.38) | ||||
| h = (beta - R_0 * T) * cos(lat) +... | ||||
|     (XYZ(3) - sign(XYZ(3)) * R_0 * sqrt(1 - e^2)) * sin (lat); | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										10
									
								
								lib/geo/ch_ENU2ECEF.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/geo/ch_ENU2ECEF.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| function XYZ = ch_ENU2ECEF(E, N, U, lat0, lon0, h0) | ||||
| % ENU  转 ECEF | ||||
| % lat0, lon0, h0: 起始点经纬高, 经纬度为rad, 高度为m | ||||
| % ENU东北天距离,单位为m | ||||
| % 返回 ECEF坐标 单位m | ||||
| 
 | ||||
| [lat, lon, h] = ch_ENU2LLA(E, N, U, lat0, lon0, h0); | ||||
| XYZ = ch_LLA2ECEF(lat, lon, h); | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										30
									
								
								lib/geo/ch_ENU2LLA.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/geo/ch_ENU2LLA.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| function [lat, lon, h] = ch_ENU2LLA(E, N ,U, lat0, lon0, h0) | ||||
| 
 | ||||
| % ENU 转 经纬高 | ||||
| % E, N ,U 系下增量,单位为m | ||||
| % lat0, lon0, h0: 起始点经纬高, 经纬度为rad, 高度为m | ||||
| % lat, lon, h 终点经纬高, 经纬度为rad, 高度为m | ||||
| 
 | ||||
| %精确解 | ||||
| XYZ0 = ch_LLA2ECEF(lat0, lon0, h0); | ||||
| [~, ~, C_ECEF2ENU, ~]= ch_earth(lat0, lon0, h0); | ||||
| dXYZ = C_ECEF2ENU' * [E N U]'; | ||||
| XYZ = dXYZ + XYZ0; | ||||
| [lat, lon, h] = ch_ECEF2LLA(XYZ); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| % % 近似算法 | ||||
| % R_0 = 6378137; %WGS84 Equatorial radius in meters | ||||
| % clat = cos(lat0); | ||||
| % | ||||
| % dlon = E / (R_0 * clat); | ||||
| % dlat = N / R_0; | ||||
| % dh = U; | ||||
| % | ||||
| % lon = lon0 + dlon; | ||||
| % lat = lat0 + dlat; | ||||
| % h = h0 + dh; | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										24
									
								
								lib/geo/ch_LLA2ECEF.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/geo/ch_LLA2ECEF.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| function [XYZ] = ch_LLA2ECEF(lat, lon, h) | ||||
| 
 | ||||
| % 经纬高转ECEF坐标 | ||||
| % lat:纬度(rad) | ||||
| % lon:经度(rad) | ||||
| % h高度(m) | ||||
| 
 | ||||
| R0 = 6378137; %WGS84 Equatorial radius in meters | ||||
| e = 0.0818191908425; %WGS84 eccentricity | ||||
| 
 | ||||
| % Calculate transverse radius of curvature using (2.105) | ||||
| RN = R0 / sqrt(1 - (e * sin(lat))^2); | ||||
| 
 | ||||
| % Convert position using (2.112) | ||||
| clat = cos(lat); | ||||
| slat = sin(lat); | ||||
| clon = cos(lon); | ||||
| slon = sin(lon); | ||||
| 
 | ||||
| XYZ = [0 0 0]'; | ||||
| 
 | ||||
| XYZ(1) = (RN + h) * clat * clon; | ||||
| XYZ(2) = (RN + h) * clat * slon; | ||||
| XYZ(3) = ((1 - e^2) * RN + h) * slat; | ||||
							
								
								
									
										25
									
								
								lib/geo/ch_LLA2ENU.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/geo/ch_LLA2ENU.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| function [E, N, U] = ch_LLA2ENU(lat, lon, h, lat0, lon0, h0) | ||||
| 
 | ||||
| % 经纬高 转 ENU | ||||
| % lat0, lon0, h0: 起始点经纬高, 经纬度为rad, 高度为m | ||||
| % lat, lon, h 终点经纬高, 经纬度为rad, 高度为m | ||||
| % E, N ,U 系下增量,单位为m | ||||
| 
 | ||||
| %精确算法 | ||||
| % XYZ0 = ch_LLA2ECEF(lat0, lon0, h0); | ||||
| % XYZ1 = ch_LLA2ECEF(lat, lon, h); | ||||
| % dXYZ = XYZ1 - XYZ0; | ||||
| %  | ||||
| %  [~, ~, C_ECEF2ENU, ~]= ch_earth(lat0, lon0, h0); | ||||
| %  dENU = C_ECEF2ENU * dXYZ; | ||||
| %  E = dENU(1); | ||||
| %  N= dENU(2); | ||||
| %  U = dENU(3); | ||||
|   | ||||
|  %近似算法 | ||||
| R_0 = 6378137; %WGS84 Equatorial radius in meters | ||||
| clat = cos(lat0); | ||||
| E = (lon - lon0) * clat * R_0; | ||||
| N =  (lat - lat0) * R_0; | ||||
| U = h - h0; | ||||
| end | ||||
							
								
								
									
										40
									
								
								lib/geo/ch_earth.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								lib/geo/ch_earth.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| 
 | ||||
| function [Rns, Rew, C_ECEF2ENU, C_ECEF2NED]= ch_earth(lat, lon, h) | ||||
| 
 | ||||
| %% 根据经纬度计算地球常用参数 | ||||
| % INPUT | ||||
| % lat: 纬度(rad) | ||||
| % lon: 经度(rad) | ||||
| 
 | ||||
| % OUTPUT | ||||
| % Rns, R_meridian(RM, ns): 南北向地球曲率半径, 子午圈曲率半径(竖着的) | ||||
| % Rew_transverse(RN, ew):东西向地球曲率半径, 卯酉圈曲率半径(横着的) | ||||
| % C_ECEF2ENU: ECEF到ENU转换矩阵 | ||||
| % C_ECEF2NED: ECEF到NED转换矩阵 | ||||
| 
 | ||||
| 
 | ||||
| R0 = 6378137;               %WGS84 赤道半径 | ||||
| e = 0.0818191908425;    %WGS84 eccentricity | ||||
| % Calculate meridian radius of curvature using (2.105) | ||||
| temp = 1 - (e * sin(lat))^2; | ||||
| Rns = R0 * (1 - e^2) / temp^1.5; | ||||
| 
 | ||||
| % Calculate transverse radius of curvature using (2.105) | ||||
| Rew = R0 / sqrt(temp); | ||||
| 
 | ||||
| clat = cos(lat); | ||||
| slat = sin(lat); | ||||
| clon = cos(lon); | ||||
| slon = sin(lon); | ||||
| 
 | ||||
| C_ECEF2ENU(1,:) =  [-slon ,             clon,                 0]; | ||||
| C_ECEF2ENU(2,:) = [ -slat*clon,    -slat*slon          clat]; | ||||
| C_ECEF2ENU(3,:) = [ clat*clon,      clat*slon,          slat]; | ||||
|             | ||||
| 
 | ||||
| C_ECEF2NED(1,:) = [-slat*clon,     -slat * slon,       clat]; | ||||
| C_ECEF2NED(2,:) = [-slon,             clon,                    0]; | ||||
| C_ECEF2NED(3,:) = [ -clat*clon,   -clat*slon,        -slat]; | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										10
									
								
								lib/geo/ch_gravity.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/geo/ch_gravity.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| function gravity = ch_gravity(lat, h) | ||||
| 
 | ||||
| % gravity: 计算重力(暂时不考虑高度) | ||||
| % | ||||
| % INPUT | ||||
| %       lat,纬度(rad) | ||||
| %       h,  高度(m), 暂时没有用 | ||||
| gravity = 9.780325 * ( 1 + 0.0053024*sin(lat)^(2) - 0.0000058*sin(lat*2)^(2)); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								lib/gnss/UTC2GPST.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/gnss/UTC2GPST.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| function [gps_week , gps_sec]=UTC2GPST(y, m, d, h, min, s) | ||||
| % UTC转GPST | ||||
| if y<90 | ||||
|     y=y+2000; | ||||
| else | ||||
|     y=y+1900; | ||||
| end | ||||
| 
 | ||||
| if m<=2 | ||||
|     y=y-1;m=m+12; | ||||
| end | ||||
| MJD=fix(365.25*y)+fix(30.6001*(m+1))+d+(h+(min+s/60)/60)/24+1720981.5-2400000.5; | ||||
| gps_week=fix((MJD-44244)/7); | ||||
| gps_sec=fix(mod((MJD-44244),7))*86400+h*3600+min*60+s; | ||||
| 
 | ||||
							
								
								
									
										43
									
								
								lib/gnss/anheader.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								lib/gnss/anheader.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| function [Obs_types, ant_delta,ifound_types,eof] = anheader(file) | ||||
| %ANHEADER Analyzes the header of a RINEX file and outputs | ||||
| %	       the list of observation types and antenna offset. | ||||
| %	       End of file is flagged 1, else 0. Likewise for the types. | ||||
| %	       Typical call: anheader('pta.96o') | ||||
| 
 | ||||
| %Kai Borre 09-12-96 | ||||
| %Copyright (c) by Kai Borre | ||||
| %$Revision: 1.0 $   $Date: 1997/09/23  $ | ||||
| 
 | ||||
| fid = fopen(file,'rt'); | ||||
| eof = 0; | ||||
| ifound_types = 0; | ||||
| Obs_types = []; | ||||
| ant_delta = []; | ||||
| 
 | ||||
| while 1			   % Gobbling the header | ||||
|    line = fgetl(fid); | ||||
|    answer = findstr(line,'END OF HEADER'); | ||||
|    if  ~isempty(answer), break; end; | ||||
|    if (line == -1), eof = 1; break; end; | ||||
|    answer = findstr(line,'ANTENNA: DELTA H/E/N'); | ||||
|    if ~isempty(answer) | ||||
|       for k = 1:3 | ||||
|          [delta, line] = strtok(line); | ||||
|          del = str2num(delta); | ||||
|          ant_delta = [ant_delta del]; | ||||
|       end; | ||||
|    end | ||||
|    answer = findstr(line,'# / TYPES OF OBSERV'); | ||||
|    if ~isempty(answer) | ||||
|       [NObs, line] = strtok(line); | ||||
|       NoObs = str2num(NObs); | ||||
|       for k = 1:NoObs | ||||
|          [ot, line] = strtok(line); | ||||
|          Obs_types = [Obs_types ot]; | ||||
|       end; | ||||
|       ifound_types = 1; | ||||
|    end; | ||||
| end; | ||||
| 
 | ||||
| %fclose(fid); | ||||
| %%%%%%%%% end anheader.m %%%%%%%%% | ||||
							
								
								
									
										92
									
								
								lib/gnss/cal2gpstime.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								lib/gnss/cal2gpstime.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| %******************************************************* | ||||
| % DESCRIPTION: | ||||
| %     This function converts calendar date/time | ||||
| %     to GPS week/time. | ||||
| %   | ||||
| % ARGUMENTS: | ||||
| %     Either 1) a single n x 6 matrix or | ||||
| %            2) six separate variables that are | ||||
| %               equal dimensioned vectors | ||||
| %  | ||||
| %     Representing: | ||||
| %     year - Two digit calendar year representing the  | ||||
| %            range 1980-2079 | ||||
| %            (e.g., 99 = 1999 and 01 = 2001). | ||||
| %     month - calendar month, must be in range 1-12. | ||||
| %     day - calendar day, must be in range 1-31. | ||||
| %     hour - hour (UTC), must be in range 0-24. | ||||
| %     min - minutes (UTC), must be in range 0-59. | ||||
| %     sec - seconds (UTC), must be in range 0-59. | ||||
| %  | ||||
| %     [ Note:  all arguments must be integers! ] | ||||
| %  | ||||
| % OUTPUT: | ||||
| %     gps_week - integer GPS week (does not take  | ||||
| %              "rollover" into account). | ||||
| %     gps_seconds - integer seconds elapsed in gps_week. | ||||
| % | ||||
| % REFERENCE: | ||||
| % 		ASEN 5090 class notes (Spring 2003). | ||||
| % | ||||
| % MODIFICATIONS:     | ||||
| %       03-14-06  :  Jan Weiss - Original/modified  | ||||
| %                                from old code.  | ||||
| %  | ||||
| % Colorado Center for Astrodynamics Research | ||||
| % Copyright 2006 University of Colorado, Boulder | ||||
| %******************************************************* | ||||
| function [ gps_week, gps_seconds ] = cal2gpstime(varargin) | ||||
| 
 | ||||
| % Unpack | ||||
| if nargin == 1 | ||||
|     cal_time = varargin{1}; | ||||
|     year = cal_time(:,1); | ||||
|     month = cal_time(:,2); | ||||
|     day = cal_time(:,3); | ||||
|     hour = cal_time(:,4); | ||||
|     min = cal_time(:,5); | ||||
|     sec = cal_time(:,6);   | ||||
|     clear cal_time | ||||
| else | ||||
|     year = varargin{1}; | ||||
|     month = varargin{2}; | ||||
|     day = varargin{3}; | ||||
|     hour = varargin{4}; | ||||
|     min = varargin{5}; | ||||
|     sec = varargin{6}; | ||||
| end | ||||
| 
 | ||||
| % Seconds in one week | ||||
| secs_per_week = 604800; | ||||
| 
 | ||||
| % Converts the two digit year to a four digit year. | ||||
| % Two digit year represents a year in the range 1980-2079. | ||||
| if (year >= 80 & year <= 99) | ||||
|     year = 1900 + year; | ||||
| end | ||||
| 
 | ||||
| if (year >= 0 & year <= 79) | ||||
|     year = 2000 + year; | ||||
| end | ||||
| 
 | ||||
| % Calculates the 'm' term used below from the given calendar month. | ||||
| if (month <= 2) | ||||
|     y = year - 1; | ||||
|     m = month + 12; | ||||
| end | ||||
| 
 | ||||
| if (month > 2) | ||||
|     y = year; | ||||
|     m = month; | ||||
| end | ||||
| 
 | ||||
| % Computes the Julian date corresponding to the given calendar date. | ||||
| JD = floor( (365.25 * y) ) + floor( (30.6001 * (m+1)) ) + ... | ||||
|     day + ( (hour + min / 60 + sec / 3600) / 24 ) + 1720981.5; | ||||
| 
 | ||||
| % Computes the GPS week corresponding to the given calendar date. | ||||
| gps_week = floor( (JD - 2444244.5) / 7 ); | ||||
| 
 | ||||
| % Computes the GPS seconds corresponding to the given calendar date. | ||||
| gps_seconds=round(((((JD-2444244.5)/7)-gps_week)*secs_per_week)/0.5)*0.5; | ||||
| 
 | ||||
							
								
								
									
										12
									
								
								lib/gnss/ch_gpsdop.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/gnss/ch_gpsdop.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| function [VDOP, HDOP, PDOP, GDOP] = ch_gpsdop(G, lat, lon) | ||||
| % GPS原理及接收机设计 谢刚 DOP章节 | ||||
| S = [-sin(lon) cos(lon) 0; -sin(lat)*cos(lon) -sin(lat)*sin(lon) cos(lat); cos(lat)*cos(lon) cos(lat)*sin(lon) sin(lat)]; | ||||
| S = [S [0 0 0]'; [0 0 0 1]]; | ||||
| H = (G'*G)^(-1); | ||||
| H = S*H*S'; | ||||
| VDOP = sqrt(H(3,3)); | ||||
| HDOP = sqrt(H(1,1) + H(2,2)); | ||||
| PDOP = sqrt (H(1,1) + H(2,2) + H(3,3)); | ||||
| GDOP = sqrt(trace(H)); | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										43
									
								
								lib/gnss/ch_gpsls.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								lib/gnss/ch_gpsls.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| function [X, dx, G] = ch_gpsls(X,  sat_pos,  pr) | ||||
| % GPS 伪距最小二乘法求解, 状态量为 X Y Z B(钟差) | ||||
| % X: X 值(1:3) 位置delta, (4) 用户钟差偏差 | ||||
| % G: 设计矩阵 | ||||
| % pr: 校正后的伪距 | ||||
| % sat_pos: 卫星位置矩阵 | ||||
| % delta: delta 值(1:3) 位置delta, (4) 用户钟差偏差 | ||||
| 
 | ||||
| B1=1; | ||||
| END_LOOP=100; | ||||
| %卫星个数 | ||||
| n = size(sat_pos, 2); | ||||
| 
 | ||||
| if n < 4 | ||||
|     dx = 0; | ||||
|     G = 0; | ||||
|     return | ||||
| end | ||||
| 
 | ||||
|     for loop = 1:10 | ||||
|         % 获得当前位置与各个基站的距离 | ||||
|         r = vecnorm(sat_pos - X(1:3)); | ||||
|          | ||||
|         % 求得H矩阵 | ||||
|         H = (sat_pos - X(1:3)) ./ r; | ||||
|         H =-H'; | ||||
|          | ||||
|         H = [H(:,1:3),  ones(n,1)]; | ||||
|          | ||||
|         dp = ((pr - r) -  X(4))'; | ||||
|          | ||||
|         % 迭代用户距离 | ||||
|         dx =  (H'*H)^(-1)*H'*dp; | ||||
|         X = X + dx; | ||||
|         G = H; | ||||
|          | ||||
|     %    END_LOOP = vnorm(delta(1:3)); | ||||
|     end | ||||
|      | ||||
|      | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										78
									
								
								lib/gnss/ch_sat_pos.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								lib/gnss/ch_sat_pos.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| function [XYZ, sv_dt]=ch_sat_pos(t, toc, f0, f1, f2, crs, deln, M0, cuc, e, cus, sqrtA, toe, cic, OMG0, cis, i0, crc, omg, OMGd, idot) | ||||
| % 输入: | ||||
| % toe: 星历参考时间: 一套星历的有效期为toe前后4小时 | ||||
| % a0 a1 a2 toc: 卫星时钟校正模型方程中3个参数,  toc: 第一数据块参考时间, 被用作时钟校正模型中时间参考点 | ||||
| 
 | ||||
| 
 | ||||
| % 卫星星历参数(16个): | ||||
| % sqrtA: 卫星轨道长半轴的平方根 | ||||
| % es: 轨道偏心率 | ||||
| % i0: toe时刻轨道倾角 | ||||
| % OMEGA0: 周内时等于0时刻的轨道升交点赤经 | ||||
| % omega: 轨道近地角距 | ||||
| % M0: toe时刻的平近点角 | ||||
| % Delta_n: 平均运动角速度校正值 | ||||
| % iDOT: 轨道倾角对时间的变化率 | ||||
| % OMEGA_DOT: 轨道升交点赤经对时间的变化率 | ||||
| % Cuc: 升交点角距余弦和校正振幅 | ||||
| % Cus: 升交点角距正弦和校正振幅 | ||||
| % Cic: 轨道倾角余弦和校正振幅 | ||||
| % Cis: 轨道倾角正弦和校正振幅 | ||||
| 
 | ||||
| %输出: | ||||
| % X, Y, Z ECEF下卫星位置 | ||||
| % sv_dt: 卫星时钟偏差 | ||||
| 
 | ||||
| %变量:  | ||||
| %摄动改正后的升交距角uk、卫星矢径rk和轨道倾角ik | ||||
| %卫星在轨道面坐标系中的坐标x,y | ||||
| %发射时刻升交点的经度L | ||||
| 
 | ||||
| 
 | ||||
| %以下为计算代码 | ||||
| %1.计算卫星运行的平均角速度 | ||||
| n0=sqrt(3.986005E+14)/(sqrtA.^3); | ||||
| n=n0+deln; | ||||
| %2.计算信号发射时卫星的平近点角 | ||||
| sv_dt = f0+f1*(t-toc)+f2*(t-toc).^2;%t为未做钟差改正的观测时刻 | ||||
| t = t - 0;%更新t为做钟差改正后的值 | ||||
| tk = t-toe;%归化时间 | ||||
| if tk>302400 | ||||
|     tk=tk-604800; | ||||
| elseif tk<-302400 | ||||
|     tk=tk+604800; | ||||
| else | ||||
|     tk=tk+0; | ||||
| end | ||||
| Mk=M0+n*tk; | ||||
| %3.计算偏近点角(迭代) | ||||
| %E=M+e*sin(E); | ||||
| ed(1)=Mk; | ||||
| for i=1:3 | ||||
|    ed(i+1)=Mk+e*sin(ed(i)); | ||||
| end | ||||
| Ek=ed(end); | ||||
| %4.计算真近点角 | ||||
| Vk=atan2(sqrt(1-e.^2)*sin(Ek),(cos(Ek)-e)); | ||||
| %5.计算升交距角(未经改进时) | ||||
| u=omg+Vk; | ||||
| %6.计算摄动改正项 | ||||
| deltau=cuc*cos(2*u)+cus*sin(2*u); | ||||
| deltar=crc*cos(2*u)+crs*sin(2*u); | ||||
| deltai=cic*cos(2*u)+cis*sin(2*u); | ||||
| %7.计算摄动改正后的升交距角uk、卫星矢径rk和轨道倾角ik | ||||
| uk=u+deltau; | ||||
| rk=(sqrtA.^2)*(1-e*cos(Ek))+deltar; | ||||
| ik=i0+deltai+idot*tk; | ||||
| %8.计算卫星在轨道面坐标系中的坐标 | ||||
| x=rk*cos(uk); | ||||
| y=rk*sin(uk); | ||||
| %9.计算发射时刻升交点的经度67 | ||||
| L=OMG0+(OMGd-7.2921151467e-5)*tk-7.2921151467e-5*toe; | ||||
| %10.计算卫星在地固坐标系下坐标 | ||||
| XYZ(1)=x*cos(L)-y*cos(ik)*sin(L); | ||||
| XYZ(2)=x*sin(L)+y*cos(ik)*cos(L); | ||||
| XYZ(3)=y*sin(ik); | ||||
| XYZ = XYZ'; | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										8
									
								
								lib/gnss/ch_sv_pos_rotate.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/gnss/ch_sv_pos_rotate.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| function SP = ch_sv_pos_rotate(SP, tau) | ||||
| %% 计算经过地球自转改正后的卫星位置 | ||||
| % Earth's rotation rate | ||||
| % SP: 卫星位置 | ||||
| omega_e = 7.2921151467e-5; %(rad/sec) | ||||
| theta = omega_e * tau; | ||||
| SP = [cos(theta) sin(theta) 0; -sin(theta) cos(theta) 0; 0 0 1]*SP; | ||||
| end | ||||
							
								
								
									
										19
									
								
								lib/gnss/check_rinex_line_length.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/gnss/check_rinex_line_length.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| %********************************************************************* | ||||
| %  | ||||
| % This function takes a string and checks if it < 80 characters long. | ||||
| % If so the string is "padded" with zeros until it is 80 characters | ||||
| % long.  Useful when reading RINEX files. | ||||
| %  | ||||
| %********************************************************************* | ||||
| function [ current_line ] = check_line_length(current_line) | ||||
| 
 | ||||
| if length(current_line) < 80     | ||||
|     add_spaces = 80 - length(current_line); | ||||
|      | ||||
|     for j = 1 : add_spaces         | ||||
|         current_line = [ current_line , '0' ];         | ||||
|     end     | ||||
| end | ||||
| 
 | ||||
| % Check if there are any blanks in the data and put a zero there. | ||||
| current_line = strrep(current_line,' ', '0'); | ||||
							
								
								
									
										118
									
								
								lib/gnss/fepoch_0.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								lib/gnss/fepoch_0.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | ||||
| function [time, dt, sats, eof] = fepoch_0(fid) | ||||
| % FEPOCH_0   Finds the next epoch in an opened RINEX file with | ||||
| %	          identification fid. From the epoch line is produced | ||||
| %	          time (in seconds of week), number of sv.s, and a mark | ||||
| %	          about end of file. Only observations with epoch flag 0 | ||||
| %	          are delt with. | ||||
| 
 | ||||
| %Kai Borre 09-14-96; revised 03-22-97; revised Sept 4, 2001 | ||||
| %Copyright (c) by Kai Borre | ||||
| %$Revision: 1.0 $  $Date: 1997/09/22  $ | ||||
| %fide = fopen(fid,'rt'); | ||||
| 
 | ||||
| % 该函数只返回o文件中一个历元的以下参数: | ||||
| 
 | ||||
| % time:周内秒 | ||||
| % dt:接收机钟差(该参数为可选项,不一定所有的o文件中都有) | ||||
| % sats:当前历元所观测到的卫星 | ||||
| % eof:是否到文件末尾 | ||||
| 
 | ||||
| global sat_index; | ||||
| time = 0; | ||||
| dt = 0; | ||||
| sats = []; | ||||
| NoSv = 0; | ||||
| eof = 0; | ||||
| 
 | ||||
| %循环读取o文件的每一行 | ||||
| while 1 | ||||
|    lin = fgets(fid); % earlier fgetl  先读一行 | ||||
|     | ||||
|    if (feof(fid) == 1); % 若到文件末尾,则结束 | ||||
|       eof = 1; | ||||
|       break | ||||
|    end; | ||||
|     | ||||
|    % 跳过空行 | ||||
|    if length(lin) <= 1 | ||||
|        continue; | ||||
|    end | ||||
|     | ||||
| %    answer = findstr(lin,'COMMENT'); % 判断该行中是否有字符串“COMMENT” | ||||
| %     | ||||
| %    if ~isempty(answer);  % 若有“COMMENT“,则继续读下一行 | ||||
| %       lin = fgetl(fid); | ||||
| %    end; | ||||
|     | ||||
|    % 如果该行数据第29个字符不为0(0代表改历元正常), | ||||
|    % 或者总长度只有29(也就是没有后面的卫星PRN数据), | ||||
|    % 则结束。 | ||||
|    % if ((strcmp(lin(29),'0') == 0) & (size(deblank(lin),2) == 29))  | ||||
|    %    eof = 1;  | ||||
|    %    break | ||||
|    % end; % We only want type 0 data | ||||
|     | ||||
|    % 如果该行第二个字符是1,或者第29个字符是0,则说明 | ||||
|    % 这一行是某一历元的开始行,接下来就可以从该行中提取时间、PRN等参数 | ||||
|    if ((strcmp(lin(2),'1') == 1)  &  (strcmp(lin(29),'0') == 1)) | ||||
|       ll = length(lin)-2; | ||||
|       if ll > 60, ll = 60; end; | ||||
|       linp = lin(1:ll);         | ||||
|       %fprintf('%60s\n',linp); | ||||
|        | ||||
|       %使用strtok函数获得间隔符前面的字符串, | ||||
|       % 首先是获得当前时间 | ||||
|       [nian, lin] = strtok(lin); | ||||
|       % year; | ||||
|        | ||||
|       [month, lin] = strtok(lin); | ||||
|       % month; | ||||
|        | ||||
|       [day, lin] = strtok(lin); | ||||
|       % day; | ||||
|        | ||||
|       [hour, lin] = strtok(lin); | ||||
|       % hour | ||||
|        | ||||
|       [minute, lin] = strtok(lin); | ||||
|       % minute | ||||
|        | ||||
|       [second, lin] = strtok(lin); | ||||
|       % second | ||||
|        | ||||
|       [OK_flag, lin] = strtok(lin);  | ||||
|       % OK_flag就是第29个字符,如果是0,则该历元正常 | ||||
|        | ||||
|       %将时间转成数值型,然后再计算出GPS周和周内秒 | ||||
|       h = str2num(hour)+str2num(minute)/60+str2num(second)/3600; | ||||
|       jd = julday(str2num(nian)+2000, str2num(month), str2num(day), h); | ||||
|       [week, sec_of_week] = gps_time(jd); | ||||
|       time = sec_of_week; | ||||
|        | ||||
|       %获得该历元卫星数 | ||||
|       [NoSv, lin] = strtok(lin,'G'); | ||||
|        | ||||
|       %储存该历元每颗卫星的PRN | ||||
|       for k = 1:str2num(NoSv) | ||||
|          [sat, lin] = strtok(lin,'G'); | ||||
|          prn(k) = str2num(sat); | ||||
|       end | ||||
|        | ||||
|       % prn是1行NoSv列的矩阵,sats是其转置 | ||||
|       sats = prn(:); | ||||
|        | ||||
|       % 接收及钟差,有的o文件中没有该参数 | ||||
|       dT = strtok(lin); | ||||
|       if isempty(dT) == 0 %如果dT不为0,则将其记录 | ||||
|          dt = str2num(dT); | ||||
|       end | ||||
|        | ||||
|       break % 跳出while循环 | ||||
|        | ||||
|    end | ||||
|     | ||||
| end;  | ||||
| 
 | ||||
| % datee=[str2num(nian) str2num(month) str2num(day) str2num(hour) str2num(minute) str2num(second)]; | ||||
| 
 | ||||
| %%%%%%%% end fepoch_0.m %%%%%%%%% | ||||
							
								
								
									
										16
									
								
								lib/gnss/get_eph.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/gnss/get_eph.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| function eph = get_eph(ephemeridesfile) | ||||
| %GET_EPH  The ephemerides contained in ephemeridesfile | ||||
| %         are reshaped into a matrix with 21 rows and | ||||
| %         as many columns as there are ephemerides. | ||||
| 
 | ||||
| %         Typical call eph = get_eph('rinex_n.dat') | ||||
| 
 | ||||
| %Kai Borre 10-10-96 | ||||
| %Copyright (c) by Kai Borre | ||||
| %$Revision: 1.0 $  $Date: 1997/09/26  $ | ||||
| 
 | ||||
| fide = fopen(ephemeridesfile); | ||||
| [eph, count] = fread(fide, Inf, 'double'); | ||||
| noeph = count/23; | ||||
| eph = reshape(eph, 23, noeph);  % ephΪһ¸ö23ÐÐnoephÁеľØÕó | ||||
| %%%%%%%% end get_eph.m %%%%%%%%%%%%%%%%%%%%% | ||||
							
								
								
									
										105
									
								
								lib/gnss/iono_correction.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								lib/gnss/iono_correction.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| %This Function approximate Ionospheric Group Delay 这个函数近似电离层群延迟 | ||||
| %CopyRight By Moein Mehrtash | ||||
| %************************************************************************ | ||||
| % Written by Moein Mehrtash, Concordia University, 3/21/2008            * | ||||
| % Email: moeinmehrtash@yahoo.com                                        * | ||||
| %************************************************************************ | ||||
| % *********************************************************************** | ||||
| %      Function for   computing an Ionospheric range correction for the * | ||||
| %      GPS L1 frequency from the parameters broadcasted in the GPS      * | ||||
| %      Navigation Message.功能:根据GPS导航信息中广播的参数计算电离层距离修正的GPS L1频率。                                              * | ||||
| %      ================================================================== | ||||
| %      References:                                                      * | ||||
| %      Klobuchar, J.A., (1996) "Ionosphercic Effects on GPS", in        * | ||||
| %        Parkinson, Spilker (ed), "Global Positioning System Theory and * | ||||
| %        Applications, pp.513-514.                                      * | ||||
| %      ICD-GPS-200, Rev. C, (1997), pp. 125-128                         * | ||||
| %      NATO, (1991), "Technical Characteristics of the NAVSTAR GPS",    * | ||||
| %        pp. A-6-31   -   A-6-33                                        * | ||||
| %      ================================================================== | ||||
| %    Input :                                                            * | ||||
| %        Pos_Rcv       : XYZ position of reciever               (Meter) * | ||||
| %        Pos_SV        : XYZ matrix position of GPS satellites  (Meter) * | ||||
| %        GPS_Time      : Time of Week                           (sec)   * | ||||
| %        Alfa(4)       : The coefficients of a cubic equation           * | ||||
| %                        representing the amplitude of the vertical     * | ||||
| %                        dalay (4 coefficients - 8 bits each)  表示垂直dalay振幅的三次方程的系数(4个系数,每个8位)         * | ||||
| %        Beta(4)       : The coefficients of a cubic equation           * | ||||
| %                        representing the period of the model           * | ||||
| %                        (4 coefficients - 8 bits each) 表示模型周期的三次方程的系数(4个系数-各8位)                * | ||||
| %    Output:                                                            * | ||||
| %       Delta_I        : Ionospheric slant range correction for         * | ||||
| %                        the L1 frequency电离层L1频率的倾斜距离校正(Sec)   * | ||||
| %     ================================================================== | ||||
| 
 | ||||
| function [ delay ]=iono_correction(RP, SP, alpha, beta, gpst) | ||||
| % RP: 接收机位置 | ||||
| % SP: 卫星位置 | ||||
| % Alpha Beta 电离层校准参数 | ||||
| % GPS Time | ||||
| % delay 单位为m | ||||
| 
 | ||||
| if norm(RP) < 1 | ||||
|     delay = 0; | ||||
|     return; | ||||
| end | ||||
| 
 | ||||
| [lat, lon, ~] = ch_ECEF2LLA(RP); | ||||
| 
 | ||||
| 
 | ||||
| lat = lat/pi; | ||||
| lon =lon/pi;   % semicircles unit Lattitdue and Longitude | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| [el, az] = satellite_az_el(SP, RP); | ||||
| E = az/pi;                                            %SemiCircle Elevation | ||||
| A = el;                                               %SemiCircle Azimoth | ||||
| % Calculate the Earth-Centered angle, Psi | ||||
| Psi = 0.0137/(E+.11)-0.022;                        %SemiCircle | ||||
| 
 | ||||
| %Compute the Subionospheric lattitude, Phi_L | ||||
| Phi_L = lat+Psi*cos(A);                         %SemiCircle | ||||
| if Phi_L>0.416 | ||||
|     Phi_L=0.416; | ||||
| elseif Phi_L<-0.416 | ||||
|     Phi_L=-0.416; | ||||
| end | ||||
| 
 | ||||
| %Compute the subionospheric longitude, Lambda_L | ||||
| Lambda_L = lon+(Psi * sin(A)/cos(Phi_L*pi));  %SemiCircle | ||||
| 
 | ||||
| %Find the geomagnetic lattitude ,Phi_m, of the subionospheric location | ||||
| %looking toward each GPS satellite: | ||||
| Phi_m = Phi_L+0.064*cos((Lambda_L-1.617)*pi); | ||||
| 
 | ||||
| %Find the Local Time ,t, at the subionospheric point | ||||
| t=4.32*10^4*Lambda_L+gpst;                 %GPS_Time(Sec) | ||||
| t= mod(t,86400); | ||||
| if t>86400 | ||||
|     t = t-86400; | ||||
| elseif t<0 | ||||
|     t=t+86400; | ||||
| end | ||||
| 
 | ||||
| %Convert Slant time delay, Compute the Slant Factor,F | ||||
| F=1+16*(.53-E)^3; | ||||
| 
 | ||||
| %Compute the ionospheric time delay T_iono by first computing x | ||||
| Per=beta(1)+beta(2)*Phi_m+beta(3)*Phi_m^2+beta(4)*Phi_m^3; | ||||
| if Per <72000                                     %Period | ||||
|     Per=72000; | ||||
| end | ||||
| x=2*pi*(t-50400)/Per;                       %Rad | ||||
| AMP=alpha(1)+alpha(2)*Phi_m+alpha(3)*Phi_m^2+alpha(4)*Phi_m^3; | ||||
| if AMP<0 | ||||
|     AMP=0; | ||||
| end | ||||
| if abs(x)>1.57 | ||||
|     T_iono=F*5*10^(-9); | ||||
| else | ||||
|     T_iono=F*(5*10^(-9)+AMP*(1-x^2/2+x^4/24)); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| delay = T_iono*299792458; | ||||
							
								
								
									
										91
									
								
								lib/gnss/parsef.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								lib/gnss/parsef.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| function varargout = parsef(input, format) | ||||
| %parsef   parse string value using FORTRAN formatting codes | ||||
| %   [val1,val2,...valn] = parsef(input, format) | ||||
| %   input is string input value | ||||
| %   format is cell array of format codes | ||||
| 
 | ||||
| global input_ | ||||
| input_ = input; | ||||
| varargout = getvals(1, format, 1); | ||||
| clear global input_ | ||||
| return | ||||
| 
 | ||||
| % this function does the work. you probably don't want to go here | ||||
| function [output, idx] = getvals(idx, format, reps) | ||||
| global input_ | ||||
| count = 1; | ||||
| output = {}; | ||||
| for k = 1:reps | ||||
| 	odx = 1; | ||||
| 	for i = 1:length(format) | ||||
| 		fmt = format{i}; | ||||
| 		switch class(fmt) | ||||
| 		case 'double' | ||||
| 			count = fmt; | ||||
| 		case 'char' | ||||
| 			type = fmt(1); | ||||
| 			if type == 'X' | ||||
| 				idx = idx+count; | ||||
| 			else | ||||
| 				[len,cnt] = sscanf(fmt,'%*c%d',1); | ||||
| 				if cnt ~= 1 | ||||
| 					error(['Invalid format specifier: ''',fmt,'''']); | ||||
| 				end | ||||
| 				switch type | ||||
| 				case {'I','i'} | ||||
| 					for j = 1:count | ||||
| 						[val,cnt] = sscanf(input_(idx:min(idx+len-1,end)),'%d',1); | ||||
| 						if cnt == 1 | ||||
| 							output{odx}(j,k) = val; | ||||
| 						else | ||||
| 							output{odx}(j,k) = NaN; | ||||
| 						end | ||||
| 						idx = idx+len; | ||||
| 					end | ||||
| 				case {'F','f'} | ||||
| 					for j = 1:count | ||||
| 						[val,cnt] = sscanf(input_(idx:min(idx+len-1,end)),'%f',1); | ||||
| 						if cnt == 1 | ||||
| 							output{odx}(j,k) = val; | ||||
| 						else | ||||
| 							output{odx}(j,k) = NaN; | ||||
| 						end | ||||
| 						idx = idx+len; | ||||
| 					end | ||||
| 				case {'E','D','G'} | ||||
| 					for j = 1:count | ||||
| 						[val,cnt] = sscanf(input_(idx:min(idx+len-1,end)),'%f%*1[DdEe]%f',2); | ||||
| 						if cnt == 2 | ||||
| 							output{odx}(j,k) = val(1) * 10^val(2); %#ok<AGROW> | ||||
| 						elseif cnt == 1 | ||||
| 							output{odx}(j,k) = val; | ||||
| 						else | ||||
| 							output{odx}(j,k) = NaN; | ||||
| 						end | ||||
| 						idx = idx+len; | ||||
| 					end | ||||
| 				case 'A' | ||||
| 					for j = 1:count | ||||
| 						output{odx}{j,k} = input_(idx:min(idx+len-1,end)); | ||||
| 						idx = idx+len; | ||||
| 					end | ||||
| 				otherwise | ||||
| 					error(['Invalid format specifier: ''',fmt,'''']); | ||||
| 				end | ||||
| 				odx = odx+1; | ||||
| 			end | ||||
| 			count = 1; | ||||
| 		case 'cell' | ||||
|  			[val, idx] = getvals(idx, fmt, count); | ||||
| 			if length(val) == 1 | ||||
| 				output(odx) = val; | ||||
| 			else | ||||
| 				output{odx} = val; | ||||
| 			end | ||||
| 			odx = odx+1; | ||||
| 			count = 1; | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
| return | ||||
| 
 | ||||
							
								
								
									
										95
									
								
								lib/gnss/read_rinex_nav.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								lib/gnss/read_rinex_nav.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| % Lucas Ward | ||||
| % ASEN 5090 | ||||
| % Read the RINEX navigation file.  The header is skipped because | ||||
| % information in it (a0, a1, iono alpha and beta parameters) is not  | ||||
| % currently needed for orbit computation.  This can be easily amended to | ||||
| % include navigation header information by adding lines in the 'while' loop | ||||
| % where the header is currently skipped. | ||||
| %  | ||||
| % Input:        - filename - enter the filename to be read.  If filename | ||||
| %                            exists, the orbit will be calculated. | ||||
| %  | ||||
| % Output:       - ephemeris - Output is a matrix with rows for each PRN and | ||||
| %                             columns as follows: | ||||
| %  | ||||
| %                  col  1:    PRN    ....... satellite PRN           | ||||
| %                  col  2:    M0     ....... mean anomaly at reference time | ||||
| %                  col  3:    delta_n  ..... mean motion difference | ||||
| %                  col  4:    e      ....... eccentricity | ||||
| %                  col  5:    sqrt(A)  ..... where A is semimajor axis | ||||
| %                  col  6:    OMEGA  ....... LoAN at weekly epoch | ||||
| %                  col  7:    i0     ....... inclination at reference time | ||||
| %                  col  8:    omega  ....... argument of perigee | ||||
| %                  col  9:    OMEGA_dot  ... rate of right ascension  | ||||
| %                  col 10:    i_dot  ....... rate of inclination angle | ||||
| %                  col 11:    Cuc    ....... cosine term, arg. of latitude | ||||
| %                  col 12:    Cus    ....... sine term, arg. of latitude | ||||
| %                  col 13:    Crc    ....... cosine term, radius | ||||
| %                  col 14:    Crs    ....... sine term, radius | ||||
| %                  col 15:    Cic    ....... cosine term, inclination | ||||
| %                  col 16:    Cis    ....... sine term, inclination | ||||
| %                  col 17:    toe    ....... time of ephemeris | ||||
| %                  col 18:    IODE   ....... Issue of Data Ephemeris | ||||
| %                  col 19:    GPS_wk ....... GPS week | ||||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||||
| function ephemeris = read_rinex_nav( filename ) | ||||
| 
 | ||||
| fid = fopen(filename); | ||||
| 
 | ||||
| if fid == -1 | ||||
|     errordlg(['The file ''' filename ''' does not exist.']); | ||||
|     return; | ||||
| end | ||||
| 
 | ||||
| % skip through header | ||||
| end_of_header = 0; | ||||
| while end_of_header == 0 | ||||
|     current_line = fgetl(fid); | ||||
|     if strfind(current_line,'END OF HEADER') | ||||
|         end_of_header=1; | ||||
|     end | ||||
| end | ||||
| 
 | ||||
| j = 0; | ||||
| while feof(fid) ~= 1 | ||||
|     j = j+1; | ||||
|      | ||||
|     current_line = fgetl(fid); | ||||
|     % parse epoch line (ignores SV clock bias, drift, and drift rate) | ||||
|     [PRN, Y, M, D, H, min, sec,af0,af1,af2] = parsef(current_line, {'I2' 'I3' 'I3' 'I3' 'I3' 'I3' ... | ||||
|                                                   'F5.1','D19.12','D19.12','D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 1 | ||||
|     current_line = fgetl(fid); | ||||
|     [IODE Crs delta_n M0] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 2 | ||||
|     current_line = fgetl(fid); | ||||
|     [Cuc e Cus sqrtA] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 3 | ||||
|     current_line = fgetl(fid); | ||||
|     [toe Cic OMEGA Cis] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 4 | ||||
|     current_line = fgetl(fid); | ||||
|     [i0 Crc omega OMEGA_dot] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 5 | ||||
|     current_line = fgetl(fid); | ||||
|     [i_dot L2_codes GPS_wk L2_dataflag ] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 6 | ||||
|     current_line = fgetl(fid); | ||||
|     [SV_acc SV_health TGD IODC] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12' 'D19.12' 'D19.12'}); | ||||
| 
 | ||||
|     % Broadcast orbit line 7 | ||||
|     current_line = fgetl(fid); | ||||
|     [msg_trans_t fit_int ] = parsef(current_line, {'D22.12' 'D19.12' 'D19.12'}); | ||||
|      | ||||
| 
 | ||||
|     [ gps_week, toc ] = UTC2GPST(Y, M, D, H, min, sec); | ||||
| 
 | ||||
|     ephemeris(j,:) = [PRN, M0, delta_n, e, sqrtA, OMEGA, i0, omega, OMEGA_dot, i_dot, Cuc, Cus, Crc, Crs, Cic, Cis, toe, IODE, GPS_wk,toc,af0,af1,af2,TGD]; | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										216
									
								
								lib/gnss/read_rinex_obs.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								lib/gnss/read_rinex_obs.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,216 @@ | ||||
| function [rinex,rec_xyz] = read_rinex_obs(fname,nlines) | ||||
| %******************************************************* | ||||
| % function [ rinex ] = read_rinex_obs(fname) | ||||
| % | ||||
| % DESCRIPTION: | ||||
| %     This function reads a RINEX format GPS data | ||||
| %     file and returns the data in an array. | ||||
| %   | ||||
| % ARGUMENTS: | ||||
| %     fname (str) - RINEX file | ||||
| %   | ||||
| % OUTPUT: | ||||
| %     rinex - rinex data (v3 struct) | ||||
| % | ||||
| % CALLED BY: | ||||
| %     process_rinex.m | ||||
| % | ||||
| % FUNCTIONS CALLED: | ||||
| %     read_rinex_header.m | ||||
| % | ||||
| % MODIFICATIONS:     | ||||
| %     XX-XX-03  :  Jan Weiss - Original | ||||
| %     03-14-06  :  Jan Weiss - Cleanup | ||||
| %               :  See SVN log for further modifications | ||||
| %     10-26-06  :  simplified for class positioning project & allows for | ||||
| %     limited number of lines read (PA) | ||||
| %  | ||||
| % Colorado Center for Astrodynamics Research | ||||
| % Copyright 2006 University of Colorado, Boulder | ||||
| %******************************************************* | ||||
| 
 | ||||
| if (nargin < 2) | ||||
|     nlines = 1e6; | ||||
| end | ||||
| 
 | ||||
| % Initialize variables | ||||
| rinex_data = []; | ||||
| line_count = 1; | ||||
| 
 | ||||
| % Read header | ||||
| [ fid, rec_xyz, observables ] = read_rinex_header(fname); | ||||
| num_obs = length(observables); | ||||
| 
 | ||||
| % Get the first line of the observations. | ||||
| current_line = fgetl(fid); | ||||
|      | ||||
| % If not at the end of the file, search for the desired information. | ||||
| while current_line ~= -1 & line_count < nlines     | ||||
|      | ||||
|     % Get the time for this data epoch. | ||||
|     current_time = [ str2num(current_line(2:3)) ; str2num(current_line(5:6)) ; ... | ||||
|             str2num(current_line(8:9)) ; str2num(current_line(11:12)) ; ... | ||||
|             str2num(current_line(14:15)) ; str2num(current_line(17:27)) ]'; | ||||
|      | ||||
|     % How many SV's are there? | ||||
|     current_num_sv = str2num(current_line(30:32));     | ||||
|      | ||||
|     % Figure out which PRN's there are. | ||||
|     for ii=1:current_num_sv         | ||||
|         current_prn(ii) = str2num(current_line(31 + 3*ii : 32 + 3*ii));         | ||||
|     end     | ||||
|      | ||||
|     % Get the data for all SV's in this epoch. | ||||
|     for ii=1:current_num_sv | ||||
|                  | ||||
|         % Get the next line. | ||||
|         current_line = fgetl(fid); | ||||
|         line_count = line_count + 1; | ||||
|          | ||||
|         % Check the length of the line and pad it with zeros to | ||||
|         % make sure it is 80 characters long. | ||||
|         current_line = check_rinex_line_length(current_line); | ||||
|          | ||||
|         % Get the observables on this line. | ||||
|         current_obs = [ str2num(current_line(1:14)) ; str2num(current_line(17:30)) ; ... | ||||
|                 str2num(current_line(33:46)) ; str2num(current_line(49:62)) ; str2num(current_line(65:78)) ]; | ||||
|          | ||||
|         % If there are > 5 observables, read another line to get the rest of the observables for this SV. | ||||
|         if num_obs > 5             | ||||
|              % Get the next line. | ||||
|              current_line = fgetl(fid); | ||||
|              line_count = line_count + 1; | ||||
| 
 | ||||
|              % Check the length of the line and pad it with zeros to | ||||
|              % make sure it is 80 characters long. | ||||
|              current_line = check_rinex_line_length(current_line); | ||||
|             | ||||
|             % Append the data in this line to the data from previous line. | ||||
|             current_obs = [ current_obs ; str2num(current_line(1:14)) ; ... | ||||
|                             str2num(current_line(17:30)) ; str2num(current_line(33:46)) ; ... | ||||
|                             str2num(current_line(49:62)) ; str2num(current_line(65:78)) ]; | ||||
|                 | ||||
|         end  % if num_obs > 5         | ||||
|         | ||||
|         % Format the data for this PRN as Date/Time, PRN, Observations. | ||||
|         current_data = [ current_time , current_prn(ii) , current_obs' ];        | ||||
|         | ||||
|         % Keep only data for the specified PRNs | ||||
|         if nargin == 3 & PRN_list & isempty(find(PRN_list == current_prn(ii))) | ||||
|             continue | ||||
|         end            | ||||
|         | ||||
|         %Append to the master rinex data file. | ||||
|         rinex_data = [ rinex_data ; current_data ];         | ||||
|         | ||||
|     end  % for ii=1:current_num_sv | ||||
|     | ||||
|     % Get the next line. | ||||
|     current_line = fgetl(fid); | ||||
|     line_count = line_count + 1;     | ||||
|     | ||||
| end  % while current_line ~= -1 | ||||
| 
 | ||||
| % Convert time format | ||||
| [ gpswk, gpssec ] = cal2gpstime(rinex_data(:,1:6)); | ||||
| rinex.data = [ gpswk gpssec rinex_data(:, 7:end) ]; | ||||
| 
 | ||||
| % Define columns | ||||
| rinex = define_cols(rinex, observables); | ||||
| 
 | ||||
| % Convert CP to meters | ||||
| rinex = convert_rinex_CP(rinex); | ||||
| 
 | ||||
| 
 | ||||
| % ========================================================================= | ||||
| function rinex = define_cols(rinex, observables) | ||||
| 
 | ||||
| % Defaults | ||||
| rinex.col.WEEK = 1; | ||||
| rinex.col.TOW = 2; | ||||
| rinex.col.PRN = 3; | ||||
| 
 | ||||
| col_offset = 3; | ||||
| 
 | ||||
| for ii=1:length(observables) | ||||
|     switch observables{ii} | ||||
|         case {'L1'} | ||||
|             rinex.col.L1 = ii + col_offset; | ||||
|         case {'L2'} | ||||
|             rinex.col.L2 = ii + col_offset; | ||||
|         case {'P1'} | ||||
|             rinex.col.P1 = ii + col_offset; | ||||
|         case {'P2'} | ||||
|             rinex.col.P2 = ii + col_offset; | ||||
|         case {'C1'} | ||||
|             rinex.col.C1 = ii + col_offset;     | ||||
|         case {'D1'} | ||||
|             rinex.col.D1 = ii + col_offset; | ||||
|         case {'S1'} | ||||
|             rinex.col.S1 = ii + col_offset; | ||||
|         case {'S2'} | ||||
|             rinex.col.S2 = ii + col_offset; | ||||
|     end  % switch     | ||||
| end  % for ii=1:length(observables) | ||||
| 
 | ||||
| 
 | ||||
| % ========================================================================= | ||||
| function [ rinex ] = convert_rinex_CP(rinex) | ||||
| 
 | ||||
| set_constants; | ||||
| 
 | ||||
| if rinex.col.L1 ~= 0 | ||||
|     rinex.data(:, rinex.col.L1) = rinex.data(:, rinex.col.L1) * LAMBDA_L1; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| % ========================================================================= | ||||
| function [ fid, rec_xyz, observables ] = read_rinex_header( file_name ) | ||||
| 
 | ||||
| % Initialize the observables variable. | ||||
| observables={}; | ||||
| 
 | ||||
| % Assign a file ID and open the given header file. | ||||
| fid=fopen(file_name); | ||||
| 
 | ||||
| % If the file does not exist, scream bloody murder! | ||||
| if fid == -1 | ||||
|     display('Error!  Header file does not exist.'); | ||||
| else     | ||||
|     % Set up a flag for when the header file is done. | ||||
|     end_of_header=0; | ||||
|      | ||||
|     % Get the first line of the file. | ||||
|     current_line = fgetl(fid); | ||||
|      | ||||
|     % If not at the end of the file, search for the desired information. | ||||
|     while end_of_header ~= 1         | ||||
|         % Search for the approximate receiver location line. | ||||
|         if strfind(current_line,'APPROX POSITION XYZ') | ||||
|              | ||||
|             % Read xyz coordinates into a matrix. | ||||
|             [rec_xyz] = sscanf(current_line,'%f'); | ||||
|         end | ||||
|          | ||||
|         % Search for the number/types of observables line. | ||||
|         if strfind(current_line,'# / TYPES OF OBSERV')             | ||||
|             % Read the non-white space characters into a temp variable. | ||||
|             [observables_temp] = sscanf(current_line,'%s');             | ||||
|              | ||||
|             % Read the number of observables space and then create | ||||
|             % a matrix containing the actual observables. | ||||
|             for ii = 1:str2num(observables_temp(1))                 | ||||
|                 observables{ii} = observables_temp( 2*ii : 2*ii+1 ); | ||||
|             end           | ||||
|         end | ||||
|                    | ||||
|         % Get the next line of the header file. | ||||
|         current_line = fgetl(fid); | ||||
|          | ||||
|         %Check if this line is at the end of the header file. | ||||
|         if strfind(current_line,'END OF HEADER') | ||||
|             end_of_header=1; | ||||
|         end         | ||||
|     end | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										204
									
								
								lib/gnss/rinexe.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								lib/gnss/rinexe.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,204 @@ | ||||
| function iono = rinexe(ephemerisfile, outputfile) | ||||
| %RINEXE Reads a RINEX Navigation Message file and | ||||
| %	     reformats the data into a matrix with 23s | ||||
| %	     rows and a column for each satellite. | ||||
| %	     The matrix is stored in outputfile | ||||
| 
 | ||||
| %Typical call: rinexe('pta.96n','pta.nav') | ||||
| 
 | ||||
| %Kai Borre 04-18-96 | ||||
| %Copyright (c) by Kai Borre | ||||
| %$Revision: 1.0 $  $Date: 1997/09/24  $ | ||||
| 
 | ||||
| % Units are either seconds, meters, or radians | ||||
| fide = fopen(ephemerisfile); | ||||
| head_lines = 0; | ||||
| iono = zeros(8,1); | ||||
| 
 | ||||
| %read the header | ||||
| header_end = []; | ||||
| while (isempty(header_end)) | ||||
|     head_lines = head_lines+1; | ||||
|     %read the line and search the ionosphere labels | ||||
|     lin = fgetl(fide); | ||||
|      | ||||
|     vers_found =  ~isempty(strfind(lin,'RINEX VERSION / TYPE')); | ||||
|     iono_found = (~isempty(strfind(lin,'ION ALPHA')) || ~isempty(strfind(lin,'IONOSPHERIC CORR'))); | ||||
| 
 | ||||
|     %if the ionosphere parameters label was found | ||||
|     if (vers_found) | ||||
|         version = str2num(lin(1:9)); | ||||
|     end | ||||
|      | ||||
|     %if the ionosphere parameters label was found | ||||
|     if (iono_found) | ||||
|         %change flag | ||||
|         %         ioparam = 1; | ||||
|         %save the 8 ionosphere parameters | ||||
|         data = textscan(lin(5:end),'%f%f%f%f%*[^\n]'); | ||||
|         if ~isempty(data(4)) | ||||
|             iono(1) = data{1}; | ||||
|             iono(2) = data{2}; | ||||
|             iono(3) = data{3}; | ||||
|             iono(4) = data{4}; | ||||
|             lin = []; | ||||
|             while isempty(lin) | ||||
|                 lin = fgetl(fide); | ||||
|             end | ||||
|             data = textscan(lin(5:end),'%f%f%f%f%*[^\n]'); | ||||
|             if ~isempty(data(4)) | ||||
|                 iono(5) = data{1}; | ||||
|                 iono(6) = data{2}; | ||||
|                 iono(7) = data{3}; | ||||
|                 iono(8) = data{4}; | ||||
|             else | ||||
|                 iono = zeros(8,1); | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|      | ||||
|     header_end = strfind(lin,'END OF HEADER'); | ||||
| end | ||||
| head_lines = head_lines + 1; | ||||
| noeph = -1; %初始化星历数目 | ||||
| while 1 | ||||
|    noeph = noeph+1; | ||||
|    line = fgetl(fide); | ||||
|    if line == -1, break;  end | ||||
| end; | ||||
| noeph = noeph/8  % 卫星星历数 = 去掉文件头之后的文件行数 / 8  | ||||
|                  % 每颗卫星星历行数是8行 | ||||
| 
 | ||||
| % 下面两行作用是回到文件头结束的地方 | ||||
| frewind(fide); | ||||
| for i = 1:head_lines, line = fgetl(fide); end; | ||||
| 
 | ||||
| % Set aside memory for the input, | ||||
| % 为星历中每个参数产生1行noeph列的0矩阵, | ||||
| % 每一列对应该星历文件中的一个PRN | ||||
| noeph = fix(noeph); | ||||
| svprn	 = zeros(1,noeph);  | ||||
| weekno	 = zeros(1,noeph); | ||||
| t0c	 = zeros(1,noeph); | ||||
| tgd	 = zeros(1,noeph); | ||||
| aodc	 = zeros(1,noeph); | ||||
| toe	 = zeros(1,noeph); | ||||
| af2	 = zeros(1,noeph); | ||||
| af1	 = zeros(1,noeph); | ||||
| af0	 = zeros(1,noeph); | ||||
| aode	 = zeros(1,noeph); | ||||
| deltan	 = zeros(1,noeph); | ||||
| M0	 = zeros(1,noeph); | ||||
| ecc	 = zeros(1,noeph); | ||||
| roota	 = zeros(1,noeph); | ||||
| toe	 = zeros(1,noeph); | ||||
| cic	 = zeros(1,noeph); | ||||
| crc	 = zeros(1,noeph); | ||||
| cis	 = zeros(1,noeph); | ||||
| crs	 = zeros(1,noeph); | ||||
| cuc	 = zeros(1,noeph); | ||||
| cus	 = zeros(1,noeph); | ||||
| Omega0	 = zeros(1,noeph); | ||||
| omega	 = zeros(1,noeph); | ||||
| i0	 = zeros(1,noeph); | ||||
| Omegadot = zeros(1,noeph); | ||||
| idot	 = zeros(1,noeph); | ||||
| accuracy = zeros(1,noeph); | ||||
| health	 = zeros(1,noeph); | ||||
| fit_interval = zeros(1,noeph); | ||||
| 
 | ||||
| % 将所有卫星的星历参数存入上面定义的矩阵中 | ||||
| for i = 1:noeph | ||||
|    line = fgetl(fide);	  % 从该组星历中第一颗卫星的星历的第一行开始 | ||||
|    svprn(i) = str2num(line(1:2)); % 存入卫星PRN | ||||
|    year = line(3:6); | ||||
|    month = line(7:9); | ||||
|    day = line(10:12); | ||||
|    hour = line(13:15); | ||||
|    minute = line(16:18); | ||||
|    second = line(19:22); | ||||
|    af0(i) = str2num(line(23:41)); | ||||
|    af1(i) = str2num(line(42:60)); | ||||
|    af2(i) = str2num(line(61:79)); | ||||
|     | ||||
|    line = fgetl(fide);	  % 读下一行 | ||||
|    IODE = line(4:22); | ||||
|    crs(i) = str2num(line(23:41)); | ||||
|    deltan(i) = str2num(line(42:60)); | ||||
|    M0(i) = str2num(line(61:79)); | ||||
|     | ||||
|    line = fgetl(fide);	  % 读下一行 | ||||
|    cuc(i) = str2num(line(4:22)); | ||||
|    ecc(i) = str2num(line(23:41)); | ||||
|    cus(i) = str2num(line(42:60)); | ||||
|    roota(i) = str2num(line(61:79)); | ||||
|     | ||||
|    line=fgetl(fide); % 读下一行 | ||||
|    toe(i) = str2num(line(4:22)); | ||||
|    cic(i) = str2num(line(23:41)); | ||||
|    Omega0(i) = str2num(line(42:60)); | ||||
|    cis(i) = str2num(line(61:79)); | ||||
|     | ||||
|    line = fgetl(fide);	    % 读下一行 | ||||
|    i0(i) =  str2num(line(4:22)); | ||||
|    crc(i) = str2num(line(23:41)); | ||||
|    omega(i) = str2num(line(42:60)); | ||||
|    Omegadot(i) = str2num(line(61:79)); | ||||
|     | ||||
|    line = fgetl(fide);	    % 读下一行 | ||||
|    idot(i) = str2num(line(4:22)); | ||||
|    codes = str2num(line(23:41)); | ||||
|    weekno = str2num(line(42:60)); | ||||
|    L2flag = str2num(line(61:79)); | ||||
|     | ||||
|    line = fgetl(fide);	    % 读下一行 | ||||
|    svaccur = str2num(line(4:22)); | ||||
|    svhealth(i) = str2num(line(23:41)); | ||||
|    tgd(i) = str2num(line(42:60)); | ||||
|    iodc = line(61:79); | ||||
|     | ||||
|    line = fgetl(fide);	    % 读下一行 | ||||
|    if length(line)>= 41 | ||||
|        tom(i) = str2num(line(4:22)); | ||||
|        fit_interval(i) = str2num(line(23:41)); | ||||
|    else | ||||
|        tom(i) = str2num(line(4:22)); | ||||
|        fit_interval(i) = 0; | ||||
|    end | ||||
| %    spare = line(42:60); | ||||
| %    spare = line(61:79); | ||||
| end | ||||
| status = fclose(fide) | ||||
| 
 | ||||
| %  Description of variable eph. | ||||
| % 把上面存好的各参数再转存到一个大矩阵“eph”中,该矩阵每行代表一种参数 | ||||
| % 每列代表一颗卫星 | ||||
| eph(1,:)  = svprn; | ||||
| eph(2,:)  = af2; | ||||
| eph(3,:)  = M0; | ||||
| eph(4,:)  = roota; | ||||
| eph(5,:)  = deltan; | ||||
| eph(6,:)  = ecc; | ||||
| eph(7,:)  = omega; | ||||
| eph(8,:)  = cuc; | ||||
| eph(9,:)  = cus; | ||||
| eph(10,:) = crc; | ||||
| eph(11,:) = crs; | ||||
| eph(12,:) = i0; | ||||
| eph(13,:) = idot; | ||||
| eph(14,:) = cic; | ||||
| eph(15,:) = cis; | ||||
| eph(16,:) = Omega0; | ||||
| eph(17,:) = Omegadot; | ||||
| eph(18,:) = toe; | ||||
| eph(19,:) = af0; | ||||
| eph(20,:) = af1; | ||||
| eph(21,:) = toe; | ||||
| eph(22,:) = fit_interval; | ||||
| eph(23,:) = svhealth; | ||||
| 
 | ||||
| fidu = fopen(outputfile,'w'); | ||||
| count = fwrite(fidu,[eph],'double'); | ||||
| fclose all | ||||
| %%%%%%%%% end rinexe.m %%%%%%%%% | ||||
|  | ||||
							
								
								
									
										25
									
								
								lib/gnss/satellite_az_el.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/gnss/satellite_az_el.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| function [az, el] = satellite_az_el(SP, RP) | ||||
| %% 计算卫星俯仰角(el), 和方位角(az) | ||||
| % get_satellite_az_el: computes the satellite azimuth and elevation | ||||
| % given the position of the user and the satellite in ECEF | ||||
| % : SP:    卫星位置ECEF | ||||
| %  RP:    用户位置ECEF | ||||
| % Output Args: | ||||
| % az: azimuth: 方位角 | ||||
| % el: elevation: 俯仰角 | ||||
| % 参考 GPS 原理及接收机设计 谢刚 | ||||
| 
 | ||||
| [lat, lon, ~] = ch_ECEF2LLA(RP); | ||||
| 
 | ||||
| C_ECEF2ENU = [-sin(lon) cos(lon) 0; -sin(lat)*cos(lon) -sin(lat)*sin(lon) cos(lat); cos(lat)*cos(lon) cos(lat)*sin(lon) sin(lat)]; | ||||
| 
 | ||||
| enu = C_ECEF2ENU*[SP - RP]; | ||||
| 
 | ||||
| % nroamlized line of silght vector | ||||
| enu = enu / norm(enu); | ||||
| 
 | ||||
| az = atan2(enu(1), enu(2)); | ||||
| el = asin(enu(3)/norm(enu)); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										92
									
								
								lib/gnss/set_constants.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								lib/gnss/set_constants.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| %******************************************************* | ||||
| % | ||||
| % DESCRIPTION: | ||||
| % 		This script contains many useful constants for GPS | ||||
| %       and related work.  It should be kept in only | ||||
| %       one place so that updates are immediately available  | ||||
| %       to all other scripts/functions. | ||||
| %   | ||||
| % ARGUMENTS: | ||||
| % 		None, just call this script to place  | ||||
| % 		the constants in your workspace. | ||||
| %   | ||||
| % OUTPUT: | ||||
| % 		Variables in your current workspace. | ||||
| %   | ||||
| % CALLED BY: | ||||
| % 		Many other codes. | ||||
| % | ||||
| % FUNCTIONS CALLED: | ||||
| % 		None. | ||||
| % | ||||
| % MODIFICATIONS:     | ||||
| %       XX-XX-02  :  Jan Weiss - Original | ||||
| %       07-25-04  :  Jan Weiss - updated header. | ||||
| %       10-19-04  :  Jan Weiss - Cleanup and added  | ||||
| %                                some conversion factors. | ||||
| %                 :  See SVN log for further updates. | ||||
| %  | ||||
| % Colorado Center for Astrodynamics Research | ||||
| % Copyright 2005 University of Colorado, Boulder | ||||
| %******************************************************* | ||||
| 
 | ||||
| % GENERAL CONSTANTS | ||||
| % ========================================================================= | ||||
| c = 299792458;          %----> Speed of light (meters/s). | ||||
| Re = 6378137 ;          %----> Earth Radius (meters) | ||||
| % ========================================================================= | ||||
| 
 | ||||
| 
 | ||||
| % CONVERSION FACTORS | ||||
| % ========================================================================= | ||||
| Hz2MHz = 1E-6; | ||||
| MHz2Hz = 1E6; | ||||
| s2ns = 1E9; | ||||
| ns2s = 1E-9; | ||||
| s2micros = 1E6; | ||||
| micros2s = 1E-6; | ||||
| s2ms = 1E3; | ||||
| ms2s = 1E-3; | ||||
| dtr = pi / 180; | ||||
| rtd = 180 / pi; | ||||
| m2cm = 100; | ||||
| cm2m = 1 / 100; | ||||
| m2mm = 1000; | ||||
| mm2m = 1 / 1000; | ||||
| ft2m = 0.3048;  % Source: http://www.nodc.noaa.gov/dsdt/ucg/ | ||||
| m2ft = 1 / 0.3048; | ||||
| ns2m = c * ns2s;  % Converts time in nano-sec to distance, | ||||
|                   % assuming the speed of light. | ||||
| % ========================================================================= | ||||
|    | ||||
| 
 | ||||
| % GNSS SPECIFIC CONSTANTS | ||||
| % ========================================================================= | ||||
| L1 = 1575.42e6;         %----> Freqs in Hz. | ||||
| L2 = 1227.60e6; | ||||
| L5 = 1176.45e6; | ||||
| 
 | ||||
| L1MHz = 1575.42;        %----> Freqs in MHz. | ||||
| L2MHz = 1227.60; | ||||
| L5MHz = 1176.45; | ||||
| 
 | ||||
| L1GHz = 1.57542;        %----> Freqs in GHz. | ||||
| L2GHz = 1.22760; | ||||
| L5GHz = 1.17645; | ||||
| 
 | ||||
| LAMBDA_L1 = c / L1;     %----> Wavelengths in meters. | ||||
| LAMBDA_L2 = c / L2; | ||||
| LAMBDA_L5 = c / L5; | ||||
| 
 | ||||
| CA_CODE_RATE = 1.023e6; %----> C/A and P code chipping rate in chips/s. | ||||
| P_CODE_RATE = 10.23e6; | ||||
| 
 | ||||
| CA_CHIP_PERIOD = 1 / CA_CODE_RATE;   %----> C/A & P code chip periods in s. | ||||
| P_CHIP_PERIOD = 1 / P_CODE_RATE; | ||||
| 
 | ||||
| CA_CHIP_LENGTH = c / CA_CODE_RATE;  %----> C/A & P code chip lengths in meters. | ||||
| P_CHIP_LENGTH = c / P_CODE_RATE; | ||||
| 
 | ||||
| CA_CODE_LENGTH = 1023;  % chips | ||||
| % ========================================================================= | ||||
| 
 | ||||
							
								
								
									
										37
									
								
								lib/gnss/sv_clock_bias.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/gnss/sv_clock_bias.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| function dtr = sv_clock_bias(t, toc, a0, a1, a2, e, sqrtA, toe, Delta_n, M0) | ||||
| % 输入: | ||||
| % a0 a1 a2 toc: 卫星时钟校正模型方程中3个参数,  toc: 第一数据块参考时间, 被用作时钟校正模型中时间参考点 | ||||
| 
 | ||||
| % dtr: 卫星时钟偏差 | ||||
| 
 | ||||
| dtr = a0+a1*(t-toc)+a2*(t-toc).^2;%t为未做钟差改正的观测时刻 | ||||
| 
 | ||||
| 
 | ||||
| F = -4.442807633e-10; | ||||
| mu = 3.986005e14; | ||||
| A = sqrtA^2; | ||||
| cmm = sqrt(mu/A^3); % computed mean motion | ||||
| tk = t - toe; | ||||
| % account for beginning or end of week crossover | ||||
| if (tk > 302400) | ||||
|     tk = tk-604800; | ||||
| end | ||||
| if (tk < -302400) | ||||
|     tk = tk+604800; | ||||
| end | ||||
| % apply mean motion correction | ||||
| n = cmm + Delta_n; | ||||
| 
 | ||||
| % Mean anomaly | ||||
| mk = M0 + n*tk; | ||||
| 
 | ||||
| % solve for eccentric anomaly | ||||
| Ek = mk; | ||||
| Ek = mk + e*sin(Ek); | ||||
| Ek = mk + e*sin(Ek); | ||||
| Ek = mk + e*sin(Ek); | ||||
| 
 | ||||
| % dsv 时间为s | ||||
| dtr = dtr + F*e*sqrtA*sin(Ek); | ||||
|   | ||||
| end | ||||
							
								
								
									
										86
									
								
								lib/gnss/tropo_correction.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								lib/gnss/tropo_correction.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | ||||
| function [corr] = tropo_correction(el, h) | ||||
| 
 | ||||
| % SYNTAX: | ||||
| %   [corr] = tropo_error_correction(el, h); | ||||
| % | ||||
| % INPUT: | ||||
| %   el = satellite elevation (rad) | ||||
| %   h  = receiver ellipsoidal height (m) | ||||
| % | ||||
| % OUTPUT: | ||||
| %   corr = tropospheric error correction | ||||
| % | ||||
| % DESCRIPTION: | ||||
| %   Computation of the pseudorange correction due to tropospheric refraction. | ||||
| %   Saastamoinen algorithm. | ||||
| 
 | ||||
| %---------------------------------------------------------------------------------------------- | ||||
| %                           goGPS v0.4.3 | ||||
| % | ||||
| % Copyright (C) 2009-2014 Mirko Reguzzoni, Eugenio Realini | ||||
| % | ||||
| % Portions of code contributed by Laboratorio di Geomatica, Polo Regionale di Como, | ||||
| %    Politecnico di Milano, Italy | ||||
| %---------------------------------------------------------------------------------------------- | ||||
| 
 | ||||
| global tropo_model | ||||
| 
 | ||||
| %Saastamoinen model requires positive ellipsoidal height | ||||
| h(h < 0) = 0; | ||||
| 
 | ||||
| % If in ATM_model section in config file tropo is set to 0 it does not use tropospheric model | ||||
| % [ATM_model] | ||||
| % tropo=0 | ||||
| if (tropo_model == 0) | ||||
|     corr = zeros(size(el)); | ||||
| else | ||||
|     if (h < 5000) | ||||
| 
 | ||||
| 	%conversion to radians | ||||
| 	el = abs(el); | ||||
| 
 | ||||
| 	    %Standard atmosphere - Berg, 1948 (Bernese) | ||||
| 	%pressure [mbar] | ||||
| 	Pr = 1013.25; | ||||
| 	%temperature [K] | ||||
| 	Tr = 291.15; | ||||
| 	%numerical constants for the algorithm [-] [m] [mbar] | ||||
| 	Hr = 50.0; | ||||
| 
 | ||||
| 	P = Pr * (1-0.0000226*h).^5.225; | ||||
| 	T = Tr - 0.0065*h; | ||||
| 	H = Hr * exp(-0.0006396*h); | ||||
| 
 | ||||
| 	%---------------------------------------------------------------------- | ||||
| 
 | ||||
| 	%linear interpolation | ||||
| 	h_a = [0; 500; 1000; 1500; 2000; 2500; 3000; 4000; 5000]; | ||||
| 	B_a = [1.156; 1.079; 1.006; 0.938; 0.874; 0.813; 0.757; 0.654; 0.563]; | ||||
| 
 | ||||
| 	t = zeros(length(T),1); | ||||
| 	B = zeros(length(T),1); | ||||
| 
 | ||||
| 	for i = 1 : length(T) | ||||
| 
 | ||||
| 	    d = h_a - h(i); | ||||
| 	    [dmin, j] = min(abs(d)); | ||||
| 	    if (d(j) > 0) | ||||
| 		index = [j-1; j]; | ||||
| 	    else | ||||
| 		index = [j; j+1]; | ||||
| 	    end | ||||
| 
 | ||||
| 	    t(i) = (h(i) - h_a(index(1))) ./ (h_a(index(2)) - h_a(index(1))); | ||||
| 	    B(i) = (1-t(i))*B_a(index(1)) + t(i)*B_a(index(2)); | ||||
| 	end | ||||
| 
 | ||||
| 	%---------------------------------------------------------------------- | ||||
| 
 | ||||
| 	e = 0.01 * H .* exp(-37.2465 + 0.213166*T - 0.000256908*T.^2); | ||||
| 
 | ||||
| 	%tropospheric error | ||||
| 	corr = ((0.002277 ./ sin(el)) .* (P - (B ./ (tan(el)).^2)) + (0.002277 ./ sin(el)) .* (1255./T + 0.05) .* e); | ||||
|     else | ||||
| 	corr = zeros(size(el)); | ||||
|     end | ||||
| end | ||||
							
								
								
									
										73
									
								
								lib/madgwick.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								lib/madgwick.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| classdef madgwick < handle | ||||
|     methods (Static = true) | ||||
|          | ||||
|         function q = imu(q, Gyroscope, Accelerometer, SamplePeriod, Beta) | ||||
|              | ||||
|             % Normalise accelerometer measurement | ||||
|             acc = Accelerometer; | ||||
|             if(norm(acc) == 0), return; end   % handle NaN | ||||
|             acc = acc / norm(acc);  % normalise magnitude | ||||
|              | ||||
|             % Gradient decent algorithm corrective step | ||||
|             F = (quatrotate(q, [0 0 1]) - acc)'; | ||||
| %             F = [2*(q(2)*q(4) - q(1)*q(3)) - Accelerometer(1) | ||||
| %                 2*(q(1)*q(2) + q(3)*q(4)) - Accelerometer(2) | ||||
| %                 2*(0.5 - q(2)^2 - q(3)^2) - Accelerometer(3)]; | ||||
| 
 | ||||
|             J = [-2*q(3),	2*q(4),    -2*q(1),	2*q(2) | ||||
|                 2*q(2),     2*q(1),     2*q(4),	2*q(3) | ||||
|                 0,         -4*q(2),    -4*q(3),	0    ]; | ||||
|             step = (J'*F); | ||||
|             step = step / norm(step);	% normalise step magnitude | ||||
|              | ||||
|             % Compute rate of change of quaternion | ||||
|             qd = 0.5 * quatmultiply(q, [0 Gyroscope]) - Beta * step'; | ||||
|              | ||||
|             % Integrate to yield quaternion | ||||
|             q = q + qd * SamplePeriod; | ||||
|             q = q / norm(q); % normalise quaternion | ||||
|         end | ||||
|          | ||||
|         function q = ahrs(q, Gyroscope, Accelerometer, Magnetometer, SamplePeriod, Beta) | ||||
|              | ||||
|             % Normalise accelerometer measurement | ||||
|             if(norm(Accelerometer) == 0), return; end	% handle NaN | ||||
|             acc = Accelerometer / norm(Accelerometer);	% normalise magnitude | ||||
|              | ||||
|             % Normalise magnetometer measurement | ||||
|             if(norm(Magnetometer) == 0), return; end	% handle NaN | ||||
|             mag = Magnetometer / norm(Magnetometer);	% normalise magnitude | ||||
|              | ||||
|             % Reference direction of Earth's magnetic feild | ||||
|             h = quatrotate(quatconj(q), mag); | ||||
|             h = [0 h]; | ||||
|             b = [0 norm([h(2) h(3)]) 0 h(4)]; | ||||
|              | ||||
|             % Gradient decent algorithm corrective step | ||||
|              F= (quatrotate(q, [0 0 1]) - acc)'; | ||||
|              F = [F;  (quatrotate(q, [b(2) 0 b(4)]) - mag)']; | ||||
|              | ||||
| %             F = [2*(q(2)*q(4) - q(1)*q(3)) - Accelerometer(1) | ||||
| %                 2*(q(1)*q(2) + q(3)*q(4)) - Accelerometer(2) | ||||
| %                 2*(0.5 - q(2)^2 - q(3)^2) - Accelerometer(3) | ||||
| %                 2*b(2)*(0.5 - q(3)^2 - q(4)^2) + 2*b(4)*(q(2)*q(4) - q(1)*q(3)) - Magnetometer(1) | ||||
| %                 2*b(2)*(q(2)*q(3) - q(1)*q(4)) + 2*b(4)*(q(1)*q(2) + q(3)*q(4)) - Magnetometer(2) | ||||
| %                 2*b(2)*(q(1)*q(3) + q(2)*q(4)) + 2*b(4)*(0.5 - q(2)^2 - q(3)^2) - Magnetometer(3)]; | ||||
|             J = [-2*q(3),                 	2*q(4),                    -2*q(1),                         2*q(2) | ||||
|                 2*q(2),                 	2*q(1),                    	2*q(4),                         2*q(3) | ||||
|                 0,                         -4*q(2),                    -4*q(3),                         0 | ||||
|                 -2*b(4)*q(3),               2*b(4)*q(4),               -4*b(2)*q(3)-2*b(4)*q(1),       -4*b(2)*q(4)+2*b(4)*q(2) | ||||
|                 -2*b(2)*q(4)+2*b(4)*q(2),	2*b(2)*q(3)+2*b(4)*q(1),	2*b(2)*q(2)+2*b(4)*q(4),       -2*b(2)*q(1)+2*b(4)*q(3) | ||||
|                 2*b(2)*q(3),                2*b(2)*q(4)-4*b(4)*q(2),	2*b(2)*q(1)-4*b(4)*q(3),        2*b(2)*q(2)]; | ||||
|             step = (J'*F); | ||||
|             step = step / norm(step);	% normalise step magnitude | ||||
|              | ||||
|             % Compute rate of change of quaternion | ||||
|             qd = 0.5 * quatmultiply(q, [0 Gyroscope]) - Beta * step'; | ||||
| 
 | ||||
|             % Integrate to yield quaternion | ||||
|             q = q + qd * SamplePeriod; | ||||
|             q = q / norm(q); % normalise quaternion | ||||
|         end | ||||
|     end | ||||
| end | ||||
							
								
								
									
										52
									
								
								lib/mahony.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/mahony.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| classdef mahony < handle | ||||
|     methods (Static = true) | ||||
|         function q = imu(q, gyr, acc, dt, Kp) | ||||
|              | ||||
|             % 속醵똑데貫뺏 | ||||
|             norm_acc =  norm(acc); | ||||
|             if((norm_acc) == 0), return; end  | ||||
|             acc = acc / norm(acc); | ||||
|              | ||||
|             qtmp = att_upt(q, gyr, dt); | ||||
|              | ||||
|             v = qmulv(qconj(qtmp), [0 0 1]'); | ||||
|              | ||||
|             e = cross(acc, v) ; | ||||
|              | ||||
|             % 럽웩 | ||||
|             gyr = gyr + Kp * e ; | ||||
|              | ||||
|             % 생롸 | ||||
|             q = qintg(q, gyr, dt); | ||||
|         end | ||||
|          | ||||
|          | ||||
|         function q = ahrs(q, gyr, acc, mag, dt, Kp) | ||||
|              | ||||
|             % 속醵똑셕데貫뺏 | ||||
|             if(norm(acc) == 0), return; end   % handle NaN | ||||
|             acc = acc / norm(acc);    % normalise magnitude | ||||
|              | ||||
|             % 늚끝데貫뺏 | ||||
|             if(norm(mag) == 0), return; end    % handle NaN | ||||
|             mag = mag / norm(mag);   % normalise magnitude | ||||
|              | ||||
|             % Reference direction of Earth's magnetic feild | ||||
|             h = qmulv(q, mag); | ||||
|             b = [norm([h(1) h(2)]) 0 h(3)]'; | ||||
|              | ||||
|             % Estimated direction of gravity and magnetic field | ||||
|             w = qmulv(qconj(q), b); | ||||
|             v = qmulv(qconj(q), [0 0 1]'); | ||||
|              | ||||
|             % Error is sum of cross product between estimated direction and measured direction of fields | ||||
|             e = cross(acc, v) + cross(mag, w); | ||||
|              | ||||
|             % Apply feedback terms | ||||
|             gyr = gyr + Kp * e ; | ||||
|              | ||||
|             % integate | ||||
|             q = qintg(q, gyr, dt); | ||||
|         end | ||||
|     end | ||||
| end | ||||
							
								
								
									
										23
									
								
								lib/mat2c.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/mat2c.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| function mat2c(mat) | ||||
|     [r, c] = size(mat); | ||||
|     mn = r*c; | ||||
| 
 | ||||
|     fprintf('{'); | ||||
|     if r==1||c==1 | ||||
|         for i=1:mn-1 | ||||
|             fprintf('%f,', mat(i)); | ||||
|         end | ||||
|         fprintf('%f};\n', mat(i+1)); | ||||
|     else | ||||
|         for i=1:r-1 | ||||
|             for j=1:c | ||||
|                 fprintf('%f,', mat(i,j)); | ||||
|             end | ||||
|             fprintf('\n'); | ||||
|         end | ||||
|         for j=1:c-1 | ||||
|             fprintf('%f,', mat(i+1,j)); | ||||
|         end | ||||
|         fprintf('%f};\n', mat(i+1,j+1)); | ||||
|     end | ||||
| end | ||||
							
								
								
									
										81
									
								
								lib/multilateration.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								lib/multilateration.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| function pos = multilateration(sv_pos, pos, pr, dim) | ||||
| %% 最小二乘法多边测距 解算标签位置 | ||||
| % M x N:  M:维度 2 OR 3  N:基站个数 | ||||
| % sv_pos: 基站位置 M x N  | ||||
| % pos:  M x 1  | ||||
| % pr:  伪距 N x 1 | ||||
| % dim : 2 or 3 : 2: 二维定位  3: 三维定位 | ||||
| 
 | ||||
| B1 = 0.1;                 % 迭代收敛阈值(位置更新量小于此值时停止) | ||||
| END_LOOP = 100;           % 初始迭代残差(设为较大值) | ||||
| sv_num = size(sv_pos, 2); % 基站数量 | ||||
| max_retry = 5;            % 最大迭代次数 | ||||
| lpos = pos;               % 保存上一次的位置,用于迭代失败时回退 | ||||
| 
 | ||||
| % 设置约束,如果基站数量少于3,则直接退出。 | ||||
| % 因为解算位置需满足以下条件: | ||||
| % 2D定位:至少3个非共线基站。 | ||||
| % 3D定位:至少4个非共面基站。 | ||||
| if sv_num < 3 | ||||
|     return | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| while (END_LOOP > B1 && max_retry > 0)  % 循环条件:位置更新量大于阈值B1且未超过最大迭代次数 | ||||
|     % 获得当前位置与各个基站的欧氏距离 | ||||
|     r = vecnorm(sv_pos - pos); | ||||
|      | ||||
|     % 求得H矩阵 | ||||
|     H = (sv_pos - pos) ./ r; % 求每个矩阵的单位方向向量, ./是将矩阵中每个对应元素逐个做除法运算 | ||||
|     if dim == 2 | ||||
|         H = [H [0 0 -1]'];   % 如果是2D模式,添加虚拟高度约束 | ||||
|     end | ||||
|     H =-H';                  % 转置并取负,H 是伪距对位置的偏导数矩阵(雅可比矩阵),用于线性化非线性问题 | ||||
|      | ||||
|     % 构建残差向量dp | ||||
|     dp = (pr - r)';          % 伪距测量残差 = 测量值 - 预测值 | ||||
|     if dim == 2 | ||||
|         dp = [dp; 0];        % 如果是2D模式,添加高度残差约束 | ||||
|     end | ||||
|      | ||||
|     % 迭代用户距离(位置增量) | ||||
|     delta =  (H'*H)^(-1)*H'*dp; % 最小二乘解算 | ||||
|      | ||||
|     %计算残差,以判断残差大小是否可以停止迭代 | ||||
|     % 残差就是“测量值减去估计值”的差距,代表你当前估计的误差。 | ||||
|     END_LOOP = norm(delta); % 欧几里得范数(向量的长度),表示这次更新的幅度。 | ||||
|      | ||||
|     %更新位置 | ||||
|     pos = pos + delta; | ||||
|     max_retry = max_retry - 1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         % 减少剩余迭代次数 | ||||
|      | ||||
|     %迭代失败 如果到达了最大迭代次数还没有收敛,则说明定位失败 | ||||
|     if(max_retry == 0 && END_LOOP > 10) | ||||
|         pos = lpos; % 就会回滚到上一次迭代的结果 | ||||
|         return; | ||||
|     end | ||||
|      | ||||
| end | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| % | ||||
| % % 最小二乘法多边测距 | ||||
| % | ||||
| % function pos = ch_multilateration(anchor_pos,  pos, pr) | ||||
| % | ||||
| % pr = pr(1:size(anchor_pos, 2)); | ||||
| % | ||||
| % b = vecnorm(anchor_pos).^(2) - pr.^(2); | ||||
| % b = b(1:end-1) - b(end); | ||||
| % b = b'; | ||||
| % | ||||
| % A =  anchor_pos - anchor_pos(:,end); | ||||
| % A = A(:,1:end-1)'*2; | ||||
| % | ||||
| % pos = (A'*A)^(-1)*A'*b; | ||||
| %                                                                                    | ||||
| %   | ||||
| % end | ||||
| 
 | ||||
							
								
								
									
										60
									
								
								lib/nav_equ_local_tan.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/nav_equ_local_tan.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| function [p, v, q] = nav_equ_local_tan(p, v, q ,acc, gyr, dt, gN) | ||||
| %  惯导解算更新,当地直角坐标系,不考虑地球自转 | ||||
| % p          位置 XYZ 单位 m | ||||
| % v          速度 XYZ 单位 m/s | ||||
| % q         Qb2n姿态,四元数表示 | ||||
| % acc      比力, 加速度计测量值 单位  (m/s^2),  | ||||
| % gyr      角速度 (rad/s)] | ||||
| % dt        dt (s) 积分间隔如 0.01s | ||||
| % gn       当地重力向量 | ||||
| 
 | ||||
| old_v = v;  % 保存当前速度,用于后续梯形积分 | ||||
| 
 | ||||
| sf = acc;   % 比力(Specific Force) = 加速度计测量值(忽略零偏和噪声) | ||||
| 
 | ||||
| %  姿态结算 | ||||
| q = att_upt(q, gyr, dt);  % 通过陀螺仪数据更新四元数 | ||||
|                              % 输入当前姿态四元数和陀螺仪角速度,输出更新后的姿态四元数 | ||||
| 
 | ||||
| 
 | ||||
| % 速度解算 | ||||
| sf = qmulv(q, sf);  % 将比力从机体系转换到导航系 | ||||
| sf = sf + gN;          % 添加重力补偿(导航系下) | ||||
| v = old_v + dt *sf;    % 积分加速度得到速度 | ||||
| 
 | ||||
| % 位置解算 | ||||
| p = p + (old_v + v) *dt/2;  % 梯形法积分速度 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| %  | ||||
| %  | ||||
| % function x = ch_nav_equ_local_tan(x ,u, dt, gN) | ||||
| %  | ||||
| % persistent a_old; | ||||
| % if isempty(a_old) | ||||
| %    a_old= u(1:3); | ||||
| % end | ||||
| %     | ||||
| % old_v = x(4:6); | ||||
| %  | ||||
| % a_new =u(1:3);  | ||||
| % %sf = sf + 0.5*cross(u(4:6)*dt, sf); | ||||
| %  | ||||
| % %  姿态结算 | ||||
| % gyr = u(4:6); | ||||
| % q_old = x(7:10); | ||||
| % x(7:10) = ch_att_upt(x(7:10), gyr, dt); | ||||
| % q_new = x(7:10); | ||||
| %  | ||||
| % % 速度解算 | ||||
| %  | ||||
| % x(4:6) = old_v + ((ch_qmulv(q_new, a_new) + ch_qmulv(q_old, a_old) )/2 + gN) *dt; | ||||
| %  | ||||
| % % 位置解算 | ||||
| % x(1:3) = x(1:3) + (old_v + x(4:6)) *dt/2; | ||||
| % a_old = a_new; | ||||
| % end | ||||
| %  | ||||
| %  | ||||
							
								
								
									
										6
									
								
								lib/ned2enu.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/ned2enu.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| function ENU  = ned2enu(NED) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										30
									
								
								lib/plot/ch_plot_att.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/plot/ch_plot_att.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| function ch_plot_att(att, varargin) | ||||
| %  plot 欧拉角 | ||||
| % att        欧拉角 | ||||
| % 可选参数: units: "rad" 或者 "deg", 默认 rad | ||||
| 
 | ||||
| 
 | ||||
| defaultUnits = 'rad'; | ||||
| 
 | ||||
| param= inputParser; | ||||
| addParameter(param,'units',defaultUnits,@isstring); | ||||
|     | ||||
| param.parse(varargin{:}); | ||||
| r = param.Results; | ||||
| 
 | ||||
| 
 | ||||
| if(~isempty(r.units)) | ||||
|     defaultUnits = r.units; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| plot(att); | ||||
| title("欧拉角"); | ||||
| legend("X", "Y", "Z"); | ||||
| xlabel("解算次数");  | ||||
| ylabel(defaultUnits);  | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										39
									
								
								lib/plot/ch_plot_gps_imu_pos.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lib/plot/ch_plot_gps_imu_pos.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| % subplot£ºÊÇ·ñ¿ªÆôsubplot | ||||
| function ch_plot_gps_imu_pos(varargin) | ||||
| %%  plot imu data | ||||
| i = 1; | ||||
| param= inputParser; | ||||
| param.addOptional('time', []); | ||||
| param.addOptional('pos', []); | ||||
| param.addOptional('gnss', []); | ||||
| 
 | ||||
| param.parse(varargin{:}); | ||||
| r = param.Results; | ||||
| 
 | ||||
| if(r.time == 0 ) | ||||
|     error('no time data'); | ||||
| end | ||||
| 
 | ||||
| figure; | ||||
| subplot(2,1,1); | ||||
| plot(r.gnss(:,2), r.gnss(:,1),'b-'); | ||||
| hold on; | ||||
| plot(r.gnss(:,2), r.gnss(:,1),'b.'); | ||||
| plot(r.pos(:,2), r.pos(:,1), 'r-'); | ||||
| plot(r.pos(1,1), r.pos(1,2),'ks'); | ||||
| legend('GNSS position estimate','GNSS aided INS trajectory','Start point') | ||||
| axis equal | ||||
| hold off; | ||||
| xlabel('X(m)'); ylabel('Y(m)');  title('Trajectory'); | ||||
| 
 | ||||
| subplot(2,1,2); | ||||
| hold on; | ||||
| plot(1:length(r.gnss), -r.gnss(:,3),'b.'); | ||||
| plot(r.time, -r.pos(:,3),'r'); | ||||
| legend('GNSS estimate','GNSS aided INS estimate') | ||||
| title('Height versus time');  xlabel('Time [s]');  ylabel('Height [m]'); | ||||
| hold off; | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
							
								
								
									
										108
									
								
								lib/plot/ch_plot_imu.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/plot/ch_plot_imu.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| % subplot:是否开启subplot | ||||
| function ch_plot_imu(varargin) | ||||
| %%  plot imu data | ||||
| i = 1; | ||||
| param= inputParser; | ||||
| param.addOptional('time', []); | ||||
| param.addOptional('acc', []); | ||||
| param.addOptional('gyr', []); | ||||
| param.addOptional('mag', []); | ||||
| param.addOptional('eul', []); | ||||
| param.addOptional('gb', []); % 加速度零偏 | ||||
| param.addOptional('wb', []); % 陀螺零偏 | ||||
| param.addOptional('phi', []); %失准角 | ||||
| param.addOptional('P_phi', []); %失准角方差 | ||||
| param.addOptional('P_wb', []); %陀螺方差 | ||||
| param.addOptional('P_pos', []); %位置方差 | ||||
| param.addOptional('title', []); | ||||
| param.addOptional('legend', []); | ||||
| 
 | ||||
| 
 | ||||
| %然后将输入的参数进行处理,如果有不同于默认值的那就覆盖掉 | ||||
| param.parse(varargin{:}); | ||||
| r = param.Results; | ||||
| 
 | ||||
| if(r.time == 0 ) | ||||
|     error('no time data'); | ||||
| end | ||||
| i = 1; | ||||
| 
 | ||||
| figure; | ||||
| 
 | ||||
| if(~isempty(r.gyr)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.gyr, {'X', 'Y', 'Z'}, 'Time (s)', 'Angular rate)', 'Gyroscope'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.acc)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.acc, {'X', 'Y', 'Z'}, 'Time (s)', 'Acceleration', 'Accelerometer'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.mag)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.mag, {'X', 'Y', 'Z'}, 'Time (s)', 'Flux ', 'Magnetometer'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.eul)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.eul, {'X', 'Y', 'Z'}, 'Time (s)', 'Angle(deg)', 'Eular Angle'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.wb)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.wb, {'X', 'Y', 'Z'}, 'Time (s)', 'Angle(deg)', '陀螺零偏'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.gb)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.gb, {'X', 'Y', 'Z'}, 'Time (s)', 'm/s^(2)', '加速度零偏'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.phi)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.phi, {'X', 'Y', 'Z'}, 'Time (s)', 'Angle(deg)', '失准角'); | ||||
| end | ||||
| 
 | ||||
| if(~isempty(r.P_phi)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.P_phi, {'X', 'Y', 'Z'}, 'Time (s)', '-', 'Phi Var(失准角方差)'); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| if(~isempty(r.P_wb)) | ||||
|     subplot(2,2,i); | ||||
|     i = i+1; | ||||
|     interial_display(r.time,  r.P_wb, {'X', 'Y', 'Z'}, 'Time (s)', '-', '陀螺零偏方差'); | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| if(~isempty(r.P_pos)) | ||||
|     subplot(2,2,i); | ||||
|     interial_display(r.time,  r.P_pos, {'X', 'Y', 'Z'}, 'Time (s)', '-', '位置方差'); | ||||
| end | ||||
| 
 | ||||
| %    linkaxes(axis, 'x'); | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| function interial_display(time, data, legendstr, xlabelstr, ylabelstr, titlestr) | ||||
| hold on; | ||||
| plot(time, data(:,1), 'r'); | ||||
| plot(time, data(:,2), 'g'); | ||||
| plot(time, data(:,3), 'b'); | ||||
| legend(legendstr); | ||||
| xlabel(xlabelstr); | ||||
| ylabel(ylabelstr); | ||||
| title(titlestr); | ||||
| hold off; | ||||
| end | ||||
							
								
								
									
										26
									
								
								lib/plot/ch_plot_pos2d.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								lib/plot/ch_plot_pos2d.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| function ch_plot_pos2d(pos, varargin) | ||||
| %  pos: 位置: X, Y | ||||
| 
 | ||||
| defaultUnits = 'm'; | ||||
| 
 | ||||
| param= inputParser; | ||||
| addParameter(param,'units',defaultUnits,@isstring); | ||||
| 
 | ||||
| param.parse(varargin{:}); | ||||
| r = param.Results; | ||||
| 
 | ||||
| 
 | ||||
| if(~isempty(r.units)) | ||||
|     defaultUnits = r.units; | ||||
| end | ||||
| 
 | ||||
| plot(pos(:,1), pos(:,2)); | ||||
| 
 | ||||
| title("2D位置" + "(" + defaultUnits + ")") ; | ||||
| xlabel("X"); ylabel("Y"); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										25
									
								
								lib/plot/ch_plot_pos3d.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/plot/ch_plot_pos3d.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| function ch_plot_pos3d(pos, varargin) | ||||
| % pos: 位置: X, Y, Z | ||||
| 
 | ||||
| defaultUnits = 'm'; | ||||
| 
 | ||||
| param= inputParser; | ||||
| addParameter(param,'units',defaultUnits,@isstring); | ||||
| 
 | ||||
| param.parse(varargin{:}); | ||||
| r = param.Results; | ||||
| 
 | ||||
| 
 | ||||
| if(~isempty(r.units)) | ||||
|     defaultUnits = r.units; | ||||
| end | ||||
| 
 | ||||
| plot(pos(:,1), pos(:,2)); | ||||
| plot3(pos(:,1), pos(:,2), pos(:,3)); | ||||
| 
 | ||||
| title("3D位置" + "(" + defaultUnits + ")") ; | ||||
|  xlabel("X"); ylabel("Y"); zlabel("Z"); | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										47
									
								
								lib/ros_read_bag.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/ros_read_bag.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| %% Example | ||||
| % path = 'imu3_codeodom_tst.bag'; | ||||
| %  | ||||
| % rosbag info 'imu3_codeodom_tst.bag' | ||||
| % [imu, eul]=  ch_ros_read_bag(path,  '/imu_hi226'); | ||||
| % ch_imu_data_plot('acc', imu.acc',  'gyr', imu.gyr', 'eul', eul',  'time',  imu.time', 'subplot', 1); | ||||
| %% | ||||
| 
 | ||||
| 
 | ||||
| function [imu, eul]= ros_read_bag(path, imu_topic_name) | ||||
| 
 | ||||
| bag = rosbag(path); | ||||
| 
 | ||||
| %ÏÔʾbagÐÅÏ¢ | ||||
| % rosbag info 'imu3_codeodom_tst.bag' | ||||
| 
 | ||||
| % bag = select(bag, 'Time', [bag.StartTime+100  bag.StartTime + 110], 'Topic',imu_topic_name); | ||||
| bag = select(bag, 'Topic', imu_topic_name); | ||||
| 
 | ||||
| 
 | ||||
| imu_cell = readMessages(bag); | ||||
| 
 | ||||
| n = length(imu_cell); | ||||
| 
 | ||||
| span = bag.EndTime -  bag.StartTime ; | ||||
| imu.time = 0: span / n : span; | ||||
| imu.time(end) = []; % remove last element | ||||
| 
 | ||||
| for i = 1:n | ||||
|     imu.gyr(1,i) = imu_cell{i,1}.AngularVelocity.X; | ||||
|     imu.gyr(2,i) = imu_cell{i,1}.AngularVelocity.Y; | ||||
|     imu.gyr(3,i) = imu_cell{i,1}.AngularVelocity.Z; | ||||
|      | ||||
|     imu.acc(1,i) = imu_cell{i,1}.LinearAcceleration.X; | ||||
|     imu.acc(2,i) = imu_cell{i,1}.LinearAcceleration.Y; | ||||
|     imu.acc(3,i) = imu_cell{i,1}.LinearAcceleration.Z; | ||||
|      | ||||
|     q(1) =  imu_cell{i, 1}.Orientation.W; | ||||
|     q(2) =  imu_cell{i, 1}.Orientation.X; | ||||
|     q(3) =  imu_cell{i, 1}.Orientation.Y; | ||||
|     q(4) =  imu_cell{i, 1}.Orientation.Z; | ||||
|     eul(:, i) = q2eul(q); | ||||
| end | ||||
| 
 | ||||
| eul = rad2deg(eul); | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										255
									
								
								lib/rotation/SixDOFanimation.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								lib/rotation/SixDOFanimation.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,255 @@ | ||||
| function fig = SixDOFanimation(varargin) | ||||
| 
 | ||||
|     %% Create local variables | ||||
| 
 | ||||
|     % Required arguments | ||||
|     p = varargin{1};                % position of body | ||||
|     R = varargin{2};                % rotation matrix of body | ||||
|     [numSamples dummy] = size(p); | ||||
| 
 | ||||
|     % Default values of optional arguments | ||||
|     SamplePlotFreq = 1; | ||||
|     Trail = 'Off'; | ||||
|     LimitRatio = 1; | ||||
|     Position = []; | ||||
|     FullScreen = false; | ||||
|     View = [30 20]; | ||||
|     AxisLength = 1; | ||||
|     ShowArrowHead = 'on'; | ||||
|     Xlabel = 'X'; | ||||
|     Ylabel = 'Y'; | ||||
|     Zlabel = 'Z'; | ||||
|     Title = '6DOF Animation'; | ||||
|     ShowLegend = true; | ||||
|     CreateAVI = false; | ||||
|     AVIfileName = '6DOF Animation'; | ||||
|     AVIfileNameEnum = true; | ||||
|     AVIfps = 30; | ||||
| 
 | ||||
|     for i = 3:2:nargin | ||||
|         if  strcmp(varargin{i}, 'SamplePlotFreq'), SamplePlotFreq = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Trail') | ||||
|             Trail = varargin{i+1}; | ||||
|             if(~strcmp(Trail, 'Off') && ~strcmp(Trail, 'DotsOnly') && ~strcmp(Trail, 'All')) | ||||
|                 error('Invalid argument.  Trail must be ''Off'', ''DotsOnly'' or ''All''.'); | ||||
|             end | ||||
|         elseif  strcmp(varargin{i}, 'LimitRatio'), LimitRatio = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Position'), Position = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'FullScreen'), FullScreen = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'View'), View = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'AxisLength'), AxisLength = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'ShowArrowHead'), ShowArrowHead = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Xlabel'), Xlabel = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Ylabel'), Ylabel = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Zlabel'), Zlabel = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'Title'), Title = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'ShowLegend'), ShowLegend = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'CreateAVI'), CreateAVI = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'AVIfileName'), AVIfileName = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'AVIfileNameEnum'), AVIfileNameEnum = varargin{i+1}; | ||||
|         elseif  strcmp(varargin{i}, 'AVIfps'), AVIfps = varargin{i+1}; | ||||
|         else error('Invalid argument.'); | ||||
|         end | ||||
|     end; | ||||
| 
 | ||||
|     %% Reduce data to samples to plot only | ||||
| 
 | ||||
|     p = p(1:SamplePlotFreq:numSamples, :); | ||||
|     R = R(:, :, 1:SamplePlotFreq:numSamples) * AxisLength; | ||||
|     if(numel(View) > 2) | ||||
|         View = View(1:SamplePlotFreq:numSamples, :); | ||||
|     end | ||||
|     [numPlotSamples dummy] = size(p); | ||||
| 
 | ||||
|     %% Setup AVI file | ||||
| 
 | ||||
|     aviobj = [];                                                            	% create null object | ||||
|     if(CreateAVI) | ||||
|         fileName = strcat(AVIfileName, '.avi'); | ||||
|         if(exist(fileName, 'file')) | ||||
|             if(AVIfileNameEnum)                                              	% if file name exists and enum enabled | ||||
|                 i = 0; | ||||
|                 while(exist(fileName, 'file'))                                  % find un-used file name by appending enum | ||||
|                     fileName = strcat(AVIfileName, sprintf('%i', i), '.avi'); | ||||
|                     i = i + 1; | ||||
|                 end | ||||
|             else                                                                % else file name exists and enum disabled | ||||
|                 fileName = [];                                                  % file will not be created | ||||
|             end | ||||
|         end | ||||
|         if(isempty(fileName)) | ||||
|             sprintf('AVI file not created as file already exists.') | ||||
|         else | ||||
|             aviobj = avifile(fileName, 'fps', AVIfps, 'compression', 'Cinepak', 'quality', 100); | ||||
|         end | ||||
|     end | ||||
| 
 | ||||
|     %% Setup figure and plot | ||||
| 
 | ||||
|     % Create figure | ||||
|     fig = figure('NumberTitle', 'off', 'Name', '6DOF Animation'); | ||||
|     if(FullScreen) | ||||
|         screenSize = get(0, 'ScreenSize'); | ||||
|         set(fig, 'Position', [0 0 screenSize(3) screenSize(4)]); | ||||
|     elseif(~isempty(Position)) | ||||
|         set(fig, 'Position', Position); | ||||
|     end | ||||
|     set(gca, 'drawmode', 'fast'); | ||||
|     lighting phong; | ||||
|     set(gcf, 'Renderer', 'zbuffer'); | ||||
|     hold on; | ||||
|     axis equal; | ||||
|     grid on; | ||||
|     view(View(1, 1), View(1, 2)); | ||||
|     title(i); | ||||
|     xlabel(Xlabel); | ||||
|     ylabel(Ylabel); | ||||
|     zlabel(Zlabel); | ||||
| 
 | ||||
|     % Create plot data arrays | ||||
|     if(strcmp(Trail, 'DotsOnly') || strcmp(Trail, 'All')) | ||||
|         x = zeros(numPlotSamples, 1); | ||||
|         y = zeros(numPlotSamples, 1); | ||||
|         z = zeros(numPlotSamples, 1); | ||||
|     end | ||||
|     if(strcmp(Trail, 'All')) | ||||
|         ox = zeros(numPlotSamples, 1); | ||||
|         oy = zeros(numPlotSamples, 1); | ||||
|         oz = zeros(numPlotSamples, 1); | ||||
|         ux = zeros(numPlotSamples, 1); | ||||
|         vx = zeros(numPlotSamples, 1); | ||||
|         wx = zeros(numPlotSamples, 1); | ||||
|         uy = zeros(numPlotSamples, 1); | ||||
|         vy = zeros(numPlotSamples, 1); | ||||
|         wy = zeros(numPlotSamples, 1); | ||||
|         uz = zeros(numPlotSamples, 1); | ||||
|         vz = zeros(numPlotSamples, 1); | ||||
|         wz = zeros(numPlotSamples, 1); | ||||
|     end | ||||
|     x(1) = p(1,1); | ||||
|     y(1) = p(1,2); | ||||
|     z(1) = p(1,3); | ||||
|     ox(1) = x(1); | ||||
|     oy(1) = y(1); | ||||
|     oz(1) = z(1); | ||||
|     ux(1) = R(1,1,1:1); | ||||
|     vx(1) = R(2,1,1:1); | ||||
|     wx(1) = R(3,1,1:1); | ||||
|     uy(1) = R(1,2,1:1); | ||||
|     vy(1) = R(2,2,1:1); | ||||
|     wy(1) = R(3,2,1:1); | ||||
|     uz(1) = R(1,3,1:1); | ||||
|     vz(1) = R(2,3,1:1); | ||||
|     wz(1) = R(3,3,1:1); | ||||
| 
 | ||||
|     % Create graphics handles | ||||
|     orgHandle = plot3(x, y, z, 'k.'); | ||||
|     if(ShowArrowHead) | ||||
|         ShowArrowHeadStr = 'on'; | ||||
|     else | ||||
|         ShowArrowHeadStr = 'off'; | ||||
|     end | ||||
|     quivXhandle = quiver3(ox, oy, oz, ux, vx, wx,  'r', 'ShowArrowHead', ShowArrowHeadStr, 'MaxHeadSize', 0.999999, 'AutoScale', 'off'); | ||||
|     quivYhandle = quiver3(ox, oy, oz, uy, vy, wy,  'g', 'ShowArrowHead', ShowArrowHeadStr, 'MaxHeadSize', 0.999999, 'AutoScale', 'off'); | ||||
|     quivZhandle = quiver3(ox, ox, oz, uz, vz, wz,  'b', 'ShowArrowHead', ShowArrowHeadStr, 'MaxHeadSize', 0.999999, 'AutoScale', 'off'); | ||||
| 
 | ||||
|     % Create legend | ||||
|     if(ShowLegend) | ||||
|         legend('Origin', 'X', 'Y', 'Z'); | ||||
|     end | ||||
|      | ||||
|     % Set initial limits | ||||
|     Xlim = [x(1)-AxisLength x(1)+AxisLength] * LimitRatio; | ||||
|     Ylim = [y(1)-AxisLength y(1)+AxisLength] * LimitRatio; | ||||
|     Zlim = [z(1)-AxisLength z(1)+AxisLength] * LimitRatio; | ||||
|     set(gca, 'Xlim', Xlim, 'Ylim', Ylim, 'Zlim', Zlim); | ||||
|      | ||||
|     % Set initial view | ||||
|     view(View(1, :)); | ||||
| 
 | ||||
|     %% Plot one sample at a time | ||||
| 
 | ||||
|     for i = 1:numPlotSamples | ||||
| 
 | ||||
|         % Update graph title | ||||
|         if(strcmp(Title, '')) | ||||
|             titleText = sprintf('Sample %i of %i', 1+((i-1)*SamplePlotFreq), numSamples); | ||||
|         else | ||||
|             titleText = strcat(Title, ' (', sprintf('Sample %i of %i', 1+((i-1)*SamplePlotFreq), numSamples), ')'); | ||||
|         end | ||||
|         title(titleText); | ||||
| 
 | ||||
|         % Plot body x y z axes | ||||
|         if(strcmp(Trail, 'DotsOnly') || strcmp(Trail, 'All')) | ||||
|             x(1:i) = p(1:i,1); | ||||
|             y(1:i) = p(1:i,2); | ||||
|             z(1:i) = p(1:i,3); | ||||
|         else | ||||
|             x = p(i,1); | ||||
|             y = p(i,2); | ||||
|             z = p(i,3); | ||||
|         end | ||||
|         if(strcmp(Trail, 'All')) | ||||
|             ox(1:i) = p(1:i,1); | ||||
|             oy(1:i) = p(1:i,2); | ||||
|             oz(1:i) = p(1:i,3); | ||||
|             ux(1:i) = R(1,1,1:i); | ||||
|             vx(1:i) = R(2,1,1:i); | ||||
|             wx(1:i) = R(3,1,1:i); | ||||
|             uy(1:i) = R(1,2,1:i); | ||||
|             vy(1:i) = R(2,2,1:i); | ||||
|             wy(1:i) = R(3,2,1:i); | ||||
|             uz(1:i) = R(1,3,1:i); | ||||
|             vz(1:i) = R(2,3,1:i); | ||||
|             wz(1:i) = R(3,3,1:i); | ||||
|         else | ||||
|             ox = p(i,1); | ||||
|             oy = p(i,2); | ||||
|             oz = p(i,3); | ||||
|             ux = R(1,1,i); | ||||
|             vx = R(2,1,i); | ||||
|             wx = R(3,1,i); | ||||
|             uy = R(1,2,i); | ||||
|             vy = R(2,2,i); | ||||
|             wy = R(3,2,i); | ||||
|             uz = R(1,3,i); | ||||
|             vz = R(2,3,i); | ||||
|             wz = R(3,3,i); | ||||
|         end | ||||
|         set(orgHandle, 'xdata', x, 'ydata', y, 'zdata', z); | ||||
|         set(quivXhandle, 'xdata', ox, 'ydata', oy, 'zdata', oz,'udata', ux, 'vdata', vx, 'wdata', wx); | ||||
|         set(quivYhandle, 'xdata', ox, 'ydata', oy, 'zdata', oz,'udata', uy, 'vdata', vy, 'wdata', wy); | ||||
|         set(quivZhandle, 'xdata', ox, 'ydata', oy, 'zdata', oz,'udata', uz, 'vdata', vz, 'wdata', wz); | ||||
| 
 | ||||
|         % Adjust axes for snug fit and draw | ||||
|         axisLimChanged = false; | ||||
|         if((p(i,1) - AxisLength) < Xlim(1)), Xlim(1) = p(i,1) - LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if((p(i,2) - AxisLength) < Ylim(1)), Ylim(1) = p(i,2) - LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if((p(i,3) - AxisLength) < Zlim(1)), Zlim(1) = p(i,3) - LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if((p(i,1) + AxisLength) > Xlim(2)), Xlim(2) = p(i,1) + LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if((p(i,2) + AxisLength) > Ylim(2)), Ylim(2) = p(i,2) + LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if((p(i,3) + AxisLength) > Zlim(2)), Zlim(2) = p(i,3) + LimitRatio*AxisLength; axisLimChanged = true; end | ||||
|         if(axisLimChanged), set(gca, 'Xlim', Xlim, 'Ylim', Ylim, 'Zlim', Zlim); end | ||||
|         drawnow; | ||||
| 
 | ||||
|         % Adjust view | ||||
|         if(numel(View) > 2) | ||||
|             view(View(i, :)); | ||||
|         end | ||||
| 
 | ||||
|         % Add frame to AVI object | ||||
|         if(~isempty(aviobj)) | ||||
|             frame = getframe(fig); | ||||
|             aviobj = addframe(aviobj, frame); | ||||
|         end | ||||
| 
 | ||||
|     end | ||||
| 
 | ||||
|     hold off; | ||||
| 
 | ||||
|     % Close AVI file | ||||
|     if(~isempty(aviobj)) | ||||
|         aviobj = close(aviobj); | ||||
|     end | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										23
									
								
								lib/rotation/eul2m.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/rotation/eul2m.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| function [Cb2n_312, Cb2n_321] = eul2m(att) | ||||
| % 将欧拉角转换为姿态阵 | ||||
| % 复用严龚敏老师的a2mat | ||||
| % | ||||
| % Input: att  单位:rad | ||||
| % 对于312((Z->X->Y))顺序,对应att = [pitch(绕X轴) roll(绕Y轴)  yaw(绕Z轴)] | ||||
| % 对于3211(Z->Y->X)顺序,对应att = [roll(绕X轴) pitch(绕Y轴)  yaw(绕Z轴)] | ||||
| % Outputs:  | ||||
| % Cb2n_312:  312欧拉角顺序下转换后的Cb2n | ||||
| % Cb2n_321:  321欧拉角顺序下转换后的Cb2n | ||||
| 
 | ||||
|     s = sin(att); c = cos(att); | ||||
|     si = s(1); sj = s(2); sk = s(3);  | ||||
|     ci = c(1); cj = c(2); ck = c(3); | ||||
|     Cb2n_312 = [ cj*ck-si*sj*sk, -ci*sk,  sj*ck+si*cj*sk; | ||||
|             cj*sk+si*sj*ck,  ci*ck,  sj*sk-si*cj*ck; | ||||
|            -ci*sj,           si,     ci*cj           ]; | ||||
|     if nargout==2  % dual Euler angle DCM | ||||
|         Cb2n_321 = [ cj*ck, si*sj*ck-ci*sk, ci*sj*ck+si*sk; | ||||
|                  cj*sk, si*sj*sk+ci*ck, ci*sj*sk-si*ck; | ||||
|                 -sj,    si*cj,          ci*cj            ]; | ||||
|     end | ||||
|      | ||||
							
								
								
									
										21
									
								
								lib/rotation/eul2q.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/rotation/eul2q.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| function [Qb2n_312, Qb2n_321] = eul2q(eul) | ||||
|      | ||||
|     [Cb2n_312, Cb2n_321] = eul2m(eul); | ||||
|      Qb2n_312 = m2q(Cb2n_312); | ||||
|      Qb2n_321 = m2q(Cb2n_321); | ||||
| %         r = eul(1); | ||||
| %         p = eul(2); | ||||
| %         y = eul(3); | ||||
| %          cp = cos(p / 2); | ||||
| %          sp = sin(p / 2); | ||||
| %          cy = cos(y / 2); | ||||
| %          sy = sin(y / 2); | ||||
| %          cr = cos(r / 2); | ||||
| %          sr = sin(r / 2); | ||||
| %          | ||||
| %         q(1) =  cr*cp*cy + sr*sp*sy; | ||||
| %         q(2) = -cr*sp*sy + cp*cy*sr; | ||||
| %         q(3) =  cr*cy*sp + sr*cp*sy; | ||||
| %         q(4) =  cr*cp*sy - sr*cy*sp; | ||||
| %         q = q'; | ||||
| % Ends | ||||
							
								
								
									
										16
									
								
								lib/rotation/m2eul.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/rotation/m2eul.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| function [eul_312, eul_321] = m2eul(Cb2n) | ||||
| % 将姿态阵转为欧拉角 | ||||
| % 复用严龚敏老师的m2att | ||||
| % | ||||
| % Input: 姿态阵Cb2n: b系->n系的坐标变换矩阵 | ||||
| % Outputs:  | ||||
| % eul_312:   312(Z->X->Y)旋转顺序下的欧拉角:  att = [pitch(绕X轴) roll(绕Y轴) yaw(绕Z轴)] | ||||
| % eul_321:   321(Z->Y->X)旋转顺序下的欧拉角:  att = [roll(绕X轴) pitch(绕Y轴)  yaw(绕Z轴)] | ||||
|     eul_312 = [ asin(Cb2n(3,2)); | ||||
|             atan2(-Cb2n(3,1),Cb2n(3,3));  | ||||
|             atan2(-Cb2n(1,2),Cb2n(2,2)) ]; | ||||
|     if nargout==2  % dual Euler angles | ||||
|         eul_321 = [ atan2(Cb2n(3,2),Cb2n(3,3));  | ||||
|                  asin(-Cb2n(3,1));  | ||||
|                  atan2(Cb2n(2,1),Cb2n(1,1)) ]; | ||||
|     end | ||||
							
								
								
									
										24
									
								
								lib/rotation/m2q.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/rotation/m2q.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| function Qb2n = m2q(Cb2n) | ||||
| % 姿态阵转四元数 | ||||
| % | ||||
| % Input: Cb2n | ||||
| % Output: Qb2n | ||||
| % | ||||
|     C11 = Cb2n(1,1); C12 = Cb2n(1,2); C13 = Cb2n(1,3);  | ||||
|     C21 = Cb2n(2,1); C22 = Cb2n(2,2); C23 = Cb2n(2,3);  | ||||
|     C31 = Cb2n(3,1); C32 = Cb2n(3,2); C33 = Cb2n(3,3);  | ||||
|     if C11>=C22+C33 | ||||
|         q1 = 0.5*sqrt(1+C11-C22-C33); | ||||
|         q0 = (C32-C23)/(4*q1); q2 = (C12+C21)/(4*q1); q3 = (C13+C31)/(4*q1); | ||||
|     elseif C22>=C11+C33 | ||||
|         q2 = 0.5*sqrt(1-C11+C22-C33); | ||||
|         q0 = (C13-C31)/(4*q2); q1 = (C12+C21)/(4*q2); q3 = (C23+C32)/(4*q2); | ||||
|     elseif C33>=C11+C22 | ||||
|         q3 = 0.5*sqrt(1-C11-C22+C33); | ||||
|         q0 = (C21-C12)/(4*q3); q1 = (C13+C31)/(4*q3); q2 = (C23+C32)/(4*q3); | ||||
|     else | ||||
|         q0 = 0.5*sqrt(1+C11+C22+C33); | ||||
|         q1 = (C32-C23)/(4*q0); q2 = (C13-C31)/(4*q0); q3 = (C21-C12)/(4*q0); | ||||
|     end | ||||
|     Qb2n = [q0; q1; q2; q3]; | ||||
|      | ||||
							
								
								
									
										8
									
								
								lib/rotation/mnormlz.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/rotation/mnormlz.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| function Cb2n = mnormlz(Cb2n) | ||||
| % 姿态阵单位化,防止矩阵蠕变 | ||||
|     for k=1:5 | ||||
| %         Cnb = 0.5 * (Cnb + (Cnb')^-1);  % Algorithm 1  | ||||
|         Cb2n = 1.5*Cb2n - 0.5*(Cb2n*Cb2n')*Cb2n;  % Algorithm 2  | ||||
|     end | ||||
|      | ||||
| %   Algorithm 3:  [s,v,d] = svd(Cnb); Cnb = s*d';  % in = s*v*d' = s*d' * d*v*d';  out = s*d' | ||||
							
								
								
									
										27
									
								
								lib/rotation/q2eul.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/rotation/q2eul.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| function [eul_312, eul_321] =  q2eul(Qb2n) | ||||
| % 四元数转欧拉角 | ||||
| % | ||||
| % Input: 四元数Qb2n | ||||
| % Outputs: | ||||
| % eul_312:   312(Z->X->Y)旋转顺序下的欧拉角:  att = [pitch(绕X轴) roll(绕Y轴) yaw(绕Z轴)] | ||||
| % eul_321:   321(Z->Y->X)旋转顺序下的欧拉角:  att = [roll(绕X轴) pitch(绕Y轴)  yaw(绕Z轴)] | ||||
| 
 | ||||
| q0 = Qb2n(1); | ||||
| q1 = Qb2n(2); | ||||
| q2 = Qb2n(3); | ||||
| q3 = Qb2n(4); | ||||
| 
 | ||||
| 
 | ||||
| roll =  -atan2( 2*( q1*q3 - q0*q2 ) , q0*q0 - q1*q1 - q2*q2 + q3*q3); | ||||
| pitch = asin( 2*(q0*q1 + q2*q3) ); | ||||
| yaw = -atan2(2*( q1*q2 - q0*q3 ), q0*q0 - q1*q1 + q2*q2 - q3*q3); | ||||
| eul_312 = [pitch; roll; yaw]; | ||||
| 
 | ||||
| if nargout==2  % dual Euler angles | ||||
|     roll =  atan2( 2*( q0*q1 + q2*q3 ) , 1 - 2*q1*q1 - 2*q2*q2); | ||||
|     pitch = asin( 2*(q0*q2 - q1*q3) ); | ||||
|     yaw = atan2(2*( q0*q3 + q1*q2 ), 1 - 2*q2*q2 - 2*q3*q3); | ||||
|     eul_321 = [roll; pitch; yaw]; | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								lib/rotation/q2m.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/rotation/q2m.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| function Cb2n = q2m(Qb2n) | ||||
| % 四元数转姿态阵 | ||||
| % | ||||
| % Input: Qb2n | ||||
| % Output: Cb2n | ||||
| % | ||||
|     q11 = Qb2n(1)*Qb2n(1); q12 = Qb2n(1)*Qb2n(2); q13 = Qb2n(1)*Qb2n(3); q14 = Qb2n(1)*Qb2n(4);  | ||||
|     q22 = Qb2n(2)*Qb2n(2); q23 = Qb2n(2)*Qb2n(3); q24 = Qb2n(2)*Qb2n(4);      | ||||
|     q33 = Qb2n(3)*Qb2n(3); q34 = Qb2n(3)*Qb2n(4);   | ||||
|     q44 = Qb2n(4)*Qb2n(4); | ||||
|     Cb2n = [ q11+q22-q33-q44,  2*(q23-q14),     2*(q24+q13); | ||||
|             2*(q23+q14),      q11-q22+q33-q44, 2*(q34-q12); | ||||
|             2*(q24-q13),      2*(q34+q12),     q11-q22-q33+q44 ]; | ||||
| 
 | ||||
|          | ||||
							
								
								
									
										2
									
								
								lib/rotation/qconj.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								lib/rotation/qconj.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| function qout = qconj(qin)  | ||||
| qout = [qin(1); -qin(2:4)]; | ||||
							
								
								
									
										10
									
								
								lib/rotation/qmul.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/rotation/qmul.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| function q = qmul(q1, q2)  | ||||
| % 四元数相乘 | ||||
| % | ||||
| % Inputs: Q1 Q2, 四元数和矩阵一样,不满足交换律 | ||||
| % Outputs: Q | ||||
| %    | ||||
|     q = [ q1(1) * q2(1) - q1(2) * q2(2) - q1(3) * q2(3) - q1(4) * q2(4); | ||||
|           q1(1) * q2(2) + q1(2) * q2(1) + q1(3) * q2(4) - q1(4) * q2(3); | ||||
|           q1(1) * q2(3) + q1(3) * q2(1) + q1(4) * q2(2) - q1(2) * q2(4); | ||||
|           q1(1) * q2(4) + q1(4) * q2(1) + q1(2) * q2(3) - q1(3) * q2(2) ]; | ||||
							
								
								
									
										24
									
								
								lib/rotation/qmulv.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/rotation/qmulv.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| function vo = qmulv(q, vi) | ||||
| % 向量通过四元数做3D旋转 | ||||
| %  | ||||
| % Inputs: q - Qb2n | ||||
| %            vi - 需要旋转的向量 | ||||
| % Output: vout - output vector, such that vout = q*vin*conjugation(q) | ||||
| %  | ||||
| % See also  q2mat, qconj, qmul. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| %     qi = [0; vi]; | ||||
| %     qo = ch_qmul(ch_qmul(q,qi),ch_qconj(q)); | ||||
| %     vo = qo(2:4,1); | ||||
| 
 | ||||
|     qo1 =              - q(2) * vi(1) - q(3) * vi(2) - q(4) * vi(3); | ||||
|     qo2 = q(1) * vi(1)                + q(3) * vi(3) - q(4) * vi(2); | ||||
|     qo3 = q(1) * vi(2)                + q(4) * vi(1) - q(2) * vi(3); | ||||
|     qo4 = q(1) * vi(3)                + q(2) * vi(2) - q(3) * vi(1); | ||||
|     vo = vi; | ||||
|     vo(1) = -qo1 * q(2) + qo2 * q(1) - qo3 * q(4) + qo4 * q(3); | ||||
|     vo(2) = -qo1 * q(3) + qo3 * q(1) - qo4 * q(2) + qo2 * q(4); | ||||
|     vo(3) = -qo1 * q(4) + qo4 * q(1) - qo2 * q(3) + qo3 * q(2); | ||||
|      | ||||
							
								
								
									
										9
									
								
								lib/rotation/qnormlz.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/rotation/qnormlz.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| function q = qnormlz(q) | ||||
| % 四元数归一化 | ||||
|     q = q/norm(q); | ||||
|     if(q(1)<0) | ||||
|         q(1) = -q(1); | ||||
|         q(2) = -q(2); | ||||
|         q(3) = -q(3); | ||||
|         q(4) = -q(4); | ||||
|     end | ||||
							
								
								
									
										5
									
								
								lib/rotation/rotx.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/rotation/rotx.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| function Cb2n = rotx(theta) | ||||
| % 3D初等旋转, theta为旋转角度,rad | ||||
| Cb2n = [1 0 0; 0 cos(theta) -sin(theta); 0 sin(theta) cos(theta)]; | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										5
									
								
								lib/rotation/roty.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/rotation/roty.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| function Cb2n = roty(theta) | ||||
| % 3D初等旋转, theta为旋转角度,rad | ||||
| Cb2n = [cos(theta), 0 sin(theta); 0 1 0; -sin(theta) 0 cos(theta)]; | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										5
									
								
								lib/rotation/rotz.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/rotation/rotz.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| function Cb2n = rotz(theta) | ||||
| % 3D初等旋转, theta为旋转角度,rad | ||||
| Cb2n = [cos(theta) -sin(theta) 0; sin(theta) cos(theta) 0; 0 0 1]; | ||||
| 
 | ||||
| end | ||||
							
								
								
									
										19
									
								
								lib/rotation/rv2m.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/rotation/rv2m.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| function m = rv2m(rv)  | ||||
| %  等效旋转矢量转换为旋转矩阵 | ||||
| % | ||||
| % Input: rv - 旋转矢量 | ||||
| % Output: m -旋转矩阵 Cb2n 严龚敏 2.2.23 | ||||
| %     m = I + sin(|rv|)/|rv|*(rvx) + [1-cos(|rv|)]/|rv|^2*(rvx)^2 | ||||
| %     where rvx is the askew matrix or rv. | ||||
| 
 | ||||
| 	nm2 = rv'*rv;  % 旋转矢量的模方 | ||||
|     if nm2<1.e-8   % 如果模方很小,则可用泰勒展开前几项求三角函数 | ||||
|         a = 1-nm2*(1/6-nm2/120); b = 0.5-nm2*(1/24-nm2/720);  % a->1, b->0.5 | ||||
|     else | ||||
|         nm = sqrt(nm2); | ||||
|         a = sin(nm)/nm;  b = (1-cos(nm))/nm2; | ||||
|     end | ||||
|     VX = askew(rv); | ||||
|     m = eye(3) + a*VX + b*VX^2; | ||||
|      | ||||
|      | ||||
							
								
								
									
										12
									
								
								lib/rotation/rv2q.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/rotation/rv2q.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| function q = rv2q(rv)  % 等效旋转矢量转换为变换四元数 | ||||
|     nm2 = rv'*rv;  % 旋转矢量的模方 | ||||
|     if nm2<1.0e-8  % 如果模方很小,则可用泰勒展开前几项求三角函数 | ||||
|         q0 = 1-nm2*(1/8-nm2/384);  | ||||
|         s = 1/2-nm2*(1/48-nm2/3840); | ||||
|     else | ||||
|         nm = sqrt(nm2); | ||||
|         q0 = cos(nm/2);  | ||||
|         s = sin(nm/2)/nm; | ||||
|     end | ||||
|     q = [q0; s*rv]; | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								lib/rotation/uv2q.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/rotation/uv2q.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| %% | ||||
| %Cartographer SLAM 姿态算法分析 | ||||
| %刘兴华 | ||||
| %电邮:xiphix@126.com | ||||
| %微信:xiphix | ||||
| 
 | ||||
| 
 | ||||
| function [q] = uv2q(v1, v2) | ||||
| %Finding quaternion representing the rotation from one vector to another | ||||
| nv1 = v1/norm(v1); | ||||
| nv2 = v2/norm(v2); | ||||
| if norm(nv1+nv2)==0 | ||||
| q = [1 0 0 0]'; | ||||
| else | ||||
| half = (nv1 + nv2)/norm(nv1 + nv2); | ||||
| q = [nv1'*half; cross(nv1, half)]; | ||||
| end | ||||
| end | ||||
							
								
								
									
										17
									
								
								lib/sv2atti.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								lib/sv2atti.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| function [Cb2n] = sv2atti(acc) | ||||
| 
 | ||||
| acc = acc / norm(acc); | ||||
| 
 | ||||
| Cb2n(3,:) = acc ; | ||||
| C3 = Cb2n(3,:); | ||||
| 
 | ||||
| if Cb2n(3,1) > 0.5 | ||||
|     C2 = [Cb2n(3,2),  -Cb2n(3,1), 0]; | ||||
| else | ||||
|     C2 = [0, Cb2n(3,3), -Cb2n(3,2)]; | ||||
| end | ||||
| C2 = C2 / norm(C2); | ||||
| C1 = cross(C2, C3); | ||||
| 
 | ||||
| Cb2n = [C1; C2; C3]; | ||||
| end | ||||
							
								
								
									
										21
									
								
								lib/triangulate.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/triangulate.m
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| % 迭代式多边测距 | ||||
| 
 | ||||
| function p = triangulate(anchor_pos, p,  pr) | ||||
| 
 | ||||
| % 基站个数 | ||||
| n = size(anchor_pos, 2); | ||||
| 
 | ||||
| % 获得当前位置与各个基站的距离 | ||||
| r = vecnorm(anchor_pos - p); | ||||
| 
 | ||||
| % 求得H矩阵 | ||||
| H = (anchor_pos - p) ./ r; | ||||
| H =-H'; | ||||
| 
 | ||||
| % 迭代用户距离 | ||||
| p =  p + (H'*H)^(-1)*H'*(pr - r)'; | ||||
| 
 | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user