Перейти к содержанию
    

Реализация ПИДа

Два звена. Первое звено задает температуру приточного воздуха в зависимости от температуры вытяжного. Второе звено задает мощность калорифера в зависимости от температуры приточного.

Надеюсь, что выдрал корректно.

 

объявление переменных:

 

double IFlowOut; // интегратор

double KdFlowOut; // переменные для ПИДа

double KiFlowOut; // переменные для ПИДа

double DFlowOut; // дифферинциатор

double IFlowIn; // интегратор

double KdFlowIn; // переменные для ПИДа

double KiFlowIn; // переменные для ПИДа

double DFlowIn; // дифферинциатор

double Yk; // нынешний выход

signed short Ek;

unsigned short EkDelta;

signed short Temperature;

signed short OldTemperatureFlowIn;

signed short OldTemperatureFlowOut;

signed long AddFlowOutTemperature; // прибавляемое значение температуры

signed short FlowOutTemperature; // измеренная температура обратного воздуха 0,0625

signed short FlowInTemperature; // измеренная температура притока 0,0625

unsigned short DeltaFlowOut; // зона нечуствительности для температуры вытяжки 0.0-20.0 0,0625

unsigned short DeltaFlowIn; // зона нечуствительности для температуры притока 0.0-20.0 0,0625

unsigned short DeltaHigh; // максимальное превышение температуры 0,0625

// притока относительно заданной температуры 0.0-50.0 0,0625

unsigned short DeltaLow; // макcимальное снижение температуры 0,0625

// притока относительно заданной температуры 0.0-20.0 0,0625

unsigned short TaskFlowIn; // задание Т притока 0,0625

 

 

 

extern void CalcVariable(void) // подсчет новых значенй для ПИДа

{

/*

Функция подсчета значений для ПИДа. Вызывается при любом изменений параметров ПИДа.

Дифференциальное звено D:

D = (Td * Kp * (OldT - T)) / Tk

Интегральное звено I:

I = (Tk * Kp * (Task - T)) / Ti

Пропорцианальное звено K:

K = Kp * (Task - T)

Выход ПИДа:

Y = K + I + D

 

где T - нынешняя температура

Task - заданная температура

OldT - предыдущая температура

Tk - такт ПИДа

Kp - коэффициент пропорцианальности

Ti - постоянная интегрирования

Td - постоянная дифференцирования

*/

// подсчет значений для пида вытяжки

if (Value.TdFlowOut!=0) KdFlowOut=((double)Value.KpFlowOut*Value.TdFlowOut*0.1)/Value.TkFlowOut;

else KdFlowOut=0.0;

if (Value.TiFlowOut!=0) KiFlowOut=((double)Value.TkFlowOut*Value.KpFlowOut)/Value.TiFlowOut;

else KiFlowOut=0.0;

TkFlowOut=Value.TkFlowOut;

// подсчет для пида притока

if (Value.TdFlowIn!=0) KdFlowIn=((double)Value.KpFlowIn*Value.TdFlowIn*0.1)/Value.TkFlowIn;

else KdFlowIn=0.0;

if (Value.TiFlowIn!=0) KiFlowIn=((double)Value.TkFlowIn*Value.KpFlowIn)/Value.TiFlowIn;

else KiFlowIn=0.0;

SystemFlags.CalcVariable=0; // сбрасываем флаг необходимости подсчета ПИДа

}

 

extern void TaskFlowInChange(void)

