001    package edu.nrao.sss.model.resource.evla;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.List;
006    import java.util.SortedMap;
007    
008    import edu.nrao.sss.electronics.Signal;
009    import edu.nrao.sss.electronics.SignalCombiner;
010    import edu.nrao.sss.electronics.SignalFilter;
011    import edu.nrao.sss.electronics.SignalManifold;
012    import edu.nrao.sss.electronics.SignalMixer;
013    import edu.nrao.sss.electronics.SignalPipe;
014    import edu.nrao.sss.electronics.SignalProcessor;
015    import edu.nrao.sss.electronics.SignalSource;
016    import edu.nrao.sss.electronics.SignalSwitch;
017    import edu.nrao.sss.measure.Frequency;
018    
019    /**
020     * The EVLA T301 4P Upconverter.
021     * <p>
022     * This device has two halves that are identical.  Each half has two inputs
023     * that are combined into one signal, mixed, filtered, and sent to an
024     * output fork.  The output fork has one of its outputs connected to the
025     * output switch in its own half and one connected to the output switch
026     * in the other half.  In their nominal positions, the top output switch
027     * is set so that it carries signals from the top half inputs, and likewise
028     * for the bottom half.  The switches may be set, though, so that only
029     * the top or bottom inputs flow through the pair of outputs.</p>
030     * <p>
031     * As used by the {@link EvlaAntennaElectronics EVLA electronics}, the
032     * top inputs carry the left circular polarized signals from the 
033     * P-band and 4-band receivers, respectively, and the bottom inputs
034     * carry the right circular polarized signals in that same order.
035     * The top output carries the combined 4/P LCP signal, and the bottom
036     * carries the 4/P RCP.</p>
037     * <img src="doc-files/T301.png" alt="T301 Dgm"/>
038     * <p>
039     * <b>Version Info:</b>
040     * <table style="margin-left:2em">
041     *   <tr><td>$Revision: 1241 $</td></tr>
042     *   <tr><td>$Date: 2008-04-25 14:37:37 -0600 (Fri, 25 Apr 2008) $</td></tr>
043     *   <tr><td>$Author: dharland $ (last person to modify)</td></tr>
044     * </table></p>
045     * 
046     * @author David M. Harland
047     * @since 2007-10-30
048     */
049    public class T301
050      implements SignalProcessor  //TODO stop implementing?
051    {
052      private static final Frequency INTERNAL_LO_FREQ = new Frequency("1.024");
053    
054      //Internal components
055      private OneHalfT301    topHalf;    //LCP
056      private OneHalfT301    bottomHalf; //RCP
057      private SignalManifold loFork;
058      private SignalSwitch   topOutputSwitch;
059      private SignalSwitch   bottomOutputSwitch;
060    
061      //============================================================================
062      // OBJECT CONSTRUCTION
063      //============================================================================
064    
065      /**
066       * Creates a new T301 4P Upconverter.
067       * The internal output switches are initially set so that the top output
068       * is derived from the two top inputs, and the bottom output is derived
069       * from the two bottom outputs.
070       */
071      public T301()
072      {
073        constructInternalComponents();
074        connectInternalComponents();
075        
076        //Set frequency sources for the mixers
077        loFork.getInputPipe().connectInputTo
078        (
079          new SignalSource()
080          {
081            public Signal getSignal()
082            {
083              return new Signal(INTERNAL_LO_FREQ);
084            }
085          }
086        );
087      }
088      
089      /**
090       * Builds, but does not connect, the internal components of this device.
091       */
092      private void constructInternalComponents()
093      {
094        topHalf    = new OneHalfT301();
095        bottomHalf = new OneHalfT301();
096        
097        loFork = new SignalManifold(2);
098        
099        topOutputSwitch =
100          SignalSwitch.makeMultiInputSwitch("4P.TOP.output-switch", 2);
101       
102        bottomOutputSwitch =
103          SignalSwitch.makeMultiInputSwitch("4P.BOTTOM.output-switch", 2);
104        
105        topOutputSwitch.nameInputs("LCP", "RCP");
106        bottomOutputSwitch.nameInputs("LCP", "RCP");
107      }
108    
109      /**
110       * Connects the prebuilt internal components of this device to one another.
111       */
112      private void connectInternalComponents()
113      {
114        loFork.getOutputPipe(0).connectOutputTo(   topHalf.mixer.getLocalOscillatorInputPipe());
115        loFork.getOutputPipe(1).connectOutputTo(bottomHalf.mixer.getLocalOscillatorInputPipe());
116        
117        topOutputSwitch.getInputPipe(0).connectInputTo(   topHalf.outputFork.getOutputPipe(1));
118        topOutputSwitch.getInputPipe(1).connectInputTo(bottomHalf.outputFork.getOutputPipe(1));
119        
120        bottomOutputSwitch.getInputPipe(0).connectInputTo(   topHalf.outputFork.getOutputPipe(0));
121        bottomOutputSwitch.getInputPipe(1).connectInputTo(bottomHalf.outputFork.getOutputPipe(0));
122        
123        topOutputSwitch.selectInput("LCP");
124        bottomOutputSwitch.selectInput("RCP");
125      }
126    
127      //============================================================================
128      // 
129      //============================================================================
130    
131      /**
132       * Returns the two top inputs for this converter.
133       * The top inputs are combined with each other, fed to a mixer, filtered,
134       * and then <i>normally</i> sent out through the top output pipe
135       * (though there are switches that can make it come out through the
136       * bottom pipe, or through no pipe at all).
137       * <p>
138       * In the EVLA antenna electronics, the top inputs will be used
139       * for left circular polarized signals.</p>
140       * 
141       * @return
142       *   the top two inputs for this converter.
143       */
144      public List<SignalPipe> getTopInputPipes()
145      {
146        List<SignalPipe> inputs = new ArrayList<SignalPipe>();
147        
148        inputs.add(topHalf.inputCombiner.getInputPipe(0));
149        inputs.add(topHalf.inputCombiner.getInputPipe(1));
150        
151        return inputs;
152      }
153    
154      /**
155       * Returns the two bottom inputs for this converter.
156       * The bottom inputs are combined with each other, fed to a mixer, filtered,
157       * and then <i>normally</i> sent out through the bottom output pipe
158       * (though there are switches that can make it come out through the
159       * top pipe, or through no pipe at all).
160       * <p>
161       * In the EVLA antenna electronics, the bottom inputs will be used
162       * for right circular polarized signals.</p>
163       * 
164       * @return
165       *   the bottom two inputs for this converter.
166       */
167      public List<SignalPipe> getBottomInputPipes()
168      {
169        List<SignalPipe> inputs = new ArrayList<SignalPipe>();
170        
171        inputs.add(bottomHalf.inputCombiner.getInputPipe(0));
172        inputs.add(bottomHalf.inputCombiner.getInputPipe(1));
173        
174        return inputs;
175      }
176      
177      /**
178       * Returns the top output for this converter.
179       * The top output <i>normally</i> comes from the top two inputs, but
180       * a switch makes it possible for this output to get its input from
181       * the bottom two inputs.
182       * 
183       * @return
184       *   the top output for this converter.
185       */
186      public SignalPipe getTopOutputPipe()
187      {
188        return topOutputSwitch.getOutputPipe(0);
189      }
190      
191      /**
192       * Returns the bottom output for this converter.
193       * The bottom output <i>normally</i> comes from the bottom two inputs, but
194       * a switch makes it possible for this output to get its input from
195       * the top two inputs.
196       * 
197       * @return
198       *   the bottom output for this converter.
199       */
200      public SignalPipe getBottomOutputPipe()
201      {
202        return bottomOutputSwitch.getOutputPipe(0);
203      }
204      
205      /**
206       * Sets the output switches so that the top output is derived from the
207       * top inputs, and likewise for the bottom.
208       * A newly created T301 is already in this state.
209       */
210      public void setOutputSwitchesToStandardPositions()
211      {
212        topOutputSwitch.selectInput("LCP");
213        bottomOutputSwitch.selectInput("RCP");
214      }
215      
216      /**
217       * Sets the output switches so that the both the top and bottom outputs
218       * are derived from the top inputs.
219       */
220      public void setOutputSwitchesForTopInputs()
221      {
222        topOutputSwitch.selectInput(0);
223        bottomOutputSwitch.selectInput(0);
224      }
225      
226      /**
227       * Sets the output switches so that the both the top and bottom outputs
228       * are derived from the bottom inputs.
229       */
230      public void setOutputSwitchesForBottomInputs()
231      {
232        topOutputSwitch.selectInput(1);
233        bottomOutputSwitch.selectInput(1);
234      }
235    
236      void nameOutputPolesOfOutputSwitches(String topSw, String bottomSw)
237      {
238        topOutputSwitch.nameOutputs(topSw);
239        bottomOutputSwitch.nameOutputs(bottomSw);
240      }
241    
242      void addSwitchesTo(SortedMap<String, SignalSwitch> map)
243      {
244        map.put(   topOutputSwitch.getName(),    topOutputSwitch);
245        map.put(bottomOutputSwitch.getName(), bottomOutputSwitch);
246      }
247    
248      /**
249       * Returns the signals produced by this converter.
250       * The returned collection will hold two signals.
251       * 
252       * @return the signals produced by this converter.
253       */
254      public Collection<Signal> getSignals()
255      {
256        Collection<Signal> signals = new ArrayList<Signal>();
257        
258        signals.add(topOutputSwitch.getSignal());
259        signals.add(bottomOutputSwitch.getSignal());
260        
261        return signals;
262      }
263    
264      //============================================================================
265      // INTERFACE SignalProcessor AND RELATED METHODS
266      //============================================================================
267      
268      /**
269       * See {@link SignalProcessor#execute()}.
270       */
271      public void execute()
272      {
273        topHalf.execute();
274        bottomHalf.execute();
275      }
276      
277      /**
278       * See {@link SignalProcessor#executeUpTo(SignalProcessor)}.
279       */
280      public void executeUpTo(SignalProcessor firstUnexecutedDevice)
281      {
282        if (firstUnexecutedDevice != this)
283        {
284          topHalf.executeUpTo(firstUnexecutedDevice);
285          bottomHalf.executeUpTo(firstUnexecutedDevice);
286        }
287      }
288    
289      /**
290       * See {@link SignalProcessor#executeFromStartOfChainUpTo(SignalProcessor)}.
291       */
292      public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice)
293      {
294        topHalf.executeFromStartOfChainUpTo(this);
295        bottomHalf.executeFromStartOfChainUpTo(this);
296        
297        executeUpTo(firstUnexecutedDevice);
298      }
299    
300      //============================================================================
301      // HELPER CLASSES
302      //============================================================================
303    
304      /**
305       * Represents roughly one half of the T301 4P Upconverter.
306       * Each half creates an output signal that is placed on a two-output fork.
307       * Note that the output switches and the fork that feeds the LO signal
308       * to the mixers are not considered to be
309       * part of this half, but are instead in addition to the
310       * two halves and are handled by class T301 directly.
311       */
312      private class OneHalfT301 implements SignalProcessor  //TODO stop implementing?
313      {
314        //TODO stop using the combiner.  Will need to coordinate this with the
315        //     creation of a front end that combines the 4 & P signals.
316        
317                SignalCombiner inputCombiner;
318                SignalMixer    mixer;
319        private SignalFilter   filter1;
320        private SignalFilter   filter2;
321                SignalManifold outputFork;
322    
323        /** Creates half of a T301. */
324        OneHalfT301()
325        {
326          constructInternalComponents();
327          connectInternalComponents();
328        }
329        
330        /**
331         * Builds, but does not connect, the internal components of this device.
332         */
333        private void constructInternalComponents()
334        {
335          inputCombiner = new SignalCombiner(2);
336          mixer         = SignalMixer.makeAdditiveMixer("mixer");
337          filter1       = SignalFilter.makeHighPass(null, "1.090");
338          filter2       = SignalFilter.makeLowPass(null, "1.450");
339          outputFork    = new SignalManifold(2);
340        }
341        
342        /**
343         * Connects the prebuilt internal components of this device to one another.
344         */
345        private void connectInternalComponents()
346        {
347          inputCombiner.getOutputPipe().connectOutputTo(mixer.getInputPipe());
348          mixer.getOutputPipe().connectOutputTo(filter1.getInputPipe());
349          filter1.getOutputPipe().connectOutputTo(filter2.getInputPipe());
350          filter2.getOutputPipe().connectOutputTo(outputFork.getInputPipe());
351        }
352    
353        //============================================================================
354        // INTERFACE SignalProcessor
355        //============================================================================
356        
357        /* (non-Javadoc)
358         * @see edu.nrao.sss.electronics.SignalProcessor#execute()
359         */
360        public void execute()
361        {
362          inputCombiner.execute();
363        }
364        
365        public void executeUpTo(SignalProcessor firstUnexecutedDevice)
366        {
367          if (firstUnexecutedDevice != this)
368            inputCombiner.executeUpTo(firstUnexecutedDevice);
369        }
370    
371        public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice)
372        {
373          inputCombiner.executeFromStartOfChainUpTo(firstUnexecutedDevice);
374        }
375      }
376    
377      //============================================================================
378      // 
379      //============================================================================
380      /*
381      public static void main(String[] args) throws Exception
382      {
383        T301 t301 = new T301();
384        
385        Map<ReceiverBand, AntennaFrontEnd> frontEnds =
386          AntennaFrontEnd.makeEvlaFrontEnds(new HashMap<ReceiverBand, SignalSource>());
387    
388        //LCP
389        List<SignalPipe> topInputs = t301.getTopInputPipes();
390        topInputs.get(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.L));
391        topInputs.get(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.L));
392        //RCP
393        List<SignalPipe> bottomInputs = t301.getBottomInputPipes();
394        bottomInputs.get(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.R));
395        bottomInputs.get(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.R));
396        
397        System.out.println("4-band, LCP, output:\n" + frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.L).getSignal());
398        System.out.println("4-band, RCP, output:\n" + frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.R).getSignal());
399        System.out.println("P-band, LCP, output:\n" + frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.L).getSignal());
400        System.out.println("P-band, RCP, output:\n" + frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.R).getSignal());
401    
402        //t301.setOutputSwitchesToStandardPositions();
403        //t301.setOutputSwitchesForTopInputs();
404        //t301.setOutputSwitchesForBottomInputs();
405        t301.execute();
406    
407        for (Signal s : t301.getSignals())
408          System.out.println("T301 Output Signal:\n" + s);
409      }
410      */
411    }