Igor_U 0 2 октября, 2005 Опубликовано 2 октября, 2005 · Жалоба Два звена. Первое звено задает температуру приточного воздуха в зависимости от температуры вытяжного. Второе звено задает мощность калорифера в зависимости от температуры приточного. Надеюсь, что выдрал корректно. объявление переменных: 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться