基于ROS2的消除重力加速度对IMU加速度影响,动态获取当前重力加速度。

IMU的全称是惯性测量单元,包括一个三轴的加速度计以及一个三轴的陀螺仪,分别测量出物体的加速度和角速度信息,不受周围环境结构、光照等外界因素影响。通常IMU的输出频率在100-1000hz之间,远高于相机或者激光雷达的输出频率

消除重力加速度的影响

  • 受力分析: IMU静止时,与IMU所在平面会有一个向上的支持力(重力反作用力),IMU就会测量的角速度就是反作用力带来的。
  • 坐标关系:IMU在平面或者斜坡,IMU的Z轴都或多或少与重力有一个夹角,因此重力的反作用力(支持力)会按照夹角分配到IMU各个轴上,我们就是将与重力坐标系转到IMU坐标系,如下图所示黑线坐标系转到红线坐标系,图中只展示了三维坐标系的二维形式。
  • 消除重力:将IMU坐标系得到的值减去重力在每个轴上的分量,就能消除重力对加速度的影响。
    在这里插入图片描述
  • 分析已知变量, IMU能获得的数据有三维的加速度以及三维的欧拉角。其中欧拉角就是重力坐标系与IMU坐标系三轴之间的夹角,因此通过欧拉角,按照z、y、x顺序,就能将重力坐标系旋转到IMU坐标系。
    R I G = R z ⋅ R y ⋅ R z R^{G}_{I} = R_{z} \cdot R_{y} \cdot R_{z} RIG=RzRyRz
    其中G表示重力坐标系,也有用W表示的世界坐标系,I为IMU坐标系。 R I G R^{G}_{I} RIG表示从重力坐标系(World)到IMU系的旋转矩阵。
    在这里插入图片描述
    所以将重力加速度转到IMU坐标系下的公式为
    G r a v i t y I ⃗ = R I ⃗ ⋅ G r a v i t y \vec{Gravity_{I}} = \vec{R_{I}} \cdot Gravity GravityI =RI Gravity,其中Gravity是常量,我们设Gravity为9.8左右(后面会用梯度下降算法来求得误差最小的重力加速度)。
    然后用获取的IMU三轴的加速度减去转换到IMU坐标系的加速度得到绝对的加速度(相对于地面静止)。代码如下:
   float accX = msg->linear_acceleration.y - std::sin(roll) * std::cos(pitch) * gravity_;float accY = msg->linear_acceleration.z - std::cos(roll) * std::cos(pitch) * gravity_;float accZ = msg->linear_acceleration.x + std::sin(pitch) * gravity_;

梯度下降算法求得当地的重力加速度

  • 首先设置一个初始重力加速度,可以设置的大一些,然后设置一个学习率,通过当前误差与理论误差的差为梯度,让初始值沿着梯度下降的方向求得误差,如果误差小于一定的值,那么就保留当前的值。

如下图所示

IMU与水平面有一定的夹角。因此下面的加速度分别是 4.874595 、 -0.502782 、 8.432.378
如果IMU与水平面平行,理论上的值应该是(0,0,9)
因为当前IMU在斜坡上,理论加速度应该为(0,0,0) ,但实际上为(4.874595 , -0.502782 , 8.432.378)。我们要做的就是消除重力的影响。
在这里插入图片描述

在这里插入图片描述
具体代码如下:
imu_processing_node.cpp

