Data Flow ->> Fuzzy Lookup & Fuzzy Grouping

本文深入探讨了数据清洗中的关键组件FuzzyLookup和FuzzyGrouping的作用,包括它们如何通过引用数据库表进行相似值匹配,以及配置选项如参考表、最大匹配数量和相似度阈值等。同时,介绍了如何利用FuzzyLookupTransformation和FuzzyGroupingTransformation对脏数据进行关联和去重。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两个任务的作用是数据清洗(Data Cleansing)。

Fuzzy Lookup通过引用另外一张数据库表或者索引来进行相似值匹配。这种组件对于标准化和查找可能错误的客户端数据非常有用。例如像地址或者像城市名这种属性栏位非常有用。

Fuzzy Lookup不仅会输出它的匹配值,同时还会输出similarity和confidence两个属性列。similarity用一个0到1之间的浮点值来表示匹配对间值得相似度。比如Jerry Chan和Jerry Chen的相似度可能是0.89。而对于Confidence,它的值越高代表它可选的匹配对越少。

Fuzzy Lookup一共有4种选择来配置参考表(Reference Table):

1)Generate New Index:根据参考表的参考栏位在内存中建立一条临时索引用来做数据匹配,任务完成后把它删除;

2)Generate New Index + Store New Index选项:相当于建立一条索引在数据库中;

3)Generate New Index + Store New Index选项 + Maintain Stored Index选项:这种情况下勾了Maintain Stored Index选项将会在reference表建一个触发器来捕捉更新以同步更新到该新建的索引;

4)Use Existing Index:从已有的数据库索引中挑选一个作为参考索引;

 

而在Advanced页面,

Maximum number of matches to output per lookup: 限制每个输入键值最大的输出匹配值对;

Similarity Threshold:相似度起步值

Token Delimiters:这个和Data Profiling中的Token Delimiters类似,把输入栏位的值按给定的Token Delimiters拆分成Token,为后面来的fuzzy lookup服务;

 

属性列表中有两个设置需要注意:

Exhaustive:当被设置为True时意味着每条input的record在做lookup的时候会和reference table中的所有记录进行匹配lookup。这样做结果当然更精确当时如果reference table大的情况性能代价就很大,默认为false;

WarmCaches:当被设置为True的情况下,reference table和index会被提前加载如内存;

 

Fuzzy Grouping和Fuzzy Lookup类似,因为它会根据你给定的similarity的程度来返回某个或者多个栏位的cleansed的值(grouping field),而其实这个值最后就是把一些记录group起来。

 

Fuzzy Lookup Transformation: Capable of joining to external data based on data similarity,
the Fuzzy Lookup Transformation is a core data cleansing tool in SSIS. This transformation
is perfect if you have dirty data input that you want to associate to data in a table in your
database based on similar values. Later in the chapter, you’ll take a look at the details of the
Fuzzy Lookup Transformation and what happens behind the scenes

Fuzzy Grouping Transformation: The main purpose is de-duplication of similar data. The
Fuzzy Grouping Transformation is ideal if you have data from a single source and you know
you have duplicates that you need to find.

转载于:https://www.cnblogs.com/jenrrychen/p/4573726.html

