001    package edu.nrao.sss.electronics;
002    
003    import java.math.BigDecimal;
004    
005    import edu.nrao.sss.measure.Frequency;
006    import edu.nrao.sss.measure.FrequencyRange;
007    
008    /**
009     * A device that multiplies the current frequencies of a signal.
010     * <p>
011     * <b>Version Info:</b>
012     * <table style="margin-left:2em">
013     *   <tr><td>$Revision: 1241 $</td></tr>
014     *   <tr><td>$Date: 2008-04-25 14:37:37 -0600 (Fri, 25 Apr 2008) $</td></tr>
015     *   <tr><td>$Author: dharland $ (last person to modify)</td></tr>
016     * </table></p>
017     * 
018     * @author David M. Harland
019     * @since 2007-10-24
020     */
021    public class SignalMultiplier
022      implements SignalProcessor, SignalSource
023    {
024      private String name;
025    
026      private BigDecimal multiplier;
027      
028      private Signal inputSignal;
029      private Signal outputSignal;
030      
031      private SignalPipe inputPipe;
032      private SignalPipe outputPipe;
033      
034      //============================================================================
035      // OBJECT CREATION
036      //============================================================================
037    
038      /**
039       * Creates a new multiplier that uses the given {@code multiplicationFactor}.
040       * 
041       * @param deviceName
042       *   an optional name for this multiplier.  If this value is <i>null</i>
043       *   a default name will be used in its place.
044       *   
045       * @param multiplicationFactor
046       *   the amount by which this device will multiply its input signals.
047       */
048      public SignalMultiplier(String deviceName, BigDecimal multiplicationFactor)
049      {
050        //TODO check value of multiplicationFactor?
051        
052        name         = (deviceName == null) ? "x"+multiplicationFactor : deviceName;
053        multiplier   = multiplicationFactor;
054        inputSignal  = null;
055        outputSignal = null;
056        inputPipe    = SignalPipe.makeAndWeldOutputTo(this);
057        outputPipe   = SignalPipe.makeAndWeldInputTo(this);
058      }
059    
060      /**
061       * Creates a new multiplier that uses the given {@code multiplicationFactor}.
062       * 
063       * @param deviceName
064       *   an optional name for this multiplier.  If this value is <i>null</i>
065       *   a default name will be used in its place.
066       *   
067       * @param multiplicationFactor
068       *   the amount by which this device will multiply its input signals.
069       */
070      public SignalMultiplier(String deviceName, String multiplicationFactor)
071      {
072        this(deviceName, new BigDecimal(multiplicationFactor));
073      }
074      
075      //============================================================================
076      // 
077      //============================================================================
078    
079      /**
080       * Returns the amount by which this device multiplies its input signals.
081       * @return the amount by which this device multiplies its input signals.
082       */
083      public BigDecimal getMultiplicationFactor()
084      {
085        return multiplier;
086      }
087      
088      /**
089       * Returns the input pipe of this device.
090       * A typical usage pattern for this method is:<pre>
091       * myMultiplier.getInputPipe().connectInputTo(mySource);</pre>
092       * 
093       * @return the input pipe of this device.
094       */
095      public SignalPipe getInputPipe()
096      {
097        return inputPipe;
098      }
099      
100      /**
101       * Returns the output pipe of this device.
102       * A typical usage pattern for this method is:<pre>
103       * myMultiplier.getOutputPipe().connectOutputTo(myProcessor);</pre>
104       * 
105       * @return the output pipe of this device.
106       */
107      public SignalPipe getOutputPipe()
108      {
109        return outputPipe;
110      }
111      
112      /**
113       * Returns a copy of the input signal most recently {@link #execute()
114       * processed} by this device.
115       * If this processor has never been executed, or if the input signal
116       * it processed most recently was <i>null</i>, the returned value will
117       * be <i>null</i>.
118       * 
119       * @return the input signal most recently sent into this multiplier.
120       */
121      public Signal getMostRecentInput()
122      {
123        return inputSignal == null ? null : inputSignal.clone();
124      }
125      
126      /**
127       * Returns a copy of the output signal most recently {@link #execute()
128       * produced} by this device.
129       * If this processor has never been executed, or if the input signal
130       * it processed most recently was <i>null</i>, the returned value will
131       * be <i>null</i>.
132       * 
133       * @return the output signal most recently produced by this multiplier.
134       */
135      public Signal getMostRecentOutput()
136      {
137        return outputSignal == null ? null : outputSignal.clone();
138      }
139    
140      /**
141       * Erases this device's memory of its most recent execution.
142       * @see #getMostRecentInput()
143       * @see #getMostRecentOutput()
144       * @see #getSignal()
145       */
146      public void eraseSignalMemory()
147      {
148        inputSignal  = null;
149        outputSignal = null;
150      }
151    
152      //============================================================================
153      // INTERFACE SignalSource
154      //============================================================================
155      
156      /**
157       * Returns a copy of the signal produced by the most recent {@link #execute()
158       * execution} of this device.
159       * If this device has never been run, or if the input signal
160       * it processed most recently was <i>null</i>, the returned value will
161       * be <i>null</i>.
162       */
163      public Signal getSignal()
164      {
165        return outputSignal == null ? null : outputSignal.clone();
166      }
167    
168      //============================================================================
169      // INTERFACE FrequencyProcessor AND SUPPORT THEREOF
170      //============================================================================
171      
172      /**
173       * Runs this device on the signal received from its input pipe and
174       * then executes the processor connected to its output pipe, if any.
175       * Both the input signal and the output produced by multiplying it are
176       * remembered by this multiplier and are available via the
177       * {@link #getMostRecentInput()} and {@link #getMostRecentOutput()} methods.
178       */
179      public void execute()
180      {
181        updateOutputSignal();
182        
183        outputPipe.execute();
184      }
185      
186      public void executeUpTo(SignalProcessor firstUnexecutedDevice)
187      {
188        //Quick exit if execution should not occur
189        if (firstUnexecutedDevice == this)
190          return;
191    
192        updateOutputSignal();
193    
194        //Tell text element of chain to do its work
195        outputPipe.executeUpTo(firstUnexecutedDevice);
196      }
197    
198      private void updateOutputSignal()
199      {
200        //Do the work and remember results
201        inputSignal = inputPipe.getSignal();
202        
203        if (inputSignal != null)
204        {
205          outputSignal = multiply(inputSignal);
206          
207          if (!outputSignal.getDevicePath().endsWith(name))
208            outputSignal.appendToDevicePath(name);
209        }
210        else
211        {
212          outputSignal = null;
213        }
214      }
215      
216      public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice)
217      {
218        inputPipe.executeFromStartOfChainUpTo(firstUnexecutedDevice);
219      }
220    
221      /**
222       * Multiplies {@code input} by this multiplier's factor and returns
223       * the multiplied signal.
224       * <p>
225       * Note that the {@code input} signal and this multiplier are
226       * not affected by calls to this method.  In other words this multiplier
227       * will not remember the input signal sent in or the output
228       * signal produced.  This is in contrast to a call to the
229       * {@link #execute()} methods.</p>
230       * 
231       * @param input
232       *   the signal to be multiplied.
233       *   
234       * @return a new signal that is the result of multiplying {@code input}
235       *         by this multiplier's factor.
236       */
237      public Signal multiply(Signal input)
238      {
239        //Quick exit for null input
240        if (input == null)
241          return null;
242        
243        FrequencyRange currRange = input.getCurrentRange();
244        
245        //Only the current frequency range is modified
246        FrequencyRange newRange = new FrequencyRange
247        (
248          currRange.getLowFrequency().multiplyBy(multiplier),
249          currRange.getHighFrequency().multiplyBy(multiplier)
250        );
251        
252        return input.clone().transform(newRange, input.getProxiedRange(), false);
253      }
254    
255      /**
256       * Multiplies {@code input} by this multiplier's factor and returns
257       * the multiplied frequency.
258       * <p>
259       * Note that the {@code input} frequency and this multiplier are
260       * not affected by calls to this method.  In other words this multiplier
261       * will not remember the input signal sent in or the output
262       * signal produced.  This is in contrast to a call to the
263       * {@link #execute()} methods.</p>
264       * 
265       * @param input
266       *   the frequency to be multiplied.
267       *   
268       * @return a new frequency that is the result of multiplying {@code input}
269       *         by this multiplier's factor.
270       */
271      public Frequency multiply(Frequency input)
272      {
273        Frequency output = input.clone();
274        
275        output.multiplyBy(multiplier);
276        
277        return output;
278      }
279    }