static unsigned int mergeSet(AS_phasorSet *Setp, const AS_shaper *shp, double SuDiff, double amax, double omega, int reflected, int verbose) { double ext, aRatio, uDiff, offset, S, tmp, offsetlim; int n, count, addCount; /* Initialize variables */ S=AS_SIGN(SuDiff); /* Extracting the sign */ uDiff=fabs(SuDiff); /* Absolute value */ offset=0.0; /* Phase offset. Positive*/ offsetlim=(reflected ? (shp->phi[shp->N - 1] - Setp->ph[Setp->N - 1].phiEnd) : DBL_MAX); count = 0; addCount = 0; while (fabs(uDiff) > AS_EPSILON && (offsetlim-offset > AS_EPSILON && count < AS_MERGE_ITER_LIM)) { /* Allocate phasors until uCommand is attained */ ext=shp->DMin; /* Maximum phase extension of added phasors, initialized to DMin of shaper. Positive */ aRatio=(reflected ? 1.0 : (shp->AMin + shp->AMax)/shp->AMin); /* Maximum possible relative magnitude of acceleration. Positive */ for (n=0; n < shp->N; n++) /* Repeat for all the pulses in the shaper */ phaseInterval(Setp, shp->phi[n]-offset, S*shp->A[n]*amax, AS_SIGN(S*shp->A[n])*AS_MAX(1.0,fabs(shp->A[n]))*amax, &aRatio, &ext, reflected); if (aRatio>0.0) { /* Possible to allocate phasors at current offset value ? */ tmp=omega/(aRatio*shp->ASum*amax); ext=AS_MIN(ext,uDiff*tmp); uDiff-=ext/tmp; /* count down uDiff, the velocity change remaining to place out */ for (n=0; n < shp->N; n++,addCount++) { /* allocate phasors at shaper locations */ tmp=shp->phi[n]-offset; addPhasor(Setp, tmp, tmp-ext, S*aRatio*shp->A[n]*amax); /* add phasor at phi[n]-offset of extension ext and */ /* acceleration sign*ratio*shaperMag*amax to the set */ } cleanSet(Setp); } offset+=ext; /* count up offset */ count++; } /* End of while loop */ if (verbose >= AS_VERB_ALL) printf("\nAntiSway/mergeSet exited while loop, count=%d. Added %d phasors totally.\n",count,addCount); if (offsetlim-offset <= AS_EPSILON) /* Could not allocate phasors further (should be possible only in reflected mode). */ return AS_ERR_MERGE_OFFSETLIM; if (count>=AS_MERGE_ITER_LIM) { if (verbose >= AS_VERB_ERR) AS_diagnose(Setp,omega,reflected,SuDiff,uDiff); return AS_ERR_MERGE_ITER; } return 0; }
unsigned int AS_Engine_man( int newCall, int hoisting, int hoisted, int verbose, const AS_shaper *shp, double uCommand, double uR, double DLc, double omega, double amaxH, double amaxS, double dt, double *aRp, AS_phasorSet *Setp ) { unsigned int sts=0; double SaComp,Sa0; if (shp->ID == AS_NO_AS) { /* If NO_AS shaper, remove unnecessary constraints */ hoisting=0; hoisted=0; amaxS=amaxH; } /* Allocate or reallocate phasors if needed */ /* Correct for hoisting */ if (hoisting) { /* Calculate compensation acceleration SaComp=-1.5*DLc*Dth/cos(thc) */ SaComp=-1.5*DLc*(-getX(Setp))*omega/cos(-getY(Setp)); /* If there is a chance SaComp can't be allocated - reduce and allocate residual separately */ if (fabs(SaComp)>amaxH-amaxS) { Sa0=AS_SIGN(SaComp)*(amaxH-amaxS); addPhasor(Setp, 0.0, -omega*dt, SaComp-Sa0); /* Add compensation residual */ AS_collapseSet(Setp, shp, amaxS); SaComp=Sa0; sts |= AS_ERR_ACC_MARGIN; if (verbose >= AS_VERB_ERR) printf("AntiSway/Engine_man: Partial compensation through residual phasor addition: %f SaComp needed, %f available |amax margin|\n",SaComp,amaxH-amaxS); } /* Adjust set so that uCommand is still met, given the compensation phasor */ sts |= makeSet_man(Setp, shp, uCommand-SaComp*dt, uR, amaxS, omega, verbose); /* Add the compensation phasor */ addPhasor(Setp, 0.0, -omega*dt, SaComp); cleanSet(Setp); } /* If no hoisting - adjust set if new command or new omega */ else if (newCall || hoisted) { sts |= makeSet_man(Setp, shp, uCommand, uR, amaxS, omega, verbose); } /* Step up time and return error status */ *aRp=timeStepSet(Setp, omega*dt); return sts; }
void AS_collapseSet(AS_phasorSet *Setp, const AS_shaper *shp, double amax) { double XSum,YSum,PhiNew,RNew,extp5,sArg,base; int n; if (Setp->N == 0) /* If no phasors in set - do nothing */ return; if (shp->ID == AS_NO_AS) { /* If NO_AS shaper - remove all */ AS_emptySet(Setp); return; } /* sum up phasors */ XSum=getX(Setp); YSum=getY(Setp); /* Remove phasors */ AS_emptySet(Setp); /* do loop over half planes */ base=0.0; n=0; do { /* Calculate residual phasor */ PhiNew=arctan360N(YSum, XSum); RNew=sqrt(XSum*XSum + YSum*YSum); sArg=RNew*AS_GRAV_ACCEL/(2.0*amax); if (sArg>1.0) { /* Too large arcsin argument - reduce! (residual allocated in next half plane) */ RNew=2.0*amax/AS_GRAV_ACCEL; extp5=0.5*AS_PI; } else extp5=asin(sArg); /* Half extension of residual phasor, given a=amax */ /* Make sure PhiNew is in the half plane [base, base-AS_PI) */ while (PhiNew <= base-AS_PI) { PhiNew+=AS_PI; RNew*=-1.0; } while (PhiNew > base) { PhiNew-=AS_PI; RNew*=-1.0; } /* Add the calculated residual phasor. */ if (PhiNew+extp5 > base) { /* Overlap into previous phase? */ addPhasor(Setp, base, PhiNew-extp5, AS_SIGN(-RNew)*amax); addPhasor(Setp, -AS_PI+PhiNew+extp5, base-AS_PI, AS_SIGN(RNew)*amax); } else if (PhiNew-extp5 < base-AS_PI) { /* Overlap into next half plane ? */ addPhasor(Setp, base, PhiNew-extp5+AS_PI, AS_SIGN(RNew)*amax); addPhasor(Setp, PhiNew+extp5, base-AS_PI, AS_SIGN(-RNew)*amax); } else /* No overlap */ addPhasor(Setp, PhiNew+extp5, PhiNew-extp5, AS_SIGN(-RNew)*amax); /* Count down sums. Loop only over the newly added phasors. (Using that phasors are added at end positions)*/ for ( ; n < Setp->N; n++) { XSum -= Setp->ph[n].R*cos(Setp->ph[n].Phi); YSum -= Setp->ph[n].R*sin(Setp->ph[n].Phi); } base-=AS_PI; } while (sArg>1.0); cleanSet(Setp); } /* end of function */
/*_* @aref ssab_servoreg Ssab_ServoReg */ void Ssab_ServoReg_exec(plc_sThread *tp, pwr_sClass_Ssab_ServoReg *object) { double aD, uD, xD, dt, control, uRamp, xDiff; int delaysteps; dt = tp->PlcThread->ScanTime; /* Constant scan time (the ideal value, not the measurement of last cycle time) */ object->enable = *object->enableP; if (!object->enable) { //bypass the reference and reset active flags and elapsed time object->uReg = *object->uRP; object->RampActive = FALSE; object->DZActive = FALSE; object->TDZElapsedTime = 0.0; object->TDZActive = FALSE; return; } /* 1. Retrieve input */ object->aR = *object->aRP; object->uR = *object->uRP; control = object->uR; object->xR = *object->xRP; object->ac = *object->acP; object->uc = *object->ucP; object->xc = *object->xcP; object->xCommand = *object->xCommandP; xDiff = object->xCommand - object->xc; object->umaxP = *object->umaxPP; object->umaxN = *object->umaxNP; object->positioning = *object->positioningP; if (object->positioning && object->enableRamp) //uR not used - use the regulator for positioning control = (xDiff > 0.0 ? object->umaxP : object->umaxN); /* 2. PID regulator */ // Should change some stuff here: Relative gain kP, Integration time Ti, Derivation time Td. if (object->enablePID && !object->positioning) { SR_addNewRef(SR_OBJ_LISTPP, object->aR, object->uR, object->xR); delaysteps = AS_ROUND(object->DelayPID/dt); if (delaysteps < 0) delaysteps = 0; if (delaysteps > object->maxdelaysteps) delaysteps = object->maxdelaysteps; SR_extractRef(SR_OBJ_LISTPP, delaysteps, &aD, &uD, &xD); control = uD + object->kPID[0]*(uD - object->uc) + object->kPID[1]*(xD - object->xc) + object->kPID[2]*(aD - object->ac); } /* 3. Square root ramp */ //This will give erroneous behavior if the command position is changed to a position close to the current in the midst of a travel. //Possibly solve this problem by taking into account further conditions. if (object->enableRamp) { uRamp = AS_SIGN(xDiff) * ( -object->DelayRamp*object->amaxS + sqrt(object->DelayRamp*object->DelayRamp*object->amaxS*object->amaxS + 2.0*fabs(xDiff)*object->amaxS) ); if ( (xDiff >= 0.0 && control > uRamp) || (xDiff < 0.0 && control < uRamp) ) { control = uRamp; object->RampActive = TRUE; } else object->RampActive = FALSE; } else object->RampActive = FALSE; /* 4. Dead zone */ if (object->enableDZ && (object->uR == 0.0) && (fabs(xDiff) < object->DeadZone)) { control = 0.0; object->DZActive = TRUE; } else object->DZActive = FALSE; /* 5. Timer dead zone */ if (object->enableTDZ && (object->uR == 0.0) && (fabs(xDiff) < object->TimerDeadZone)) { object->TDZElapsedTime += *(object->ScanTime); if (object->TDZElapsedTime > object->TDZTime) { control = 0.0; object->TDZActive = TRUE; object->TDZElapsedTime = object->TDZTime; } else object->TDZActive = FALSE; } else { object->TDZElapsedTime = 0.0; object->TDZActive = FALSE; } /* 6. Check bounds */ if (control > object->umaxP) control = object->umaxP; if (control < object->umaxN) control = object->umaxN; /* 8. Set output */ object->uReg = control; }