#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/imu.hpp>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2/convert.h>
#include <nav_msgs/msg/path.hpp>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <iostream>
#include <vector>
#include <mutex>// 在类中添加私有互斥锁成员
std::mutex mutex_;class ImuProcessingNode : public rclcpp::Node
{
public:ImuProcessingNode() : Node("imu_processing_node"){std::cout << "ImuProcessingNode" << std::endl;imu_subscriber_ = this->create_subscription<sensor_msgs::msg::Imu>("/imu/data_raw", 10, std::bind(&ImuProcessingNode::imuCallback, this, std::placeholders::_1));// imu_subscriber_ = this->create_subscription<sensor_msgs::msg::Imu>(//     "/imu/data_raw", 10, std::bind(&ImuProcessingNode::calculateCorrectedLinearAcceleration, this, std::placeholders::_1));trajectory_publisher_ = this->create_publisher<nav_msgs::msg::Path>( // Use Path message type"integrated_trajectory", 10);// Initialize necessary variables hereimu_time_.reserve(imu_que_length_);imu_roll_.reserve(imu_que_length_);imu_pitch_.reserve(imu_que_length_);imu_yaw_.reserve(imu_que_length_);imu_acc_x_.reserve(imu_que_length_);imu_acc_y_.reserve(imu_que_length_);imu_acc_z_.reserve(imu_que_length_);imu_angular_velo_x_.reserve(imu_que_length_);imu_angular_velo_y_.reserve(imu_que_length_);imu_angular_velo_z_.reserve(imu_que_length_);imu_shift_x_.reserve(imu_que_length_);imu_shift_y_.reserve(imu_que_length_);imu_shift_z_.reserve(imu_que_length_);imu_velo_x_.reserve(imu_que_length_);imu_velo_y_.reserve(imu_que_length_);imu_velo_z_.reserve(imu_que_length_);imu_angular_rotation_x_.reserve(imu_que_length_);imu_angular_rotation_y_.reserve(imu_que_length_);imu_angular_rotation_z_.reserve(imu_que_length_);}private:double sumXYZ(double x, double y, double z){// 计算平方和double squared_sum = x * x + y * y + z * z;return squared_sum;}// 在 ImuProcessingNode 类中添加一个新的私有函数来计算矫正后的线性加速度的平方和void calculateCorrectedLinearAcceleration(const sensor_msgs::msg::Imu::SharedPtr msg){// 使用互斥锁保护代码块{std::lock_guard<std::mutex> lock(mutex_); // 加锁gravity_ = 9.9;double roll, pitch, yaw;tf2::Quaternion orientation;tf2::fromMsg(msg->orientation, orientation);tf2::Matrix3x3(orientation).getRPY(roll, pitch, yaw);float accX = msg->linear_acceleration.y - std::sin(roll) * std::cos(pitch) * gravity_;float accY = msg->linear_acceleration.z - std::cos(roll) * std::cos(pitch) * gravity_;float accZ = msg->linear_acceleration.x + std::sin(pitch) * gravity_;// 优化步骤double target_squared_sum = 0.002; // 目标平方和double current_squared_sum = sumXYZ(accX, accY, accZ);std::cout << "current_squared_sum::" << current_squared_sum << std::endl;int count = 0;double zhi = gravity_;double sum = 100.0;while (current_squared_sum > target_squared_sum) // 当平方和大于目标值时继续优化{// 使用梯度下降更新 gravity_double learning_rate = 0.01;                                // 学习率double gradient = current_squared_sum - target_squared_sum; // 梯度gravity_ -= learning_rate * gradient;                       // 更新 gravity_// std::cout<<"计算次数::"<<count<<"gravity_::"<<gravity_<<" gradient::"<<gradient <<" current_squared_sum::"<<current_squared_sum<<std::endl;accX = msg->linear_acceleration.y - std::sin(roll) * std::cos(pitch) * gravity_;accY = msg->linear_acceleration.z - std::cos(roll) * std::cos(pitch) * gravity_;accZ = msg->linear_acceleration.x + std::sin(pitch) * gravity_;count = count + 1;if (sum > current_squared_sum){sum = current_squared_sum;zhi = gravity_;}if (count > 55000){break;}// // 重新计算矫正后的线性加速度平方和current_squared_sum = sumXYZ(accX, accY, accZ);}if (sum < 0.0021){imu_handler = true;std::cout << "重力优化"<< "error::" << sum << "gravity_::" << zhi << std::endl;gravity_ = zhi;}else{std::cout << "error::" << sum << "gravity_::" << zhi << std::endl;}} // 自动解锁}void AccumulateIMUShiftAndRotation(){float roll = imu_roll_[imu_pointer_last_];float pitch = imu_pitch_[imu_pointer_last_];float yaw = imu_yaw_[imu_pointer_last_];float accX = imu_acc_x_[imu_pointer_last_];float accY = imu_acc_y_[imu_pointer_last_];float accZ = imu_acc_z_[imu_pointer_last_];float x1 = std::cos(roll) * accX - std::sin(roll) * accY;float y1 = std::sin(roll) * accX + std::cos(roll) * accY;float z1 = accZ;float x2 = x1;float y2 = std::cos(pitch) * y1 - std::sin(pitch) * z1;float z2 = std::sin(pitch) * y1 + std::cos(pitch) * z1;accX = std::cos(yaw) * x2 + std::sin(yaw) * z2;accY = y2;accZ = -std::sin(yaw) * x2 + std::cos(yaw) * z2;std::cout<<"accX::"<<accX<<" accY::"<<accY<<" accZ::"<<accZ <<std::endl;int imuPointerBack = (imu_pointer_last_ + imu_que_length_ - 1) % imu_que_length_;double timeDiff = imu_time_[imu_pointer_last_] - imu_time_[imuPointerBack];// std::cout<<"timeDiff::"<<timeDiff <<" imu_pointer_last_:"<<imu_pointer_last_<<" imuPointerBack:"<<imuPointerBack<<std::endl;if (timeDiff < scanPeriod){imu_shift_x_[imu_pointer_last_] = imu_shift_x_[imuPointerBack] + imu_velo_x_[imuPointerBack] * timeDiff + accX * timeDiff * timeDiff / 2;imu_shift_y_[imu_pointer_last_] = imu_shift_y_[imuPointerBack] + imu_velo_y_[imuPointerBack] * timeDiff + accY * timeDiff * timeDiff / 2;imu_shift_z_[imu_pointer_last_] = imu_shift_z_[imuPointerBack] + imu_velo_z_[imuPointerBack] * timeDiff + accZ * timeDiff * timeDiff / 2;imu_velo_x_[imu_pointer_last_] = imu_velo_x_[imuPointerBack] + accX * timeDiff;imu_velo_y_[imu_pointer_last_] = imu_velo_y_[imuPointerBack] + accY * timeDiff;imu_velo_z_[imu_pointer_last_] = imu_velo_z_[imuPointerBack] + accZ * timeDiff;imu_angular_rotation_x_[imu_pointer_last_] = imu_angular_rotation_x_[imuPointerBack] + imu_angular_velo_x_[imuPointerBack] * timeDiff;imu_angular_rotation_y_[imu_pointer_last_] = imu_angular_rotation_y_[imuPointerBack] + imu_angular_velo_y_[imuPointerBack] * timeDiff;imu_angular_rotation_z_[imu_pointer_last_] = imu_angular_rotation_z_[imuPointerBack] + imu_angular_velo_z_[imuPointerBack] * timeDiff;}}void imuCallback(const sensor_msgs::msg::Imu::SharedPtr msg){// Print original IMU valuesRCLCPP_INFO(this->get_logger(), "Original IMU Orientation: (%f, %f, %f, %f)",msg->orientation.x, msg->orientation.y, msg->orientation.z, msg->orientation.w);RCLCPP_INFO(this->get_logger(), "Original IMU Linear Acceleration: (%f, %f, %f)",msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z);RCLCPP_INFO(this->get_logger(), "Original IMU Angular Velocity: (%f, %f, %f)",msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z);// Process IMU data, remove gravity influence, integrate, and publish trajectorydouble roll, pitch, yaw;tf2::Quaternion orientation;tf2::fromMsg(msg->orientation, orientation);tf2::Matrix3x3(orientation).getRPY(roll, pitch, yaw);if (!imu_handler){calculateCorrectedLinearAcceleration(msg);}else{float accX = msg->linear_acceleration.y - std::sin(roll) * std::cos(pitch) * gravity_;float accY = msg->linear_acceleration.z - std::cos(roll) * std::cos(pitch) * gravity_;float accZ = msg->linear_acceleration.x + std::sin(pitch) * gravity_;imu_pointer_last_ = (imu_pointer_last_ + 1) % imu_que_length_;imu_time_[imu_pointer_last_] = msg->header.stamp.sec + msg->header.stamp.nanosec * 1e-9;imu_roll_[imu_pointer_last_] = roll;imu_pitch_[imu_pointer_last_] = pitch;imu_yaw_[imu_pointer_last_] = yaw;imu_acc_x_[imu_pointer_last_] = accX;imu_acc_y_[imu_pointer_last_] = accY;imu_acc_z_[imu_pointer_last_] = accZ;imu_angular_velo_x_[imu_pointer_last_] = msg->angular_velocity.x;imu_angular_velo_y_[imu_pointer_last_] = msg->angular_velocity.y;imu_angular_velo_z_[imu_pointer_last_] = msg->angular_velocity.z;// Print transformed IMU valuesRCLCPP_INFO(this->get_logger(), "Transformed IMU RPY: (%f, %f, %f)", roll, pitch, yaw);RCLCPP_INFO(this->get_logger(), "Transformed IMU Linear Acceleration: (%f, %f, %f)", accX, accY, accZ);AccumulateIMUShiftAndRotation();// Update variables and publish trajectory using trajectory_publisher_// Publish integrated trajectorynav_msgs::msg::Path integrated_trajectory;integrated_trajectory.header = msg->header;integrated_trajectory.header.frame_id = "base_link";geometry_msgs::msg::PoseStamped integrated_pose;integrated_pose.header = msg->header;integrated_pose.pose.position.x = imu_shift_x_[imu_pointer_last_];integrated_pose.pose.position.y = imu_shift_y_[imu_pointer_last_];integrated_pose.pose.position.z = imu_shift_z_[imu_pointer_last_];// Assuming imu_angular_rotation_x_, imu_angular_rotation_y_, imu_angular_rotation_z_// contain the integrated orientation valuestf2::Quaternion orientation1;orientation1.setRPY(imu_angular_rotation_x_[imu_pointer_last_],imu_angular_rotation_y_[imu_pointer_last_],imu_angular_rotation_z_[imu_pointer_last_]);integrated_pose.pose.orientation = tf2::toMsg(orientation1);std::cout<<"x:"<<integrated_pose.pose.position.x<<" y:"<<integrated_pose.pose.position.y<<" z:"<<integrated_pose.pose.position.z<<std::endl;integrated_trajectory.poses.push_back(integrated_pose); // Add the pose to the trajectorytrajectory_publisher_->publish(integrated_trajectory);}}rclcpp::Subscription<sensor_msgs::msg::Imu>::SharedPtr imu_subscriber_;rclcpp::Publisher<nav_msgs::msg::Path>::SharedPtr trajectory_publisher_;bool imu_handler = false;int imu_pointer_last_ = 0;float gravity_ = 9.8;const int imu_que_length_ = 10;double scanPeriod = 0.1;std::vector<double> imu_time_;std::vector<double> imu_roll_;std::vector<double> imu_pitch_;std::vector<double> imu_yaw_;std::vector<float> imu_acc_x_;std::vector<float> imu_acc_y_;std::vector<float> imu_acc_z_;std::vector<float> imu_angular_velo_x_;std::vector<float> imu_angular_velo_y_;std::vector<float> imu_angular_velo_z_;std::vector<double> imu_shift_x_;std::vector<double> imu_shift_y_;std::vector<double> imu_shift_z_;std::vector<float> imu_velo_x_;std::vector<float> imu_velo_y_;std::vector<float> imu_velo_z_;std::vector<float> imu_angular_rotation_x_;std::vector<float> imu_angular_rotation_y_;std::vector<float> imu_angular_rotation_z_;
};int main(int argc, char **argv)
{// RCLCPP_INFO("begin", "Start IMU");std::cout << "Start IMU" << std::endl;rclcpp::init(argc, argv);auto node = std::make_shared<ImuProcessingNode>();rclcpp::spin(node);std::cout << "End IMU" << std::endl;rclcpp::shutdown();return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(my_imu_processing_pkg)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(std_srvs REQUIRED)
find_package(tf2 REQUIRED)
find_package(nav_msgs REQUIRED)set(dependenciesrclcppsensor_msgsstd_msgsstd_srvstf2nav_msgs
)include_directories(include)add_executable(imu_processing_node"src/imu_processing_node.cpp"
)ament_target_dependencies(imu_processing_node ${dependencies})install(TARGETS imu_processing_nodeDESTINATION lib/${PROJECT_NAME}
)install(DIRECTORY launchDESTINATION share/${PROJECT_NAME}
)if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)# the following line skips the linter which checks for copyrights# comment the line when a copyright and license is added to all source filesset(ament_cmake_copyright_FOUND TRUE)# the following line skips cpplint (only works in a git repo)# comment the line when this package is in a git repo and when# a copyright and license is added to all source filesset(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies()
endif()ament_package()

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>my_imu_processing_pkg</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="2267507789@qq.com">philtell</maintainer><license>TODO: License declaration</license><buildtool_depend>ament_cmake</buildtool_depend><depend>rclcpp</depend><depend>sensor_msgs</depend><depend>std_msgs</depend><depend>std_srvs</depend><depend>tf2</depend><depend>nav_msgs</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>

运行命令为: ros2 run my_imu_processing_pkg imu_processing_node

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/53827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

容灾设备系统组成,容灾备份系统组成包括哪些

随着信息技术的快速发展&#xff0c;企业对数据的需求越来越大&#xff0c;数据已经成为企业的核心财产。但是&#xff0c;数据安全性和完整性面临巨大挑战。在这种环境下&#xff0c;容灾备份系统应运而生&#xff0c;成为保证企业数据安全的关键因素。下面我们就详细介绍容灾…

关于JAVA程序的内存分布

目录 1.Java程序运行时内存说明 2.JVM内存划分 3.Java中数据类型 4.Java中的String 5.结合HelloWorld分析java程序内存分布 1.Java程序运行时内存说明 编写的.java程序文件需要java编译器javac转成.class文件&#xff0c;然后通过jvm&#xff08;名为java的可执行程序&…

STM32F103 USB OTA升级BootLoader (一)

1.配置外部高速晶振 2.勾选USB功能 3.将USB模式配置Virtual Port Com 4.将系统主频配置为72M,USB频率配置为48M. 5.配置好项目名称&#xff0c;开发环境&#xff0c;最后获取代码。 6.修改Flash大小和勾选Use Micro LIB 7.修改main.c代码 #include "main.h" #includ…

浏览器安装selenium驱动,以Microsoft Edge安装驱动为例

Selenium是一个用于Web应用程序测试的自动化工具。它可以直接在浏览器中运行&#xff0c;模拟真实用户对浏览器进行操作。利用selenium&#xff0c;可以驱动浏览器执行特定的动作&#xff0c;比如&#xff1a;点击、下拉等等&#xff0c;还可以获取浏览器当前呈现的页面的源代码…

8/26 回溯法 周总结 记录个人的想法

DAY1 77. 组合 这道题是经典的回溯题&#xff0c; 递归函数参数和返回值显而易见 终止条件是path.size()k 递归逻辑&#xff0c;需要理解每次调用回溯的startIndex的含义&#xff0c;图解&#xff1a; DAY2 216. 组合总和 III:这道题与77题作类比&#xff1a; 77&#xff1…

自定义loadbalance实现feignclient的自定义路由

自定义loadbalance实现feignclient的自定义路由 项目背景 服务A有多个同事同时开发&#xff0c;每个同事都在dev或者test环境发布自己的代码&#xff0c;注册到注册中心有好几个(本文nacos为例)&#xff0c;这时候调用feign可能会导致请求到不同分支的服务上面&#xff0c;会…

React(7)

1.React Hooks 使用hooks理由 1. 高阶组件为了复用&#xff0c;导致代码层级复杂 2. 生命周期的复杂 3. 写成functional组件,无状态组件 &#xff0c;因为需要状态&#xff0c;又改成了class,成本高 1.1 useState useState();括号里面处的是初始值&#xff1b;返回的是一个…

【算法系列 | 7】深入解析查找算法之—布隆过滤器

序言 心若有阳光&#xff0c;你便会看见这个世界有那么多美好值得期待和向往。 决定开一个算法专栏&#xff0c;希望能帮助大家很好的了解算法。主要深入解析每个算法&#xff0c;从概念到示例。 我们一起努力&#xff0c;成为更好的自己&#xff01; 今天第3讲&#xff0c;讲一…

stm32之8.中断

&#xff08;Exceptions&#xff09;异常是导致程序流更改的事件&#xff0c;发生这种情况&#xff0c;处理器将挂起当前执行的任务&#xff0c;并执行程序的一部分&#xff0c;称之为异常处理函数。在完成异常处理程序的执行之后&#xff0c;处理器将恢复正常的程序执行&#…

python+TensorFlow实现人脸识别智能小程序的项目(包含TensorFlow版本与Pytorch版本)

pythonTensorFlow实现人脸识别智能小程序的项目&#xff08;包含TensorFlow版本与Pytorch版本&#xff09; 一&#xff1a;TensorFlow基础知识内容部分&#xff08;简明扼要&#xff0c;快速适应&#xff09;1、下载Cifar10数据集&#xff0c;并进行解压缩处理2、将Cifar10数据…

WebSocket详解以及应用

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;websocket、网络、长连接、前端☀️每日 一言&#xff1a;任何一个你不喜欢而又离不开的地方&#xff0c;任何一种你不喜欢而又无法摆脱的生活&#xff0c;都是监狱&#xff01; 一、前言 我们在…

C#-集合小例子

目录 背景&#xff1a; 过程: 1.添加1-100数: 2.求和: 3.平均值: 4.代码:​ 总结: 背景&#xff1a; 往集合里面添加100个数&#xff0c;首先得有ArrayList导入命名空间&#xff0c;这个例子分为3步&#xff0c;1.添加1-100个数2.进行1-100之间的总和3.求总和的平均值&…

如何把本地项目上传github

一、在gitHub上创建新项目 【1】点击添加&#xff08;&#xff09;-->New repository 【2】填写新项目的配置项 Repository name&#xff1a;项目名称 Description &#xff1a;项目的描述 Choose a license&#xff1a;license 【3】点击确定&#xff0c;项目已在githu…

数据结构数组栈的实现

Hello&#xff0c;今天我们来实现一下数组栈&#xff0c;学完这个我们又更进一步了。 一、栈 栈的概念 栈是一种特殊的线性表&#xff0c;它只允许在固定的一端进行插入和删除元素的操作。 进行数据的插入和删除只在栈顶实现&#xff0c;另一端就是栈底。 栈的元素是后进先出。…

四川玖璨电商:2023怎样运营短视频?

​短视频的兴起和流行让越来越多的人关注和运营短视频号。如何运营短视频号&#xff0c;吸引更多的观众和粉丝&#xff1f;下面四川玖璨电商小编将介绍几个关键点。 首先&#xff0c;确定短视频的定位和主题非常重要。根据自己的兴趣和特长&#xff0c;确定一个独特的主题&…

Diffusion Models for Image Restoration and Enhancement – A Comprehensive Survey

图像恢复与增强的扩散模型综述 论文链接&#xff1a;https://arxiv.org/abs/2308.09388 项目地址&#xff1a;https://github.com/lixinustc/Awesome-diffusion-model-for-image-processing/ Abstract 图像恢复(IR)一直是低水平视觉领域不可或缺的一项具有挑战性的任务&…

excel中如果A列中某项有多条记录,针对A列中相同的项,将B列值进行相加合并统计

excel中如果A列中某项有多条记录&#xff0c;针对A列中相同的项&#xff0c;将B列值进行相加合并统计。注意&#xff1a;B列的数据类型要为数字 如&#xff1a; 实现方法&#xff1a; C1、D1中分别输入公式&#xff0c;然后下拉 IF(COUNTIF($A$1:A1,A1)1, A1,"") …

C++:构造方法(函数);拷贝(复制)构造函数:浅拷贝、深拷贝;析构函数。

1.构造方法(函数) 构造方法是一种特殊的成员方法&#xff0c;与其他成员方法不同: 构造方法的名字必须与类名相同&#xff1b; 无类型、可有参数、可重载 会自动生成&#xff0c;可自定义 一般形式:类名(形参)&#xff1b; 例: Stu(int age); 当用户没自定义构造方法时&…

光伏发电+boost+储能+双向dcdc+并网逆变器控制(低压用户型电能路由器仿真模型)【含个人笔记+建模参考】

MATALB代码链接&#xff1a;光伏发电boost十储能十双向dcdc十并网逆变器 个人笔记与建模参考请私信发送 包含Boost、Buck-boost双向DCDC、并网逆变器三大控制部分 boost电路应用mppt&#xff0c; 采用扰动观察法实现光能最大功率点跟踪 电流环的逆变器控制策略 双向dcdc储能系…

Windows商店引入SUSE Linux Enterprise Server和openSUSE Leap

在上个月的Build 2017开发者大会上&#xff0c;微软宣布将SUSE&#xff0c;Ubuntu和Fedora引入Windows 商店&#xff0c;反应出微软对开放源码社区的更多承诺。 该公司去年以铂金会员身份加入Linux基金会。现在&#xff0c;微软针对内测者的Windows商店已经开始提供 部分Linux发…