最近在做PID控制buck-boost四开关同步升降压
大概原理图如下

PWMA与PWMB互补, 即Q1和Q4同相, Q2和Q3与Q1和Q4互补
Vout与Vin的关系与PWMA的占空比D的关系由下式确定:
在输入Vin稳定的情况下, Vout与D显然是个非线性的关系

常规的做法是通过PID去控制占空比D从而控制电压, 但是在这里由于离散PID的公式:
可以看到输出u与误差e基本是线性的, 所以不能直接用于控制这里非线性的D, 会导致高占空比时微调很小的占空比值就会导致电压出现很大波动。
解决方式: 直接控制受控量(即电压)。
static uint32_t voltage_to_duty(float expect_mV)
{
if(expect_mV < 10.0f)
return 0;
float denominator = expect_mV + INPUT_VOLTAGE_MV;
if(denominator < 100.0f)
denominator = 100.0f;
float duty_cycle = expect_mV / denominator;
// 硬件保护
if(duty_cycle > MAX_DUTY_RATIO)
duty_cycle = MAX_DUTY_RATIO;
return (uint32_t)(duty_cycle * PWM_PERIOD_ARR);
}
void pwm_set_duty(uint32_t pwm_duty)
{
__HAL_HRTIM_SETCOMPARE(&hhrtim1, HRTIM_TIMERINDEX_TIMER_E, HRTIM_COMPAREUNIT_3, (pwm_duty >> 1) + 1);
hhrtim1.Instance->sTimerxRegs[TIMER_E].CMP1CxR = pwm_duty;
}
static void PID_ctrl_routine(void *pvParameters)
{
static uint32_t target_voltage_mV = 0;
static uint32_t target_voltage_buffer_mV = 0;
static float next_output_voltage_mV = 0.0f;
static uint32_t *buf_ptr;
static float temp_current_voltage_mV = 0.0f;
static float last_voltage_mV = 0.0f;
static float last_last_voltage_mV = 0.0f;
while(1)
{
//1. 等待ADC数据
if(xQueueReceive(adc_queue, &buf_ptr, portMAX_DELAY) == pdTRUE)
{
//2. 查询target是否改变
if(pdPASS == xQueueReceive(pid_ctrl_queue_mV, &target_voltage_buffer_mV, 0))
{
if(target_voltage_mV != target_voltage_buffer_mV)
{
target_voltage_mV = target_voltage_buffer_mV;
// pid_reset_ctrl_block(pid_handle); //使用增量式pid更改target后不能重置
}
}
//3. 计算实际电压/电流
for(uint8_t i = 0; i < ADC_BUFFER_LENGTH / 2; i++)
{
origin_voltage_sum += buf_ptr[i] & 0x0FFF;
origin_current_sum += buf_ptr[i] >> 16;
}
// 读取到的电压 20分压
temp_current_voltage_mV = origin_voltage_sum / 4095.0f * 3300.0f * 20.0f / (float)(ADC_BUFFER_LENGTH / 2)
* 1.0048f;
if(temp_current_voltage_mV >= 10.0f)
temp_current_voltage_mV += 60.0f;
if(temp_current_voltage_mV < 0)
temp_current_voltage_mV = 0;
now_current_A = origin_current_sum / 4095.0f * 3300.0f * 2.0f / 1000.0f / (
ADC_BUFFER_LENGTH / 2); //单位A
//4. 对均值进行二阶rc滤波
temp_current_voltage_mV = RC_ALPHA_DENO_1 * temp_current_voltage_mV + RC_ALPHA_DENO_2 * last_voltage_mV +
RC_ALPHA_DENO_3 * last_last_voltage_mV;
now_voltage_mV = temp_current_voltage_mV;
last_last_voltage_mV = last_voltage_mV;
last_voltage_mV = temp_current_voltage_mV;
//4. 进行pid计算
float error_mV = (float)target_voltage_mV - temp_current_voltage_mV;
pid_compute(pid_handle, error_mV, &next_output_voltage_mV);
uint32_t output_duty = voltage_to_duty(next_output_voltage_mV);
pwm_set_duty(output_duty);
}
}
}直接使PID控制”目标电压”, 然后进行一次转换转为占空比, 从而将控制线性化。
该找时间学学自控原理了。。。