001 package edu.nrao.sss.model.resource.evla; 002 003 import java.awt.event.ActionEvent; 004 import java.awt.event.ActionListener; 005 import java.util.ArrayList; 006 import java.util.Collection; 007 import java.util.HashMap; 008 import java.util.HashSet; 009 import java.util.List; 010 import java.util.Map; 011 import java.util.Set; 012 import java.util.SortedMap; 013 import java.util.SortedSet; 014 import java.util.TreeMap; 015 import java.util.TreeSet; 016 017 import edu.nrao.sss.astronomy.PolarizationType; 018 import edu.nrao.sss.electronics.DigitalSignal; 019 import edu.nrao.sss.electronics.Digitizer; 020 import edu.nrao.sss.electronics.LocalOscillator; 021 import edu.nrao.sss.electronics.SignalManifold; 022 import edu.nrao.sss.electronics.SignalPipe; 023 import edu.nrao.sss.electronics.SignalSource; 024 import edu.nrao.sss.electronics.SignalSwitch; 025 import edu.nrao.sss.electronics.SignalTransferSwitch; 026 import edu.nrao.sss.measure.Frequency; 027 import edu.nrao.sss.measure.FrequencyRange; 028 import edu.nrao.sss.measure.FrequencyUnits; 029 import edu.nrao.sss.model.resource.AntennaElectronics; 030 import edu.nrao.sss.model.resource.AntennaElectronicsConfiguration; 031 import edu.nrao.sss.model.resource.AntennaFrontEnd; 032 import edu.nrao.sss.model.resource.ReceiverBand; 033 import edu.nrao.sss.model.resource.TelescopeType; 034 035 /** 036 * The electronics of an EVLA antenna. This class represents the hardware from 037 * the feed horns through the digitizers. 038 * <p> 039 * <b>Version Info:</b> 040 * <table style="margin-left:2em"> 041 * <tr><td>$Revision: 1701 $</td></tr> 042 * <tr><td>$Date: 2008-11-07 16:24:23 -0700 (Fri, 07 Nov 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 EvlaAntennaElectronics 050 implements AntennaElectronics 051 { 052 //--------- ELECTRONIC COMPONENTS --------- 053 054 //Feeds 055 private Map<ReceiverBand, AntennaFrontEnd> frontEnds; 056 057 //Switches 058 private SignalSwitch switch1_1, switch1_2; 059 private SignalSwitch switch2_1, switch2_2; 060 private SignalSwitch switch3_1, switch3_2; 061 private SignalSwitch switch4_1, switch4_2; 062 063 private SignalTransferSwitch switch5, switch6; 064 065 private SignalSwitch switch7, switch8, switch9; 066 067 //Local Oscillators 068 private LocalOscillator L301_1, L301_2; 069 private LocalOscillator L302_1, L302_2, L302_3, L302_4; 070 071 //Converters 072 private T301 fourPConverter; 073 private T302 lscConverter; 074 private T303 uxConverter; 075 private T304 downConverterA, downConverterB, downConverterC, downConverterD; 076 077 //Digitizers 078 private D301 samplerA, samplerB, samplerC, samplerD; 079 080 //--------- HELPER VARIABLES --------- 081 082 //Putting all the signal switches in one collection makes part 083 //of the code easier. 084 private HashSet<SignalSwitch> signalSwitches; 085 086 //Maps receiver bands to text codes for the converters they use. 087 //The codes are "UX", "LSC", and "X" (which is not a converter). 088 //Bands 4 & P are treated specially and here are mapped to "LSC". 089 private HashMap<ReceiverBand, String> receiverConverterMap; 090 091 //Maps some receiver bands to the text name of an input pole of the top input 092 //switch on the LSC converter. Bands L, S, & C map to "S2-2"; bands 4 & P 093 //map to "4P.TOP". 094 private HashMap<ReceiverBand, String> lscTopInputMap; 095 096 //Maps some receiver bands to the text name of an input pole of the top input 097 //switch on the LSC converter. Bands L, S, & C map to "S2-1"; bands 4 & P 098 //map to "4P.BOTTOM". 099 private HashMap<ReceiverBand, String> lscBottomInputMap; 100 101 //Used by the methods that configure these electronics by specifying 102 //receiver bands. These plans are supplied from an external source and, 103 //if non-null, are used in place our our default plans. 104 private Map<ReceiverBand, Map<String, Frequency>> tuningPlans; 105 106 private static Map<ReceiverBand, Map<String, Frequency>> DEFAULT_TUNING_PLANS; 107 108 //Default sampler settings 109 private Map<ReceiverBand, Integer> defaultSampleBits; 110 111 //The front end (receiver) for which we're currently configured. 112 //TODO need to handle multiple simultaneous front ends, such as 4 & P 113 private AntennaFrontEnd currentFrontEnd; 114 115 //--------- OTHER --------- 116 117 Collection<DigitalSignal> mostRecentSignals; 118 List<List<DigitalSignal>> mostRecentSignalPairs; 119 120 //Execution listeners 121 private List<ActionListener> execListeners; 122 123 //Holds list of messages regarding the most recent configuration 124 private List<String> configurationProblems; 125 126 //============================================================================ 127 // OBJECT CONSTRUCTION 128 //============================================================================ 129 130 /** Creates a new instance. */ 131 public EvlaAntennaElectronics() { construct(); } 132 133 /** Used by constructors and clone(). */ 134 private void construct() 135 { 136 constructInternalComponents(); 137 connectInternalComponents(); 138 nameTheSwitchPoles(); 139 mapReceiversToConverters(); 140 mapReceiversToSamplingBits(); 141 142 initTuners(); 143 144 mostRecentSignals = new ArrayList<DigitalSignal>(); 145 mostRecentSignalPairs = new ArrayList<List<DigitalSignal>>(); 146 147 execListeners = new ArrayList<ActionListener>(); 148 149 tuningPlans = new HashMap<ReceiverBand, Map<String,Frequency>>(); 150 151 configurationProblems = new ArrayList<String>(); 152 153 //Choice of X band is arbitrary 154 configureFor(ReceiverBand.EVLA_X); 155 } 156 157 /** 158 * Builds, but does not connect, the internal components of this device. 159 */ 160 private void constructInternalComponents() 161 { 162 constructSwitches(); 163 constructOscillators(); 164 constructFrontEndsAndConnectOscillators(); 165 constructConvertersAndConnectOscillators(); 166 constructDigitizers(); 167 } 168 169 /** 170 * Builds the switches that live in between the converters, feeds, 171 * and digitizers. 172 */ 173 private void constructSwitches() 174 { 175 switch1_1 = SignalSwitch.makeMultiInputSwitch("S1-1", 4); 176 switch1_2 = SignalSwitch.makeMultiInputSwitch("S1-2", 4); 177 switch2_1 = SignalSwitch.makeMultiInputSwitch("S2-1", 4); 178 switch2_2 = SignalSwitch.makeMultiInputSwitch("S2-2", 4); 179 switch3_1 = SignalSwitch.makeMultiInputSwitch("S3-1", 4); 180 switch3_2 = SignalSwitch.makeMultiInputSwitch("S3-2", 4); 181 switch4_1 = SignalSwitch.makeMultiInputSwitch("S4-1", 4); 182 switch4_2 = SignalSwitch.makeMultiInputSwitch("S4-2", 4); 183 184 switch5 = new SignalTransferSwitch("S5", 2); 185 switch6 = new SignalTransferSwitch("S6", 2); 186 187 switch7 = SignalSwitch.makeMultiOutputSwitch("S7", 4); 188 switch8 = SignalSwitch.makeMultiOutputSwitch("S8", 4); 189 switch9 = SignalSwitch.makeMultiOutputSwitch("S9", 4); 190 } 191 192 /** Builds the local oscillators. */ 193 private void constructOscillators() 194 { 195 //L301s 196 Frequency lowFreq = new Frequency("11904.0", FrequencyUnits.MEGAHERTZ); 197 Frequency highFreq = new Frequency("20352.0", FrequencyUnits.MEGAHERTZ); 198 Frequency stepSize = new Frequency( "256.0", FrequencyUnits.MEGAHERTZ); 199 200 L301_1 = new LocalOscillator(new FrequencyRange(lowFreq,highFreq),stepSize); 201 L301_2 = L301_1.clone(); 202 203 L301_1.setName("L301-1"); 204 L301_2.setName("L301-2"); 205 206 //L302s 207 lowFreq = new Frequency("10.8", FrequencyUnits.GIGAHERTZ); 208 highFreq = new Frequency("14.8", FrequencyUnits.GIGAHERTZ); 209 210 L302_1 = new LocalOscillator(new FrequencyRange(lowFreq, highFreq)); 211 L302_2 = L302_1.clone(); 212 L302_3 = L302_1.clone(); 213 L302_4 = L302_1.clone(); 214 215 L302_1.setName("L302-1"); 216 L302_2.setName("L302-2"); 217 L302_3.setName("L302-3"); 218 L302_4.setName("L302-4"); 219 } 220 221 /** Builds the receiver band front ends and connects them to LOs. */ 222 private void constructFrontEndsAndConnectOscillators() 223 { 224 Map<ReceiverBand, SignalSource> loSignals = 225 new HashMap<ReceiverBand, SignalSource>(); 226 227 loSignals.put(ReceiverBand.EVLA_Q, switch7.getOutputPipe(0)); 228 loSignals.put(ReceiverBand.EVLA_Ka, switch7.getOutputPipe(1)); 229 loSignals.put(ReceiverBand.EVLA_K, switch7.getOutputPipe(2)); 230 231 frontEnds = AntennaFrontEnd.makeEvlaFrontEnds(loSignals); 232 } 233 234 /** Builds the converters and connects them to the LOs. */ 235 private void constructConvertersAndConnectOscillators() 236 { 237 //Converters that use no external LOs 238 fourPConverter = new T301(); 239 240 //Converters and switches that take input from L301s. 241 //Rem: indexing starts from 0 in methods, but from 1 on diagrams 242 switch7.getInputPipe(0).connectInputTo(switch8.getOutputPipe(1)); 243 switch8.getInputPipe(0).connectInputTo(L301_1); 244 switch9.getInputPipe(0).connectInputTo(L301_2); 245 246 lscConverter = new T302(switch8.getOutputPipe(2), //switch position 3 247 switch9.getOutputPipe(2)); //switch position 3 248 249 uxConverter = new T303(switch7.getOutputPipe(3), //switch position 4 250 switch9.getOutputPipe(1)); //switch position 2 251 252 //Converters that take input from L302s 253 downConverterA = new T304("T304-A", L302_1, L302_3); 254 downConverterB = new T304("T304-B", L302_2, L302_4); 255 downConverterC = new T304("T304-C", L302_1, L302_3); 256 downConverterD = new T304("T304-D", L302_2, L302_4); 257 } 258 259 /** Builds the digitizers. */ 260 private void constructDigitizers() 261 { 262 samplerA = new D301("D301 (DTS A)"); 263 samplerB = new D301("D302 (DTS B)"); 264 samplerC = new D301("D303 (DTS C)"); 265 samplerD = new D301("D304 (DTS D)"); 266 267 samplerA.setOutputNames("A0", "A1", "C1"); 268 samplerB.setOutputNames("B0", "B1", "D1"); 269 samplerC.setOutputNames("C0", "A2", "C2"); 270 samplerD.setOutputNames("D0", "B2", "D2"); 271 } 272 273 /** 274 * Connects the prebuilt internal components of this device to one another. 275 */ 276 private void connectInternalComponents() 277 { 278 connectFrontEndOutputs(); 279 connectConverters(); 280 connectDigitizers(); 281 } 282 283 /** Connects the outputs of the front ends to their targets. */ 284 private void connectFrontEndOutputs() 285 { 286 //BANDS Q, Ka, K, & Ku 287 // LCP 288 switch1_2.getInputPipe(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Q ).getOuputPipe(PolarizationType.L)); 289 switch1_2.getInputPipe(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Ka).getOuputPipe(PolarizationType.L)); 290 switch1_2.getInputPipe(2).connectInputTo(frontEnds.get(ReceiverBand.EVLA_K ).getOuputPipe(PolarizationType.L)); 291 switch1_2.getInputPipe(3).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Ku).getOuputPipe(PolarizationType.L)); 292 // RCP 293 switch1_1.getInputPipe(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Q ).getOuputPipe(PolarizationType.R)); 294 switch1_1.getInputPipe(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Ka).getOuputPipe(PolarizationType.R)); 295 switch1_1.getInputPipe(2).connectInputTo(frontEnds.get(ReceiverBand.EVLA_K ).getOuputPipe(PolarizationType.R)); 296 switch1_1.getInputPipe(3).connectInputTo(frontEnds.get(ReceiverBand.EVLA_Ku).getOuputPipe(PolarizationType.R)); 297 298 //BANDS C, S, & L 299 // LCP 300 switch2_2.getInputPipe(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_L ).getOuputPipe(PolarizationType.L)); 301 switch2_2.getInputPipe(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_S ).getOuputPipe(PolarizationType.L)); 302 switch2_2.getInputPipe(2).connectInputTo(frontEnds.get(ReceiverBand.EVLA_C ).getOuputPipe(PolarizationType.L)); 303 // RCP 304 switch2_1.getInputPipe(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_L ).getOuputPipe(PolarizationType.R)); 305 switch2_1.getInputPipe(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_S ).getOuputPipe(PolarizationType.R)); 306 switch2_1.getInputPipe(2).connectInputTo(frontEnds.get(ReceiverBand.EVLA_C ).getOuputPipe(PolarizationType.R)); 307 308 //BAND X 309 // LCP 310 SignalManifold xTopFork = new SignalManifold(2); 311 xTopFork.getInputPipe().connectInputTo(frontEnds.get(ReceiverBand.EVLA_X).getOuputPipe(PolarizationType.L)); 312 switch3_2.getInputPipe(0).connectInputTo(xTopFork.getOutputPipe(0)); 313 switch4_2.getInputPipe(0).connectInputTo(xTopFork.getOutputPipe(1)); 314 // RCP 315 SignalManifold xBottomFork = new SignalManifold(2); 316 xBottomFork.getInputPipe().connectInputTo(frontEnds.get(ReceiverBand.EVLA_X).getOuputPipe(PolarizationType.R)); 317 switch3_1.getInputPipe(0).connectInputTo(xBottomFork.getOutputPipe(0)); 318 switch4_1.getInputPipe(0).connectInputTo(xBottomFork.getOutputPipe(1)); 319 320 //BANDS P & 4 321 // LCP 322 List<SignalPipe> fourPTopInputs = fourPConverter.getTopInputPipes(); 323 fourPTopInputs.get(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.L)); 324 fourPTopInputs.get(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.L)); 325 // RCP 326 List<SignalPipe> fourPBottomInputs = fourPConverter.getBottomInputPipes(); 327 fourPBottomInputs.get(0).connectInputTo(frontEnds.get(ReceiverBand.EVLA_P).getOuputPipe(PolarizationType.R)); 328 fourPBottomInputs.get(1).connectInputTo(frontEnds.get(ReceiverBand.EVLA_4).getOuputPipe(PolarizationType.R)); 329 } 330 331 /** 332 * Connects those inputs and outputs of the converters that have not already 333 * been connected. (The LOs were connected elsewhere.) 334 */ 335 private void connectConverters() 336 { 337 //T303 UX CONVERTER 338 List<SignalPipe> uxTopOutputs = uxConverter.getTopOutputPipes(); 339 List<SignalPipe> uxBottomOutputs = uxConverter.getBottomOutputPipes(); 340 // LCP 341 uxConverter.getTopInputPipe().connectInputTo(switch1_2.getOutputPipe(0)); 342 switch3_2.getInputPipe(2).connectInputTo(uxTopOutputs.get(0)); 343 switch4_2.getInputPipe(2).connectInputTo(uxTopOutputs.get(1)); 344 // RCP 345 uxConverter.getBottomInputPipe().connectInputTo(switch1_1.getOutputPipe(0)); 346 switch3_1.getInputPipe(2).connectInputTo(uxBottomOutputs.get(0)); 347 switch4_1.getInputPipe(2).connectInputTo(uxBottomOutputs.get(1)); 348 349 //T302 LSC & T301 4P CONVERTERS 350 List<SignalPipe> lscTopInputs = lscConverter.getTopInputPipes(); 351 List<SignalPipe> lscBottomInputs = lscConverter.getBottomInputPipes(); 352 // LCP 353 lscTopInputs.get(0).connectInputTo(switch2_2.getOutputPipe(0)); 354 lscTopInputs.get(1).connectInputTo(fourPConverter.getTopOutputPipe()); 355 switch3_2.getInputPipe(1).connectInputTo(lscConverter.getTopLO1Output()); 356 switch4_2.getInputPipe(1).connectInputTo(lscConverter.getTopLO2Output()); 357 // RCP 358 lscBottomInputs.get(0).connectInputTo(switch2_1.getOutputPipe(0)); 359 lscBottomInputs.get(1).connectInputTo(fourPConverter.getBottomOutputPipe()); 360 switch3_1.getInputPipe(1).connectInputTo(lscConverter.getBottomLO1Output()); 361 switch4_1.getInputPipe(1).connectInputTo(lscConverter.getBottomLO2Output()); 362 363 //INTER-CONVERTER SWITCHES 364 switch3_1.getOutputPipe(0).connectOutputTo(switch5.getInputPipe(0)); 365 switch4_1.getOutputPipe(0).connectOutputTo(switch6.getInputPipe(0)); 366 switch3_2.getOutputPipe(0).connectOutputTo(switch5.getInputPipe(1)); 367 switch4_2.getOutputPipe(0).connectOutputTo(switch6.getInputPipe(1)); 368 369 //T304 DOWNCONVERTERS 370 downConverterA.getInputPipe().connectInputTo(switch5.getOutputPipe(0)); 371 downConverterB.getInputPipe().connectInputTo(switch6.getOutputPipe(0)); 372 downConverterC.getInputPipe().connectInputTo(switch5.getOutputPipe(1)); 373 downConverterD.getInputPipe().connectInputTo(switch6.getOutputPipe(1)); 374 } 375 376 /** Connects the inputs of the digitizers. */ 377 private void connectDigitizers() 378 { 379 //EIGHT BIT INPUTS 380 samplerA.getEightBitInputPipe().connectInputTo(downConverterA.getLO1OutputPipe(0)); 381 samplerB.getEightBitInputPipe().connectInputTo(downConverterB.getLO1OutputPipe(0)); 382 samplerC.getEightBitInputPipe().connectInputTo(downConverterC.getLO1OutputPipe(0)); 383 samplerD.getEightBitInputPipe().connectInputTo(downConverterD.getLO1OutputPipe(0)); 384 385 //THREE BIT INPUTS 386 List<SignalPipe> inputPipes; 387 // A 388 inputPipes = samplerA.getThreeBitInputPipes(); 389 inputPipes.get(0).connectInputTo(downConverterA.getLO1OutputPipe(1)); 390 inputPipes.get(1).connectInputTo(downConverterC.getLO1OutputPipe(1)); 391 // B 392 inputPipes = samplerB.getThreeBitInputPipes(); 393 inputPipes.get(0).connectInputTo(downConverterB.getLO1OutputPipe(1)); 394 inputPipes.get(1).connectInputTo(downConverterD.getLO1OutputPipe(1)); 395 // C 396 inputPipes = samplerC.getThreeBitInputPipes(); 397 inputPipes.get(0).connectInputTo(downConverterA.getLO2OutputPipe()); 398 inputPipes.get(1).connectInputTo(downConverterC.getLO2OutputPipe()); 399 // D 400 inputPipes = samplerD.getThreeBitInputPipes(); 401 inputPipes.get(0).connectInputTo(downConverterB.getLO2OutputPipe()); 402 inputPipes.get(1).connectInputTo(downConverterD.getLO2OutputPipe()); 403 } 404 405 /** Naming the switch poles helps with the configuration logic. */ 406 private void nameTheSwitchPoles() 407 { 408 //Name the poles from receiver bands and converters. 409 //(Converter names must be coordinated w/ method mapReceiversToConverters) 410 switch1_1.nameInputs(ReceiverBand.EVLA_Q.name(), 411 ReceiverBand.EVLA_Ka.name(), 412 ReceiverBand.EVLA_K.name(), 413 ReceiverBand.EVLA_Ku.name()); 414 switch1_1.nameOutputs("UX"); 415 416 switch1_2.nameInputs(ReceiverBand.EVLA_Q.name(), 417 ReceiverBand.EVLA_Ka.name(), 418 ReceiverBand.EVLA_K.name(), 419 ReceiverBand.EVLA_Ku.name()); 420 switch1_2.nameOutputs("UX"); 421 422 switch2_1.nameInputs(ReceiverBand.EVLA_L.name(), 423 ReceiverBand.EVLA_S.name(), 424 ReceiverBand.EVLA_C.name(), 425 "spare"); 426 switch2_1.nameOutputs("LSC"); 427 428 switch2_2.nameInputs(ReceiverBand.EVLA_L.name(), 429 ReceiverBand.EVLA_S.name(), 430 ReceiverBand.EVLA_C.name(), 431 "spare"); 432 switch2_2.nameOutputs("LSC"); 433 434 switch3_1.nameInputs("X", "LSC", "UX", "spare"); 435 switch3_1.nameOutputs("S5"); 436 437 switch3_2.nameInputs("X", "LSC", "UX", "spare"); 438 switch3_2.nameOutputs("S5"); 439 440 switch4_1.nameInputs("X", "LSC", "UX", "spare"); 441 switch4_1.nameOutputs("S6"); 442 443 switch4_2.nameInputs("X", "LSC", "UX", "spare"); 444 switch4_2.nameOutputs("S6"); 445 446 switch7.nameInputs("S8"); 447 switch7.nameOutputs(ReceiverBand.EVLA_Q.name(), 448 ReceiverBand.EVLA_Ka.name(), 449 ReceiverBand.EVLA_K.name(), 450 "UX"); 451 452 switch8.nameInputs("L301-1"); 453 switch8.nameOutputs("off", "UX", "LSC", "spare"); 454 455 switch9.nameInputs("L301-2"); 456 switch9.nameOutputs("off", "UX", "LSC", "spare"); 457 458 //Put all (non-transfer) switches in one collection 459 signalSwitches = new HashSet<SignalSwitch>(); 460 signalSwitches.add(switch1_1); signalSwitches.add(switch1_2); 461 signalSwitches.add(switch2_1); signalSwitches.add(switch2_2); 462 signalSwitches.add(switch3_1); signalSwitches.add(switch3_2); 463 signalSwitches.add(switch4_1); signalSwitches.add(switch4_2); 464 signalSwitches.add(switch7); 465 signalSwitches.add(switch8); 466 signalSwitches.add(switch9); 467 468 //Name some switches internal to the converters 469 fourPConverter.nameOutputPolesOfOutputSwitches("LSC", "LSC"); 470 lscConverter.nameInputPolesOfInputSwitches("S2-2", "4P.TOP", "S2-1", "4P.BOTTOM"); 471 uxConverter.nameOutputPolesOfOutputSwitches("S3-2", "S4-2", "S3-1", "S4-1"); 472 } 473 474 /** This method helps the switch configuration logic. */ 475 private void mapReceiversToConverters() 476 { 477 receiverConverterMap = new HashMap<ReceiverBand, String>(); 478 479 //The converter names below are the same as those used 480 //for naming the switch poles. 481 482 //Q, Ka, K, and Ku use the T303 UX Converter 483 receiverConverterMap.put(ReceiverBand.EVLA_Q, "UX"); 484 receiverConverterMap.put(ReceiverBand.EVLA_Ka, "UX"); 485 receiverConverterMap.put(ReceiverBand.EVLA_K, "UX"); 486 receiverConverterMap.put(ReceiverBand.EVLA_Ku, "UX"); 487 488 //X doesn't use one 489 receiverConverterMap.put(ReceiverBand.EVLA_X, "X"); 490 491 //C, S, L, P, & 4 use T302 LSC Converter (we ignore T301 4P Converter) 492 receiverConverterMap.put(ReceiverBand.EVLA_C, "LSC"); 493 receiverConverterMap.put(ReceiverBand.EVLA_S, "LSC"); 494 receiverConverterMap.put(ReceiverBand.EVLA_L, "LSC"); 495 receiverConverterMap.put(ReceiverBand.EVLA_P, "LSC"); 496 receiverConverterMap.put(ReceiverBand.EVLA_4, "LSC"); 497 498 //Input switches on T302 LSC Converter 499 lscTopInputMap = new HashMap<ReceiverBand, String>(); 500 lscTopInputMap.put(ReceiverBand.EVLA_C, "S2-2"); 501 lscTopInputMap.put(ReceiverBand.EVLA_S, "S2-2"); 502 lscTopInputMap.put(ReceiverBand.EVLA_L, "S2-2"); 503 lscTopInputMap.put(ReceiverBand.EVLA_P, "4P.TOP"); 504 lscTopInputMap.put(ReceiverBand.EVLA_4, "4P.TOP"); 505 506 lscBottomInputMap = new HashMap<ReceiverBand, String>(); 507 lscBottomInputMap.put(ReceiverBand.EVLA_C, "S2-1"); 508 lscBottomInputMap.put(ReceiverBand.EVLA_S, "S2-1"); 509 lscBottomInputMap.put(ReceiverBand.EVLA_L, "S2-1"); 510 lscBottomInputMap.put(ReceiverBand.EVLA_P, "4P.BOTTOM"); 511 lscBottomInputMap.put(ReceiverBand.EVLA_4, "4P.BOTTOM"); 512 } 513 514 /** This method helps the T304 and D301 configuration logic. */ 515 private void mapReceiversToSamplingBits() 516 { 517 defaultSampleBits = new HashMap<ReceiverBand, Integer>(); 518 519 defaultSampleBits.put(ReceiverBand.EVLA_Q, 3); 520 defaultSampleBits.put(ReceiverBand.EVLA_Ka, 3); 521 defaultSampleBits.put(ReceiverBand.EVLA_K, 3); 522 defaultSampleBits.put(ReceiverBand.EVLA_Ku, 3); 523 defaultSampleBits.put(ReceiverBand.EVLA_X, 3); 524 defaultSampleBits.put(ReceiverBand.EVLA_C, 3); 525 defaultSampleBits.put(ReceiverBand.EVLA_S, 8); 526 defaultSampleBits.put(ReceiverBand.EVLA_L, 8); 527 defaultSampleBits.put(ReceiverBand.EVLA_P, 8); 528 defaultSampleBits.put(ReceiverBand.EVLA_4, 8); 529 } 530 531 //============================================================================ 532 // INTERFACE AntennaElectronics AND SUPPORTING METHODS 533 //============================================================================ 534 //---------------------------------------------------------------------------- 535 // Execution & Output 536 //---------------------------------------------------------------------------- 537 538 /* (non-Javadoc) 539 * @see edu.nrao.sss.model.resource.AntennaElectronics#execute() 540 */ 541 public Collection<DigitalSignal> execute() 542 { 543 samplerA.eraseSignalMemory(); 544 samplerB.eraseSignalMemory(); 545 samplerC.eraseSignalMemory(); 546 samplerD.eraseSignalMemory(); 547 548 currentFrontEnd.execute(); 549 550 updateSignals(); 551 552 notifyExecutionListeners(); 553 554 return getSignals(); 555 } 556 557 /** Called by execute(); remembers output signals for quick fetch. */ 558 private void updateSignals() 559 { 560 mostRecentSignals.clear(); 561 562 mostRecentSignals.addAll(samplerA.getSignals()); 563 mostRecentSignals.addAll(samplerC.getSignals()); 564 mostRecentSignals.addAll(samplerB.getSignals()); 565 mostRecentSignals.addAll(samplerD.getSignals()); 566 567 mostRecentSignalPairs.clear(); //Will build just-in-time 568 } 569 570 /* (non-Javadoc) 571 * @see edu.nrao.sss.model.resource.AntennaElectronics#getSignals() 572 */ 573 public Collection<DigitalSignal> getSignals() 574 { 575 return new ArrayList<DigitalSignal>(mostRecentSignals); 576 } 577 578 /* (non-Javadoc) 579 * @see edu.nrao.sss.model.resource.AntennaElectronics#getSignalPairs() 580 */ 581 public List<List<DigitalSignal>> getSignalPairs() 582 { 583 //The execute method cleared the mostRecentSignalPairs. If it is 584 //still empty, but we have signals, we need to rebuild pairs. 585 if (mostRecentSignalPairs.size() == 0 && mostRecentSignals.size() > 0) 586 buildSignalPairs(); 587 588 List<List<DigitalSignal>> pairs = new ArrayList<List<DigitalSignal>>(); 589 590 for (List<DigitalSignal> pair : mostRecentSignalPairs) 591 pairs.add(new ArrayList<DigitalSignal>(pair)); 592 593 return pairs; 594 } 595 596 //Expected names for the digital signals, ordered & arranged into pairs 597 private static final String[][] SIGNAL_NAMES = 598 { 599 {"A0", "C0"}, {"B0", "D0"}, 600 {"A1", "C1"}, {"A2", "C2"}, 601 {"B1", "D1"}, {"B2", "D2"} 602 }; 603 604 private void buildSignalPairs() 605 { 606 //Make temp map of signals, using name as key 607 Map<String, DigitalSignal> signalMap = new HashMap<String, DigitalSignal>(); 608 609 for (DigitalSignal signal : mostRecentSignals) 610 signalMap.put(signal.getName(), signal); 611 612 //Iterate through names looking for match in temp map 613 for (String[] pairNames : SIGNAL_NAMES) 614 { 615 ArrayList<DigitalSignal> pair = new ArrayList<DigitalSignal>(); 616 617 //If map has one member of pair, make new pair. 618 //Note: other member could be signal or null. 619 if (signalMap.containsKey(pairNames[0]) || 620 signalMap.containsKey(pairNames[1])) 621 { 622 pair.add(signalMap.get(pairNames[0])); 623 pair.add(signalMap.get(pairNames[1])); 624 625 mostRecentSignalPairs.add(pair); 626 } 627 } 628 } 629 630 private void notifyExecutionListeners() 631 { 632 ActionEvent event = 633 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "execute"); 634 635 //TODO notify listeners in a diff thread? 636 for (ActionListener listener : execListeners) 637 listener.actionPerformed(event); 638 } 639 640 public void addExecutionListener(ActionListener newListener) 641 { 642 if (newListener != null) 643 execListeners.add(newListener); 644 } 645 646 public void removeExecutionListener(ActionListener formerListener) 647 { 648 execListeners.remove(formerListener); 649 } 650 651 //---------------------------------------------------------------------------- 652 // Intelligent Configuration 653 //---------------------------------------------------------------------------- 654 655 /** 656 * Configures these electronics to work with the given receiver band. 657 * 658 * @param band 659 * the receiver band, or frequency range, for which these electronics 660 * should be configured. If this band does not belong to the EVLA 661 * telescope, no reconfiguration will occur and this method will 662 * return <i>false</i>. 663 * 664 * @return 665 * <i>true</i> if the configuration occurred without any problems. 666 * If any problems were encountered, they will be listed in 667 * {@link #getConfigurationProblems()}. 668 * 669 * @see AntennaElectronics#configureFor(ReceiverBand) 670 */ 671 public boolean configureFor(ReceiverBand band) 672 { 673 boolean success = true; 674 675 configurationProblems.clear(); 676 677 //Make sure incoming band belongs to EVLA telescope 678 if (band == null || !band.getTelescope().equals(TelescopeType.EVLA)) 679 { 680 success = false; 681 configurationProblems.add( 682 "Reconfiguration of the EVLA antenna electronics was unsuccessful "+ 683 " because receiver band '" + band + "' is not an EVLA receiver."); 684 } 685 else //we have a good band 686 { 687 configureFrontEndsFor(band); 688 configureSwitchesFor(band); 689 tuneLocOscsFor(band); 690 691 int bits = defaultSampleBits.get(band); 692 693 boolean wide = (bits <= 3); 694 downConverterA.configureForWidestOutput(wide); 695 downConverterB.configureForWidestOutput(wide); 696 downConverterC.configureForWidestOutput(wide); 697 downConverterD.configureForWidestOutput(wide); 698 699 samplerA.setBitsPerSample(bits); 700 samplerB.setBitsPerSample(bits); 701 samplerC.setBitsPerSample(bits); 702 samplerD.setBitsPerSample(bits); 703 } 704 705 return success; 706 } 707 708 //private boolean configureFrontEndsFor(Set<ReceiverBand> bands) 709 private boolean configureFrontEndsFor(ReceiverBand band) 710 { 711 //Turn on the requested receiver and turn all other off 712 //(except that we keep 4 & P on all the time) 713 for (AntennaFrontEnd fe : frontEnds.values()) 714 { 715 //if (bands.contains(fe.getBand())) 716 if (band.equals(fe.getBand()) || 717 fe.getBand().equals(ReceiverBand.EVLA_4) || 718 fe.getBand().equals(ReceiverBand.EVLA_P)) 719 { 720 fe.turnOn(); 721 } 722 else 723 { 724 fe.turnOff(); 725 } 726 } 727 //TODO handle multiple receivers 728 //currentFrontEnd = frontEnds.get(bands.iterator().next()); 729 currentFrontEnd = frontEnds.get(band); 730 731 return true; 732 } 733 734 private boolean configureSwitchesFor(ReceiverBand band) 735 { 736 configurationProblems.clear(); 737 738 String receiver = band.name(); 739 String converter = receiverConverterMap.get(band); 740 741 for (SignalSwitch ss : signalSwitches) 742 { 743 //Input poles 744 if (ss.hasInputNamed(receiver )) ss.selectInput(receiver ); 745 else if (ss.hasInputNamed(converter)) ss.selectInput(converter); 746 //else leave as is 747 748 //Output poles 749 if (ss.hasOutputNamed(receiver )) ss.selectOutput(receiver ); 750 else if (ss.hasOutputNamed(converter)) ss.selectOutput(converter); 751 //else leave as is 752 } 753 754 //Input to T302 LSC Converter 755 String lscTopInputPole = lscTopInputMap.get(band); 756 if (lscTopInputPole != null) 757 { 758 lscConverter.setInputSwitches(lscTopInputPole, lscBottomInputMap.get(band)); 759 } 760 761 //TODO T303 should be able to look at input freqs and set own switches. For now: 762 //Special T303 logic for Ku Band 763 if (band == ReceiverBand.EVLA_Ku) 764 uxConverter.setOutputSwitches("LO1", "LO2"); 765 else 766 uxConverter.setOutputSwitches("DIRECT", "LO2"); 767 768 return true; 769 } 770 771 /** 772 * <i>This method is not yet programmed; 773 * it will send one band to {@link #configureFor(ReceiverBand)}.</i> 774 */ 775 public boolean configureFor(Set<ReceiverBand> bands) 776 { 777 //TODO handle multiple receivers 778 return configureFor(bands.iterator().next()); 779 } 780 781 /** 782 * <i>This method is not yet supported.</i> 783 */ 784 public boolean configureToProduce(Collection<DigitalSignal> signals) 785 { 786 throw new UnsupportedOperationException("not yet programmed"); //TODO code me 787 } 788 789 //---------------------------------------------------------------------------- 790 // Manual Configuration 791 //---------------------------------------------------------------------------- 792 793 /* (non-Javadoc) 794 * @see edu.nrao.sss.model.resource.AntennaElectronics#getLocalOscillators() 795 */ 796 public SortedMap<String, LocalOscillator> getLocalOscillators() 797 { 798 SortedMap<String, LocalOscillator> map = 799 new TreeMap<String, LocalOscillator>(); 800 801 map.put(L301_1.getName(), L301_1); 802 map.put(L301_2.getName(), L301_2); 803 804 map.put(L302_1.getName(), L302_1); 805 map.put(L302_2.getName(), L302_2); 806 map.put(L302_3.getName(), L302_3); 807 map.put(L302_4.getName(), L302_4); 808 809 return map; 810 } 811 812 /* (non-Javadoc) 813 * @see edu.nrao.sss.model.resource.AntennaElectronics#getSwitches() 814 */ 815 public SortedMap<String, SignalSwitch> getSwitches() 816 { 817 //First our own switches 818 SortedMap<String, SignalSwitch> map = new TreeMap<String, SignalSwitch>(); 819 820 for (SignalSwitch ss : signalSwitches) 821 map.put(ss.getName(), ss); 822 823 //Now those of our complex devices 824 fourPConverter.addSwitchesTo(map); 825 826 lscConverter.addSwitchesTo(map); 827 828 uxConverter.addSwitchesTo(map); 829 830 downConverterA.addSwitchesTo(map); 831 downConverterB.addSwitchesTo(map); 832 downConverterC.addSwitchesTo(map); 833 downConverterD.addSwitchesTo(map); 834 835 return map; 836 } 837 838 /* (non-Javadoc) 839 * @see edu.nrao.sss.model.resource.AntennaElectronics#getTransferSwitches() 840 */ 841 public SortedMap<String, SignalTransferSwitch> getTransferSwitches() 842 { 843 SortedMap<String, SignalTransferSwitch> map = 844 new TreeMap<String, SignalTransferSwitch>(); 845 846 map.put(switch5.getName(), switch5); 847 map.put(switch6.getName(), switch6); 848 849 //TODO see if we have xfer switches in T30x that we want to expose 850 851 return map; 852 } 853 854 /* (non-Javadoc) 855 * @see edu.nrao.sss.model.resource.AntennaElectronics#getDigitizers() 856 */ 857 public SortedMap<String, Digitizer> getDigitizers() 858 { 859 SortedMap<String, Digitizer> map = new TreeMap<String, Digitizer>(); 860 861 map.put(samplerA.getName(), samplerA); 862 map.put(samplerB.getName(), samplerB); 863 map.put(samplerC.getName(), samplerC); 864 map.put(samplerD.getName(), samplerD); 865 866 return map; 867 } 868 869 /* (non-Javadoc) 870 * @see AntennaElectronics#configureFrom(AntennaElectronicsConfiguration) 871 */ 872 public boolean configureFrom(AntennaElectronicsConfiguration configuration) 873 { 874 boolean success = true; 875 876 configurationProblems.clear(); 877 878 //TODO reject if config.telescope != EVLA 879 880 configureFor(configuration.getBands()); 881 882 success &= configureLocOscsFrom(configuration.getLoTunings()); 883 success &= configureDigitizersFrom(configuration.getBitsPerSample()); 884 success &= configureXfersFrom(configuration.getTransferSwitchPositions()); 885 success &= configureSwitchesFrom(configuration.getSwitchPositions()); 886 887 return success; 888 } 889 890 /** Helps configureFrom(AntennaElectronicsConfiguration). */ 891 private boolean configureLocOscsFrom(SortedMap<String, Frequency> loCfg) 892 { 893 boolean success = true; 894 895 SortedMap<String, LocalOscillator> loMap = getLocalOscillators(); 896 897 for (String loName : loCfg.keySet()) 898 { 899 LocalOscillator lo = loMap.get(loName); 900 if (lo != null) 901 { 902 lo.tuneTo(loCfg.get(loName)); 903 } 904 else 905 { 906 success = false; 907 configurationProblems.add("EVLA electronics has no LO named '" + 908 loName + "'."); 909 } 910 } 911 912 return success; 913 } 914 915 /** Helps configureFrom(AntennaElectronicsConfiguration). */ 916 private boolean configureDigitizersFrom(Map<String, Integer> digCfg) 917 { 918 boolean success = true; 919 920 SortedMap<String, Digitizer> digMap = getDigitizers(); 921 922 for (String digName : digCfg.keySet()) 923 { 924 Digitizer dig = digMap.get(digName); 925 if (dig != null) 926 { 927 dig.setBitsPerSample(digCfg.get(digName)); 928 } 929 else 930 { 931 success = false; 932 configurationProblems.add("EVLA electronics has no digitizer named '" + 933 digName + "'."); 934 } 935 } 936 937 return success; 938 } 939 940 /** Helps configureFrom(AntennaElectronicsConfiguration). */ 941 private boolean configureXfersFrom(SortedMap<String, String> xferCfg) 942 { 943 boolean success = true; 944 945 SortedMap<String, SignalTransferSwitch> xferMap = getTransferSwitches(); 946 947 for (String xferName : xferCfg.keySet()) 948 { 949 SignalTransferSwitch xs = xferMap.get(xferName); 950 if (xs != null) 951 { 952 String orientation = xferCfg.get(xferName); 953 954 if ("clockwise".equalsIgnoreCase(orientation)) 955 { 956 xs.setToClockwiseOutputs(); 957 } 958 else if ("counterclockwise".equalsIgnoreCase(orientation)) 959 { 960 xs.setToCounterclockwiseOutputs(); 961 } 962 else 963 { 964 success = false; 965 configurationProblems.add( 966 "Cannot set switch '" + xferName + "' to orientation of '" + 967 orientation + 968 "'. Valid values are 'clockwise' and 'counterclockwise'."); 969 } 970 } 971 else 972 { 973 success = false; 974 configurationProblems.add( 975 "EVLA electronics has no transfer switch named '" + xferName + "'."); 976 } 977 } 978 979 return success; 980 } 981 982 /** Helps configureFrom(AntennaElectronicsConfiguration). */ 983 private boolean configureSwitchesFrom(SortedMap<String, Map<String, String>> switchCfg) 984 { 985 boolean success = true; 986 987 SortedMap<String, SignalSwitch> switchMap = getSwitches(); 988 989 for (String switchName : switchCfg.keySet()) 990 { 991 SignalSwitch ss = switchMap.get(switchName); 992 if (ss != null) 993 { 994 Map<String, String> poleCfg = switchCfg.get(switchName); 995 996 if (poleCfg.containsKey("input")) 997 ss.selectInput(poleCfg.get("input")); 998 999 if (poleCfg.containsKey("output")) 1000 ss.selectOutput(poleCfg.get("output")); 1001 } 1002 else 1003 { 1004 success = false; 1005 configurationProblems.add("EVLA electronics has no switch named '" + 1006 switchName + "'."); 1007 } 1008 } 1009 return success; 1010 } 1011 1012 /* (non-Javadoc) 1013 * @see edu.nrao.sss.model.resource.AntennaElectronics#getConfiguration() 1014 */ 1015 public AntennaElectronicsConfiguration getConfiguration() 1016 { 1017 AntennaElectronicsConfiguration config = 1018 new AntennaElectronicsConfiguration(TelescopeType.EVLA); 1019 1020 //Receiver bands 1021 config.getBands().add(currentFrontEnd.getBand()); 1022 1023 //Local oscillators 1024 SortedMap<String, LocalOscillator> loSrcMap = getLocalOscillators(); 1025 Map<String, Frequency> loDestMap = config.getLoTunings(); 1026 for (LocalOscillator lo : loSrcMap.values()) 1027 loDestMap.put(lo.getName(), lo.getCurrentTuning()); 1028 1029 //Bits per sample 1030 SortedMap<String, Digitizer> digSrcMap = getDigitizers(); 1031 Map<String, Integer> digDestMap = config.getBitsPerSample(); 1032 for (Digitizer d : digSrcMap.values()) 1033 digDestMap.put(d.getName(), d.getBitsPerSample()); 1034 1035 //Transfer switches 1036 SortedMap<String, SignalTransferSwitch> xferSrcMap = getTransferSwitches(); 1037 Map<String, String> xferDestMap = config.getTransferSwitchPositions(); 1038 for (SignalTransferSwitch xs : xferSrcMap.values()) 1039 xferDestMap.put(xs.getName(), xferSwitchSetting(xs.isSetToClockwise())); 1040 1041 //Plain switches 1042 SortedMap<String, SignalSwitch> switchSrcMap = getSwitches(); 1043 Map<String, Map<String, String>> switchDestMap = config.getSwitchPositions(); 1044 for (SignalSwitch ss : switchSrcMap.values()) 1045 switchDestMap.put(ss.getName(), switchSetting(ss)); 1046 1047 return config; 1048 } 1049 1050 //Helps getConfiguration() 1051 private String xferSwitchSetting(boolean isClockwise) 1052 { 1053 return isClockwise ? "clockwise" : "counterclockwise"; 1054 } 1055 1056 //Helps getConfiguration() 1057 private Map<String, String> switchSetting(SignalSwitch s) 1058 { 1059 Map<String, String> map = new HashMap<String, String>(); 1060 1061 map.put("input", s.getNameOfSelectedInput()); 1062 map.put("output", s.getNameOfSelectedOutput()); 1063 1064 return map; 1065 } 1066 1067 public void submitTuningPlan(Map<ReceiverBand, Map<String, Frequency>> plans) 1068 { 1069 tuningPlans.putAll(plans); 1070 } 1071 1072 public void submitTuningPlan(ReceiverBand band, Map<String, Frequency> plan) 1073 { 1074 tuningPlans.put(band, plan); 1075 } 1076 1077 private void tuneLocOscsFor(ReceiverBand band) 1078 { 1079 Map<String, Frequency> plan = tuningPlans.get(band); 1080 1081 if (plan == null) 1082 { 1083 if (DEFAULT_TUNING_PLANS == null) 1084 DEFAULT_TUNING_PLANS = TelescopeType.EVLA.getTuningPlan(); 1085 1086 plan = DEFAULT_TUNING_PLANS.get(band); 1087 } 1088 1089 if (plan != null) 1090 { 1091 SortedMap<String, LocalOscillator> locOscMap = 1092 getLocalOscillators(); 1093 1094 for (String loName : plan.keySet()) 1095 { 1096 locOscMap.get(loName).tuneTo(plan.get(loName)); 1097 } 1098 } 1099 } 1100 1101 //============================================================================ 1102 // QUERIES 1103 //============================================================================ 1104 1105 /* (non-Javadoc) 1106 * @see edu.nrao.sss.model.resource.AntennaElectronics#getActiveReceivers() 1107 */ 1108 public SortedSet<ReceiverBand> getActiveReceivers() 1109 { 1110 //TODO update when we start handling multiple receivers 1111 SortedSet<ReceiverBand> active = new TreeSet<ReceiverBand>(); 1112 active.add(currentFrontEnd.getBand()); 1113 return active; 1114 } 1115 1116 /* (non-Javadoc) 1117 * @see edu.nrao.sss.model.resource.AntennaElectronics#getActiveFrontEnds() 1118 */ 1119 public SortedSet<AntennaFrontEnd> getActiveFrontEnds() 1120 { 1121 //TODO update when we start handling multiple receivers 1122 SortedSet<AntennaFrontEnd> active = new TreeSet<AntennaFrontEnd>(); 1123 active.add(currentFrontEnd); 1124 return active; 1125 } 1126 1127 /* (non-Javadoc) 1128 * @see edu.nrao.sss.model.resource.AntennaElectronics#getConfigurationProblems() 1129 */ 1130 public List<String> getConfigurationProblems() 1131 { 1132 return new ArrayList<String>(configurationProblems); 1133 } 1134 1135 //============================================================================ 1136 // EVLA-ONLY METHODS - SETTING QUANTIZATION 1137 //============================================================================ 1138 1139 /** 1140 * Sets the quantization to {@code bits} for the given IF. 1141 * This is a convenience method that sets several switches into the proper 1142 * positions for the type of output requested for the given IF. 1143 * 1144 * @param ifCode 1145 * a single letter, case insensitive, code for one of the intermediate 1146 * frequency singles of the EVLA antennas. The following list illustrates 1147 * what happens when a set of signals in 3-bit mode are changed to 8-bits: 1148 * <ul> 1149 * <li>'A' results in the replacement of A1 & C1 with A0.</li> 1150 * <li>'B' results in the replacement of B1 & D1 with B0.</li> 1151 * <li>'C' results in the replacement of A2, C1, & C2 with C0.</li> 1152 * <li>'D' results in the replacement of B2, D1, & D2 with D0.</li> 1153 * </ul> 1154 * If this value is not in the range 'A'-'D' then this method will do 1155 * nothing. 1156 * 1157 * @param bits 1158 * the only legal values are <tt>3</tt> and <tt>8</tt>, however this method 1159 * will accept any integer. If the value is less than 6, 3 will be used, 1160 * otherwise 8 will be used. 1161 * 1162 * @since 2008-10-20 1163 * 1164 * @see #setQuantization(int, int, int, int) 1165 */ 1166 public void setQuantization(char ifCode, int bits) 1167 { 1168 D301 dts = null; 1169 T304 t304 = null; 1170 1171 switch (Character.toUpperCase(ifCode)) 1172 { 1173 case 'A': t304 = downConverterA; dts = samplerA; break; 1174 case 'B': t304 = downConverterB; dts = samplerB; break; 1175 case 'C': t304 = downConverterC; dts = samplerC; break; 1176 case 'D': t304 = downConverterD; dts = samplerD; break; 1177 1178 default: return; 1179 } 1180 1181 t304.configureForWidestOutput(bits < 6); 1182 dts.setBitsPerSample(bits); 1183 } 1184 1185 /** 1186 * Sets the quantization levels of all IFs at once. 1187 * <p> 1188 * For all parameters 1189 * the only legal values are <tt>3</tt> and <tt>8</tt>, however this method 1190 * will accept any integer. If the value is less than 6, 3 will be used, 1191 * otherwise 8 will be used.</p> 1192 * 1193 * @param ifA the number of bits for the 'A' IF. 1194 * @param ifB the number of bits for the 'B' IF. 1195 * @param ifC the number of bits for the 'C' IF. 1196 * @param ifD the number of bits for the 'D' IF. 1197 * 1198 * @since 2008-10-23 1199 */ 1200 public void setQuantization(int ifA, int ifB, int ifC, int ifD) 1201 { 1202 downConverterA.configureForWidestOutput(ifA < 6); 1203 downConverterB.configureForWidestOutput(ifB < 6); 1204 downConverterC.configureForWidestOutput(ifC < 6); 1205 downConverterD.configureForWidestOutput(ifD < 6); 1206 1207 samplerA.setBitsPerSample(ifA); 1208 samplerB.setBitsPerSample(ifB); 1209 samplerC.setBitsPerSample(ifC); 1210 samplerD.setBitsPerSample(ifD); 1211 } 1212 1213 //============================================================================ 1214 // EVLA-ONLY METHODS - TUNING TO SKY FREQUENCIES 1215 //============================================================================ 1216 // 2008-10-24 DMH: 1217 // 1218 // Our first pass at automated tuning (as opposed to setting LO frequencies 1219 // and switch positions manually) is to use a group of tuners that have 1220 // been customized by receiver band and that have some "insider knowledge" 1221 // about the structure of these electronics. This was done because it was 1222 // fast and easy to do. However, it means that should these electronics 1223 // be changed, one or more of the tuners may also need to be changed. That 1224 // is not good design. Our desire is to craft a second generation tuner 1225 // that is generalized to where it can inspect the targeted electronics 1226 // and deduce which LOs and switches to manipulate and how to set them. 1227 1228 private final Map<ReceiverBand, EvlaTuner> TUNERS = 1229 new HashMap<ReceiverBand, EvlaTuner>(); 1230 1231 private void initTuners() 1232 { 1233 EvlaTuner lsc = new EvlaTunerLSC(this); 1234 EvlaTuner ux = new EvlaTunerUX(this); 1235 1236 TUNERS.put(ReceiverBand.EVLA_4, null); 1237 TUNERS.put(ReceiverBand.EVLA_P, null); 1238 TUNERS.put(ReceiverBand.EVLA_L, lsc); 1239 TUNERS.put(ReceiverBand.EVLA_S, lsc); 1240 TUNERS.put(ReceiverBand.EVLA_C, lsc); 1241 TUNERS.put(ReceiverBand.EVLA_X, new EvlaTunerDirect(this)); 1242 TUNERS.put(ReceiverBand.EVLA_Ku, new EvlaTunerKu(this)); 1243 TUNERS.put(ReceiverBand.EVLA_K, ux); 1244 TUNERS.put(ReceiverBand.EVLA_Ka, ux); 1245 TUNERS.put(ReceiverBand.EVLA_Q, ux); 1246 } 1247 1248 /** 1249 * Attempts to configure the EVLA antenna electronics to receive the given 1250 * central sky frequencies. 1251 * 1252 * @param centerFreq3Bit1 the central sky frequency of a 2.048GHz, 3-bit, signal. 1253 * @param centerFreq3bit2 the central sky frequency of a 2.048GHz, 3-bit, signal. 1254 * @param centerFreq3Bit3 the central sky frequency of a 2.048GHz, 3-bit, signal. 1255 * @param centerFreq3bit4 the central sky frequency of a 2.048GHz, 3-bit, signal. 1256 * 1257 * @since 2008-10-24 1258 */ 1259 public void tuneTo(Frequency centerFreq3Bit1, Frequency centerFreq3bit2, 1260 Frequency centerFreq3Bit3, Frequency centerFreq3bit4) 1261 { 1262 EvlaTuner tuner = TUNERS.get(currentFrontEnd.getBand()); 1263 1264 if (tuner != null) 1265 tuner.tuneTo(centerFreq3Bit1, centerFreq3bit2, centerFreq3Bit3, centerFreq3bit4); 1266 } 1267 1268 /** 1269 * Attempts to configure the EVLA antenna electronics to receive the given 1270 * central sky frequencies. 1271 * 1272 * @param centerFreq8Bit1 the central sky frequency of a 1.024GHz, 8-bit, signal. 1273 * @param centerFreq8bit2 the central sky frequency of a 1.024GHz, 8-bit, signal. 1274 * 1275 * @since 2008-10-24 1276 */ 1277 public void tuneTo(Frequency centerFreq8Bit1, Frequency centerFreq8bit2) 1278 { 1279 EvlaTuner tuner = TUNERS.get(currentFrontEnd.getBand()); 1280 1281 if (tuner != null) 1282 tuner.tuneTo(centerFreq8Bit1, centerFreq8bit2); 1283 } 1284 1285 /** 1286 * Attempts to configure the EVLA antenna electronics to receive the given 1287 * central sky frequencies. 1288 * 1289 * @param centerFreq3Bit1 the central sky frequency of a 2.048GHz, 3-bit, signal. 1290 * @param centerFreq3bit2 the central sky frequency of a 2.048GHz, 3-bit, signal. 1291 * @param centerFreq8Bit the central sky frequency of a 1.024GHz, 8-bit, signal. 1292 * 1293 * @since 2008-10-24 1294 */ 1295 public void tuneTo(Frequency centerFreq3Bit1, Frequency centerFreq3bit2, 1296 Frequency centerFreq8Bit) 1297 { 1298 EvlaTuner tuner = TUNERS.get(currentFrontEnd.getBand()); 1299 1300 if (tuner != null) 1301 tuner.tuneTo(centerFreq3Bit1, centerFreq3bit2, centerFreq8Bit); 1302 } 1303 1304 //============================================================================ 1305 // EVLA-ONLY METHODS - MISC 1306 //============================================================================ 1307 1308 /** 1309 * Returns the T303 UX converter held by these electronics. Clients should 1310 * only query, not set, properties of the returned object. 1311 */ 1312 T303 getUxConverter() { return uxConverter; } 1313 1314 /** 1315 * Returns the T304 down converter held by these electronics. Clients should 1316 * only query, not set, properties of the returned object. 1317 */ 1318 T304 getDownConverter(char ifCode) 1319 { 1320 switch (Character.toUpperCase(ifCode)) 1321 { 1322 case 'A': return downConverterA; 1323 case 'B': return downConverterB; 1324 case 'C': return downConverterC; 1325 case 'D': return downConverterD; 1326 1327 default: return null; 1328 } 1329 } 1330 1331 //============================================================================ 1332 // 1333 //============================================================================ 1334 1335 /** 1336 * Returns a copy of this electronics. 1337 * <p> 1338 * If anything goes wrong during the cloning procedure, 1339 * a {@code RuntimeException} will be thrown.</p> 1340 */ 1341 @Override 1342 public EvlaAntennaElectronics clone() 1343 { 1344 EvlaAntennaElectronics clone = null; 1345 1346 try 1347 { 1348 //This line takes care of the primitive & immutable fields properly 1349 clone = (EvlaAntennaElectronics)super.clone(); 1350 1351 //This code is a little different than our usual cloning code. 1352 //We rely on the construct method to create all new components and 1353 //stitch them together. We then configure the clone with a configuration 1354 //from this instance. 1355 clone.construct(); 1356 clone.configureFrom(this.getConfiguration()); 1357 } 1358 catch (Exception ex) 1359 { 1360 throw new RuntimeException(ex); 1361 } 1362 1363 return clone; 1364 } 1365 1366 /** Returns <i>true</i> if {@code o} is equal to this electronics. */ 1367 @Override 1368 public boolean equals(Object o) 1369 { 1370 //Quick exit if o is this 1371 if (o == this) 1372 return true; 1373 1374 //Quick exit if o is null 1375 if (o == null) 1376 return false; 1377 1378 //Quick exit if classes are different 1379 if (!o.getClass().equals(this.getClass())) 1380 return false; 1381 1382 //A safe cast if we got this far 1383 EvlaAntennaElectronics other = (EvlaAntennaElectronics)o; 1384 1385 return other.getConfiguration().equals(this.getConfiguration()); 1386 } 1387 1388 /** Returns a hash code value for this electronics. */ 1389 @Override 1390 public int hashCode() 1391 { 1392 //Taken from the Effective Java book by Joshua Bloch. 1393 //The constants 17 & 37 are arbitrary & carry no meaning. 1394 int result = 17; 1395 1396 //You MUST keep this method in sync w/ the equals method 1397 1398 result = 37 * result + getConfiguration().hashCode(); 1399 1400 return result; 1401 } 1402 1403 //============================================================================ 1404 // 1405 //============================================================================ 1406 /* 1407 public static void main(String[] args) throws Exception 1408 { 1409 EvlaAntennaElectronics evla = new EvlaAntennaElectronics(); 1410 1411 evla.configureFor(ReceiverBand.EVLA_K); 1412 1413 System.out.println("INPUT: " + evla.currentFrontEnd.getBand().getDisplayName() + 1414 ", " + evla.currentFrontEnd.getBand().getFrequencyRange() + "\n"); 1415 1416 System.out.println("LO TUNINGS"); 1417 SortedMap<String, LocalOscillator> lo = evla.getLocalOscillators(); 1418 for (String loName : lo.keySet()) 1419 { 1420 System.out.println(loName + ": " + lo.get(loName).getCurrentTuning()); 1421 } 1422 1423 System.out.println("\nOUTPUT SIGNALS"); 1424 1425 for (DigitalSignal signal : evla.execute()) 1426 { 1427 System.out.println(signal); 1428 } 1429 1430 System.out.println("OUTPUT SIGNAL PAIRS"); 1431 1432 for (List<DigitalSignal> pair : evla.getSignalPairs()) 1433 { 1434 System.out.print(" PAIR: "); 1435 for (DigitalSignal member : pair) 1436 if (member == null) 1437 System.out.print("NULL "); 1438 else 1439 System.out.print(member.getName() + ' '); 1440 System.out.println(); 1441 } 1442 1443 System.out.println("\nANTENNA ELECTRONICS CONFIGURATION"); 1444 1445 AntennaElectronicsConfiguration config = evla.getConfiguration(); 1446 System.out.println(config.getBands()); 1447 System.out.println(config.getLoTunings()); 1448 System.out.println(config.getBitsPerSample()); 1449 System.out.println(config.getTransferSwitchPositions()); 1450 System.out.println(config.getSwitchPositions()); 1451 1452 System.out.println(); 1453 System.out.println("ANTENNA ELECTRONICS CONFIGURATION - XML"); 1454 System.out.println(config.toXml()); 1455 } 1456 */ 1457 /* 1458 public static void main(String[] args) throws Exception 1459 { 1460 EvlaAntennaElectronics evla = new EvlaAntennaElectronics(); 1461 1462 evla.configureFor(ReceiverBand.EVLA_Ka); 1463 1464 System.out.println("INPUT: " + evla.currentFrontEnd.getBand().getDisplayName() + 1465 ", " + evla.currentFrontEnd.getBand().getFrequencyRange() + "\n"); 1466 1467 System.out.println("LO TUNINGS"); 1468 SortedMap<String, LocalOscillator> lo = evla.getLocalOscillators(); 1469 for (String loName : lo.keySet()) 1470 { 1471 System.out.println(loName + ": " + lo.get(loName).getCurrentTuning()); 1472 } 1473 1474 System.out.println("\nOUTPUT SIGNALS"); 1475 1476 for (DigitalSignal signal : evla.execute()) 1477 { 1478 System.out.println(signal.getName() + ": " + signal.getProxiedRange()); 1479 } 1480 1481 lo.get("L301-1").tuneTo(new Frequency("12.4")); 1482 1483 System.out.println("\nLO TUNINGS"); 1484 for (String loName : lo.keySet()) 1485 { 1486 System.out.println(loName + ": " + lo.get(loName).getCurrentTuning()); 1487 } 1488 1489 System.out.println("\nOUTPUT SIGNALS"); 1490 1491 for (DigitalSignal signal : evla.execute()) 1492 { 1493 System.out.println(signal.getName() + ": " + signal.getProxiedRange()); 1494 } 1495 } 1496 */ 1497 /* 1498 public static void main(String[] args) throws Exception 1499 { 1500 //Debugging 2008-04-07 to see why a null LO signal does not act 1501 //like an LO signal of zero hertz. Should lead to RF=receiver range 1502 //and IF=RF. Instead, am seeing RF=0.0-0.0, IF=2.048GHz-2.048GHz. 1503 EvlaAntennaElectronics evla = new EvlaAntennaElectronics(); 1504 1505 evla.configureFor(ReceiverBand.EVLA_L); 1506 evla.execute(); 1507 1508 evla.getSwitches().get("S8").selectOutput("off"); 1509 evla.execute(); 1510 } 1511 */ 1512 }