0

Declaration:

I have asked same question here, I feel the community is big here, thus asked again. If there is a feature to link the questions, I would do that too:

https://engineering.stackexchange.com/questions/55184/how-to-calculate-the-integral-and-derivative-term-and-integral-and-derivative-ti

I am designing a PID controller.

  1. While calculating integral controller, should you calculate mean of all the past errors or only calculate mean of past n samples? In the case of latter, how to pick n?

  2. While calculating derivative controller, should you just fit a straight line to past m (for eg, past 5 points) points or take derivative of all the past errors and pass through a low pass filter (LPF)? In the case of latter, can anyone suggest a fast way to do that in C++ (derivative + LPF time not more than 0.3 ms).

  3. About integral (Ti) and derivative (Td) time in the Standard form, How to choose the numbers? I am working on arresting atmospheric seeing related oscillations. What it means is when any astronomical object is imaged, due to atmosphere dynamics (random changes in refractive index of many stacked layers), the image position on the focal plane oscillates. These oscillations have typical frequencies of 500 Hz and in good conditions have smaller amplitudes about 1 arcsecond and bad conditions up to 4-6 arcsecond. The frame rate of my pid controller is 655 fps (655 Hz), which is faster than atmospheric seeing, but the question is how to decide the Ti and Td of pid controller in standard form?

Follows my current implementation of PID controller:

Here Kp, Ki, Kd are global variables.

Some other global variables are:

Ni - Number of points to compute integral error, if <0 means all past points, else past Ni points

Nd - Fits a straight line on past Nd points, the derivative is the slope of the fitted line.

XTemp and YTemp are image shifts of the current image with respect to the reference image, thus the correction will be negative of this.

limMinInt, limMaxInt are the min/max values integral controller can have, but neither I am not so sure of having this logic, nor I have any reasonable criteria to fix these values.

limMin, limMax are the min/max values of the output of the PID, however like above, do not know how to fix these values.

correctionShiftX, correctionShiftY are the values I want to find using the PID logic

*correctionX, *correctionY are the values given to actuator using the conversion matrix.

The function parameters are mostly pointers, thus are preserved from one iteration to next.

Please suggest if you can suggest improvement in this logic. Currently this PID logic, I am only able to arrest for about 3 minutes.

I believe a good pid tuning is required which also includes a good implementation.

