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 }