#define _GNU_SOURCE #define _XOPEN_SOURCE 500 // 启用POSIX扩展功能,支持usleep和useconds_t #include <stdio.h> #include <stdlib.h> #include <unistd.h> // 自定义正弦函数实现(避免依赖数学库) float my_sin(float x) { // 将角度标准化到[-π, π]范围 x = x - (int)(x / (6.283185307f)) * 6.283185307f; if (x > 3.141592653f) x -= 6.283185307f; else if (x < -3.141592653f) x += 6.283185307f; // 泰勒级数近似计算sin(x),精度足够本次使用 float result = x; float term = x; int i; for (i = 3; i <= 15; i += 2) { term *= -x * x / (i * (i - 1)); result += term; } return result; } // 云台轴枚举 typedef enum { AXIS_PAN, // 水平轴(左右) AXIS_TILT // 垂直轴(上下) } GimbalAxis; // PID控制器结构体 typedef struct { float kp; // 比例系数 float ki; // 积分系数 float kd; // 微分系数 float target; // 目标值 float current; // 当前值 float error; // 当前误差 float last_error; // 上一次误差 float integral; // 积分项 float derivative; // 微分项 float output_limit; // 输出限制 } PIDController; // 声明pid_init函数,消除隐式声明警告 void pid_init(PIDController *pid, float kp, float ki, float kd, float target, float output_limit); // 云台结构体 typedef struct { PIDController pan_axis; // 水平轴PID控制器 PIDController tilt_axis; // 垂直轴PID控制器 float pan_angle; // 水平轴当前角度 float tilt_angle; // 垂直轴当前角度 } Gimbal; // 初始化PID控制器 void pid_init(PIDController *pid, float kp, float ki, float kd, float target, float output_limit) { pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->target = target; pid->current = 0.0f; pid->error = 0.0f; pid->last_error = 0.0f; pid->integral = 0.0f; pid->derivative = 0.0f; pid->output_limit = output_limit; } // 初始化云台 void gimbal_init(Gimbal *gimbal) { // 初始化水平轴PID参数 pid_init(&gimbal->pan_axis, 3.5f, 0.05f, 1.2f, 0.0f, 100.0f); // 初始化垂直轴PID参数 pid_init(&gimbal->tilt_axis, 4.0f, 0.08f, 1.5f, 0.0f, 100.0f); gimbal->pan_angle = 0.0f; gimbal->tilt_angle = 0.0f; } // 计算PID输出 float pid_compute(PIDController *pid, float current_value, float dt) { // 更新当前值 pid->current = current_value; // 计算误差 pid->error = pid->target - pid->current; // 计算积分项 (带积分限幅防止饱和) // 修复:当ki为0时不计算积分项,避免除零错误 if (pid->ki != 0.0f) { pid->integral += pid->error * dt; float max_integral = pid->output_limit / pid->ki; float min_integral = -max_integral; if (pid->integral > max_integral) { pid->integral = max_integral; } else if (pid->integral < min_integral) { pid->integral = min_integral; } } else { pid->integral = 0.0f; // ki为0时不累积积分 } // 计算微分项 pid->derivative = (pid->error - pid->last_error) / dt; // 计算PID输出 float output = pid->kp * pid->error + pid->ki * pid->integral + pid->kd * pid->derivative; // 输出限幅 if (output > pid->output_limit) { output = pid->output_limit; } else if (output < -pid->output_limit) { output = -pid->output_limit; } // 保存当前误差用于下次计算 pid->last_error = pid->error; return output; } // 模拟读取IMU数据,返回带有噪声的角度 void read_imu_data(float *pan_angle, float *tilt_angle, float time) { // 使用自定义正弦函数生成模拟抖动 *pan_angle = 5.0f * my_sin(time * 1.2f) + 2.0f * my_sin(time * 3.8f) + ((rand() % 20 - 10) / 10.0f); *tilt_angle = 3.0f * my_sin(time * 0.8f) + 1.5f * my_sin(time * 4.2f) + ((rand() % 20 - 10) / 10.0f); } // 驱动电机 void drive_motors(float pan_output, float tilt_output) { // 这里只是模拟电机驱动,实际应用中会输出PWM信号到电机驱动器 // printf("电机输出 - 水平轴: %.2f, 垂直轴: %.2f\n", pan_output, tilt_output); } int main() { Gimbal gimbal; gimbal_init(&gimbal); float time = 0.0f; const float dt = 0.01f; // 控制周期10ms float pan_angle, tilt_angle; float pan_output, tilt_output; // 初始化随机数种子 srand(0); // 模拟20秒的控制过程 for (int i = 0; i < 2000; i++) { // 1. 读取IMU数据(包含抖动) read_imu_data(&pan_angle, &tilt_angle, time); // 2. 计算PID控制量 pan_output = pid_compute(&gimbal.pan_axis, pan_angle, dt); tilt_output = pid_compute(&gimbal.tilt_axis, tilt_angle, dt); // 3. 驱动电机进行补偿 drive_motors(pan_output, tilt_output); // 更新云台角度(根据输出更新当前角度,模拟物理运动) gimbal.pan_angle += pan_output * dt; gimbal.tilt_angle += tilt_output * dt; // 5. 每隔100ms打印一次数据 if (i % 10 == 0) { printf("时间: %.1fs | 水平轴 - 原始: %.2f°, 补偿后: %.2f° | 垂直轴 - 原始: %.2f°, 补偿后: %.2f°\n", time, pan_angle, gimbal.pan_angle, tilt_angle, gimbal.tilt_angle); } // 延时,模拟控制周期 usleep((useconds_t)(dt * 1000000)); time += dt; } return 0; } /* 编译说明: 由于已实现自定义正弦函数,无需链接数学库,编译命令: gcc gimbal_control.c -o gimbal_control */ 修改此代码
最新发布
08-01
<think>我们被要求修改云台摄像头防抖算法的C语言实现代码,特别是PID控制部分,并考虑改进方案。 根据引用[1],我们可以使用模糊PID控制算法或者自适应Kalman滤波技术等改进算法来提高控制精度和响应速度。 引用[3]给出了一段云台控制的C代码片段,其中使用了简单的控制方式(直接调整PWM占空比),但并没有实现完整的PID控制。 目标:在现有代码基础上,改进为PID控制算法,并考虑进一步优化为模糊PID。 步骤: 1. 首先,我们需要实现一个标准的PID控制器。 2. 然后,考虑如何将模糊控制与PID结合(即模糊PID)或者引入其他改进方法。 3. 最后,根据云台电机的实时状态(如角度、角速度)和目标锁定要求(如目标位置)来调整控制输出。 现有代码分析(引用[3]): - 函数Spinnig_Level(int diff)用于水平方向旋转控制。 - 它直接通过调整PWM的占空比(Oc_L)来控制舵机,且限制了占空比的范围(660到840)。 - 该函数只是简单地将当前值与上一次的值进行移动平均(通过Oc_Lp数组),但并没有使用反馈控制。 改进方案: 1. 实现PID控制器: 我们需要测量云台的角度(通过陀螺仪或编码器)作为反馈,然后计算误差(目标角度 - 当前角度), 然后根据PID公式计算控制量。 2. 模糊PID:在PID的基础上,根据误差和误差变化率动态调整PID参数(Kp, Ki, Kd)。 由于引用[3]中的代码片段比较简单,我们首先构建一个PID结构体和一个PID计算函数。 计划: 第一步:实现标准PID控制器 第二步:在标准PID的基础上,引入模糊控制逻辑来调整PID参数(即模糊自适应PID) 我们先从标准PID开始。 标准PID控制器结构体设计: ```c typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 float integral; // 积分项 float prev_error; // 上一次的误差 float output; // 输出值 float output_max; // 输出最大值 float output_min; // 输出最小值 } PID_Controller; ``` 初始化PID控制器: ```c void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd, float min, float max) { pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->integral = 0.0; pid->prev_error = 0.0; pid->output = 0.0; pid->output_min = min; pid->output_max = max; } ``` PID计算函数(位置式PID): ```c float PID_Compute(PID_Controller *pid, float setpoint, float input) { // 计算误差 float error = setpoint - input; // 比例项 float proportional = pid->Kp * error; // 积分项(并做积分限幅,防止积分饱和) pid->integral += error; // 积分限幅 if (pid->integral > pid->output_max) pid->integral = pid->output_max; else if (pid->integral < pid->output_min) pid->integral = pid->output_min; float integral = pid->Ki * pid->integral; // 微分项 float derivative = pid->Kd * (error - pid->prev_error); pid->prev_error = error; // 计算总输出 pid->output = proportional + integral + derivative; // 输出限幅 if (pid->output > pid->output_max) pid->output = pid->output_max; else if (pid->output < pid->output_min) pid->output = pid->output_min; return pid->output; } ``` 第二步:模糊PID 模糊PID需要根据当前误差和误差变化率来调整Kp, Ki, Kd。这需要设计模糊规则表,并实现模糊推理。 由于模糊控制实现相对复杂,我们可以先实现一个简单的模糊规则,例如根据误差的绝对值大小来调整参数。 这里我们采用一个简化的方法:根据误差大小分段调整参数(类似于非线性PID),作为模糊PID的简化替代。 但为了完整性,下面给出模糊PID控制器的设计思路: 1. 定义输入变量:误差e和误差变化率ec,输出变量为ΔKp, ΔKi, ΔKd。 2. 定义模糊集合:e和ec的模糊集合为{NB, NM, NS, ZO, PS, PM, PB},输出同理。 3. 设计模糊规则表。 4. 使用模糊推理(如Mamdani)和解模糊(如重心法)得到ΔKp, ΔKi, ΔKd。 由于代码量较大,我们可以先实现标准PID,然后逐步扩展为模糊PID。 现在,我们修改原函数Spinnig_Level,假设我们已经通过传感器得到了当前角度(current_angle),目标角度(target_angle)由外部给出。 修改后的函数可能如下(使用标准PID): ```c // 假设已经定义并初始化了水平方向的PID控制器 PID_Controller pid_level; void Spinnig_Level(float target_angle, float current_angle) { // 计算PID输出 float output = PID_Compute(&pid_level, target_angle, current_angle); // 将输出转换为PWM占空比,注意原代码中PWM占空比范围是660~840 // 假设输出范围已经映射到PWM占空比的范围,这里需要根据实际情况调整 // 例如,我们可以将PID的输出范围设定为-100到100,然后映射到660~840(中值750) int pwm_value = 750 + (int)output; // 这里假设output已经是在一定范围内,比如-90到90,这样pwm_value在660~840之间 // 限幅,确保在660~840之间 if (pwm_value < 660) pwm_value = 660; else if (pwm_value > 840) pwm_value = 840; // 更新PWM TIM_SetCompare1(TIM1, pwm_value); } ``` 注意:上述代码中,我们假设PID输出已经经过调整,使得输出值可以直接加到750(中间值)上。实际中,我们需要根据PID的输出范围调整映射关系。 改进为模糊PID: 我们可以创建一个模糊PID控制器结构体,包含一个基础PID控制器和模糊规则表等。然后,在每次计算PID之前,先根据当前的误差和误差变化率调整PID参数。 由于时间关系,这里只给出框架: ```c typedef struct { PID_Controller pid; // 模糊控制器相关参数 // ... } Fuzzy_PID_Controller; float Fuzzy_PID_Compute(Fuzzy_PID_Controller *fpid, float setpoint, float input) { // 计算当前误差e和误差变化率ec float e = setpoint - input; float ec = e - fpid->pid.prev_error; // 注意:这里ec近似为两次误差的差(实际是误差的差分) // 根据e和ec,通过模糊规则计算ΔKp, ΔKi, ΔKd // 这里省略模糊推理过程,假设有函数Fuzzy_Tuning返回调整量 float delta_Kp, delta_Ki, delta_Kd; Fuzzy_Tuning(e, ec, &delta_Kp, &delta_Ki, &delta_Kd); // 更新PID参数 fpid->pid.Kp += delta_Kp; fpid->pid.Ki += delta_Ki; fpid->pid.Kd += delta_Kd; // 调用PID计算 return PID_Compute(&fpid->pid, setpoint, input); } ``` 其中,Fuzzy_Tuning函数需要实现模糊推理,这需要大量的代码来实现隶属度函数、模糊规则和解模糊等。由于问题复杂,我们可以先实现标准PID,然后根据实际控制效果再考虑是否引入模糊控制。 另外,引用[1]还提到了自适应Kalman滤波技术,这可以用于对传感器信号进行滤波,减少噪声对控制的影响。我们可以在读取传感器数据后,先进行Kalman滤波,然后将滤波后的值作为PID的输入。 总结改进步骤: 1. 在现有系统中加入角度反馈(例如MPU6050等传感器)。 2. 实现标准PID控制器,并替换原有的直接控制方式。 3. 考虑加入Kalman滤波处理传感器数据。 4. 在标准PID控制效果不理想时,考虑升级为模糊PID。 根据引用[2],在目标锁定过程中,需要利用视觉传感器和图像处理算法,因此目标角度的设定可能由图像处理结果给出。 最后,由于代码的完整实现需要硬件平台支持,以上代码仅提供思路,实际参数需要调试。 注意:原代码中Oc_Lp数组似乎用于记录历史PWM值,但未明确用途。在PID控制器中,积分项已经包含了历史误差,因此可以去掉原代码中的历史PWM值记录。 以上为改进方案,具体实现时需要根据实际硬件调整参数和接口。</think>### 云台摄像头防抖算法改进方案(C语言实现) 针对云台摄像头防抖算法的PID控制改进,以下是优化方案和C语言实现代码: #### 1. **标准PID控制器实现** ```c typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 float integral; // 积分项累计 float prev_error; // 上次误差 float output_min; // 输出最小值 float output_max; // 输出最大值 } PID_Controller; void PID_Init(PID_Controller* pid, float Kp, float Ki, float Kd, float min, float max) { pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->integral = 0; pid->prev_error = 0; pid->output_min = min; pid->output_max = max; } float PID_Compute(PID_Controller* pid, float setpoint, float input) { // 计算误差 float error = setpoint - input; // 比例项 float proportional = pid->Kp * error; // 积分项(抗饱和处理) pid->integral += error; if (pid->integral > pid->output_max) pid->integral = pid->output_max; else if (pid->integral < pid->output_min) pid->integral = pid->output_min; float integral = pid->Ki * pid->integral; // 微分项 float derivative = pid->Kd * (error - pid->prev_error); pid->prev_error = error; // 计算总输出 float output = proportional + integral + derivative; // 输出限幅 if (output > pid->output_max) output = pid->output_max; else if (output < pid->output_min) output = pid->output_min; return output; } ``` #### 2. **模糊PID改进方案** ```c // 模糊规则表(简化的三角隶属函数) float fuzzy_adjustment(float error, float d_error) { // 根据误差和误差变化率动态调整PID参数 float delta_Kp = 0, delta_Ki = 0, delta_Kd = 0; // 误差绝对值大时增加Kp if (fabs(error) > 10.0f) delta_Kp = 0.2f; // 误差变化快时增加Kd if (fabs(d_error) > 5.0f) delta_Kd = 0.15f; // 系统接近稳态时增加Ki if (fabs(error) < 2.0f && fabs(d_error) < 1.0f) delta_Ki = 0.1f; return delta_Kp, delta_Ki, delta_Kd; } // 模糊自适应PID float Fuzzy_PID_Compute(PID_Controller* pid, float setpoint, float input) { float error = setpoint - input; float d_error = error - pid->prev_error; // 动态调整参数 float delta_Kp, delta_Ki, delta_Kd; fuzzy_adjustment(error, d_error, &delta_Kp, &delta_Ki, &delta_Kd); pid->Kp += delta_Kp; pid->Ki += delta_Ki; pid->Kd += delta_Kd; // 执行标准PID计算 return PID_Compute(pid, setpoint, input); } ``` #### 3. **卡尔曼滤波集成** ```c // 简化的Kalman滤波器 typedef struct { float Q; // 过程噪声协方差 float R; // 测量噪声协方差 float P; // 估计误差协方差 float X; // 状态值 } KalmanFilter; float Kalman_Update(KalmanFilter* kf, float measurement) { // 预测 kf->P = kf->P + kf->Q; // 更新 float K = kf->P / (kf->P + kf->R); // 卡尔曼增益 kf->X = kf->X + K * (measurement - kf->X); kf->P = (1 - K) * kf->P; return kf->X; } // 在控制循环中应用 void Stabilization_Loop() { KalmanFilter kf_x = {.Q=0.01, .R=0.5, .P=1, .X=0}; PID_Controller pid_x; PID_Init(&pid_x, 1.5, 0.05, 0.2, -100, 100); while(1) { float raw_angle = Read_Gyro(); // 读取原始传感器数据 float filtered_angle = Kalman_Update(&kf_x, raw_angle); float control_output = Fuzzy_PID_Compute(&pid_x, TARGET_ANGLE, filtered_angle); // 转换为PWM输出(引用[3]的接口) int pwm_value = 750 + (int)(control_output * 0.5); if (pwm_value < 660) pwm_value = 660; if (pwm_value > 840) pwm_value = 840; TIM_SetCompare1(TIM1, pwm_value); } } ``` #### 4. **关键改进点说明** 1. **动态参数调整** 通过模糊规则根据误差大小和变化率实时调整PID参数,提高系统响应速度和稳定性[^1]。 2. **传感器噪声处理** 集成卡尔曼滤波器降低陀螺仪和加速度计噪声,提高控制精度[^1]。 3. **抗积分饱和** 在PID结构中增加积分限幅,防止电机堵转时积分项过大导致系统振荡。 4. **非线性映射** 根据引用[3]的硬件特性(PWM范围660-840),将控制输出映射到有效工作区间。 5. **模块化设计** 分离PID、模糊控制和滤波模块,便于单独调试和参数整定。 #### 5. **参数整定建议** 1. 初始PID参数(测试值): ```c PID_Init(&pid_x, 1.5, 0.05, 0.2, -100, 100); // X轴 PID_Init(&pid_y, 1.8, 0.03, 0.15, -100, 100); // Y轴 ``` 2. 模糊规则调整原则: - 大误差:优先增大$K_p$快速减小误差 - 小误差:增大$K_i$消除稳态误差 - 快速变化:增大$K_d$抑制超调 3. 卡尔曼滤波器参数: ```c // Q: 过程噪声(系统不确定性) R: 测量噪声(传感器精度) KalmanFilter kf = {.Q=0.01, .R=0.5}; ``` > **注意**:实际参数需通过阶跃响应测试整定,建议使用Ziegler-Nichols方法或试凑法优化。 --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值