{

unsigned char N;

// задание температуры приточного воздуха в зависимости от разницы температур между вытяжным и заданным

TkFlowOut=Value.TkFlowOut; // востанавливаем время фильтра

// запрещаем прерывания

N=__save_interrupt();

__disable_interrupt();

Temperature=(signed short)(AddFlowOutTemperature/TkFlowOut); // высчитываем среднеарифметическую температуру притока

Ek=TaskFlowOut-Temperature; // вычисляем разницу приточного и заданного

AddFlowOutTemperature=0; // обнуляем накопленую температуру приточного воздуха

// разрешаем прерывания

__restore_interrupt(N);

EkDelta=abs(Ek); // абсолютная разница

if (EkDelta<DeltaFlowOut) Ek=0; // если абсолютная разница меньше величины гистерезиса, то разницу обнуляем

DFlowOut=KdFlowOut*(OldTemperatureFlowOut-Temperature); // высчитываем Д звено

Yk=(double)Ek*Value.KpFlowOut+IFlowOut; // складываем И звено с разницей умноженной на П

if((Yk<MaxTaskFlowIn) & (Yk>0.0)) IFlowOut+=Ek*KiFlowOut; // если подсчитанное значение выхода превышает ограничение,

// то И звено не интегрируем. Ограничение задается в variable.h как MaxTaskFlowIn

Yk=Yk+DFlowOut; // к выходу ПИД прибавляем D звено

if (Yk>MaxTaskFlowIn) Yk=MaxTaskFlowIn; else if (Yk<0.0) Yk=0.0; // выход обрезаем сверху MaxTaskFlowIn, снизу 0

Ek=DeltaHigh+DeltaLow; // в Ek - границы задания

if (Yk!=0.0) Yk=((double)Ek*Yk)/MaxTaskFlowIn; // высчитываем значение заданной температуры в пределах ограниченном DeltaHigh и DeltaLow

if (HighError.Start==1)

{

Yk=TaskFlowOut+(double)DeltaHigh/2; // если запущена настройка ПИДа, то задание высчитываем как половина от DeltaHigh

}

else

{

Yk=Yk+(TaskFlowOut-DeltaLow); // если не запущена настройка ПИДа, то переводим задание из значения подсчитанного Yk

}

TaskFlowIn=(unsigned short)Yk; // запоминаем значение

Value.TaskFlowIn=(unsigned short)Yk/1.6; // запоминаем значение

// обновление переменных

OldTemperatureFlowOut=Temperature;

}

 

extern void FazaChange(void)

{

// задание мощности калорифера в зависимости от разницы температур между приточным воздухом и заданным

 

unsigned char N;

unsigned char __flash *AdrFaza;

 

N=__save_interrupt();

__disable_interrupt();

Temperature=FlowInTemperature;

__restore_interrupt(N);

Ek=TaskFlowIn-Temperature; // в Ек разница температур между заданным значением и измеренным

EkDelta=abs(Ek); // абсолютная разница

if (EkDelta<DeltaFlowIn) Ek=0; // если абсолютная разница меньше величины гистерезиса, то разницу обнуляем

DFlowIn=(KdFlowIn*(OldTemperatureFlowIn-Temperature)); // высчитываем Д звено

Yk=(double)Ek*Value.KpFlowIn+IFlowIn; // складываем И звено с разницей температур умноженной на П

if((Yk<MaxPower) & (Yk>0.0)) IFlowIn+=Ek*KiFlowIn;// если подсчитанное значение выхода превышает ограничение,

// то И звено не интегрируем. Ограничение задается в variable.h как MaxPower

Yk=Yk+DFlowIn; // к выходу ПИД прибавляем D звено

if (Yk>MaxPower) Yk=MaxPower; else if (Yk<0) Yk=0; // выход обрезаем сверху значением MaxPower, снизу 0

Value.FazaValue=(unsigned short)(Yk/100.0); // обновляем значение мощности калорифера в процентах

// в озу формируем новую последовательность ШИМ для А канала

AdrFaza=&TableFazaA[0]+(7*Value.FazaValue);

for (N=0; N<7; N++) FazaA[N]=*(AdrFaza+N);

// в озу формируем новую последовательность ШИМ для В канала

AdrFaza=&TableFazaB[0]+(7*Value.FazaValue);

for (N=0; N<7; N++) FazaB[N]=*(AdrFaza+N);

// обновление переменных

OldTemperatureFlowIn=Temperature;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...