001/* An actor that converts a DoubleToken to a FixToken.
002
003 Copyright (c) 1998-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.conversions;
029
030import ptolemy.data.DoubleToken;
031import ptolemy.data.FixToken;
032import ptolemy.data.IntMatrixToken;
033import ptolemy.data.expr.Parameter;
034import ptolemy.data.type.BaseType;
035import ptolemy.data.type.FixType;
036import ptolemy.kernel.CompositeEntity;
037import ptolemy.kernel.util.Attribute;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.NameDuplicationException;
040import ptolemy.kernel.util.StringAttribute;
041import ptolemy.kernel.util.Workspace;
042import ptolemy.math.FixPoint;
043import ptolemy.math.FixPointQuantization;
044import ptolemy.math.Overflow;
045import ptolemy.math.Precision;
046import ptolemy.math.Rounding;
047
048///////////////////////////////////////////////////////////////////
049//// DoubleToFix
050
051/**
052 This actor converts a DoubleToken to a FixToken with a specified
053 precision. Note that this conversion is lossy, in that the output
054 is an approximation of the input. The approximation can be
055 constructed using a variety of rounding and overflow strategies.
056 <p>
057 The precision of the output is given by the <i>precision</i> parameter,
058 which is an integer matrix of the form [<i>m</i>, <i>n</i>], where
059 the total number of bits in the output is <i>m</i>, of which
060 <i>n</i> are integer bits. The default precision is [16, 2], which means
061 that an output has 16 bits, of which 2 bits represent the
062 integer part.
063 <p>
064 The rounding strategy is defined by the <i>rounding</i> parameter and
065 defaults to <i>nearest</i> (or <i>half_floor</i>), selecting the nearest
066 representable value. The floor value nearer to minus infinity is used
067 for values half way between representable values. Other strategies
068 such as <i>truncate</i> are described under ptolemy.math.Rounding.
069 <p>
070 The overflow strategy is defined by the <i>overflow</i> parameter and
071 defaults to <i>saturate</i> (or <i>clip</i>). Out of range values are
072 saturated to the nearest representable value. Other strategies
073 such as <i>modulo</i> are described under ptolemy.math.Overflow.
074
075 @author Bart Kienhuis, Contributor: Edward A. Lee, Ed.Willink,
076 @version $Id$
077 @since Ptolemy II 0.4
078 @Pt.ProposedRating Green (pwhitake)
079 @Pt.AcceptedRating Green (pwhitake)
080 @see ptolemy.data.FixToken
081 @see ptolemy.math.Overflow
082 @see ptolemy.math.Precision
083 @see ptolemy.math.Rounding
084 */
085public class DoubleToFix extends Converter {
086    /** Construct an actor with the given container and name.
087     *  @param container The container.
088     *  @param name The name of this actor.
089     *  @exception IllegalActionException If the actor cannot be contained
090     *   by the proposed container.
091     *  @exception NameDuplicationException If the container already has an
092     *   actor with this name.
093     */
094    public DoubleToFix(CompositeEntity container, String name)
095            throws NameDuplicationException, IllegalActionException {
096        super(container, name);
097        input.setTypeEquals(BaseType.DOUBLE);
098        output.setTypeEquals(BaseType.UNSIZED_FIX);
099
100        precision = new Parameter(this, "precision");
101        precision.setTypeEquals(BaseType.INT_MATRIX);
102        precision.setExpression("[16, 2]");
103
104        rounding = new StringAttribute(this, "rounding");
105        rounding.setExpression("nearest");
106
107        overflow = new StringAttribute(this, "overflow");
108        overflow.setExpression("saturate");
109    }
110
111    ///////////////////////////////////////////////////////////////////
112    ////                     ports and parameters                  ////
113
114    /** The precision of the output fixed-point number, which is represented
115     by a 2-element integer matrix. */
116    public Parameter precision;
117
118    /** The overflow strategy used, such as "saturate" or "modulo". */
119    public StringAttribute overflow;
120
121    /** The rounding strategy used, such as "nearest" or "truncate". */
122    public StringAttribute rounding;
123
124    ///////////////////////////////////////////////////////////////////
125    ////                         public methods                    ////
126
127    /** Override the base class to set locally cached variables.
128     *  @param attribute The attribute that changed.
129     *  @exception IllegalActionException If the parameter value is invalid.
130     */
131    @Override
132    public void attributeChanged(Attribute attribute)
133            throws IllegalActionException {
134        if (attribute == precision) {
135            IntMatrixToken token = (IntMatrixToken) precision.getToken();
136
137            if (token.getRowCount() != 1 || token.getColumnCount() != 2) {
138                throw new IllegalActionException(this,
139                        "Invalid precision (not a 1 by 2 matrix).");
140            }
141
142            Precision precision = new Precision(token.getElementAt(0, 0),
143                    token.getElementAt(0, 1));
144            output.setTypeEquals(new FixType(precision));
145            _quantization = _quantization.setPrecision(precision);
146        } else if (attribute == rounding) {
147            Rounding r = Rounding.getName(rounding.getExpression());
148            _quantization = _quantization.setRounding(r);
149        } else if (attribute == overflow) {
150            Overflow o = Overflow.forName(overflow.getExpression());
151            _quantization = _quantization.setOverflow(o);
152        } else {
153            super.attributeChanged(attribute);
154        }
155    }
156
157    /** Clone the actor into the specified workspace.
158     *  @param workspace The workspace for the new object.
159     *  @return A new actor.
160     *  @exception CloneNotSupportedException If a derived class contains
161     *   an attribute that cannot be cloned.
162     */
163    @Override
164    public Object clone(Workspace workspace) throws CloneNotSupportedException {
165        DoubleToFix newObject = (DoubleToFix) super.clone(workspace);
166
167        newObject._quantization = new FixPointQuantization(
168                newObject._quantization.getPrecision(),
169                newObject._quantization.getOverflow(),
170                newObject._quantization.getRounding());
171
172        return newObject;
173    }
174
175    /** Read at most one token from the input and output the converted
176     *  fixed-point value with the precision given by the
177     *  <i>precision</i> parameter, overflow strategy given by the
178     *  <i>overflow</i> parameter, and rounding strategy given by the
179     *  <i>rounding</i> parameter.
180     *  @exception IllegalActionException If there is no director.
181     */
182    @Override
183    public void fire() throws IllegalActionException {
184        super.fire();
185        DoubleToken in = (DoubleToken) input.get(0);
186        FixPoint fixValue = new FixPoint(in.doubleValue(), _quantization);
187        FixToken result = new FixToken(fixValue);
188        output.send(0, result);
189    }
190
191    /** Return false if the input port has no token, otherwise return
192     *  what the superclass returns (presumably true).
193     *  @exception IllegalActionException If there is no director.
194     */
195    @Override
196    public boolean prefire() throws IllegalActionException {
197        if (!input.hasToken(0)) {
198            return false;
199        }
200
201        return super.prefire();
202    }
203
204    ///////////////////////////////////////////////////////////////////
205    ////                         private variables                 ////
206    // The quantization of the output.
207    private FixPointQuantization _quantization = new FixPointQuantization(null,
208            Overflow.SATURATE, Rounding.NEAREST);
209}