Петлі управління PID з великими та непередбачуваними аномаліями


10

Коротке запитання
Чи існує загальний спосіб впоратися з дуже великими аномаліями (порядком величини) в інакше рівномірній контрольній області?

Передумови
Я працюю над алгоритмом управління, який рухає двигун в цілому рівномірну область управління. Без завантаження / мінімального завантаження PID-контролер працює чудово (швидка реакція, мало-не перекриття). Проблема, з якою я стикаюся, полягає в тому, що зазвичай буде хоча б одне місце з високим навантаженням. Положення визначається користувачем під час встановлення, тому немає розумного способу мені знати, коли / де його очікувати.

Коли я налаштовую PID на обробку місця з високим навантаженням, він спричиняє великі пагони на не завантажених ділянках (що я повністю очікував). Поки це нормально перекривати середину ходу, на корпусі немає механічних жорстких зупинок. Відсутність жорстких вершин означає, що будь-яке значне перекриття може призвести до відключення рукоятки управління від двигуна (що призведе до мертвого блоку).

Речі, які я прототипую

  • Вкладені PID (дуже агресивні, коли далеко від цілі, консервативні, коли поруч)
  • Фіксований приріст, коли далеко, PID, коли близько
  • Консервативний PID (працює без навантаження) + зовнішнє управління, яке шукає, щоб PID зупинився і застосував додаткову енергію до тих пір, поки: не буде досягнуто цілі або не буде виявлено швидка швидкість зміни (тобто залишення області з високим навантаженням)

Обмеження

  • Повна поїздка визначена
  • Неможливо додати жорсткі вершини (на даний момент)
  • Помилка, ймовірно, ніколи не зникне
  • Високе навантаження могло бути отримано за менш ніж 10% ходу (мається на увазі відсутність "запущеного старту")

Відповіді:


2

Схоже, ваш розрахунок помилок не накопичує помилок під час роботи з похідним терміном, і ви, можливо, захочете змінити це, оскільки лише похідний термін здатний реагувати на швидкі зміни в процесі.

Якщо я правильно зрозумів ваш код

// Determine the error delta
dE = abs(last_error - new_error);
last_error = new_error;

завжди буде обчислювати термін управління на основі поточної помилки, що є традиційним способом, яким було реалізовано PID. Це добре, оскільки I термін повинен так чи інакше піклуватися про накопичені помилки.

Однак у мене був клієнт, який придумав таку ідею, яку ви можете спробувати. Оскільки у вас є частина кривої процесу, де потрібні більш агресивні зміни, ви можете дозволити навіть помилці частини D накопичуватися:

if(TD)                                                 // Calculate D term
{  
   Last_C += (Error - Last_C) / TD;                    // D term simulates
   Dterm = (Error - Last_C) * KD;                      // capacitor discharging
}
else    
   Dterm = 0;                                          // D term is OFF (TD is 0)

Тут слід зазначити дві цікаві речі:

  • Значення TD - це не похідне посилення (яке є KD), а похідне час, константа користувача, яка контролює час накопичення помилок. Якщо було встановлено нуль, D-частина PID відключена, не зважаючи на встановлене значення посилення KD.

  • Зверніть увагу, як поточна помилка використовувалася для 'зарядки' значення Last_C перед тим, як передати його на обчислення частини D. Змінна Last_C діє як конденсатор, вона нарощуватиметься, коли помилка була великою, так що ваша похідна частина діяла б також на основі недавньої "історії" помилки, а після цього (коли помилок було менше) ця "історія помилки 'розрядиться, як конденсатор.

Звичайно, слід обмежити загальний вихід таким чином, як ви, мабуть, вже робите (антивідонне скидання, невдалий автоматичний перенос вручну та інші звичні речі).

Я можу розмістити докладніші відомості про інші умови мого алгоритму PID, якщо вам це здається корисним, але ви можете спробувати це і подивитися, що відбувається. Він служив моєму клієнту роками.


Дякуємо за вклад. Мені доведеться спробувати це. Швидкий погляд, здається, має сенс.
Адам Льюїс

Я бачу, тому ви маєте внесок у термін "D" у вашому "головному" PID плюс усе, що виявляє стійла, приносить обчислення.
Дражен Чіка

1
Це правильно. Під час налаштування використовується Pter's Dterm, не дуже агресивна. Що ускладнює це питання - це те, що навантаження може вирватися за дуже короткий проміжок часу. IE від'єднується зв'язок. Це різке зняття сили спричиняє великі переступи, коли існує яка-небудь функція згладжування (підсумовування), застосована до сил стійла.
Адам Льюїс

