001/* Moving average. 002 003 Copyright (c) 2007-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.actor.lib; 029 030import ptolemy.data.DoubleToken; 031import ptolemy.data.IntToken; 032import ptolemy.data.Token; 033import ptolemy.data.expr.Parameter; 034import ptolemy.data.type.BaseType; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NameDuplicationException; 039 040/////////////////////////////////////////////////////////////////// 041//// MovingAverage 042 043/** 044 This actor outputs the moving average of the input sequence. 045 The maximum number of prior inputs to be averaged is given by 046 the <i>maxPastInputsToAverage</i> parameter. The output is 047 the average of the all the previous inputs that have been 048 received if fewer than <i>maxPastInputsToAverage</i> have 049 been received, and the average of the previous 050 <i>maxPastInputsToAverage</i> inputs otherwise. 051 The input can be any data type that supports division 052 by a double. 053 054 @author Edward A. Lee 055 @version $Id$ 056 @since Ptolemy II 6.1 057 @Pt.ProposedRating Yellow (eal) 058 @Pt.AcceptedRating Red (eal) 059 @see ptolemy.data.Token 060 */ 061public class MovingAverage extends Transformer { 062 /** Construct an actor with the given container and name. 063 * @param container The container. 064 * @param name The name of this actor. 065 * @exception IllegalActionException If the actor cannot be contained 066 * by the proposed container. 067 * @exception NameDuplicationException If the container already has an 068 * actor with this name. 069 */ 070 public MovingAverage(CompositeEntity container, String name) 071 throws NameDuplicationException, IllegalActionException { 072 super(container, name); 073 074 maxPastInputsToAverage = new Parameter(this, "maxPastInputsToAverage"); 075 maxPastInputsToAverage.setTypeEquals(BaseType.INT); 076 maxPastInputsToAverage.setExpression("10"); 077 } 078 079 /////////////////////////////////////////////////////////////////// 080 //// public variables //// 081 082 /** The maximum number of past inputs to average. This is an integer 083 * that defaults to 10. 084 */ 085 public Parameter maxPastInputsToAverage; 086 087 /////////////////////////////////////////////////////////////////// 088 //// public methods //// 089 090 /** Set a flag that causes recalculation of various local variables 091 * that are used in execution on the next invocation of fire(). 092 * @param attribute The attribute that changed. 093 * @exception IllegalActionException If the attribute contains 094 * an invalid value or if the super method throws it. 095 */ 096 @Override 097 public void attributeChanged(Attribute attribute) 098 throws IllegalActionException { 099 if (attribute == maxPastInputsToAverage) { 100 _maxPastInputsToAverage = ((IntToken) maxPastInputsToAverage 101 .getToken()).intValue(); 102 if (_maxPastInputsToAverage <= 0) { 103 throw new IllegalActionException(this, 104 "Value of maxPastInputsToAverage is required to be positive."); 105 } 106 _reinitializeNeeded = true; 107 } else { 108 super.attributeChanged(attribute); 109 } 110 } 111 112 // FIXME: State update should occur in postfire. 113 114 /** Consume the inputs and produce the output. 115 * @exception IllegalActionException If parameter values are invalid, 116 * or if there is no director, or if runtime type conflicts occur. 117 */ 118 @Override 119 public void fire() throws IllegalActionException { 120 super.fire(); 121 122 // Transfer current input to _data[] 123 if (_mostRecent <= 0) { 124 _mostRecent = _maxPastInputsToAverage - 1; 125 } else { 126 --_mostRecent; 127 } 128 _data[_mostRecent] = input.get(0); 129 130 if (_count < _maxPastInputsToAverage) { 131 _count++; 132 _factor = new DoubleToken(1.0 / _count); 133 } 134 135 // Compute the average. 136 Token sum = _data[_mostRecent]; 137 for (int i = 1; i < _count; i++) { 138 int dataIndex = (_mostRecent + i) % _data.length; 139 sum = sum.add(_data[dataIndex]); 140 } 141 output.send(0, _factor.multiply(sum)); 142 } 143 144 /** Return false if the input does not have a token. 145 * Otherwise, return what the superclass returns. 146 * @return False if the number of input tokens available is not at least 147 * equal to the decimation parameter. 148 * @exception IllegalActionException If the superclass throws it. 149 */ 150 @Override 151 public boolean prefire() throws IllegalActionException { 152 // If an attribute has changed since the last fire(), or if 153 // this is the first fire(), then reinitialize. 154 if (_reinitializeNeeded) { 155 _reinitialize(); 156 } 157 158 if (input.hasToken(0)) { 159 return super.prefire(); 160 } else { 161 if (_debugging) { 162 _debug("Called prefire(), which returns false."); 163 } 164 return false; 165 } 166 } 167 168 /** Perform domain-specific initialization by calling the 169 * initialize(Actor) method of the director. The director may 170 * reject the actor by throwing an exception if the actor is 171 * incompatible with the domain. 172 * Set a flag that reinitializes the data buffer at the first firing. 173 * @exception IllegalActionException If the superclass throws it. 174 */ 175 @Override 176 public void initialize() throws IllegalActionException { 177 super.initialize(); 178 179 // Must be sure to throw away the old data buffer. 180 _data = null; 181 _reinitializeNeeded = true; 182 } 183 184 /////////////////////////////////////////////////////////////////// 185 //// protected methods //// 186 187 /** Reinitialize local variables in response to changes in attributes. 188 * @exception IllegalActionException If there is a problem reinitializing. 189 */ 190 protected void _reinitialize() throws IllegalActionException { 191 // Create new data array and initialize index into it. 192 int length = _maxPastInputsToAverage; 193 _data = new Token[length]; 194 _count = 0; 195 _mostRecent = _maxPastInputsToAverage; 196 _reinitializeNeeded = false; 197 } 198 199 /////////////////////////////////////////////////////////////////// 200 //// protected variables //// 201 202 /** The delay line. */ 203 protected Token[] _data; 204 205 /** The index into the delay line of the most recent input. */ 206 protected int _mostRecent; 207 208 /** Count of the number of inputs received, bounded by the 209 * size of the _data array. 210 */ 211 protected int _count; 212 213 /** Maximum number of past inputs to average. */ 214 protected int _maxPastInputsToAverage = 10; 215 216 /** Indicator that at least an attribute has been changed 217 * since the last initialization. 218 */ 219 protected boolean _reinitializeNeeded = true; 220 221 /////////////////////////////////////////////////////////////////// 222 //// private variables //// 223 224 /** The factor by which to multiply the sum of the past inputs. */ 225 private DoubleToken _factor; 226}