001 package edu.nrao.sss.model.resource.evla; 002 003 import java.math.BigDecimal; 004 import java.util.ArrayList; 005 import java.util.GregorianCalendar; 006 import java.util.List; 007 import java.util.Random; 008 009 import static edu.nrao.sss.astronomy.PolarizationType.L; 010 import static edu.nrao.sss.astronomy.PolarizationType.R; 011 import static edu.nrao.sss.measure.FrequencyUnits.HERTZ; 012 import static edu.nrao.sss.measure.FrequencyUnits.KILOHERTZ; 013 import static edu.nrao.sss.measure.FrequencyUnits.MEGAHERTZ; 014 015 import ca.nrc.widar.jaxb.vci.AutoCorrAlgorithmType; 016 import ca.nrc.widar.jaxb.vci.AutoCorrMode; 017 import ca.nrc.widar.jaxb.vci.AutoCorrSubset; 018 import ca.nrc.widar.jaxb.vci.BaseBand; 019 import ca.nrc.widar.jaxb.vci.BlbProdIntegration; 020 import ca.nrc.widar.jaxb.vci.BurstMode; 021 import ca.nrc.widar.jaxb.vci.BurstModeType; 022 import ca.nrc.widar.jaxb.vci.EnableDisableType; 023 import ca.nrc.widar.jaxb.vci.OnOffType; 024 import ca.nrc.widar.jaxb.vci.PhasedArray; 025 import ca.nrc.widar.jaxb.vci.PulsarBinning; 026 import ca.nrc.widar.jaxb.vci.PulsarGating; 027 import ca.nrc.widar.jaxb.vci.RadarMode; 028 import ca.nrc.widar.jaxb.vci.StartFromType; 029 import ca.nrc.widar.jaxb.vci.ToneExtraction; 030 import ca.nrc.widar.jaxb.vci.WbcPolProduct; 031 import ca.nrc.widar.jaxb.vci.WideBandCorrelator; 032 import edu.nrao.sss.astronomy.PolarizationType; 033 import edu.nrao.sss.astronomy.StokesParameter; 034 import edu.nrao.sss.electronics.DigitalSignal; 035 import edu.nrao.sss.electronics.LocalOscillator; 036 import edu.nrao.sss.electronics.SignalMixer; 037 import edu.nrao.sss.measure.Frequency; 038 import edu.nrao.sss.measure.FrequencyRange; 039 import edu.nrao.sss.measure.TimeDuration; 040 import edu.nrao.sss.measure.TimeUnits; 041 import edu.nrao.sss.model.resource.AntennaElectronics; 042 import edu.nrao.sss.model.resource.CorrelatorBaseband; 043 import edu.nrao.sss.model.resource.CorrelatorConfiguration; 044 import edu.nrao.sss.model.resource.CorrelatorName; 045 import edu.nrao.sss.model.resource.ReceiverBand; 046 import edu.nrao.sss.model.resource.TelescopeType; 047 import edu.nrao.sss.util.EnumerationUtility; 048 049 /** 050 * Helper for test classes; builds widar components. 051 * <p> 052 * <b>Version Info:</b> 053 * <table style="margin-left:2em"> 054 * <tr><td>$Revision: 2200 $</td></tr> 055 * <tr><td>$Date: 2009-04-15 16:00:47 -0600 (Wed, 15 Apr 2009) $</td></tr> 056 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 057 * </table></p> 058 * 059 * @author David M. Harland 060 * @since 2008-12-09 061 */ 062 public class WidarBuilder 063 { 064 private static final EnumerationUtility ENUM_UTIL = 065 EnumerationUtility.getSharedInstance(); 066 067 private Random random = new Random(System.currentTimeMillis()); 068 069 private SignalMixer signalMixer; 070 private LocalOscillator locOsc; 071 072 /** 073 * 074 */ 075 public WidarBuilder() 076 { 077 signalMixer = SignalMixer.makeSubtractiveMixer("dummy"); 078 locOsc = new LocalOscillator(new FrequencyRange(new Frequency("0.0"), 079 new Frequency("99.0"))); 080 signalMixer.getLocalOscillatorInputPipe().connectInputTo(locOsc); 081 } 082 083 //============================================================================ 084 // CORRELATOR 085 //============================================================================ 086 087 /** 088 * 089 */ 090 public EvlaWidarConfiguration makeCorrelator() 091 { 092 AntennaElectronics evla = new EvlaAntennaElectronics(); 093 094 EvlaWidarConfiguration widar = (EvlaWidarConfiguration) 095 CorrelatorConfiguration.makeFor(CorrelatorName.WIDAR, evla); 096 097 configure(widar); 098 099 return widar; 100 } 101 102 /** 103 * 104 */ 105 public void configure(EvlaWidarConfiguration widar) 106 { 107 //Configure for a particular receiver 108 ReceiverBand[] bands = new ReceiverBand[0]; 109 bands = TelescopeType.EVLA.getReceivers().toArray(bands); 110 AntennaElectronics evla = widar.getSignalSource(); 111 evla.configureFor(bands[random.nextInt(bands.length)]); 112 evla.execute(); 113 114 for (CorrelatorBaseband bb : widar.getBasebands()) 115 configure((WidarBaseband)bb); 116 } 117 118 //============================================================================ 119 // BASEBAND 120 //============================================================================ 121 122 /** 123 * 124 */ 125 public WidarBaseband makeBaseband() 126 { 127 return random.nextDouble() < 0.2 ? makeBasebandSinglet() : makeBasebandPair(); 128 } 129 130 /** 131 * 132 */ 133 public WidarBasebandPair makeBasebandPair() 134 { 135 DigitalSignal ds1 = makeDigitalSignal(); 136 PolarizationType polzn = ds1.getPolarization().equals(L) ? R : L; 137 DigitalSignal ds2 = (DigitalSignal)ds1.clone(polzn); 138 139 String ds1Name = ds1.getName(); 140 if (ds1Name.equals("A0")) ds2.appendToDevicePath(":C0"); 141 else if (ds1Name.equals("A1")) ds2.appendToDevicePath(":C1"); 142 else if (ds1Name.equals("C0")) ds2.appendToDevicePath(":A0"); 143 else if (ds1Name.equals("C1")) ds2.appendToDevicePath(":A1"); 144 145 ds1 = mixDown(ds1); 146 ds2 = mixDown(ds2); 147 148 WidarBasebandPair bbp = new WidarBasebandPair(ds1, ds2); 149 150 configure(bbp); 151 152 return bbp; 153 } 154 155 /** 156 * 157 */ 158 public WidarBasebandSinglet makeBasebandSinglet() 159 { 160 DigitalSignal ds = mixDown(makeDigitalSignal()); 161 162 WidarBasebandSinglet bb = new WidarBasebandSinglet(ds); 163 164 configure(bb); 165 166 return bb; 167 } 168 169 /** 170 * 171 */ 172 public void configure(WidarBaseband bb) 173 { 174 bb.setSinglePhaseCenter(random.nextDouble() < 0.8); 175 176 //Delay models lifespan 177 if (random.nextBoolean()) 178 { 179 TimeDuration delayModLife = bb.overrideDefaultDelayModelLifespan(true); 180 int seconds = 1 + random.nextInt(9); 181 delayModLife.set(""+seconds+"s"); 182 } 183 184 //Pulsar gating 185 if (random.nextDouble() < 0.2) 186 { 187 configure(bb.overrideDefaultPulsarGating(true)); 188 } 189 190 //Wide band correlation 191 if (random.nextDouble() < 0.2) 192 { 193 configure(bb.overrideDefaultWideBandCorrelator(true), bb); 194 } 195 196 int sbCount = random.nextInt(17); //0..16 197 for (int i=1; i <= sbCount; i++) 198 { 199 WidarSubband sb = bb.makeNewSubband(); 200 bb.addSubband(sb); 201 configure(sb); 202 } 203 } 204 205 //============================================================================ 206 // SUBBAND 207 //============================================================================ 208 209 /** 210 * Creates a new subband whose values were assigned somewhat randomly. 211 * The newly created subband may belong to a baseband pair, baseband singlet, 212 * or to no baseband at all. 213 */ 214 public WidarSubband makeSubband() 215 { 216 WidarSubband sb = new WidarSubband(); 217 218 double rand = random.nextDouble(); 219 220 if (rand < 0.9) 221 { 222 WidarBaseband bb = makeBaseband(); 223 bb.removeAllSubbands(); 224 bb.addSubband(sb); 225 } 226 227 configure(sb); 228 229 return sb; 230 } 231 232 /** 233 * 234 */ 235 public void configure(WidarSubband sb) 236 { 237 boolean haveBaseband = (sb.getBaseband() != null); 238 239 if (random.nextDouble() < 0.5) 240 sb.setUseStage2Mixer(random.nextBoolean()); 241 242 int rqBits = 4; 243 if (haveBaseband) 244 { 245 int iqBits = sb.getBaseband().getInitialQuantization(); 246 boolean unlikely = (random.nextDouble() < 0.2); 247 248 //Bias towards 8->7 and 3->4 249 if (iqBits == 3) rqBits = unlikely ? 7 : 4; 250 else rqBits = unlikely ? 4 : 7; 251 252 sb.setRequantization(rqBits); 253 } 254 255 setFreqRangeFor(sb, haveBaseband); 256 257 configure((WidarCorrelationProductGroup)sb.addNewCorrelationProductGroup()); 258 259 sb.setMixerPhaseErrorCorr(sb.getUseStage2Mixer() ? random.nextBoolean() : false); 260 261 if (random.nextDouble() < 0.1) sb.setSignalToNoiseRatio(random.nextInt(101)); 262 if (random.nextDouble() < 0.1) sb.setPulsarGatingPhase(random.nextInt(101)); 263 264 if (random.nextBoolean()) configure(sb.overrideDefaultAutoCorrMode (true)); 265 if (random.nextBoolean()) configure(sb.overrideDefaultBurstMode (true)); 266 if (random.nextBoolean()) configure(sb.overrideDefaultPhasedArray (true)); 267 if (random.nextBoolean()) configure(sb.overrideDefaultPulsarBinning (true)); 268 if (random.nextBoolean()) configure(sb.overrideDefaultRadarMode (true)); 269 if (random.nextBoolean()) configure(sb.overrideDefaultToneExtraction(true)); 270 } 271 272 /** 273 * 274 */ 275 private DigitalSignal makeDigitalSignal() 276 { 277 int quant = random.nextBoolean() ? 3 : 8; 278 String bw = (quant == 3) ? "2.048" : "1.024"; 279 String rate = (quant == 3) ? "4.096" : "2.048"; 280 281 PolarizationType polzn = random.nextBoolean() ? L : R; 282 283 int lowFreqMHz = random.nextInt(47952); 284 285 Frequency bandwidth = new Frequency(bw); 286 Frequency low = new Frequency(new BigDecimal(lowFreqMHz), MEGAHERTZ); 287 Frequency high = low.clone().add(bandwidth); 288 289 FrequencyRange range = new FrequencyRange(low, high); 290 291 DigitalSignal ds = new DigitalSignal(range, polzn, new Frequency(rate), quant); 292 293 String c1 = polzn.equals(R) ? "A" : "C"; 294 String c2 = (quant == 3) ? "1" : "0"; 295 ds.appendToDevicePath(":" + c1 + c2); 296 297 return ds; 298 } 299 300 private DigitalSignal mixDown(DigitalSignal ds) 301 { 302 DigitalSignal mixed; 303 304 FrequencyRange sigRange = ds.getCurrentRange(); 305 Frequency oldCenter = sigRange.getCenterFrequency(); 306 Frequency newCenter = sigRange.getWidth().divideBy("2.0"); 307 308 locOsc.tuneTo(oldCenter.add(newCenter)); 309 mixed = (DigitalSignal)signalMixer.mix(ds); 310 311 if (random.nextBoolean()) //mix again to reverse direction of frequencies 312 { 313 locOsc.tuneTo(sigRange.getWidth()); 314 mixed = (DigitalSignal)signalMixer.mix(mixed); 315 } 316 317 return mixed; 318 } 319 320 private void setFreqRangeFor(WidarSubband sb, boolean haveBaseband) 321 { 322 //Bandwidth 323 double minHz = sb.getMinimumBandwidth().toUnits(HERTZ).doubleValue(); 324 double maxHz = sb.getMaximumBandwidth().toUnits(HERTZ).doubleValue(); 325 326 double hertz = minHz + (maxHz - minHz) * random.nextDouble(); 327 328 sb.setBandwidth(new Frequency(BigDecimal.valueOf(hertz), HERTZ)); 329 330 //Center frequency 331 Frequency center; 332 if (!haveBaseband) 333 { 334 center = sb.getBandwidth().divideBy("2.0"); 335 } 336 else 337 { 338 double kHz = sb.getBaseband().getBandwidth().toUnits(KILOHERTZ).doubleValue(); 339 kHz *= random.nextDouble(); 340 kHz = Math.rint(kHz); 341 center = new Frequency(BigDecimal.valueOf(kHz), KILOHERTZ); 342 } 343 sb.setCentralFrequency(center.normalize()); 344 } 345 346 //============================================================================ 347 // CORRELATION PRODUCTS 348 //============================================================================ 349 350 /** 351 * @param group 352 */ 353 public void configure(WidarCorrelationProductGroup group) 354 { 355 group.setRecirculationFactor(makeRecircFactor()); 356 357 configure(group.getIntegrationTime()); 358 359 if (random.nextDouble() < 0.2) 360 configure(group.overrideDefaultAutoCorrSubset(true)); 361 362 //Add polarization products 363 group.removeAllPolarizationProducts(); 364 if (group.getAllowablePolarizationProducts().size() > 0) 365 { 366 boolean success = false; 367 while (!success) 368 for (StokesParameter sp : makePolarizations()) 369 success |= group.addPolarizationProduct(sp); 370 } 371 372 //Allocate BLBPs 373 int minCount = group.getSubband().getRequantization() == 4 ? 1 : 4; 374 group.setBlbpCount(random.nextInt(5) + minCount); 375 } 376 377 public void configure(WbcPolProduct wpp, int id, int laggedId, int promptId) 378 { 379 wpp.setPpid(id); 380 wpp.setLaggedBBID(laggedId); 381 wpp.setPromptBBID(promptId); 382 383 if (random.nextBoolean()) 384 wpp.setIntegFactor(10 + random.nextInt(91)); 385 386 int mult = 1 + random.nextInt(64); 387 388 //TODO temp code due to min of 64 in VCI schema 389 if (mult == 1) mult = 2; 390 391 wpp.setSpectChannels(32 * mult); 392 } 393 394 /** 395 * Randomly sets the integration time. 396 * This method sometimes sets the individual components and 397 * sometimes sets the total time. Roughly once every 50 calls 398 * it sets the total time to its minimum. 399 */ 400 public void configure(WidarIntegrationTime wit) 401 { 402 double r = random.nextDouble(); 403 404 if (r < 0.02) 405 { 406 wit.setTotalIntegrationTime(wit.getMinimumTotalIntegrationTime()); 407 } 408 else if (r < 0.50) 409 { 410 BlbProdIntegration prodInt = new BlbProdIntegration(); 411 configure(prodInt); 412 413 wit.setMinimumHardwareIntegrationTime( 414 new TimeDuration(""+prodInt.getMinIntegTime(), TimeUnits.MICROSECOND)); 415 416 wit.setCorrelatorChipMultiplier (prodInt.getCcIntegFactor()); 417 wit.setLongTermAccumulatorMultiplier(prodInt.getLtaIntegFactor()); 418 wit.setBackEndMultiplier (prodInt.getCbeIntegFactor()); 419 } 420 else 421 { 422 double microSec = 1.0 + random.nextDouble() * 1e6 * 30.0; //30s max 423 wit.setTotalIntegrationTime(new TimeDuration(""+microSec, TimeUnits.MICROSECOND)); 424 } 425 } 426 427 private int makeRecircFactor() 428 { 429 //No recirc 1/2 the time 430 if (random.nextBoolean()) 431 return 1; 432 433 int power = random.nextInt(7) + 1; 434 435 return (int)Math.pow(2.0, power); 436 } 437 438 /** Returns a list of 1, 2, or 4 unique stokes params based on L & R polzns. */ 439 private List<StokesParameter> makePolarizations() 440 { 441 List<StokesParameter> polarizations = new ArrayList<StokesParameter>(); 442 443 //Do all 4 products half the time 444 if (random.nextBoolean()) 445 { 446 polarizations.add(StokesParameter.LL); 447 polarizations.add(StokesParameter.RR); 448 polarizations.add(StokesParameter.LR); 449 polarizations.add(StokesParameter.RL); 450 } 451 //Do 2 products 1/4 of the time 452 else if (random.nextBoolean()) 453 { 454 if (random.nextBoolean()) 455 { 456 polarizations.add(StokesParameter.LL); 457 polarizations.add(StokesParameter.RR); 458 } 459 else 460 { 461 polarizations.add(StokesParameter.LR); 462 polarizations.add(StokesParameter.RL); 463 } 464 } 465 //Do 1 product 1/4 of the time 466 else 467 { 468 polarizations.add(random.nextBoolean() ? StokesParameter.LL : StokesParameter.RR); 469 } 470 471 return polarizations; 472 } 473 474 //============================================================================ 475 // MISC 476 //============================================================================ 477 478 /** 479 * 480 */ 481 private void configure(AutoCorrMode acm) 482 { 483 acm.setStatus(ENUM_UTIL.getRandomValueFor(OnOffType.class)); 484 485 BlbProdIntegration prodInt = new BlbProdIntegration(); 486 configure(prodInt); 487 acm.setBlbProdIntegration(prodInt); 488 489 //Not ready to deal w/ BLBPs and BLBs yet 490 } 491 492 /** 493 * 494 */ 495 private void configure(AutoCorrSubset acs) 496 { 497 acs.setAlgorithm(ENUM_UTIL.getRandomValueFor(AutoCorrAlgorithmType.class)); 498 acs.setStartFrom(ENUM_UTIL.getRandomValueFor(StartFromType.class)); 499 acs.setDwellTime(2 + random.nextInt(18)); 500 } 501 502 /** 503 * 504 */ 505 private void configure(BlbProdIntegration prodInt) 506 { 507 //2.5 - 400.0 microSec 508 //prodInt.setMinIntegTime(397.5 * random.nextDouble() + 2.5); 509 //TODO: vci says 250 is max; need to confirm 510 prodInt.setMinIntegTime(247.5 * random.nextDouble() + 2.5); 511 prodInt.setCcIntegFactor (random.nextInt(29)+1); 512 prodInt.setLtaIntegFactor(random.nextInt(29)+1); 513 prodInt.setCbeIntegFactor(random.nextInt(29)+1); 514 prodInt.setRecirculation(makeRecircFactor()); 515 } 516 517 /** 518 * 519 */ 520 private void configure(BurstMode bm) 521 { 522 //Current time is fine 523 if (VciJaxbUtil.DTF != null) 524 bm.setEpoch(VciJaxbUtil.DTF.newXMLGregorianCalendar(new GregorianCalendar())); 525 526 if (random.nextDouble() < 0.8) 527 { 528 if (random.nextBoolean()) 529 { 530 bm.setMode(BurstModeType.CMIB_CONTROLLED); 531 bm.setSchedule("TBD"); 532 } 533 else 534 { 535 bm.setMode(BurstModeType.DUMPTRIG_CONTROLLED); 536 } 537 } 538 else 539 { 540 bm.setMode(BurstModeType.OFF); 541 } 542 543 bm.setDuration (random.nextInt(100) + 1); 544 bm.setBlankPeriod(random.nextInt(100) + 1); 545 } 546 547 /** 548 * 549 */ 550 private void configure(PhasedArray pa) 551 { 552 //TODO code me 553 } 554 555 /** 556 * 557 */ 558 private void configure(PulsarBinning pb) 559 { 560 //Not ready to deal w/ BLBPs and BLBs yet 561 562 //Current time is fine 563 if (VciJaxbUtil.DTF != null) 564 pb.setEpoch(VciJaxbUtil.DTF.newXMLGregorianCalendar(new GregorianCalendar())); 565 566 //Sometimes we'll omit, but if we won't include 2nd deriv w/out 1st 567 if (random.nextBoolean()) 568 { 569 pb.setFirstDerivative(random.nextInt(201) - 100); 570 if (random.nextBoolean()) 571 pb.setSecondDerivative(random.nextInt(201) - 100); 572 } 573 574 if (random.nextBoolean()) 575 pb.setNumBins(1000 + random.nextInt(3001)); 576 577 pb.setPeriod(1 + random.nextInt(100)); 578 579 pb.setStatus(ENUM_UTIL.getRandomValueFor(OnOffType.class)); 580 } 581 582 /** 583 * 584 */ 585 private void configure(PulsarGating pg) 586 { 587 //Current time is fine 588 if (VciJaxbUtil.DTF != null) 589 pg.setEpoch(VciJaxbUtil.DTF.newXMLGregorianCalendar(new GregorianCalendar())); 590 591 //Sometimes we'll omit, but if we won't include 2nd deriv w/out 1st 592 if (random.nextBoolean()) 593 { 594 pg.setFirstDerivative(random.nextInt(201) - 100); 595 if (random.nextBoolean()) 596 pg.setSecondDerivative(random.nextInt(201) - 100); 597 } 598 599 if (random.nextBoolean()) 600 pg.setGateWidth((double)random.nextInt(1001) / 1000.0); 601 602 pg.setPeriod((double)random.nextInt(10000) / 100.0); 603 604 //Status: usually we'll enable, sometimes disable, sometimes omit 605 double d = random.nextDouble(); 606 if (d < 0.1) 607 pg.setStatus(EnableDisableType.DISABLE); 608 else if (d < 0.9) 609 pg.setStatus(EnableDisableType.ENABLE); 610 //else leave at default 611 } 612 613 /** 614 * 615 */ 616 private void configure(RadarMode rm) 617 { 618 if (random.nextBoolean()) 619 { 620 rm.setStatus(OnOffType.ON); 621 rm.setDuration(1 + random.nextInt(100)); 622 } 623 else 624 { 625 rm.setStatus(OnOffType.OFF); 626 } 627 628 if (random.nextDouble() < 0.2) 629 rm.setDestination("http://some.random.org/radarMode/data/"); 630 } 631 632 /** 633 * 634 */ 635 private void configure(ToneExtraction te) 636 { 637 if (random.nextDouble() < 0.2) 638 te.setDestination("http://some.random.org/toneExtraction/data/"); 639 640 if (random.nextBoolean()) 641 te.setDwellTime(1 + random.nextInt(100)); 642 643 if (random.nextBoolean()) 644 te.setIntegFactor(10 + random.nextInt(991)); //10..1000 645 646 te.setNumTones(random.nextInt(33)); 647 648 te.setStatus(ENUM_UTIL.getRandomValueFor(EnableDisableType.class)); 649 } 650 651 /** 652 * 653 */ 654 private void configure(WideBandCorrelator wbc, WidarBaseband containingBB) 655 { 656 List<WbcPolProduct> products = wbc.getWbcPolProduct(); 657 products.clear(); 658 659 BaseBand vciBB = containingBB.toVci()[0]; 660 661 int idA = vciBB.getBbA(); 662 int idB = containingBB.isPair() ? vciBB.getBbB() : idA; 663 664 //VCI says 0..32 is valid number; we'll stick w/ lower # 665 int count = random.nextInt(5); //0..4 666 int id = 0; 667 668 while (++id <= count) 669 { 670 WbcPolProduct newProd = new WbcPolProduct(); 671 configure(newProd, id, idA, idB); 672 products.add(newProd); 673 } 674 } 675 676 //============================================================================ 677 // 678 //============================================================================ 679 /* 680 public static void main(String... args) throws Exception 681 { 682 WidarBuilder builder = new WidarBuilder(); 683 WidarBaseband bb = builder.makeBaseband(); 684 bb.toVci(); 685 } 686 */ 687 }