Зла проблема, було б цікаво дізнатися, наскільки добре впорається з цим нечіткий логічний алгоритм. Принаймні, ви могли б вбудувати більше свого досвіду, пов’язаного з проблемою, в алгоритм, а не залишатися в межах стандартних рішень. У будь-якому випадку, удачі з цим :-)
Дражен Чіка

1

Початкове рішення

stalled_pwm_output = ШІМ / | ΔE |

PWM = Максимальне значення ШІМ
ΔE = last_error - new_error

Початкові відносини успішно збільшують вихід ШІМ на основі відсутності змін у двигуні. Дивіться графік нижче для отримання зразка.

Такий підхід застосовується до ситуації, коли неагресивний PID зупинився. Однак, прикро (і очевидно) питання, що коли неагресивний PID здатний досягти встановленої точки і намагається сповільнити, staled_pwm_output наростає. Цей наліт спричиняє великий промах під час подорожі в незавантажене місце.

1 / ΔE проти ΔE

Поточне рішення

Теорія

stalled_pwm_output = (kE * PID_PWM) / | ΔE |

kE = Постійний масштабування
PID_PWM = Поточний запит PWM від неагресивного PID
ΔE = last_error - new_error

У моїх теперішніх стосунках досі використовується концепція 1 / ΔE, але використовується неагресивний вихід PWM PID для визначення виходу stall_pwm_output. Це дозволяє PID відмовити назад stall_pwm_output, коли він починає наближатися до цільової заданої точки, але дозволяє 100% вихід ШІМ при зупинці. Константа масштабування kE потрібна для того, щоб ШІМ потрапляв у точку насичення (вище 10000 у графіках нижче).

Псевдокодекс

Зауважте, що результат від cal_stall_pwm додається до виходу ШІМ PID в моїй поточній логіці управління.

int calc_stall_pwm(int pid_pwm, int new_error)
{
    int ret = 0;
    int dE = 0;
    static int last_error = 0;
    const int kE = 1;

    // Allow the stall_control until the setpoint is achived
    if( FALSE == motor_has_reached_target())
    {
        // Determine the error delta
        dE = abs(last_error - new_error);
        last_error = new_error;

        // Protect from divide by zeros
        dE = (dE == 0) ? 1 : dE;

        // Determine the stall_pwm_output
        ret = (kE * pid_pwm) / dE;
    }

    return ret;
}

Вихідні дані

Постійний вихід ШІМ Постійний вихід ШІМ

Зауважте, що у графіку вихідної ширини ШІМ раптове падіння ШІМ на ~ 3400 - це вбудована функція безпеки, що активується, оскільки мотор не зміг досягти положення протягом заданого часу.

Випуск нереалізованих ШІМ Виведення ШІМ без навантаження


1

Ти не кажеш, що це ти контролюєш ... швидкість двигуна? посада? Ну, як би там не було, першим кроком було б визначити, що буде прийнятною помилкою. Наприклад, якщо керування швидкістю, може бути встановлена ​​максимальна помилка в межах 1% від цілі. Не визначаючи прийнятну помилку, ви не можете визначити, яка роздільна здатність вам потрібна для АЦП або кількості ШІМ. Без цього компенсація PID могла б бути ідеальною, але все-таки матиме граничні коливання циклу.

Тоді вам потрібно знати динаміку системи відкритого циклу. Без цього ви не можете знати, які виграші потрібні пропорційній (P), інтегральній (I) та похідній (D) частинам циклу. Ви можете виміряти динаміку за допомогою кроку введення (зміна кроку рівня приводу або ШІМ) або крокової зміни навантаження (схоже, це буде стосуватися вас).

Використання зміни помилки циклу на цикл у знаменнику вашого керуючого альго для зміни значення ШІМ гарантує, що цикл ніколи не відшаровується. Це забезпечує граничне коливання циклу управління. Більшість клієнтів не змирилися з цим.

P частина циклу піклується про негайну помилку (негайно реагує на помилку). Але це буде кінцевий коефіцієнт підсилення, тому деяка помилка залишиться. I частина циклу реагує повільно з часом, застосовуючи нескінченний посил (нескінченний час для нескінченного посилення), щоб виправити ту помилку, яку залишила P частина.

Оскільки частина I повільна, вона може вийти з фази з виправленням, необхідним для мінімізації помилок, навіть якщо для вас встановлено правильний посилення. Отже, він завивається, потребує довгого відновлення. Або він залишається в опозиції до частини П.

Найкращий спосіб впоратися з намотуванням - обмежити максимальне збережене значення в інтеграторі лише трохи більше, ніж потрібно для виправлення пропорційної помилки в гіршому випадку. Якщо інтегратор вийде з фази і протистоїть P один від одного, найкраще зробити це встановити значення інтегратора на нуль. Algo може бути розроблений для розуміння цього і при необхідності скинути інтегратор.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.