001    package edu.nrao.sss.electronics;
002    
003    import javax.xml.bind.annotation.XmlElement;
004    
005    import edu.nrao.sss.astronomy.PolarizationType;
006    import edu.nrao.sss.measure.Frequency;
007    import edu.nrao.sss.measure.FrequencyRange;
008    import edu.nrao.sss.util.StringUtil;
009    
010    /**
011     * A {@link Signal frequency signal} that has been digitized.
012     * <p>
013     * <b>Version Info:</b>
014     * <table style="margin-left:2em">
015     *   <tr><td>$Revision: 1707 $</td></tr>
016     *   <tr><td>$Date: 2008-11-14 10:23:59 -0700 (Fri, 14 Nov 2008) $</td></tr>
017     *   <tr><td>$Author: dharland $ (last person to modify)</td></tr>
018     * </table></p>
019     * 
020     * @author David M. Harland
021     * @since 2007-10-24
022     */
023    public class DigitalSignal
024      extends Signal
025    {
026      @XmlElement private Frequency samplingRate;
027      @XmlElement private int       bitDepth;
028      
029      /**
030       * Creates a new digital signal with the given attributes.
031       * 
032       * @param originalRange
033       *   the frequency range of this signal.  If this value is <i>null</i>
034       *   a {@link NullPointerException} will be thrown.
035       *   
036       * @param polarization
037       *   the polarization of this signal.  If this value is <i>null</i>
038       *   it will be converted to {@link PolarizationType#UNSPECIFIED}.
039       * 
040       * @param samplingRate
041       *   the number of samples taken per second.
042       * 
043       * @param bitsPerSample
044       *   the number of bits per sample.  If this value is less than one
045       *   an {@link IllegalArgumentException} will be thrown.
046       */
047      public DigitalSignal(FrequencyRange   originalRange,
048                           PolarizationType polarization,
049                           Frequency        samplingRate,
050                           int              bitsPerSample)
051      {
052        super(originalRange, polarization);
053        init(samplingRate, bitsPerSample);
054      }
055      
056      /**
057       * Creates a new digital signal from another signal.
058       * 
059       * @param analogSignal
060       *   another signal, usually analog, whose properties will
061       *   be copied into this signal.
062       *   
063       * @param samplingRate
064       *   the number of samples taken per second.
065       * 
066       * @param bitsPerSample
067       *   the number of bits per sample.  If this value is less than one
068       *   an {@link IllegalArgumentException} will be thrown.
069       */
070      public DigitalSignal(Signal    analogSignal,
071                           Frequency samplingRate,
072                           int       bitsPerSample)
073      {
074        super(analogSignal);
075        init(samplingRate, bitsPerSample);
076      }
077    
078      //This method is here only for frameworks such
079      //as JAXB and Hibernate that need no-arg constructors.
080      @SuppressWarnings("unused")
081      private DigitalSignal()
082      {
083        super();
084        samplingRate = new Frequency();
085        bitDepth     = 0;
086      }
087          
088      /** Does the work for the constructors. */
089      private void init(Frequency rate, int bits)
090      {
091        if (bits < 1)
092          throw new IllegalArgumentException("bitsPerSample may not be " +
093            bits + ", it must be greater than zero.");
094        
095        samplingRate = rate.clone();
096        bitDepth     = bits;
097      }
098    
099      /**
100       * Returns the rate at which this signal was sampled.
101       * @return the rate at which this signal was sampled.
102       */
103      public Frequency getSamplingRate()
104      {
105        return samplingRate;
106      }
107      
108      /**
109       * Returns the number of bits per sample.
110       * @return the number of bits per sample.
111       */
112      public int getBitDepth()
113      {
114        return bitDepth;
115      }
116    
117      /**
118       * Returns a text representation of this signal.
119       */
120      @Override
121      public String toString()
122      {
123        final String EOL = StringUtil.EOL;
124        
125        StringBuilder buff = new StringBuilder(super.toString());
126        
127        buff.append("Bits per Sample....").append(bitDepth).append(EOL);
128        buff.append("Sampling Rate......").append(samplingRate).append(EOL);
129        
130        return buff.toString();
131      }
132    
133      /**
134       * Creates and returns a copy of this signal.
135       * <p>
136       * If anything goes wrong during the cloning procedure,
137       * a {@link RuntimeException} will be thrown.</p>
138       */
139      @Override
140      public DigitalSignal clone()
141      {
142        DigitalSignal clone = null;
143        
144        try
145        {
146          clone = (DigitalSignal)super.clone();
147          
148          clone.samplingRate = this.samplingRate.clone();
149        }
150        catch (Exception ex)
151        {
152          throw new RuntimeException(ex);
153        }
154        
155        return clone;
156      }
157      
158      /** Returns <i>true</i> if {@code o} is equal to this signal. */
159      @Override
160      public boolean equals(Object o)
161      {
162        //Quick exit if o is this
163        if (o == this)
164          return true;
165        
166        //Quick exit if super class finds difference
167        if (!super.equals(o))
168          return false;
169    
170        //A safe cast if we got this far
171        DigitalSignal other = (DigitalSignal)o;
172        
173        //Intentionally not comparing slope, intercept, and mappingUnits
174        return
175          other.samplingRate.equals(this.samplingRate) &&
176          other.bitDepth == this.bitDepth;
177      }
178    
179      /** Returns a hash code value for this signal. */
180      @Override
181      public int hashCode()
182      {
183        //Taken from the Effective Java book by Joshua Bloch.
184        //The constants 17 & 37 are arbitrary & carry no meaning.
185        int result = super.hashCode();
186        
187        //You MUST keep this method in sync w/ the equals method
188        
189        result = 37 * result + samplingRate.hashCode();
190        result = 37 * result + bitDepth;
191        
192        return result;
193      }
194    }