inline int getCorrection(double XTemp, double YTemp, deque<double> &integralErrorX, deque<double> &integralErrorY,
                  deque<double> &derivativeErrorX, deque<double> &derivativeErrorY, uint64_t *integralCounter, uint64_t *derivativeCounter,
                  double *correctionX, double *correctionY, uint64_t curr_count, uint64_t nbImagesReceived
) {
    uint64_t i;
    double toCorrectXTemp, toCorrectYTemp;
    double xMean =  (double) (Nd + 1) / (double) 2;
    double xixbaryiybarX = 0, xixbaryiybarY = 0;
    double xixbarsq = 0;
    double integralErrorVoltageX = 0;
    double integralErrorVoltageY = 0;
    double derivativeErrorVoltageX = 0;
    double derivativeErrorVoltageY = 0;

    toCorrectXTemp = -1 * XTemp;
    toCorrectYTemp = -1 * YTemp;

    double correctionShiftX, correctionShiftY;

    if (Ni > 0) {
        if (integralErrorX.size() == Ni) {
            integralErrorX.pop_front();
            integralErrorY.pop_front();
        }
        integralErrorX.push_back(toCorrectXTemp);
        integralErrorY.push_back(toCorrectYTemp);

        if (integralErrorX.size() < Ni) {
            integralErrorVoltageX = 0;
            integralErrorVoltageY = 0;
        } else {
            integralErrorVoltageX = accumulate(integralErrorX.end() - Ni, integralErrorX.end(), 0.0) / Ni;
            integralErrorVoltageY = accumulate(integralErrorY.end() - Ni, integralErrorY.end(), 0.0) / Ni;
        }
    }
    else {
        if (integralErrorX.empty()) {
            integralErrorX.push_back(toCorrectXTemp);
            integralErrorY.push_back(toCorrectYTemp);
            integralErrorVoltageX = 0;
            integralErrorVoltageY = 0;
        }
        else {
            double sumX = integralErrorX.front();
            double sumY = integralErrorY.front();
            integralErrorX.pop_front();
            integralErrorY.pop_front();
            sumX += toCorrectXTemp;
            sumY += toCorrectYTemp;
            integralErrorX.push_back(sumX);
            integralErrorY.push_back(sumY);
            integralErrorVoltageX = sumX / (curr_count + 1);
            integralErrorVoltageY = sumY / (curr_count + 1);
        }
    }

    if (derivativeErrorX.size() == Nd) {
        derivativeErrorX.pop_front();
        derivativeErrorY.pop_front();
    }
    derivativeErrorX.push_back(toCorrectXTemp);
    derivativeErrorY.push_back(toCorrectYTemp);

    if (derivativeErrorX.size() < Nd) {
        derivativeErrorVoltageX = 0;
        derivativeErrorVoltageY = 0;
    }
    else {
        double meanDerivativeErrorVoltageX = 0;
        double meanDerivativeErrorVoltageY = 0;

        meanDerivativeErrorVoltageX = accumulate(derivativeErrorX.end()-Nd, derivativeErrorX.end(), 0.0) / Nd;
        meanDerivativeErrorVoltageY = accumulate(derivativeErrorY.end()-Nd, derivativeErrorY.end(), 0.0) / Nd;

        i = 0;
        for (auto it=derivativeErrorX.cbegin(); it!=derivativeErrorX.cend(); it++) {
            xixbaryiybarX += (*it - meanDerivativeErrorVoltageX) * (i + 1 - xMean);
            xixbarsq += ((i + 1 - xMean) * (i + 1 - xMean));
            i += 1;
        }
        i = 0;
        for(auto it=derivativeErrorY.cbegin(); it!=derivativeErrorY.cend(); it++){
            xixbaryiybarY += (*it - meanDerivativeErrorVoltageY) * (i + 1 - xMean);
            i += 1;
        }

        derivativeErrorVoltageX = xixbaryiybarX / xixbarsq;
        derivativeErrorVoltageY = xixbaryiybarY / xixbarsq;
    }

    double integralContributionX = Ki * integralErrorVoltageX;
    double integralContributionY = Ki * integralErrorVoltageY;

    if (integralContributionX <= limMinInt) {
        integralContributionX = limMinInt;
    }
    if (integralContributionX >= limMaxInt) {
        integralContributionX = limMaxInt;
    }
    if (integralContributionY <= limMinInt) {
        integralContributionY = limMinInt;
    }
    if (integralContributionY >= limMaxInt) {
        integralContributionY = limMaxInt;
    }
    correctionShiftX = Kp * toCorrectXTemp + integralContributionX + Kd * derivativeErrorVoltageX;
    correctionShiftY = Kp * toCorrectYTemp + integralContributionX + Kd * derivativeErrorVoltageY;

    if (correctionShiftX <= limMin) {
        correctionShiftX = limMin;
    }
    if (correctionShiftX >= limMax) {
        correctionShiftX = limMax;
    }
    if (correctionShiftY <= limMin) {
        correctionShiftY = limMin;
    }
    if (correctionShiftY >= limMax) {
        correctionShiftY = limMax;
    }

    *correctionX = A00*correctionShiftX + A01*correctionShiftY;
    *correctionY = A10*correctionShiftX + A11*correctionShiftY;

    sprintf(
        logString,
        "%ld, %ld, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf",
        curr_count, nbImagesReceived, toCorrectXTemp, toCorrectYTemp,
        integralContributionX, integralContributionY, derivativeErrorVoltageX,
        derivativeErrorVoltageY, correctionShiftX, correctionShiftY,
        *correctionX, *correctionY
    );
    shift_uncorected_log(logString);
    return 0;
}
Jonas
  • 121,568
  • 97
  • 310
  • 388
Harsh M
  • 625
  • 2
  • 11
  • 25
  • I don't understand. Get your integral and derivative code working on a PC, then transfer to your PID. IMHO, debugging on the PC is a lot easier and quicker than on a PID or other embedded system. – Thomas Matthews May 12 '23 at 05:08
  • You should also search the internet for "C++ integral derivative example". – Thomas Matthews May 12 '23 at 05:09
  • When you used the debugger, which part of your code is causing the issue? Please indicate in your code. Also, please state the expected values and the actual values. – Thomas Matthews May 12 '23 at 05:10
  • @ThomasMatthews Thank you for the comment. It is very hard to model atmospheric turbulence. As far as i know there is no known publically available mathematical model of atmospheric turbulence that can be used to simulate and estimate the pid parameters. There is no compilation issue in the code. What I am asking is from people who have worked on control systems with systems having no known mathematical model, what is the best way to implement a closed loop feedback system. – Harsh M May 12 '23 at 05:17
  • I have searched internet and have arrived at this implementation but as I have mentioned, I am not able to make it work for more than 3 minutes. I expect the system to atleast work for 45 minutes to an hour, to be considered a reasonable system. Because typical astronomical observations last for about 15 minutes to an hour to have any scientific value – Harsh M May 12 '23 at 05:19
  • Digital devices are discreet-time by nature. Continuous-time equations do not sit well on them. You need to study reformulation of continuous-time transfer functions into their discreet-time counterparts. Z transform instead of Laplace, summation vs integration and difference vs differentiation... – Red.Wave May 12 '23 at 07:21
  • @Red.Wave can you elaborate by providing an improvement in the code? may be as an answer. If not a code, a detailed description about implementation can also help me. I am a physicist, do not have experience in control systems. – Harsh M May 12 '23 at 08:08
  • I mean this question 1st should be answered in the control engineering context, rather than programming context. Unfortunately discreet-time systems are undereducated in engineering curriculums, while they're the ones actually used in digital control systems. I can help you find issues with C++ implementation, so long as you have the theoretical solution. For the theoretical solution, you need to consult a control engineering expert. – Red.Wave May 12 '23 at 15:11

0 Answers0