Package flanagan.control

Source Code of flanagan.control.SecondOrder

/*      Class SecondOrder
*
*       This class contains the constructor to create an instance of
*       a second order process,
*           a.d^2(output)/dt^2 + b.d(output)/dt + c.output  =  d.input
*       and the methods needed to use this process in simulation
*       of control loops.
*
*       This class is a subclass of the superclass BlackBox.
*
*       Author:  Michael Thomas Flanagan.
*
*       Created: March 2003
*       Updated: 23 April 2003, 3 May 2005, 3 April 2006, 2 July 2006, 6 April 2008
*
*
*       DOCUMENTATION:
*       See Michael T Flanagan's JAVA library on-line web page:
*       http://www.ee.ucl.ac.uk/~mflanaga/java/SecondOrder.html
*       http://www.ee.ucl.ac.uk/~mflanaga/java/
*
* Copyright (c) 2003 - 2008  Michael Thomas Flanagan
*
* PERMISSION TO COPY:
*
* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee,
* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies
* and associated documentation or publications.
*
* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions
* and the following disclaimer and requires written permission from the Michael Thomas Flanagan:
*
* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan:
*
* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose.
* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software
* or its derivatives.
*
***************************************************************************************/


package flanagan.control;
import flanagan.complex.Complex;
import flanagan.complex.ComplexPoly;

public class SecondOrder extends BlackBox{

    private double aConst = 1.0D// a constant in differential equation above
    private double bConst = 1.0D// b constant in differential equation above
    private double cConst = 1.0D// c constant in differential equation above
    private double dConst = 1.0D// d constant in differential equation above
    private double omegaN = 1.0D// undamped natural frequency (resonant frequency)
    private double zeta = 1.0D;    // damping ratio
    private double kConst = 1.0D// the standard form gain constant
    private double sigma = 1.0D;   // attenuation (zeta*omegaN)

    // Constructor
    // Sets all constants to unity
    public SecondOrder(){
        super("Second Order Process");
        super.setSnumer(new ComplexPoly(1.0D));
        super.setSdenom(new ComplexPoly(1.0D, 1.0D, 1.0D));
        super.setZtransformMethod(1);
        super.addDeadTimeExtras();
    }

    // Constructor
    // within constants set from argument list
    public SecondOrder(double aa, double bb, double cc, double dd){
        super("Second Order Process");
        this.aConst = aa;
        this.bConst = bb;
        this.cConst = cc;
        this.dConst = dd;
        if(this.cConst>0.0D)this.standardForm();
        super.setSnumer(new ComplexPoly(this.dConst));
        super.setSdenom(new ComplexPoly(this.cConst, this.bConst, this.aConst));
        super.setZtransformMethod(1);
        super.addDeadTimeExtras();
    }

