001/* A simple phase unwrapper.
002
003 Copyright (c) 1990-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.type.BaseType;
032import ptolemy.kernel.CompositeEntity;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.NameDuplicationException;
035
036///////////////////////////////////////////////////////////////////
037//// PhaseUnwrap
038
039/**
040
041 This actor unwraps a phase plot, removing discontinuities of
042 magnitude 2*PI. The input is assumed to be a sequence of phases in
043 radians in the range [-PI, PI].  The input and output types
044 are double.  This actor assumes that the phase never
045 changes by more than PI in one sample period. This is not a very
046 sophisticated phase unwrapper, but for many applications, it does
047 the job.
048
049 @author Joe Buck and Edward A. Lee and Elaine Cheong
050 @version $Id$
051 @since Ptolemy II 1.0
052 @Pt.ProposedRating Yellow (celaine)
053 @Pt.AcceptedRating Yellow (celaine)
054 */
055public class PhaseUnwrap extends Transformer {
056    /** Construct an actor with the given container and name.
057     *  @param container The container.
058     *  @param name The name of this actor.
059     *  @exception IllegalActionException If the actor cannot be contained
060     *   by the proposed container.
061     *  @exception NameDuplicationException If the container already has an
062     *   actor with this name.
063     */
064    public PhaseUnwrap(CompositeEntity container, String name)
065            throws NameDuplicationException, IllegalActionException {
066        super(container, name);
067
068        input.setTypeEquals(BaseType.DOUBLE);
069        output.setTypeEquals(BaseType.DOUBLE);
070    }
071
072    ///////////////////////////////////////////////////////////////////
073    ////                         public methods                    ////
074
075    /** Consume at most one input token and output a value that
076     *  represents the same angle, but differs from the previous output
077     *  (or from 0.0, if this is the first output), by less than 2*PI.
078     *  If there is no input token, then no output is produced.
079     *  @exception IllegalActionException If there is no director.
080     */
081    @Override
082    public void fire() throws IllegalActionException {
083        super.fire();
084        if (input.hasToken(0)) {
085            double newPhase = ((DoubleToken) input.get(0)).doubleValue();
086
087            // compute the phase change and check for wraparound
088            double phaseChange = newPhase - _previousPhaseInput;
089
090            if (phaseChange < -Math.PI) {
091                phaseChange += 2 * Math.PI;
092            }
093
094            if (phaseChange > Math.PI) {
095                phaseChange -= 2 * Math.PI;
096            }
097
098            _tempPreviousPhaseOutput = _previousPhaseOutput + phaseChange;
099            _tempPreviousPhaseInput = newPhase;
100            output.send(0, new DoubleToken(_tempPreviousPhaseOutput));
101        }
102    }
103
104    /** Reset the state of the actor to assume the most recently seen
105     *  phase is zero.
106     *  @exception IllegalActionException If the parent class throws it.
107     */
108    @Override
109    public void initialize() throws IllegalActionException {
110        super.initialize();
111        _previousPhaseInput = 0.0;
112        _previousPhaseOutput = 0.0;
113        _tempPreviousPhaseInput = 0.0;
114        _tempPreviousPhaseOutput = 0.0;
115    }
116
117    /** Record the final value of the most recent value of the input,
118     *  for use in the next phase.
119     *  @exception IllegalActionException If the base class throws it.
120     */
121    @Override
122    public boolean postfire() throws IllegalActionException {
123        _previousPhaseInput = _tempPreviousPhaseInput;
124        _previousPhaseOutput = _tempPreviousPhaseOutput;
125        return super.postfire();
126    }
127
128    ///////////////////////////////////////////////////////////////////
129    ////                         private variables                 ////
130    // The value of the input in the previous phase.  Needed to work
131    // in the CT domain.
132    private double _previousPhaseInput = 0.0;
133
134    // The value of the input in the previous phase.
135    private double _tempPreviousPhaseInput = 0.0;
136
137    // The value of the output in the previous phase.  Needed to work
138    // in the CT domain.
139    private double _previousPhaseOutput = 0.0;
140
141    // The value of the output in the previous phase.
142    private double _tempPreviousPhaseOutput = 0.0;
143}