incubator-nuttx/libs/libdsp/lib_pid.c

353 lines
8.6 KiB
C

/****************************************************************************
* libs/libdsp/lib_pid.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <dsp.h>
#include <string.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pid_controller_init
*
* Description:
* Initialize PID controller. This function does not initialize saturation
* limits.
*
* Input Parameters:
* pid - (out) pointer to the PID controller data
* KP - (in) proportional gain
* KI - (in) integral gain
* KD - (in) derivative gain
*
* Returned Value:
* None
*
****************************************************************************/
void pid_controller_init(FAR pid_controller_f32_t *pid, float KP, float KI,
float KD)
{
LIBDSP_DEBUGASSERT(pid != NULL);
/* Reset controller data */
memset(pid, 0, sizeof(pid_controller_f32_t));
/* Copy controller parameters */
pid->KP = KP;
pid->KI = KI;
pid->KD = KD;
pid->KC = 0.0;
}
/****************************************************************************
* Name: pi_controller_init
*
* Description:
* Initialize PI controller. This function does not initialize saturation
* limits.
*
* Input Parameters:
* pid - (out) pointer to the PID controller data
* KP - (in) proportional gain
* KI - (in) integral gain
*
* Returned Value:
* None
*
****************************************************************************/
void pi_controller_init(FAR pid_controller_f32_t *pid, float KP, float KI)
{
LIBDSP_DEBUGASSERT(pid != NULL);
/* Reset controller data */
memset(pid, 0, sizeof(pid_controller_f32_t));
/* Copy controller parameters */
pid->KP = KP;
pid->KI = KI;
pid->KD = 0.0f;
pid->KC = 0.0f;
/* No windup-protection at default */
pid->aw_en = false;
pid->ireset_en = false;
}
/****************************************************************************
* Name: pid_saturation_set
*
* Description:
* Set controller saturation limits. Sometimes we need change saturation
* configuration in the run-time, so this function is separate from
* pid_controller_init().
*
* Input Parameters:
* pid - (out) pointer to the PID controller data
* min - (in) lower limit
* max - (in) upper limit
*
* Returned Value:
* None
*
****************************************************************************/
void pid_saturation_set(FAR pid_controller_f32_t *pid, float min, float max)
{
LIBDSP_DEBUGASSERT(pid != NULL);
LIBDSP_DEBUGASSERT(min < max);
pid->sat.max = max;
pid->sat.min = min;
/* Enable saturation in PID controller */
pid->pidsat_en = true;
}
/****************************************************************************
* Name: pi_saturation_set
*
* Description:
*
* Input Parameters:
* pid - (out) pointer to the PID controller data
* min - (in) lower limit
* max - (in) upper limit
*
* Returned Value:
* None
*
****************************************************************************/
void pi_saturation_set(FAR pid_controller_f32_t *pid, float min, float max)
{
LIBDSP_DEBUGASSERT(pid != NULL);
LIBDSP_DEBUGASSERT(min < max);
pid->sat.max = max;
pid->sat.min = min;
/* Enable saturation in PI controller */
pid->pisat_en = true;
}
/****************************************************************************
* Name: pid_antiwindup_enable
****************************************************************************/
void pi_antiwindup_enable(FAR pid_controller_f32_t *pid, float KC,
bool enable)
{
pid->aw_en = enable;
pid->KC = KC;
}
/****************************************************************************
* Name: pid_ireset_enable
****************************************************************************/
void pi_ireset_enable(FAR pid_controller_f32_t *pid, bool enable)
{
pid->ireset_en = enable;
}
/****************************************************************************
* Name: pid_integral_reset
****************************************************************************/
void pid_integral_reset(FAR pid_controller_f32_t *pid)
{
pid->part[1] = 0.0f;
pid->aw = 0.0f;
}
/****************************************************************************
* Name: pi_integral_reset
****************************************************************************/
void pi_integral_reset(FAR pid_controller_f32_t *pid)
{
pid_integral_reset(pid);
}
/****************************************************************************
* Name: pi_controller
*
* Description:
* PI controller with output saturation and windup protection
*
* Input Parameters:
* pid - (in/out) pointer to the PI controller data
* err - (in) current controller error
*
* Returned Value:
* Return controller output.
*
****************************************************************************/
float pi_controller(FAR pid_controller_f32_t *pid, float err)
{
LIBDSP_DEBUGASSERT(pid != NULL);
float tmp = 0.0f;
/* Store error in controller structure */
pid->err = err;
/* Get proportional part */
pid->part[0] = pid->KP * err;
/* Get intergral part */
pid->part[1] += pid->KI * (err - pid->aw);
/* Add proportional, integral */
pid->out = pid->part[0] + pid->part[1];
/* Store not saturated output */
tmp = pid->out;
/* Saturate output if enabled */
if (pid->pisat_en == true)
{
if (pid->out > pid->sat.max)
{
if (pid->ireset_en == true)
{
/* Reset I part */
if (err > 0.0f)
{
pi_integral_reset(pid);
}
}
/* Limit output to the upper limit */
pid->out = pid->sat.max;
}
else if (pid->out < pid->sat.min)
{
if (pid->ireset_en == true)
{
/* Reset I part */
if (err < 0.0f)
{
pi_integral_reset(pid);
}
}
/* Limit output to the lower limit */
pid->out = pid->sat.min;
}
}
/* Anti-windup I-part decay if enabled */
if (pid->aw_en == true)
{
pid->aw = pid->KC * (tmp - pid->out);
}
/* Return regulator output */
return pid->out;
}
/****************************************************************************
* Name: pid_controller
*
* Description:
* PID controller with output saturation and windup protection
*
* Input Parameters:
* pid - (in/out) pointer to the PID controller data
* err - (in) current controller error
*
* Returned Value:
* Return controller output.
*
****************************************************************************/
float pid_controller(FAR pid_controller_f32_t *pid, float err)
{
LIBDSP_DEBUGASSERT(pid != NULL);
/* Get PI output */
pi_controller(pid, err);
/* Get derivative part */
pid->part[2] = pid->KD * (err - pid->err_prev);
/* Add derivative part to the PI part */
pid->out += pid->part[2];
/* Store current error */
pid->err_prev = err;
/* Saturate output if enabled */
if (pid->pidsat_en == true)
{
if (pid->out > pid->sat.max)
{
/* Limit output to the upper limit */
pid->out = pid->sat.max;
}
else if (pid->out < pid->sat.min)
{
/* Limit output to the lower limit */
pid->out = pid->sat.min;
}
}
/* Return regulator output */
return pid->out;
}