001/* An actor to compute the average of the input values received so far over 002model time. 003 004 Copyright (c) 2008-2014 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.domains.de.lib; 030 031import ptolemy.actor.util.Time; 032import ptolemy.data.DoubleToken; 033import ptolemy.data.Token; 034import ptolemy.data.type.BaseType; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.IllegalActionException; 037import ptolemy.kernel.util.NameDuplicationException; 038import ptolemy.kernel.util.Workspace; 039 040/** 041 An actor to compute the average of the input values received so far over model 042 time. This actor can fire whenever there is a token at its input port, or the 043 model time has advanced since last firing. It records the last token that it 044 received. In each firing, the produce of the last token and the amount of model 045 time increment is added to a sum variable. The average value received so far is 046 obtained by dividing the sum by the current model time. This average is sent to 047 the output port in each firing. If a token is available at the input port, this 048 actor reads that token and overwrites the last token with it. 049 050 @author tfeng 051 @version $Id$ 052 @since Ptolemy II 8.0 053 @Pt.ProposedRating Yellow (tfeng) 054 @Pt.AcceptedRating Red (tfeng) 055 */ 056public class AverageOverTime extends DETransformer { 057 058 /** Construct an actor with the given container and name. 059 * @param container The container. 060 * @param name The name of this actor. 061 * @exception IllegalActionException If the actor cannot be contained 062 * by the proposed container. 063 * @exception NameDuplicationException If the container already has an 064 * actor with this name. 065 */ 066 public AverageOverTime(CompositeEntity container, String name) 067 throws NameDuplicationException, IllegalActionException { 068 super(container, name); 069 070 input.setTypeAtMost(BaseType.SCALAR); 071 output.setTypeEquals(BaseType.SCALAR.divide(BaseType.DOUBLE)); 072 } 073 074 /** Clone this actor into the specified workspace. The new actor is 075 * <i>not</i> added to the directory of that workspace (you must do this 076 * yourself if you want it there). 077 * The result is a new actor with the same ports as the original, but 078 * no connections and no container. A container must be set before 079 * much can be done with this actor. 080 * 081 * @param workspace The workspace for the cloned object. 082 * @exception CloneNotSupportedException If cloned ports cannot have 083 * as their container the cloned entity (this should not occur), or 084 * if one of the attributes cannot be cloned. 085 * @return A new AverageOverTime actor. 086 */ 087 @Override 088 public Object clone(Workspace workspace) throws CloneNotSupportedException { 089 AverageOverTime newObject = (AverageOverTime) super.clone(workspace); 090 newObject._sum = null; 091 newObject._lastToken = null; 092 newObject._lastTime = null; 093 094 newObject.input.setTypeAtMost(BaseType.SCALAR); 095 newObject.output.setTypeEquals(BaseType.SCALAR.divide(BaseType.DOUBLE)); 096 097 return newObject; 098 } 099 100 /** Fire this actor. If there is a least one token at the input port, 101 * consume the first token. Output the current average value via the output 102 * port. 103 * @exception IllegalActionException If thrown when trying to read the 104 * input token or to write the output token. 105 */ 106 @Override 107 public void fire() throws IllegalActionException { 108 super.fire(); 109 110 Time modelTime = getDirector().getModelTime(); 111 DoubleToken currentTime = new DoubleToken(modelTime.getDoubleValue()); 112 if (_lastToken != null) { 113 DoubleToken lastTime = new DoubleToken(_lastTime.getDoubleValue()); 114 Token increase = _lastToken 115 .multiply(currentTime.subtract(lastTime)); 116 if (_sum == null) { 117 _sum = increase; 118 } else { 119 _sum = _sum.add(increase); 120 } 121 } 122 _lastTime = modelTime; 123 if (input.hasToken(0)) { 124 _lastToken = input.get(0); 125 } 126 if (_sum != null) { 127 output.broadcast(_sum.divide(currentTime)); 128 } 129 } 130 131 /** Initialize this actor. 132 * 133 * @exception IllegalActionException If the superclass throws it. 134 */ 135 @Override 136 public void initialize() throws IllegalActionException { 137 super.initialize(); 138 139 _sum = null; 140 _lastToken = null; 141 _lastTime = getDirector().getModelTime(); 142 } 143 144 @Override 145 public boolean postfire() throws IllegalActionException { 146 boolean result = super.postfire(); 147 _lastTime = getDirector().getModelTime(); 148 return result; 149 } 150 151 /** Determine whether this actor can fire in the current iteration. Return 152 * true if there is at least one token at the input port, or the model time 153 * has advanced since last firing. 154 * 155 * @exception IllegalActionException If the superclass throws it. 156 */ 157 @Override 158 public boolean prefire() throws IllegalActionException { 159 boolean result = super.prefire(); 160 if (!result) { 161 result = input.hasToken(0) 162 || !_lastTime.equals(getDirector().getModelTime()); 163 } 164 return result; 165 } 166 167 // The last time at which this actor was fired. 168 private Time _lastTime; 169 170 // The last received input token. 171 private Token _lastToken; 172 173 // The sum accumulated so far. 174 private Token _sum; 175}