public int CompareTo(object obj) { try { PIDSet p = ( PIDSet )obj; return(Temp.CompareTo(p.Temp)); } catch { return(-1); } }
public bool EqualTo(PIDSet p) { if (p != null) { return((this.P == p.P) && (this.I == p.I) && (this.D == p.D)); } else { return(false); } }
public virtual PIDSet getPidParams( ) { PIDSet pid = new PIDSet( ); gpib_.Write(":SOUR:TEMP:LCON:GAIN?"); pid.P = readFloat( ); gpib_.Write(":SOUR:TEMP:LCON:INT?"); pid.I = readFloat( ); gpib_.Write(":SOUR:TEMP:LCON:DER?"); pid.D = readFloat( ); return(pid); }
public void setCurrSourcePidParams(PIDSet pid) { gpib_.Write(SET_SOURCE_CURRENT); setCurrentSourcePidParams(pid.P, pid.I, pid.D); gpib_.Write(SET_SOURCE_TEMPERATURE); // be pragmatic and set back to temperature ctrl }
public virtual void setTempSourcePidParams(PIDSet pid) { setTemperatureSourcePidParams(pid.P, pid.I, pid.D); }
public virtual void setPidParams(PIDSet pid) { setTempSourcePidParams(pid); }
public double StabilizeTemperatureSelfTuningFalse( ) // was StabilizeTemperature { if (doOverrideSettings) { settings_ = overridingSettings_; } gpib_.Write(SET_SOURCE_TEMPERATURE); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); var target = this.getTargetTemperature( ); LogMessage("Starting to stabilize"); bool hitTimeout = false; TimeSpan timeout = new TimeSpan(0, 0, 0, 0, ( int )(settings_.StabilizationTimeout * 1000)); DateTime start = DateTime.UtcNow; Queue <double> tempQ = new Queue <double>( ); double avg = 0; double stddev = 1000; // a large number double temp; double dif; TimeSpan delay = new TimeSpan(0, 0, 0, 0, ( int )(settings_.StabilizationDelay * 1000)); ; Stopwatch t = new Stopwatch( ); t.Start( ); PIDSet PID = new PIDSet( ), stablePIDset_; double sum = 0; double sum2 = 0; bool exitForbidden = true; int iteration = 0; do { try { iteration++; hitTimeout = (DateTime.UtcNow - start) > timeout; Thread.Sleep(( int )delay.TotalMilliseconds); stablePIDset_ = calcStablePidSet(target); temp = measureTemperature( ); tempQ.Enqueue(temp); sum += temp; sum2 += Math.Pow(temp, 2); if (tempQ.Count > settings_.StabilizationSamples) { double tdequed = tempQ.Dequeue( ); sum -= tdequed; sum2 -= Math.Pow(tdequed, 2); exitForbidden = false; } avg = sum / tempQ.Count; stddev = Math.Sqrt(sum2 / ( double )tempQ.Count - Math.Pow(avg, 2)); bool stdDevOK = (stddev < settings_.MaxTStdDev); bool offsetOK = (Math.Abs(avg - target) < settings_.MaxTError); if (debugMode_) { LogMessage(("Iteration = " + iteration + " Samples used in calculation = " + settings_.StabilizationSamples)); LogMessage(("T = " + temp)); LogMessage(("stddev = " + stddev + " Limit = " + settings_.MaxTStdDev + " OK =" + stdDevOK.ToString( ))); LogMessage(("Mean offset = " + (avg - target) + " Limit = " + settings_.MaxTError + " OK =" + offsetOK.ToString( ))); LogMessage("----"); } isStable_ = stdDevOK && offsetOK; if (isStable_) { if (!PID.EqualTo(stablePIDset_)) { LogMessage("Switching to stable PID parameters"); // ...if necessary setTempSourcePidParams(stablePIDset_); PID = stablePIDset_; isStable_ = false; // isStable must be recalculated at least once if PID's were changed.. } } else if (!PID.EqualTo(settings_.Fast)) { LogMessage("Switching to fast PID parameters"); setTempSourcePidParams(settings_.Fast); PID = settings_.Fast; } dif = temp - target; if (writeLogMessages_) { if (t.ElapsedMilliseconds > 10000) { LogMessage("Currently at: " + measureTemperature( ) + ". Dif is: " + dif); t.Reset( ); t.Start( ); } } } catch (Exception ex) { LogMessage("Got an exception in stabilization loop: " + ex.Message + "(this has no effect on temperature)"); continue; } } while((!hitTimeout && !isStable_) || exitForbidden || stabilizeForever_); DateTime stop = DateTime.UtcNow; if (hitTimeout) { LogMessage("Hit timelimit while stabilizing temperature"); throw new Exception("Hit timelimit while stabilizing temperature"); } else { LogMessage("Done stabilizing after " + (stop - start).TotalSeconds.ToString("####.0") + " Seconds."); return((stop - start).TotalMinutes); } }
public double StabilizeTemperatureSelfTuningTrue( ) // Experimental self-tuning of the PID controller. { gpib_.Write(SET_SOURCE_TEMPERATURE); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); // Get values from settings_ // Note that StabilizationSamples and StabilizationDelay combines to give a lower bound on time, // e.g., StabilizationSamples = 10 and StabilizationDelay = 0.1 yields 1.0 seconds. PIDSet PID = settings_.StabilizationPID; LogMessage(string.Format("StabilizationPID = {0}, {1}, {2} before stabilization.", PID.P, PID.I, PID.D)); int samples = settings_.StabilizationSamples; LogMessage(string.Format("StabilizationSamples = {0} samples.", samples)); TimeSpan delay = new TimeSpan(0, 0, 0, 0, ( int )(settings_.StabilizationDelay * 1000)); LogMessage(string.Format("StabilizationDelay = {0} seconds.", delay.TotalSeconds)); TimeSpan timeout = new TimeSpan(0, 0, 0, 0, ( int )(settings_.StabilizationTimeout * 1000)); LogMessage(string.Format("StabilizationTimeout = {0} seconds.", timeout.TotalSeconds)); double stdDev = settings_.StabilizationStdDev; LogMessage(string.Format("StabilizationStdDev = {0} degree Celcius.", stdDev)); // Chi-square value for samples degrees of freedom, was "double chi2 = settings_.StabilizationChi2;" double alpha = settings_.StabilizationAlpha; double chi2 = Syntune.UberMath.FSharp.Statistics.Newton.inverseChi2(0.01, samples, 1.0 - alpha); // string.Format( "StabilizationChi2 = {0}.", chi2 ).LogInfo( ); double gamma = settings_.StabilizationGamma; // Hand-tuned constant for PID tuning // string.Format( "StabilizationGamma = {0}.", gamma ).LogInfo( ); // Upper bound for convergence: sumOfSquares / acceptableVariance < chi2 // The Chi-squared value is choosen based on sample size and the confidence desired. // Please consult a textbook in statistics (or Beta) for a table over the Chi-squared distribution. // This criteria only an approximate solution but it seems to work well in practice. double upperBound = chi2 * Math.Pow(stdDev, 2); // Measuremet variables var targetTemperature = this.getTargetTemperature( ); double difference = 0; double square = 0; double sumOfSquares = 0; Queue <double> squares = new Queue <double>( ); // Auxilliary variables for PID tuning // The tuning algorithm is based on "Self-Tuning of PID Controllers by Adaptive Interaction" // by Feng Lin et al. double auxP = 0, auxI = 0, auxD = 0, weight; // The number of iterations done; just interesting to know int numberOfIterations = 0; LogMessage("Stabilizing ..."); var start = DateTime.UtcNow; // Continue to measure until timeout or a sufficient numer of samples and convergence do { Thread.Sleep(( int )delay.TotalMilliseconds); numberOfIterations++; difference = targetTemperature - measureTemperature( ); square = Math.Pow(difference, 2); sumOfSquares += square; squares.Enqueue(square); // string.Format( "{0}", difference ).LogInfo( ); // Just verifying convergence auxD = (difference - auxD) / delay.TotalSeconds; auxI = difference * delay.TotalSeconds + auxI; auxP = difference; weight = gamma * difference * delay.TotalSeconds; // The constant D have been hardwired to 0, which seems to work well in practise. // Dynamic D behave unpredictable for many values of gamma. PID = new PIDSet { P = PID.P - weight * auxP, I = PID.I - weight * auxI, D = 0 // PID.D - weight * auxD }; setTempSourcePidParams(PID); if (squares.Count > samples) { sumOfSquares -= squares.Dequeue( ); } } while((DateTime.UtcNow - start) < timeout && (squares.Count < samples || upperBound < sumOfSquares)); var stop = DateTime.UtcNow; settings_.StabilizationPID = PID; LogMessage(string.Format("StabilizationPID = {0}, {1}, {2} after {3} iterations.", PID.P, PID.I, PID.D, numberOfIterations)); if ((stop - start) < timeout) { LogMessage("The temperature stabilized after " + (stop - start).TotalSeconds.ToString("####.0") + " seconds."); return((stop - start).TotalSeconds); } else { LogMessage("Hit timelimit while stabilizing temperature"); throw new Exception("Hit timelimit while stabilizing temperature"); } }
public PIDSet calcStablePidSet(double temp) { PIDSet low = new PIDSet( ), high = new PIDSet( ), p = new PIDSet( ); settings_.StablePids.Sort( ); low = settings_.StablePids[0]; for (int i = 0; i < settings_.StablePids.Count; i++) { if (temp == settings_.StablePids[i].Temp) { return(settings_.StablePids[i]); } if (temp > settings_.StablePids[i].Temp) { low = settings_.StablePids[i]; } else { break; } } high = settings_.StablePids[settings_.StablePids.Count - 1]; for (int i = settings_.StablePids.Count - 1; i > -1; i--) { if (temp == settings_.StablePids[i].Temp) { return(settings_.StablePids[i]); } if (temp < settings_.StablePids[i].Temp) { high = settings_.StablePids[i]; } else { break; } } if (low == settings_.StablePids[settings_.StablePids.Count - 1]) { return(settings_.StablePids[settings_.StablePids.Count - 1]); } if (high == settings_.StablePids[0]) { return(settings_.StablePids[0]); } p.Temp = temp; p.P = low.P + (temp - low.Temp) * ((high.P - low.P) / (high.Temp - low.Temp)); p.I = low.I + (temp - low.Temp) * ((high.I - low.I) / (high.Temp - low.Temp)); p.D = low.D + (temp - low.Temp) * ((high.D - low.D) / (high.Temp - low.Temp)); p.ILimit = low.ILimit + (temp - low.Temp) * ((high.ILimit - low.ILimit) / (high.Temp - low.Temp)); return(p); }