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.SignalManifold; 010 import edu.nrao.sss.electronics.SignalMixer; 011 import edu.nrao.sss.electronics.SignalPipe; 012 import edu.nrao.sss.electronics.SignalProcessor; 013 import edu.nrao.sss.electronics.SignalSource; 014 import edu.nrao.sss.electronics.SignalSwitch; 015 import edu.nrao.sss.measure.Frequency; 016 017 /** 018 * The EVLA T302 LSC Upconverter. 019 * <p> 020 * This device has two halves that are identical. Each half has two inputs, 021 * only one of which may be selected (by an internal switch) at a time. 022 * The input is split onto two paths, each of which is mixed with a different 023 * local oscillator signal and output. The local oscillator deemed 024 * "LO1" influences equally one input in the top half and one in the bottom. 025 * The same is true for LO2.</p> 026 * <p> 027 * As used by the {@link EvlaAntennaElectronics EVLA electronics}, the 028 * top inputs carry left circular polarized signals that have come from 029 * either the 4/P converter, or from a switch that outputs either the 030 * L, S, or C band LCP signal. The bottom inputs are similar, except that 031 * they carry RCP signals. Note: the text above is accurate only if the 032 * 4/P converter output switches are in there standard positions. 033 * It is possible to feed the 4/P LCP or RCP to both the top and bottom 034 * inputs of this T302.</p> 035 * <img src="doc-files/T302.png" alt="T302 Dgm"/> 036 * <p> 037 * <b>Version Info:</b> 038 * <table style="margin-left:2em"> 039 * <tr><td>$Revision: 1241 $</td></tr> 040 * <tr><td>$Date: 2008-04-25 14:37:37 -0600 (Fri, 25 Apr 2008) $</td></tr> 041 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 042 * </table></p> 043 * 044 * @author David M. Harland 045 * @since 2007-10-30 046 */ 047 public class T302 048 implements SignalProcessor 049 { 050 //The target output range of this device is 8-12GHz, making tgt ctr = 10GHz. 051 //This value is used for helping the suggestLOFrequencies() method. 052 //TODO this information should be set by the outside world, not treated 053 // as internal knowledge. 054 private static final Frequency CENTER_OF_TARGET_OUTPUT = new Frequency("10.0"); 055 056 //Internal components 057 private OneHalfT302 topHalf; 058 private OneHalfT302 bottomHalf; 059 private SignalManifold lo1Fork; 060 private SignalManifold lo2Fork; 061 062 //============================================================================ 063 // OBJECT CONSTRUCTION 064 //============================================================================ 065 066 /** 067 * Creates a new T302 LSC Upconverter that uses the given sources as its 068 * local oscillators. 069 * 070 * @param LO1 071 * provider of the LO-1 local oscillator signal. 072 * 073 * @param LO2 074 * provider of the LO-2 local oscillator signal. 075 */ 076 public T302(SignalSource LO1, SignalSource LO2) 077 { 078 constructInternalComponents(); 079 connectInternalComponents(); 080 081 //Set frequency sources for the mixers 082 lo1Fork.getInputPipe().connectInputTo(LO1); 083 lo2Fork.getInputPipe().connectInputTo(LO2); 084 } 085 086 /** 087 * Builds, but does not connect, the internal components of this device. 088 */ 089 private void constructInternalComponents() 090 { 091 topHalf = new OneHalfT302("LSC.TOP"); 092 bottomHalf = new OneHalfT302("LSC.BOTTOM"); 093 094 lo1Fork = new SignalManifold(2); 095 lo2Fork = new SignalManifold(2); 096 } 097 098 /** 099 * Connects the prebuilt internal components of this device to one another. 100 */ 101 private void connectInternalComponents() 102 { 103 lo1Fork.getOutputPipe(0).connectOutputTo( topHalf.lo1Mixer.getLocalOscillatorInputPipe()); 104 lo1Fork.getOutputPipe(1).connectOutputTo(bottomHalf.lo1Mixer.getLocalOscillatorInputPipe()); 105 106 lo2Fork.getOutputPipe(0).connectOutputTo( topHalf.lo2Mixer.getLocalOscillatorInputPipe()); 107 lo2Fork.getOutputPipe(1).connectOutputTo(bottomHalf.lo2Mixer.getLocalOscillatorInputPipe()); 108 } 109 110 //============================================================================ 111 // INPUTS AND OUTPUTS 112 //============================================================================ 113 114 /** 115 * Sets the input top and bottom input switches to select one 116 * of their inputs. The names of the poles of these switches 117 * are set by a call to 118 * {@link #nameInputPolesOfInputSwitches(String, String, String, String)}. 119 * 120 * @param topSwInputPoleName 121 * the name of an input pole of the top input switch of this converter. 122 * 123 * @param bottomSwInputPoleName 124 * the name of an input pole of the bottom input switch of this converter. 125 */ 126 public void setInputSwitches(String topSwInputPoleName, 127 String bottomSwInputPoleName) 128 { 129 topHalf.inputSwitch.selectInput(topSwInputPoleName); 130 bottomHalf.inputSwitch.selectInput(bottomSwInputPoleName); 131 } 132 133 /** 134 * Returns the two top inputs for this converter. 135 * An internal switch will select only one of these two inputs. 136 * The selected input will be sent down two pathways. 137 * On one pathway it is mixed with the LO-1 signal, on the other with 138 * the LO-2 signal. These are then sent out through the top two outputs. 139 * <p> 140 * In the EVLA antenna electronics, the top inputs will be used 141 * for left circular polarized signals coming from switch S2-2 (input 142 * pole 0) and the T301 top output (input pole 1).</p> 143 * 144 * @return the top two inputs for this converter. 145 */ 146 public List<SignalPipe> getTopInputPipes() 147 { 148 List<SignalPipe> inputs = new ArrayList<SignalPipe>(); 149 150 inputs.add(topHalf.inputSwitch.getInputPipe(0)); 151 inputs.add(topHalf.inputSwitch.getInputPipe(1)); 152 153 return inputs; 154 } 155 156 /** 157 * Returns the two bottom inputs for this converter. 158 * An internal switch will select only one of these two inputs. 159 * The selected input will be sent down two pathways. 160 * On one pathway it is mixed with the LO-1 signal, on the other with 161 * the LO-2 signal. These are then sent out through the bottom two outputs. 162 * <p> 163 * In the EVLA antenna electronics, the bottom inputs will be used 164 * for rigth circular polarized signals coming from switch S2-1 (input 165 * pole 0) and the T301 bottom output (input pole 1).</p> 166 * 167 * @return the bottom two inputs for this converter. 168 */ 169 public List<SignalPipe> getBottomInputPipes() 170 { 171 List<SignalPipe> inputs = new ArrayList<SignalPipe>(); 172 173 inputs.add(bottomHalf.inputSwitch.getInputPipe(0)); 174 inputs.add(bottomHalf.inputSwitch.getInputPipe(1)); 175 176 return inputs; 177 } 178 179 /** 180 * Returns the output that came from one of the top inputs and 181 * was mixed with the LO-1 signal. 182 * 183 * @return the output that came from one of the top inputs and 184 * was mixed with the LO-1 signal. 185 */ 186 public SignalPipe getTopLO1Output() 187 { 188 return topHalf.lo1Mixer.getOutputPipe(); 189 } 190 191 /** 192 * Returns the output that came from one of the top inputs and 193 * was mixed with the LO-2 signal. 194 * 195 * @return the output that came from one of the top inputs and 196 * was mixed with the LO-2 signal. 197 */ 198 public SignalPipe getTopLO2Output() 199 { 200 return topHalf.lo2Mixer.getOutputPipe(); 201 } 202 203 /** 204 * Returns the output that came from one of the bottom inputs and 205 * was mixed with the LO-1 signal. 206 * 207 * @return the output that came from one of the bottom inputs and 208 * was mixed with the LO-1 signal. 209 */ 210 public SignalPipe getBottomLO1Output() 211 { 212 return bottomHalf.lo1Mixer.getOutputPipe(); 213 } 214 215 /** 216 * Returns the output that came from one of the bottom inputs and 217 * was mixed with the LO-2 signal. 218 * 219 * @return the output that came from one of the bottom inputs and 220 * was mixed with the LO-2 signal. 221 */ 222 public SignalPipe getBottomLO2Output() 223 { 224 return bottomHalf.lo2Mixer.getOutputPipe(); 225 } 226 227 void nameInputPolesOfInputSwitches(String topSwPole0, String topSwPole1, 228 String bottomSwPole0, String bottomSwPole1) 229 { 230 topHalf.inputSwitch.nameInputs(topSwPole0, topSwPole1); 231 bottomHalf.inputSwitch.nameInputs(bottomSwPole0, bottomSwPole1); 232 } 233 234 void addSwitchesTo(SortedMap<String, SignalSwitch> map) 235 { 236 map.put( topHalf.inputSwitch.getName(), topHalf.inputSwitch); 237 map.put(bottomHalf.inputSwitch.getName(), bottomHalf.inputSwitch); 238 } 239 240 /** 241 * Returns the signals produced by this converter. 242 * The returned collection will hold four signals. 243 * 244 * @return the signals produced by this converter. 245 */ 246 public Collection<Signal> getSignals() 247 { 248 Collection<Signal> signals = new ArrayList<Signal>(); 249 250 signals.add(topHalf.lo1Mixer.getMostRecentOutput()); 251 signals.add(topHalf.lo2Mixer.getMostRecentOutput()); 252 signals.add(bottomHalf.lo1Mixer.getMostRecentOutput()); 253 signals.add(bottomHalf.lo2Mixer.getMostRecentOutput()); 254 255 return signals; 256 } 257 258 /** 259 * Suggests frequencies for tuning the local oscillators that were used in the 260 * {@link #T302(SignalSource, SignalSource) construction} of this device. 261 * The suggested tunings take into account the current input signals being 262 * fed to this converter, as well as a target center for the output signal 263 * of 10.0 GHz. 264 * <p> 265 * <b>Note:</b> this method makes some assumptions in its determinations. 266 * These assumptions, which may not suit all clients, are as follows: 267 * <ol> 268 * <li>The bottom half is receiving signals that have the same frequencies 269 * as their counterparts in the top half.</li> 270 * <li>The LO1 and LO2 oscillators will be tuned to the same 271 * frequencies.</li> 272 * </ol> 273 * 274 * @return a list containing the suggested frequency for LO1 at index 0 and 275 * the suggested frequency for LO2 at index 1. 276 */ 277 public List<Frequency> suggestLOFrequencies() 278 { 279 return topHalf.suggestLOFrequencies(); 280 } 281 282 //============================================================================ 283 // INTERFACE SignalProcessor 284 //============================================================================ 285 286 /** 287 * See {@link SignalProcessor#execute()}. 288 */ 289 public void execute() 290 { 291 topHalf.execute(); 292 bottomHalf.execute(); 293 } 294 295 /** 296 * See {@link SignalProcessor#executeUpTo(SignalProcessor)}. 297 */ 298 public void executeUpTo(SignalProcessor firstUnexecutedDevice) 299 { 300 if (firstUnexecutedDevice != this) 301 { 302 topHalf.executeUpTo(firstUnexecutedDevice); 303 bottomHalf.executeUpTo(firstUnexecutedDevice); 304 } 305 } 306 307 /** 308 * See {@link SignalProcessor#executeFromStartOfChainUpTo(SignalProcessor)}. 309 */ 310 public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice) 311 { 312 topHalf.executeFromStartOfChainUpTo(this); 313 bottomHalf.executeFromStartOfChainUpTo(this); 314 315 executeUpTo(firstUnexecutedDevice); 316 } 317 318 //============================================================================ 319 // HELPER CLASSES 320 //============================================================================ 321 322 /** 323 * Represents roughly one half of the T302 LSC Upconverter. 324 * Each half creates a pair of output signals from an input signal selected 325 * by a switch that has two input signals. 326 * Note that the forks that feed the LO signals 327 * to the mixers are not considered to be 328 * part of this half, but are instead in addition to the 329 * two halves and are handled by class T302 directly. 330 */ 331 private class OneHalfT302 implements SignalProcessor 332 { 333 private String name; 334 SignalSwitch inputSwitch; 335 private SignalManifold inputFork; 336 SignalMixer lo1Mixer; 337 SignalMixer lo2Mixer; 338 339 /** Creates half of a T302. */ 340 OneHalfT302(String nameOfThisHalf) 341 { 342 name = nameOfThisHalf; 343 constructInternalComponents(); 344 connectInternalComponents(); 345 } 346 347 /** 348 * Builds, but does not connect, the internal components of this device. 349 */ 350 private void constructInternalComponents() 351 { 352 String switchName = name + ".input-switch"; 353 354 inputSwitch = SignalSwitch.makeMultiInputSwitch(switchName, 2); 355 lo1Mixer = SignalMixer.makeSubtractiveMixer("LO1-mixer"); 356 lo2Mixer = SignalMixer.makeSubtractiveMixer("LO2-mixer"); 357 inputFork = new SignalManifold(2); 358 } 359 360 /** 361 * Connects the prebuilt internal components of this device to one another. 362 */ 363 private void connectInternalComponents() 364 { 365 inputSwitch.getOutputPipe(0).connectOutputTo(inputFork.getInputPipe()); 366 inputFork.getOutputPipe(0).connectOutputTo(lo1Mixer.getInputPipe()); 367 inputFork.getOutputPipe(1).connectOutputTo(lo2Mixer.getInputPipe()); 368 } 369 370 /** 371 * This method currently assumes that both LOs should be set 372 * to the same frequency. 373 */ 374 List<Frequency> suggestLOFrequencies() 375 { 376 List<Frequency> loSettings = new ArrayList<Frequency>(); 377 378 inputSwitch.executeFromStartOfChainUpTo(this); 379 380 Signal inputSignal = inputSwitch.getSignal(); 381 382 if (inputSignal != null) 383 { 384 Frequency inputCenter = 385 inputSignal.getCurrentRange().getCenterFrequency(); 386 387 Frequency setting = CENTER_OF_TARGET_OUTPUT.clone().add(inputCenter); 388 389 loSettings.add(setting); 390 loSettings.add(setting.clone()); 391 } 392 else 393 { 394 loSettings.add(new Frequency()); 395 loSettings.add(new Frequency()); 396 } 397 398 return loSettings; 399 } 400 401 //============================================================================ 402 // INTERFACE SignalProcessor 403 //============================================================================ 404 405 /* (non-Javadoc) 406 * @see edu.nrao.sss.electronics.SignalProcessor#execute() 407 */ 408 public void execute() 409 { 410 inputSwitch.execute(); 411 } 412 413 public void executeUpTo(SignalProcessor firstUnexecutedDevice) 414 { 415 if (firstUnexecutedDevice != this) 416 inputSwitch.executeUpTo(firstUnexecutedDevice); 417 } 418 419 public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice) 420 { 421 inputSwitch.executeFromStartOfChainUpTo(firstUnexecutedDevice); 422 } 423 } 424 425 //============================================================================ 426 // 427 //============================================================================ 428 /* 429 public static void main(String[] args) throws Exception 430 { 431 //LOs 432 Frequency lowFreq = new Frequency(11904.0, edu.nrao.sss.measure.FrequencyUnits.MEGAHERTZ); 433 Frequency highFreq = new Frequency(20352.0, edu.nrao.sss.measure.FrequencyUnits.MEGAHERTZ); 434 Frequency stepSize = new Frequency( 256.0, edu.nrao.sss.measure.FrequencyUnits.MEGAHERTZ); 435 436 edu.nrao.sss.electronics.LocalOscillator L301_1 = 437 new edu.nrao.sss.electronics.LocalOscillator(new edu.nrao.sss.measure.FrequencyRange(lowFreq,highFreq),stepSize); 438 edu.nrao.sss.electronics.LocalOscillator L301_2 = L301_1.clone(); 439 440 //LSC INPUTS 441 SignalSwitch lcpSwitch = SignalSwitch.makeMultiInputSwitch("LCP", 3); 442 SignalSwitch rcpSwitch = SignalSwitch.makeMultiInputSwitch("RCP", 3); 443 444 java.util.Map<edu.nrao.sss.model.resource.ReceiverBand, edu.nrao.sss.model.resource.AntennaFrontEnd> frontEnds = 445 edu.nrao.sss.model.resource.AntennaFrontEnd.makeEvlaFrontEnds(new java.util.HashMap<edu.nrao.sss.model.resource.ReceiverBand, SignalSource>()); 446 447 edu.nrao.sss.model.resource.AntennaFrontEnd fe = frontEnds.get(edu.nrao.sss.model.resource.ReceiverBand.EVLA_L); 448 lcpSwitch.getInputPipe(0).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.L)); 449 rcpSwitch.getInputPipe(0).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.R)); 450 451 fe = frontEnds.get(edu.nrao.sss.model.resource.ReceiverBand.EVLA_S); 452 lcpSwitch.getInputPipe(1).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.L)); 453 rcpSwitch.getInputPipe(1).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.R)); 454 455 fe = frontEnds.get(edu.nrao.sss.model.resource.ReceiverBand.EVLA_C); 456 lcpSwitch.getInputPipe(2).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.L)); 457 rcpSwitch.getInputPipe(2).connectInputTo(fe.getOuputPipe(edu.nrao.sss.astronomy.PolarizationType.R)); 458 459 //4P INPUTS 460 //ignoring these 461 462 //CONNECT INPUTS TO T302 463 T302 t302 = new T302(L301_1, L301_2); 464 465 List<SignalPipe> topInputs = t302.getTopInputPipes(); 466 List<SignalPipe> bottomInputs = t302.getBottomInputPipes(); 467 468 lcpSwitch.getOutputPipe(0).connectOutputTo(topInputs.get(0)); 469 rcpSwitch.getOutputPipe(0).connectOutputTo(bottomInputs.get(0)); 470 471 t302.namePolesOfInputSwitches("LSC", "null"); 472 t302.setInputSwitches("LSC"); 473 //t302.setInputSwitches("null"); 474 475 //RUN T302 WITH DIFFERENT INPUTS 476 for (int pole=0; pole < 3; pole++) 477 { 478 lcpSwitch.selectInput(pole); 479 rcpSwitch.selectInput(pole); 480 481 List<Frequency> loSettings = t302.suggestLOFrequencies(); 482 L301_1.tuneTo(loSettings.get(0)); 483 L301_2.tuneTo(loSettings.get(1)); 484 485 t302.executeFromStartOfChainUpTo(null); 486 487 System.out.println("---------- LOs tuned to " + L301_1.getCurrentTuning() + " ----------\n"); 488 489 for (Signal s : t302.getSignals()) 490 System.out.println("T302 Output Signal:\n" + s); 491 } 492 } 493 */ 494 }