    // Set a, b, c and d
    public void setCoeff(double aa, double bb, double cc, double dd){
        this.aConst = aa;
        this.bConst = bb;
        this.cConst = cc;
        this.dConst = dd;
        if(this.cConst>0.0D)this.standardForm();
        Complex[] num = Complex.oneDarray(1);
        num[0].reset(this.dConst, 0.0);
        super.sNumer.resetPoly(num);
        Complex[] den = Complex.oneDarray(3);
        den[0].reset(this.cConst, 0.0);
        den[1].reset(this.bConst, 0.0);
        den[2].reset(this.aConst, 0.0);
        super.sDenom.resetPoly(den);
        super.fixedName = "Second Order Process";
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    // Private method for setting the contants of the ntural frequency standard form
    private void standardForm(){
            this.omegaN = Math.sqrt(this.cConst/this.aConst);
            this.zeta = this.bConst/(2.0D*this.aConst*this.omegaN);
            this.kConst = this.dConst/this.cConst;
            this.sigma = this.zeta*this.omegaN;
    }

    public void setA(double aa){
        this.aConst = aa;
        Complex co = new Complex(this.aConst, 0.0);
        super.sDenom.resetCoeff(2, co);
        if(this.cConst>0.0D)this.standardForm();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setB(double bb){
        this.bConst = bb;
        Complex co = new Complex(this.bConst, 0.0);
        super.sDenom.resetCoeff(1, co);
        if(this.cConst>0.0D)this.standardForm();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setC(double cc){
        this.cConst = cc;
        Complex co = new Complex(this.cConst, 0.0);
        super.sDenom.resetCoeff(0, co);
        if(this.cConst>0.0D)this.standardForm();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setD(double dd){
        this.dConst = dd;
        Complex co = new Complex(this.dConst, 0.0);
        super.sNumer.resetCoeff(0, co);
        if(this.cConst>0.0D)this.standardForm();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setStandardForm(double zet, double omega, double kk){
        if(omega<=0)throw new IllegalArgumentException("zero or negative natural frequency");
        if(zet<0)throw new IllegalArgumentException("negative damping ratio");
        this.zeta = zet;
        this.omegaN = omega;
        this.kConst = kk;
        this.sigma = this.omegaN*this.zeta;
        this.reverseStandard();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setZeta(double zet){
        if(zet<0)throw new IllegalArgumentException("negative damping ratio");
        this.zeta = zet;
        this.sigma = this.omegaN*this.zeta;
        this.reverseStandard();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setOmegaN(double omega){
        if(omega<=0)throw new IllegalArgumentException("zero or negative natural frequency");
        this.omegaN = omega;
        this.sigma = this.omegaN*this.zeta;
        this.reverseStandard();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    public void setK(double kk){
        this.kConst = kk;
        this.reverseStandard();
        this.calcPolesZerosS();
        super.addDeadTimeExtras();
    }

    // Private method for obtaining a, b c and d from zeta, omegan and k
    private void reverseStandard(){
        this.aConst = this.omegaN*this.omegaN;
        this.bConst = 2.0D*this.zeta*this.omegaN;
        this.cConst = 1.0D;
        this.dConst = this.kConst*this.aConst;
        Complex[] num = Complex.oneDarray(1);
        num[0].reset(this.dConst, 0.0);
        super.sNumer.resetPoly(num);
        Complex[] den = Complex.oneDarray(3);
        den[0].reset(this.cConst, 0.0);
        den[1].reset(this.bConst, 0.0);
        den[2].reset(this.aConst, 0.0);
        super.sDenom.resetPoly(den);
    }

    public double getA(){
        return this.aConst;
    }

    public double getB(){
        return this.bConst;
    }

    public double getC(){
        return this.cConst;
    }

    public double getD(){
        return this.dConst;
    }

    public double getOmegaN(){
        return this.omegaN;
    }

    public double getZeta(){
        return this.zeta;
    }

    public double getK(){
        return this.kConst;
    }

    public double getAttenuation(){
        return this.sigma;
    }

    // Calculate the zeros and poles in the s-domain
    protected void calcPolesZerosS(){
        super.sPoles = super.sDenom.roots();
    }

    //  Get the s-domain output for a given s-value and a given input.
    public Complex getOutputS(Complex sValue, Complex iinput){
        super.sValue=sValue;
        super.inputS=iinput;
        return this.getOutputS();
    }

    //  Get the s-domain output for the stored input and  s-value.
    public Complex getOutputS(){
        Complex num = Complex.plusOne();
        num = num.times(this.dConst);
        Complex den = new Complex();
        den = this.sValue.times(this.sValue.times(this.aConst));
        den = den.plus(this.sValue.times(this.aConst));
        den = den.plus(this.cConst);
        Complex term = new Complex();
        term = num.over(den);
        super.outputS = term.times(super.inputS);
        if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime)));
        return super.outputS;
    }

    // Perform z transform using an already set delta T
    public void zTransform(){
        if(super.deltaT==0.0D)System.out.println("z-transform attempted in SecondOrder with a zero sampling period");
        if(ztransMethod==0){
            this.mapstozAdHoc();
        }
        else{
            Complex[] ncoef = null;
            Complex[] dcoef = null;
            double bT = this.bConst*this.deltaT;
            double t2 = this.deltaT*this.deltaT;
            double cT2 = this.cConst*t2;
            double dT2 = this.dConst*t2;
            switch(this.integMethod){
                // Trapezium Rule
                case 0: ncoef = Complex.oneDarray(3);
                        ncoef[0].reset(dT2/4.0D, 0.0D);
                        ncoef[1].reset(dT2/2.0D, 0.0D);
                        ncoef[2].reset(dT2/4.0D, 0.0D);
                        super.zNumer=new ComplexPoly(2);
                        super.zNumer.resetPoly(ncoef);
                        super.zNumerDeg=2;
                        dcoef = Complex.oneDarray(3);
                        dcoef[0].reset(this.aConst - bT + cT2/4.0D, 0.0D);
                        dcoef[1].reset(-2.0D*this.aConst + bT + cT2/2.0D, 0.0D);
                        dcoef[2].reset(this.aConst + cT2/4.0D, 0.0D);
                        super.zDenom=new ComplexPoly(2);
                        super.zDenom.resetPoly(dcoef);
                        super.zDenomDeg=2;
                        super.zZeros = zNumer.roots();
                        super.zPoles = zDenom.roots();
                        break;
                //  Backward Rectangular Rule
                case 1: ncoef = Complex.oneDarray(3);
                        ncoef[0].reset(0.0D, 0.0D);
                        ncoef[1].reset(0.0D, 0.0D);
                        ncoef[2].reset(dT2, 0.0D);
                        super.zNumer=new ComplexPoly(2);
                        super.zNumer.resetPoly(ncoef);
                        super.zNumerDeg=2;
                        dcoef = Complex.oneDarray(3);
                        dcoef[0].reset(this.aConst - bT, 0.0D);
                        dcoef[1].reset(-2.0D*this.aConst, 0.0D);
                        dcoef[2].reset(this.aConst + bT + cT2, 0.0D);
                        super.zDenom=new ComplexPoly(2);
                        super.zDenom.resetPoly(dcoef);
                        super.zDenomDeg=2;
                        super.zPoles = zDenom.roots();
                        super.zZeros = Complex.oneDarray(2);
                        super.zZeros[0].reset(0.0D, 0.0D);
                        super.zZeros[1].reset(0.0D, 0.0D);
                        break;
                // Foreward Rectangular Rule
                case 2: ncoef = Complex.oneDarray(3);
                        ncoef[0].reset(0.0D, 0.0D);
                        ncoef[1].reset(0.0D, 0.0D);
                        ncoef[2].reset(dT2, 0.0D);
                        super.zNumer=new ComplexPoly(2);
                        super.zNumer.resetPoly(ncoef);
                        super.zNumerDeg=2;
                        dcoef = Complex.oneDarray(3);
                        dcoef[0].reset(this.aConst - bT + cT2, 0.0D);
                        dcoef[1].reset(-2.0D*this.aConst + bT, 0.0D);
                        dcoef[2].reset(this.aConst, 0.0D);
                        super.zDenom=new ComplexPoly(2);
                        super.zDenom.resetPoly(dcoef);
                        super.zDenomDeg=2;
                        super.zPoles = zDenom.roots();
                        super.zZeros = Complex.oneDarray(2);
                        super.zZeros[0].reset(0.0D, 0.0D);
                        super.zZeros[1].reset(0.0D, 0.0D);
                        break;
                default:    System.out.println("Integration method option in SecondOrder must be 0,1 or 2");
                            System.out.println("It was set at "+integMethod);
                            System.out.println("z-transform not performed");
            }
        }
    }

    // Perform z transform setting delta T
    public void zTransform(double deltaT){
        super.deltaT=deltaT;
        super.deadTimeWarning("zTransform");
        zTransform();
    }

    //  Calculate the current time domain output for a given input and given time
    //  resets deltaT
    public void calcOutputT(double ttime, double inp){
        if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time");
        super.deltaT = ttime - super.time[this.sampLen-1];
        super.sampFreq = 1.0D/super.deltaT;
        super.deadTimeWarning("calcOutputT(time, input)");
        for(int i=0; i<super.sampLen-2; i++){
            super.time[i]=super.time[i+1];
            super.inputT[i]=super.inputT[i+1];
            super.outputT[i]=super.outputT[i+1];
        }
        super.time[super.sampLen-1]=ttime;
        super.inputT[super.sampLen-1]=inp;
        super.outputT[super.sampLen-1]=Double.NaN;
        this.calcOutputT();
    }

    //  Get the output for the stored sampled input, time and deltaT.
    public void calcOutputT(){
        super.outputT[sampLen-1] = (this.cConst*super.inputT[sampLen-1] + this.bConst*(super.inputT[sampLen-1]-super.inputT[sampLen-3])/super.deltaT + this.cConst*(super.inputT[sampLen-1]-2.0D*super.inputT[sampLen-2]+super.inputT[sampLen-3])/(super.deltaT*super.deltaT))/this.dConst;
    }

    // Get the s-domain zeros
    public Complex[] getSzeros(){
        System.out.println("This standard second order process (class SecondOrder) has no s-domain zeros");
        return null;
    }

    // Deep copy
    public SecondOrder copy(){
        if(this==null){
            return null;
        }
        else{
            SecondOrder bb = new SecondOrder();

            bb.aConst = this.aConst;
            bb.bConst = this.bConst;
            bb.cConst = this.cConst;
            bb.dConst = this.dConst;
            bb.omegaN = this.omegaN;
            bb.zeta = this.zeta;
            bb.kConst = this.kConst;
            bb.sigma = this.sigma;

            bb.sampLen = this.sampLen;
            bb.inputT = this.inputT.clone();
            bb.outputT = this.outputT.clone();
            bb.time = this.time.clone();
            bb.forgetFactor = this.forgetFactor;
            bb.deltaT = this.deltaT;
            bb.sampFreq = this.sampFreq;
            bb.inputS = this.inputS.copy();
            bb.outputS = this.outputS.copy();
            bb.sValue = this.sValue.copy();
            bb.zValue = this.zValue.copy();
            bb.sNumer = this.sNumer.copy();
            bb.sDenom = this.sDenom.copy();
            bb.zNumer = this.zNumer.copy();
            bb.zDenom = this.zDenom.copy();
            bb.sPoles = Complex.copy(this.sPoles);
            bb.sZeros = Complex.copy(this.sZeros);
            bb.zPoles = Complex.copy(this.zPoles);
            bb.zZeros = Complex.copy(this.zZeros);
            bb.sNumerDeg = this.sNumerDeg;
            bb.sDenomDeg = this.sDenomDeg;
            bb.zNumerDeg = this.zNumerDeg;
            bb.zDenomDeg = this.zDenomDeg;
            bb.deadTime = this.deadTime;
            bb.orderPade = this.orderPade;
            bb.sNumerPade = this.sNumerPade.copy();
            bb.sDenomPade = this.sDenomPade.copy();
            bb.sPolesPade = Complex.copy(this.sPolesPade);
            bb.sZerosPade = Complex.copy(this.sZerosPade);
            bb.sNumerDegPade = this.sNumerDegPade;
            bb.sDenomDegPade = this.sDenomDegPade;
            bb.maptozero = this.maptozero;
            bb.padeAdded = this.padeAdded;
            bb.integrationSum = this.integrationSum;
            bb.integMethod = this.integMethod;
            bb.ztransMethod = this.ztransMethod;
            bb.name = this.name;
            bb.fixedName = this.fixedName;
            bb.nPlotPoints = this.nPlotPoints;

            return bb;
        }
    }

    // Clone - overrides Java.Object method clone
    public Object clone(){
        Object ret = null;

        if(this!=null){
            SecondOrder bb = new SecondOrder();

            bb.aConst = this.aConst;
            bb.bConst = this.bConst;
            bb.cConst = this.cConst;
            bb.dConst = this.dConst;
            bb.omegaN = this.omegaN;
            bb.zeta = this.zeta;
            bb.kConst = this.kConst;
            bb.sigma = this.sigma;

            bb.sampLen = this.sampLen;
            bb.inputT = this.inputT.clone();
            bb.outputT = this.outputT.clone();
            bb.time = this.time.clone();
            bb.forgetFactor = this.forgetFactor;
            bb.deltaT = this.deltaT;
            bb.sampFreq = this.sampFreq;
            bb.inputS = this.inputS.copy();
            bb.outputS = this.outputS.copy();
            bb.sValue = this.sValue.copy();
            bb.zValue = this.zValue.copy();
            bb.sNumer = this.sNumer.copy();
            bb.sDenom = this.sDenom.copy();
            bb.zNumer = this.zNumer.copy();
            bb.zDenom = this.zDenom.copy();
            bb.sPoles = Complex.copy(this.sPoles);
            bb.sZeros = Complex.copy(this.sZeros);
            bb.zPoles = Complex.copy(this.zPoles);
            bb.zZeros = Complex.copy(this.zZeros);
            bb.sNumerDeg = this.sNumerDeg;
            bb.sDenomDeg = this.sDenomDeg;
            bb.zNumerDeg = this.zNumerDeg;
            bb.zDenomDeg = this.zDenomDeg;
            bb.deadTime = this.deadTime;
            bb.orderPade = this.orderPade;
            bb.sNumerPade = this.sNumerPade.copy();
            bb.sDenomPade = this.sDenomPade.copy();
            bb.sPolesPade = Complex.copy(this.sPolesPade);
            bb.sZerosPade = Complex.copy(this.sZerosPade);
            bb.sNumerDegPade = this.sNumerDegPade;
            bb.sDenomDegPade = this.sDenomDegPade;
            bb.maptozero = this.maptozero;
            bb.padeAdded = this.padeAdded;
            bb.integrationSum = this.integrationSum;
            bb.integMethod = this.integMethod;
            bb.ztransMethod = this.ztransMethod;
            bb.name = this.name;
            bb.fixedName = this.fixedName;
            bb.nPlotPoints = this.nPlotPoints;

            ret = (Object) bb;
        }
        return ret;
    }

}




TOP

Related Classes of flanagan.control.SecondOrder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.