t3est

t3est

转载于:https://www.cnblogs.com/rilisoft/p/11589822.html

下面的代码运行中显示以下问题:科里奥利力矩阵以及更新机器人动力学 (真实状态)部分错误使用 * 用于矩阵乘法的维度不正确。请检查并确保第一个矩阵中的列数与第二个矩阵中的行数匹配。要单独对矩阵的每个元素进行运算,请使用 TIMES (.*)执行按元素相乘。 classdef UnderwaterPositioningSystem < handle % 水下机器人位置保持系统 % 包含超声定位、EKF滤波和自适应控制器 properties % 超声探头参数 r = 0.5; % 探头安装半径(m) beta = deg2rad(60); % 探头倾角(60度) alpha = deg2rad([0, 120, 240]); % 探头方位角 % EKF参数 x_est; % 状态估计 [dx, dy, vx, vy, theta, phi, wx, wy]^T P_est; % 估计协方差矩阵 Q; % 过程噪声协方差 R; % 测量噪声协方差 % 控制器参数 Kp = 2.0; % 比例增益 Ki = 0.1; % 积分增益 Kd = 3.0; % 微分增益 integral_error = [0; 0]; % 积分误差项 prev_error = [0; 0]; % 上一次误差 % 机器人物理参数 mass = 50; % 质量(kg) inertia = [10, 0; 0, 10]; % 转动惯量(kg·m&sup2;) drag_coeff = 1.5; % 阻尼系数 thruster_gain = 0.8;% 推进器增益 % 流体动力学参数 added_mass = diag([15, 15, 20, 5, 5, 10]); % 附加质量矩阵 quadratic_drag = diag([0.8, 0.8, 1.2, 0.3, 0.3, 0.5]); % 二次阻尼 linear_drag = diag([1.5, 1.5, 2.0, 0.5, 0.5, 1.0]); % 线性阻尼 % 目标位置 target_position = [0; 0]; % [dx_target; dy_target] % 历史记录 position_history = []; true_position_history = []; control_history = []; time_history = []; thruster_history = []; % 推进器指令历史记录 error_history = []; % 位置误差历史记录 % 时间步长 dt = 0.1; % 控制周期(100ms) % 真实状态 (用于仿真) true_position = [0; 0]; true_velocity = [0; 0]; true_orientation = [0; 0]; true_ang_velocity = [0; 0]; end methods function obj = UnderwaterPositioningSystem() % 构造函数 - 初始化系统 % 初始化EKF状态 (dx, dy, vx, vy, theta, phi, wx, wy) obj.x_est = zeros(8, 1); % 初始化协方差矩阵 (增大不确定性) obj.P_est = diag([0.5, 0.5, 0.2, 0.2, 0.1, 0.1, 0.1, 0.1]); % 过程噪声协方差 (模型不确定性) obj.Q = diag([0.05, 0.05, 0.1, 0.1, 0.02, 0.02, 0.05, 0.05]); % 测量噪声协方差 (传感器噪声) obj.R = diag([0.1, 0.1, 0.02, 0.02]); % dx, dy, theta, phi % 初始化历史记录 obj.position_history = zeros(2, 1000); obj.true_position_history = zeros(2, 1000); obj.control_history = zeros(4, 1000); obj.thruster_history = zeros(4, 1000); % 推进器指令历史 obj.time_history = zeros(1, 1000); obj.error_history = zeros(2, 1000); % 位置误差历史 end function [theta, phi, dx, dy] = ultrasound_positioning(obj, d, orientation) % 改进的超声定位解算,考虑姿态影响 % 输入:d - 三个探头的测量距离 [d1, d2, d3] % orientation - 当前姿态 [theta, phi] % 输出:姿态和水下位置 % 获取当前姿态 pitch = orientation(1); roll = orientation(2); % 旋转矩阵 (ZYX欧拉角) R = [cos(pitch)*cos(roll), -cos(pitch)*sin(roll), sin(pitch); sin(roll), cos(roll), 0; -sin(pitch)*cos(roll), sin(pitch)*sin(roll), cos(pitch)]; % 计算探头方向向量 (考虑姿态) v = @(i) R * [sin(obj.beta)*cos(obj.alpha(i)); sin(obj.beta)*sin(obj.alpha(i)); -cos(obj.beta)]; % 探头安装位置 p = @(i) [obj.r*cos(obj.alpha(i)); obj.r*sin(obj.alpha(i)); 0]; % 计算水底点坐标 P1 = p(1) + d(1) * v(1); P2 = p(2) + d(2) * v(2); P3 = p(3) + d(3) * v(3); % 拟合水底平面 vec1 = P2 - P1; vec2 = P3 - P1; n = cross(vec1, vec2); n_hat = n / norm(n); % 解算姿态角 theta = asin(-n_hat(1)); phi = atan2(n_hat(2), -n_hat(3)); % 计算水平偏移量 O_prime = dot(n_hat, P1) * n_hat; dx = O_prime(1); dy = O_prime(2); end function ekf_predict(obj, u) % EKF预测步骤 % u - 控制输入 [Fx; Fy; M_theta; M_phi] % 状态变量: x = [dx, dy, vx, vy, theta, phi, wx, wy]^T % 从状态向量中提取当前值 dx = obj.x_est(1); dy = obj.x_est(2); vx = obj.x_est(3); vy = obj.x_est(4); theta = obj.x_est(5); phi = obj.x_est(6); wx = obj.x_est(7); wy = obj.x_est(8); % 控制输入 Fx = u(1); Fy = u(2); M_theta = u(3); M_phi = u(4); % 状态转移函数 (非线性动力学模型) % 位置更新 dx_new = dx + vx * obj.dt; dy_new = dy + vy * obj.dt; % 速度更新 (考虑阻尼和水流) vx_new = vx + (Fx - obj.drag_coeff * vx)/obj.mass * obj.dt; vy_new = vy + (Fy - obj.drag_coeff * vy)/obj.mass * obj.dt; % 姿态更新 theta_new = theta + wx * obj.dt; phi_new = phi + wy * obj.dt; % 角速度更新 wx_new = wx + (M_theta - obj.drag_coeff * wx)/obj.inertia(1,1) * obj.dt; wy_new = wy + (M_phi - obj.drag_coeff * wy)/obj.inertia(2,2) * obj.dt; % 更新状态预测 obj.x_est = [dx_new; dy_new; vx_new; vy_new; ... theta_new; phi_new; wx_new; wy_new]; % 改进的雅可比矩阵计算 (包含耦合项) F = eye(8); F(1,3) = obj.dt; % ∂dx/∂vx F(2,4) = obj.dt; % ∂dy/∂vy F(3,3) = 1 - (obj.drag_coeff/obj.mass)*obj.dt; % ∂vx/∂vx F(4,4) = 1 - (obj.drag_coeff/obj.mass)*obj.dt; % ∂vy/∂vy F(5,7) = obj.dt; % ∂theta/∂wx F(6,8) = obj.dt; % ∂phi/∂wy F(7,7) = 1 - (obj.drag_coeff/obj.inertia(1,1))*obj.dt; % ∂wx/∂wx F(8,8) = 1 - (obj.drag_coeff/obj.inertia(2,2))*obj.dt; % ∂wy/∂wy % 添加耦合项 F(3,5) = -sin(theta)*obj.dt; % 俯仰角对X加速度的影响 F(4,6) = -sin(phi)*obj.dt; % 横滚角对Y加速度的影响 % 更新协方差矩阵 obj.P_est = F * obj.P_est * F&#39; + obj.Q; end function ekf_update(obj, z) % EKF更新步骤 % z - 测量值 [dx_meas; dy_meas; theta_meas; phi_meas] % 观测矩阵 (测量是状态的一部分) H = [1 0 0 0 0 0 0 0; 0 1 0 0 0 0 0 0; 0 0 0 0 1 0 0 0; 0 0 0 0 0 1 0 0]; % 计算卡尔曼增益 S = H * obj.P_est * H&#39; + obj.R; K = obj.P_est * H&#39; / S; % 更新状态估计 innovation = z - H * obj.x_est; obj.x_est = obj.x_est + K * innovation; % 更新协方差矩阵 obj.P_est = (eye(8) - K * H) * obj.P_est; end function u = adaptive_controller(obj) % 改进的自适应PID控制器 % 返回控制输入 u = [Fx; Fy; M_theta; M_phi] % 从状态估计中提取位置和姿态 dx_est = obj.x_est(1); dy_est = obj.x_est(2); vx_est = obj.x_est(3); vy_est = obj.x_est(4); theta_est = obj.x_est(5); phi_est = obj.x_est(6); % 位置误差 error_pos = [dx_est; dy_est] - obj.target_position; obj.error_history(:, end+1) = error_pos; % 记录误差 % 姿态误差 (目标姿态为水平) error_att = [theta_est; phi_est]; % 计算误差范数和变化率 error_norm = norm(error_pos); error_rate = norm([vx_est; vy_est]); % 自适应增益调整 if error_norm > 0.5 % 大误差区域 - 高增益 Kp_adaptive = obj.Kp * 2.0; Ki_adaptive = obj.Ki * 0.5; % 限制积分 Kd_adaptive = obj.Kd * 1.5; elseif error_norm > 0.1 % 中等误差区域 Kp_adaptive = obj.Kp * 1.2; Ki_adaptive = obj.Ki * 0.8; Kd_adaptive = obj.Kd * 1.0; else % 小误差区域 - 低增益防震荡 Kp_adaptive = obj.Kp * 0.8; Ki_adaptive = obj.Ki * 1.0; Kd_adaptive = obj.Kd * 0.8; end % 添加误差变化率影响 if error_rate > 0.3 Kd_adaptive = Kd_adaptive * min(2.0, 1 + error_rate); end % 位置控制 (PID) obj.integral_error = obj.integral_error + error_pos * obj.dt; % 积分项限幅防饱和 max_integral = 5.0; % 积分上限 obj.integral_error(1) = sign(obj.integral_error(1)) * min(abs(obj.integral_error(1)), max_integral); obj.integral_error(2) = sign(obj.integral_error(2)) * min(abs(obj.integral_error(2)), max_integral); % 力计算 Fx = -Kp_adaptive * error_pos(1) - Ki_adaptive * obj.integral_error(1) - Kd_adaptive * vx_est; Fy = -Kp_adaptive * error_pos(2) - Ki_adaptive * obj.integral_error(2) - Kd_adaptive * vy_est; % 姿态-位置解耦补偿 Fx_comp = Fx * cos(theta_est) - Fy * sin(phi_est); Fy_comp = Fx * sin(theta_est) + Fy * cos(phi_est); % 姿态控制 (PD) M_theta = -Kp_adaptive * 0.5 * error_att(1) - Kd_adaptive * obj.x_est(7); M_phi = -Kp_adaptive * 0.5 * error_att(2) - Kd_adaptive * obj.x_est(8); % 限制最大控制量 max_force = 50; % N max_torque = 20; % N·m Fx_comp = sign(Fx_comp) * min(abs(Fx_comp), max_force); Fy_comp = sign(Fy_comp) * min(abs(Fy_comp), max_force); M_theta = sign(M_theta) * min(abs(M_theta), max_torque); M_phi = sign(M_phi) * min(abs(M_phi), max_torque); % 更新误差记录 obj.prev_error = error_pos; % 控制输出 u = [Fx_comp; Fy_comp; M_theta; M_phi]; end function thruster_commands = thruster_allocation(obj, u) % 推进器分配 % 输入:u = [Fx; Fy; M_theta; M_phi] % 输出:推进器指令 [T1, T2, T3, T4] % 假设有4个推进器:前、后、左、右 % 分配矩阵 % [ Fx ] [ 0 0 1 -1 ] [ T1 ] % [ Fy ] = [ 1 -1 0 0 ] [ T2 ] % [ M_theta] [ l l 0 0 ] [ T3 ] % [ M_phi ] [ 0 0 l l ] [ T4 ] l = 0.8; % 力臂长度(m) % 构建分配矩阵 A = [0, 0, 1, -1; 1, -1, 0, 0; l, l, 0, 0; 0, 0, l, l]; % 求解推进器指令 thruster_commands = A \ u; % 应用推进器增益和饱和限制 max_thrust = 30; % N thruster_commands = obj.thruster_gain * thruster_commands; thruster_commands = min(max(thruster_commands, -max_thrust), max_thrust); end function S = skew(~, v) % 计算叉乘的斜对称矩阵 S = [0, -v(3), v(2); v(3), 0, -v(1); -v(2), v(1), 0]; end function update_robot_dynamics(obj, u, flow_disturbance) % 改进的机器人动力学模型,包含流体动力学效应 % 输入:控制输入u,水流干扰flow_disturbance % 控制力 Fx = u(1); Fy = u(2); M_theta = u(3); M_phi = u(4); % 从状态中提取当前值 vel = [obj.true_velocity; 0]; % 添加Z方向速度(设为0) ang_vel = [0; 0; obj.true_ang_velocity]; % 添加偏航角速度(设为0) % 构建广义速度向量 (6自由度) nu = [vel; ang_vel]; % 科里奥利力矩阵 C = [zeros(3) -obj.mass*obj.skew(ang_vel); -obj.mass*obj.skew(ang_vel) -obj.skew(obj.added_mass(4:6,4:6)*ang_vel)]; % 阻尼力 (线性 + 二次) D = obj.linear_drag * abs(nu) + obj.quadratic_drag * (nu .* abs(nu)); % 广义力 (只考虑水平方向) F_generalized = [Fx; Fy; 0; 0; M_theta; M_phi] + [flow_disturbance; 0; 0; 0; 0]; % 质量矩阵 (包含附加质量) M = diag([obj.mass, obj.mass, obj.mass, ... obj.inertia(1,1), obj.inertia(2,2), obj.inertia(1,1)]) + obj.added_mass; % 加速度计算 (考虑附加质量和阻尼) acc = M \ (F_generalized - C*nu - D*nu); % 状态更新 (只更新水平方向) obj.true_velocity = obj.true_velocity + acc(1:2)*obj.dt; obj.true_ang_velocity = obj.true_ang_velocity + acc(5:6)*obj.dt; obj.true_position = obj.true_position + obj.true_velocity*obj.dt; obj.true_orientation = obj.true_orientation + obj.true_ang_velocity*obj.dt; end function simulate(obj, total_time, flow_conditions) % 系统仿真 % total_time: 总仿真时间(s) % flow_conditions: 水流干扰条件 % 初始化真实状态 obj.true_position = [0.5; -0.3]; % 初始偏移 obj.true_velocity = [0; 0]; obj.true_orientation = [deg2rad(1.5); deg2rad(-1.0)]; obj.true_ang_velocity = [0; 0]; % 初始化EKF状态 obj.x_est(1:2) = obj.true_position; % 初始位置偏移 obj.x_est(5:6) = obj.true_orientation; % 初始姿态 % 初始化控制器状态 obj.integral_error = [0; 0]; obj.prev_error = [0; 0]; % 主循环 num_steps = round(total_time / obj.dt); time = 0; for k = 1:num_steps % 记录时间 time = time + obj.dt; obj.time_history(k) = time; % 生成水流干扰 (随时间变化) flow_disturbance = [0.5 * sin(0.3*time) + flow_conditions(1); 0.3 * cos(0.2*time) + flow_conditions(2)]; % 控制器计算 u = obj.adaptive_controller(); % 推进器分配 thruster_cmds = obj.thruster_allocation(u); obj.thruster_history(:, k) = thruster_cmds; % 记录推进器指令 % 更新机器人动力学 (真实状态) obj.update_robot_dynamics(u, flow_disturbance); % 模拟超声测量 (含噪声) measurement_noise = 0.02; % 测量噪声水平 % 计算真实距离 (考虑姿态影响) true_depth = 10; % 水深10米 true_distances = true_depth * ones(3,1); for i = 1:3 % 考虑姿态对测量的影响 attitude_factor = 1 + 0.1 * sin(obj.true_orientation(1)) * cos(obj.alpha(i)) ... + 0.1 * sin(obj.true_orientation(2)) * sin(obj.alpha(i)); true_distances(i) = true_depth / attitude_factor; end d_meas = true_distances + measurement_noise * randn(3,1); % 超声定位 (使用改进的算法) [theta_meas, phi_meas, dx_meas, dy_meas] = ... obj.ultrasound_positioning(d_meas, obj.true_orientation); % EKF更新 z = [dx_meas; dy_meas; theta_meas; phi_meas]; obj.ekf_update(z); % 记录位置和控制历史 obj.position_history(:, k) = obj.x_est(1:2); obj.true_position_history(:, k) = obj.true_position; obj.control_history(:, k) = u; % EKF预测 (使用上一个控制输入) obj.ekf_predict(u); % 显示状态 if mod(k, 10) == 0 fprintf(&#39;时间: %.1fs, 估计X偏移: %.3fm, 真实X偏移: %.3fm, 估计Y偏移: %.3fm, 真实Y偏移: %.3fm\n&#39;, ... time, obj.x_est(1), obj.true_position(1), obj.x_est(2), obj.true_position(2)); end end % 截断历史记录 obj.time_history = obj.time_history(1:num_steps); obj.position_history = obj.position_history(:, 1:num_steps); obj.true_position_history = obj.true_position_history(:, 1:num_steps); obj.control_history = obj.control_history(:, 1:num_steps); obj.thruster_history = obj.thruster_history(:, 1:num_steps); obj.error_history = obj.error_history(:, 1:num_steps); % 绘制结果 obj.plot_results(); % 分析性能 obj.analyze_performance(); end function plot_results(obj) % 绘制仿真结果 figure(&#39;Position&#39;, [100, 100, 1200, 800], &#39;Name&#39;, &#39;水下机器人位置保持系统仿真结果&#39;); % 位置轨迹 subplot(2, 2, 1); plot(obj.time_history, obj.position_history(1, :), &#39;b-&#39;, &#39;LineWidth&#39;, 1.5); hold on; plot(obj.time_history, obj.true_position_history(1, :), &#39;r--&#39;, &#39;LineWidth&#39;, 1.5); plot(obj.time_history, obj.position_history(2, :), &#39;g-&#39;, &#39;LineWidth&#39;, 1.5); plot(obj.time_history, obj.true_position_history(2, :), &#39;m--&#39;, &#39;LineWidth&#39;, 1.5); plot(obj.time_history, zeros(size(obj.time_history)), &#39;k--&#39;, &#39;LineWidth&#39;, 1.0); title(&#39;水下机器人位置偏移&#39;); xlabel(&#39;时间 (s)&#39;); ylabel(&#39;偏移量 (m)&#39;); legend(&#39;估计X偏移&#39;, &#39;真实X偏移&#39;, &#39;估计Y偏移&#39;, &#39;真实Y偏移&#39;, &#39;目标位置&#39;); grid on; % 控制力 subplot(2, 2, 2); plot(obj.time_history, obj.control_history(1, :), &#39;b&#39;, &#39;LineWidth&#39;, 1.5); hold on; plot(obj.time_history, obj.control_history(2, :), &#39;r&#39;, &#39;LineWidth&#39;, 1.5); title(&#39;控制力&#39;); xlabel(&#39;时间 (s)&#39;); ylabel(&#39;力 (N)&#39;); legend(&#39;X方向控制力&#39;, &#39;Y方向控制力&#39;); grid on; % 姿态角 subplot(2, 2, 3); plot(obj.time_history, rad2deg(obj.x_est(5) * ones(size(obj.time_history))), &#39;b&#39;, &#39;LineWidth&#39;, 1.5); hold on; plot(obj.time_history, rad2deg(obj.x_est(6) * ones(size(obj.time_history))), &#39;r&#39;, &#39;LineWidth&#39;, 1.5); plot(obj.time_history, rad2deg(obj.true_orientation(1)) * ones(size(obj.time_history)), &#39;b--&#39;, &#39;LineWidth&#39;, 1.0); plot(obj.time_history, rad2deg(obj.true_orientation(2)) * ones(size(obj.time_history)), &#39;r--&#39;, &#39;LineWidth&#39;, 1.0); plot(obj.time_history, zeros(size(obj.time_history)), &#39;k--&#39;, &#39;LineWidth&#39;, 1.0); title(&#39;机器人姿态&#39;); xlabel(&#39;时间 (s)&#39;); ylabel(&#39;角度 (°)&#39;); legend(&#39;估计俯仰角&#39;, &#39;估计横滚角&#39;, &#39;真实俯仰角&#39;, &#39;真实横滚角&#39;, &#39;目标姿态&#39;); grid on; % 位置轨迹图 subplot(2, 2, 4); plot(obj.position_history(1, :), obj.position_history(2, :), &#39;b&#39;, &#39;LineWidth&#39;, 1.5); hold on; plot(obj.true_position_history(1, :), obj.true_position_history(2, :), &#39;r&#39;, &#39;LineWidth&#39;, 1.5); plot(0, 0, &#39;go&#39;, &#39;MarkerSize&#39;, 10, &#39;LineWidth&#39;, 2); title(&#39;水下机器人运动轨迹&#39;); xlabel(&#39;X位置 (m)&#39;); ylabel(&#39;Y位置 (m)&#39;); legend(&#39;估计轨迹&#39;, &#39;真实轨迹&#39;, &#39;目标位置&#39;); axis equal; grid on; % 添加标题 sgtitle(&#39;水下机器人位置保持系统仿真结果&#39;, &#39;FontSize&#39;, 16, &#39;FontWeight&#39;, &#39;bold&#39;); end function analyze_performance(obj) % 性能分析 % 计算稳态误差 (取后20%数据) steady_state_idx = round(0.8 * length(obj.time_history)); ss_error_x = rms(obj.position_history(1, steady_state_idx:end) - obj.true_position_history(1, steady_state_idx:end)); ss_error_y = rms(obj.position_history(2, steady_state_idx:end) - obj.true_position_history(2, steady_state_idx:end)); % 收敛时间 (误差<0.05m的时间) conv_threshold = 0.05; conv_time_x = find(abs(obj.position_history(1,:) - obj.true_position_history(1,:)) < conv_threshold, 1) * obj.dt; conv_time_y = find(abs(obj.position_history(2,:) - obj.true_position_history(2,:)) < conv_threshold, 1) * obj.dt; % 控制能量消耗 control_energy = sum(sum(obj.control_history.^2)) * obj.dt; fprintf(&#39;\n性能分析结果:\n&#39;); fprintf(&#39;X方向估计误差: %.4f m\n&#39;, ss_error_x); fprintf(&#39;Y方向估计误差: %.4f m\n&#39;, ss_error_y); fprintf(&#39;X方向收敛时间: %.2f s\n&#39;, conv_time_x); fprintf(&#39;Y方向收敛时间: %.2f s\n&#39;, conv_time_y); fprintf(&#39;控制能量消耗: %.2f N&sup2;·s\n&#39;, control_energy); % 绘制估计误差 figure(&#39;Name&#39;, &#39;位置估计误差分析&#39;); subplot(2,1,1); plot(obj.time_history, obj.position_history(1,:) - obj.true_position_history(1,:), &#39;b&#39;); hold on; plot(obj.time_history, obj.position_history(2,:) - obj.true_position_history(2,:), &#39;r&#39;); title(&#39;位置估计误差&#39;); xlabel(&#39;时间 (s)&#39;); ylabel(&#39;误差 (m)&#39;); legend(&#39;X方向误差&#39;, &#39;Y方向误差&#39;); grid on; subplot(2,1,2); plot(obj.time_history, abs(obj.position_history(1,:) - obj.true_position_history(1,:)), &#39;b&#39;); hold on; plot(obj.time_history, abs(obj.position_history(2,:) - obj.true_position_history(2,:)), &#39;r&#39;); title(&#39;位置估计绝对误差&#39;); xlabel(&#39;时间 (s)&#39;); ylabel(&#39;绝对误差 (m)&#39;); legend(&#39;X方向&#39;, &#39;Y方向&#39;); grid on; end end end
最新发布
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值