Mittwoch, 13. Mai 2015

PT1 & PT2 Filtering/Damping

The functions below can be used to perform PT1 and PT2 damping of input values, which is, smoothing a potentially cluttered input.
Electrically speaking, the PT1 filter acts as a low-pass filter.
For continuous damping, the output of the last operation (outValue) must be stored and used for the next operation. This leads to a result history of 1 value which is enough to damp the input. The functions utilize a conversion of the 2byte input to 4byte to gain precision for division operations.

uint16 dampPT1( uint16 inValue,
                uint16* outValue,
                const uint16 riseFactor,
                const uint16 fallFactor)
{
    if(outValue == NULL)
    {
        return;
    }
    // Transformation of input to 32 bit internal format to gain precision and add remainder
    uint32 calcValue = (((uint32) inValue) << 16) + 32768;
    if (*outValue < calcValue)
    {
        if (m_riseFactor == 0)
        {
            *outValue = calcValue;
        }
        else
        {
            calcValue -= m_dampBuffer;
            calcValue /= m_riseFactor;
            if (calcValue == 0)
            {
                calcValue = 1;
            }
            *outValue += calcValue;
        }
    }
    else
    {
        if (outValue > calcValue)
        {
            if (fallFactor == 0)
            {
                *outValue = calcValue;
            }
            else
            {
                calcValue = *outValue - calcValue;
                calcValue /= fallFactor;
                if (calcValue == 0)
                {
                    calcValue = 1;
                }
                *outValue -= calcValue;
            }
        }
    }
    return (uint16) ((*outValue) >> 16);
}

uint16 dampLimitPT1(uint16 inValue,
                    uint16* outValue,
                    const uint16 riseFactor,
                    const uint16 fallFactor,
                    const uint16 riseLimit, const uint16 fallLimit)
{
    if(outValue == NULL)
    {
        return;
    }
    // Transformation of input to 32 bit internal format to gain precision and add remainder
    uint32 calcValue = (((uint32) inValue) << 16) + 32768;

    //  Check if characteristic is rising or falling
    if (*outValue < calcValue)
    {
        // Calculate differnce between old and new value
        calcValue -= *outValue;
        if (riseFactor != 0)
        {
            // division of the difference by k
            calcValue /= (uint32) riseFactor;
        }
        else
        {
            // do nothing here
        }
        // Check if limit reached
        if ((riseLimit != 0xFFFF) && (calcValue > ((uint32) riseLimit << 16)))
        {
            // Limit reached, set Delta to the maximum
            calcValue = ((uint32) riseLimit << 16);
        }
        *outValue += calcValue;
    }
    else
    {
        // Calculate differnce between old and new value
        calcValue -= *outValue;
        if (fallFactor != 0)
        {
            // division of the difference by k
            calcValue /= (uint32) fallFactor;
        }
        else
        {
            // do nothing here
        }
        // Check if limit reached
        if ((fallLimit != 0xFFFF) && calcValue > ((uint32) fallLimit << 16))
        {
            // Limit reached, set Delta to the maximum
            calcValue = ((uint32) fallLimit << 16);
        }
        *outValue -= calcValue;
    }
    return (uint16) (*outValue >> 16);
}

uint16 dampPT2(uint16 inValue,
               uint16* bufferPT1,
               uint16* bufferPT2,
               const uint16 riseFactor,
               const uint16 fallFactor)
{
    // perform PT1 limited damping on a PT1 damped input
    // first damping is configured using rising factor,
    // second damping is configured using falling factor
    return dampPT1(
               dampPT1(inValue, bufferPT1, riseFactor, riseFactor),
               bufferPT2, fallFactor, fallFactor);
}

uint16 dampLimitPT2( uint16 inValue,
                     uint16* bufferPT1,
                     uint16* bufferPT2,
                     const uint16 riseFactor,
                     const uint16 fallFactor,
                     const uint16 riseLimit,
                     const uint16 fallLimit)
{
    // perform PT1 limited damping on a PT1 damped input
    // first damping is configured using rising factor,
    // second damping is configured using falling factor and the limits
    return dampLimitPT1(
              dampPT1(inValue, bufferPT1, riseFactor, riseFactor),
              bufferPT2, fallFactor, fallFactor, riseLimit, fallLimit);
}