if(f_start) {
	auto_ = auto;
	outA = out;
	impQupTm_ = impQdwnTm_ = 0;
	impQup_ = impQdwn_ = 0;
}

//Call standard analog PID
Kzd = min(1e3/(f_frq*Tzd),1);
Kint = min(1e3/(f_frq*Ti),1);
Kdif = min(1e3/(f_frq*Td),1);

//Scale error
if(var.isEVal() || max <= min) return out;
sp = max(min,min(max,sp));

//Prepare values
spv = 100*(sp-min)/(max-min);
val = 100*(var-min)/(max-min);
val += K1*in1 + K2*in2;
val = min(100,max(-100,val));

//Error
err = spv - val;
err = (abs(err)<Zi) ? 0 : ((err>0) ? err-Zi : err+Zi );
err *= Kp;
err = min(100,max(-100,err));

integ += Kint*err;						//Integral
difer -= Kdif*(difer-val);			//Differential wait
dlag  += Kzd*((difer-val)-dlag);	//Differential lag

//Automatic mode enabled
if(auto) {
	outA_ = err + integ + Kd*dlag + K3*in3 + K4*in4;
	if(QO) outA_ = min(outA, outA_);
	if(QZ) outA_ = max(outA, outA_);
	outA = outA_;
}
else {
	casc = false;
	if(followSp) sp = var;
	outA = manIn;
}

//Check output limits
outA = manIn = min(Hup,max(Hdwn,outA));

//Fix integral for manual and limits
integ = outA - err - Kd*dlag - K3*in3 - K4*in4;

if(analog) return outA;

if(f_start || f_stop) { impQup = impQdwn = false; return 0; }

//Call impuls generator
outA_ = (impAnOut < 0) ? 2*(outA-50) : (outA-impAnOut);
if(perLag <= 0 && ((outA_*KImpRfact) >= (100*TImpMin/TImpPer) || (-outA_/KImpRfact) >= (100*TImpMin/TImpPer)))
{
	impLag = max(abs(outA_)*TImpPer/100,TImpMin);
	impLag = (outA_>0) ? impLag*KImpRfact : impLag/KImpRfact;
	perLag = TImpPer;
	if(outA_ > 0) impQup = !QO; else impQdwn = !QZ;
}
else if(perLag > 0) {
	perLag -= 1e3/f_frq;
	if((TImpPer-perLag) >= impLag) {
		impQup = impQdwn = false;
		if(!auto) perLag = 0;
	}
}

if(!auto && auto != auto_)	manIn = (impAnOut < 0) ? 50 : impAnOut;
auto_ = auto;

if(impQup && !impQup_) impQupTm_ = 2*f_frq;
impQupTm_ = max(0,impQupTm_-1);
impQupTm = (impQup || impQupTm_ > 0.1);
impQup_ = impQup;
if(impQdwn && !impQdwn_) impQdwnTm_ = 2*f_frq;
impQdwnTm_ = max(0,impQdwnTm_-1);
impQdwnTm = (impQdwn || impQdwnTm_ > 0.1);
impQdwn_ = impQdwn;

if(impAnImit > 0) {
	if(impQup)	out += 100/(impAnImit*f_frq);
	if(impQdwn)	out -= 100/(impAnImit*f_frq);
	return max(0, min(100,out));
}
return max(0, min(100,impAnOut));