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}