001 package edu.nrao.sss.model.resource.evla; 002 003 import java.io.Writer; 004 import java.math.BigDecimal; 005 import java.util.ArrayList; 006 import java.util.Arrays; 007 import java.util.List; 008 import java.util.SortedSet; 009 import java.util.TreeSet; 010 011 import javax.xml.bind.JAXBException; 012 import javax.xml.bind.annotation.XmlElement; 013 import javax.xml.bind.annotation.XmlElementWrapper; 014 import javax.xml.bind.annotation.XmlTransient; 015 import javax.xml.bind.annotation.XmlType; 016 017 import static ca.nrc.widar.jaxb.vci.UpperLowerType.LOWER; 018 import static ca.nrc.widar.jaxb.vci.UpperLowerType.UPPER; 019 import static ca.nrc.widar.jaxb.vci.YesNoType.NO; 020 import static ca.nrc.widar.jaxb.vci.YesNoType.YES; 021 022 import static edu.nrao.sss.measure.FrequencyUnits.HERTZ; 023 import static edu.nrao.sss.measure.FrequencyUnits.KILOHERTZ; 024 import static edu.nrao.sss.measure.FrequencyUnits.MEGAHERTZ; 025 import static edu.nrao.sss.measure.TimeUnits.SECOND; 026 027 import ca.nrc.widar.jaxb.vci.BaseBand; 028 import ca.nrc.widar.jaxb.vci.BbParams; 029 import ca.nrc.widar.jaxb.vci.InputStateCounts; 030 import ca.nrc.widar.jaxb.vci.PulsarGating; 031 import ca.nrc.widar.jaxb.vci.StbSourceType; 032 import ca.nrc.widar.jaxb.vci.SubBand; 033 import ca.nrc.widar.jaxb.vci.WideBandCorrelator; 034 035 import edu.nrao.sss.astronomy.PolarizationType; 036 import edu.nrao.sss.electronics.DigitalSignal; 037 import edu.nrao.sss.electronics.Signal; 038 import edu.nrao.sss.measure.Frequency; 039 import edu.nrao.sss.measure.FrequencyRange; 040 import edu.nrao.sss.measure.FrequencyUnits; 041 import edu.nrao.sss.measure.TimeDuration; 042 import edu.nrao.sss.model.resource.CorrelatorBasebandAbs; 043 import edu.nrao.sss.model.resource.CorrelatorConfiguration; 044 import edu.nrao.sss.model.resource.CorrelatorSubband; 045 import edu.nrao.sss.util.JaxbUtility; 046 047 /** 048 * Common parent for the WIDAR baseband singlet and pair classes. 049 * <p> 050 * <b>Version Info:</b> 051 * <table style="margin-left:2em"> 052 * <tr><td>$Revision: 2296 $</td></tr> 053 * <tr><td>$Date: 2009-05-12 14:50:22 -0600 (Tue, 12 May 2009) $</td></tr> 054 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 055 * </table></p> 056 * 057 * @author David M. Harland 058 * @since 2008-06-25 059 */ 060 @XmlType(propOrder={"delayModelLifespan","pulsarGating","singlePhaseCenter", 061 "wideBandCorrelator", "widarSubbands" 062 }) 063 public abstract class WidarBaseband 064 extends CorrelatorBasebandAbs 065 { 066 private static final Frequency MIN_BW = new Frequency( "31250.0", HERTZ); 067 private static final Frequency MAX_BW_3_BIT = new Frequency("2048000000.0", HERTZ); 068 private static final Frequency MAX_BW_8_BIT = new Frequency("1024000000.0", HERTZ); 069 070 private EvlaWidarConfiguration container; 071 072 /** Helps create a new WIDAR baseband. */ 073 WidarBaseband() 074 { 075 super(); 076 setVciDefaults(); 077 } 078 079 //============================================================================ 080 // CONTAINER 081 //============================================================================ 082 083 /** 084 * Returns the correlator configuration that holds this baseband. 085 * It is possible for the returned value to be <i>null</i>. 086 * If not <i>null</i>, the returned object will always be of type 087 * {@link EvlaWidarConfiguration}. 088 */ 089 protected CorrelatorConfiguration getContainer() 090 { 091 return container; 092 } 093 094 /** 095 * Convenience method that returns the same object as 096 * {@link #getContainer()}. 097 */ 098 EvlaWidarConfiguration getEvlaWidarConfiguration() 099 { 100 return container; 101 } 102 103 /** 104 * Sets the correlator configuration to which this baseband belongs. 105 * The {@code newContainer} is allowed to be <i>null</i>. 106 * If not <i>null</i>, the type of {@code newContainer} must be 107 * {@link EvlaWidarConfiguration}. 108 */ 109 protected void setContainer(CorrelatorConfiguration newContainer) 110 { 111 container = (EvlaWidarConfiguration)newContainer; 112 } 113 114 /** 115 * Convenience method that performs the same function as 116 * {@link #setContainer(CorrelatorConfiguration)}. 117 */ 118 void setEvlaWidarConfiguration(EvlaWidarConfiguration newCfg) 119 { 120 //Because of the way we have the Hibernate mappings configured, we must 121 //call the method below and not simply set the variable. 122 setContainer(newCfg); 123 } 124 125 //============================================================================ 126 // FREQUENCY 127 // 128 // In our initial implementation we assumed, based on documentation, that 129 // clients were permitted to choose their own bandwidth. The client selected 130 // bandwidth was constrained to be a value from a set of discrete legal 131 // values. On 2008-Aug-29 Michael Rupen informed us that the bandwidth 132 // had to be exactly equal to the bandwidth of the incoming IF signal(s). 133 // The section of the VCI documentation that shows multiple possible values 134 // for the bandwidth was meant to accommodate VLBI situations where a single 135 // baseband was composed of signals from many antennas arranged sequentially 136 // every so many Hertz. It was not meant to imply client choice for 137 // baseband bandwidths. 138 // 139 // Some of the original code has been removed, but could be recovered from 140 // subversion if need be. Much of what remains, though, is still influenced 141 // by the original assumption. 142 //============================================================================ 143 144 boolean proxiedRangeIsReversed(Signal signal) 145 { 146 return signal.proxiedRangeIsReversed(); 147 } 148 149 /* (non-Javadoc) 150 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#getMinimumBandwidth() 151 */ 152 public Frequency getMinimumBandwidth() 153 { 154 return MIN_BW.clone(); 155 } 156 157 /* (non-Javadoc) 158 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#getMaximumBandwidth() 159 */ 160 public Frequency getMaximumBandwidth() 161 { 162 Frequency max = (getInitialQuantization() == 8) ? MAX_BW_8_BIT 163 : MAX_BW_3_BIT; 164 Frequency inputBw = getInputBandwidth(); 165 166 return 167 (inputBw != null && inputBw.compareTo(max) <= 0) ? inputBw : max.clone(); 168 } 169 170 /** Returns the bandwidth of this baseband's input signal. */ 171 abstract Frequency getInputBandwidth(); 172 173 /* (non-Javadoc) 174 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#hasDiscreteBandwidths() 175 */ 176 public boolean hasDiscreteBandwidths() 177 { 178 return true; 179 } 180 181 /* (non-Javadoc) 182 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#getAllowableBandwidths() 183 */ 184 public SortedSet<Frequency> getAllowableBandwidths() 185 { 186 SortedSet<Frequency> bws = new TreeSet<Frequency>(); 187 188 double minHz = 189 getMinimumBandwidth().toUnits(HERTZ).doubleValue(); 190 191 double maxHz = 192 getMaximumBandwidth().toUnits(HERTZ).doubleValue(); 193 194 //Only non-negative powers-of-two multiples of min are allowed 195 for (double hertz = minHz; hertz <= maxHz; hertz *= 2.0) 196 { 197 bws.add(new Frequency(BigDecimal.valueOf(hertz), HERTZ).normalize()); 198 } 199 200 return bws; 201 } 202 203 /** 204 * Does nothing. The bandwidth of a WIDAR baseband is completely 205 * determined by the input signal(s). 206 */ 207 @Override 208 public void setBandwidth(Frequency newWidth) { } 209 210 //============================================================================ 211 // QUANTIZATION & POLARIZATION 212 //============================================================================ 213 214 int getInitialQuantization(DigitalSignal signal) 215 { 216 return signal == null ? 3 : signal.getBitDepth(); 217 } 218 219 List<PolarizationType> getPolarizations(Signal... signals) 220 { 221 List<PolarizationType> answer = new ArrayList<PolarizationType>(); 222 for (Signal s : signals) 223 answer.add(s.getPolarization()); 224 return answer; 225 } 226 227 //============================================================================ 228 // PARTNERED BASEBANDS 229 //============================================================================ 230 231 /** 232 * Returns <i>true</i> if <tt>other</tt> is loosely partnered with this 233 * baseband. 234 * In general baseband pairs do not have partners while baseband 235 * singlets do. 236 * 237 * @param other 238 * another WIDAR baseband that may or may not be a partner of this one. 239 * 240 * @return 241 * <i>true</i> if <tt>other</tt> is this baseband's partner. 242 */ 243 public abstract boolean isPartnerOf(WidarBaseband other); 244 245 /** 246 * Returns <i>true</i> if this baseband has a partner. 247 * In general baseband pairs do not have partners while baseband 248 * singlets do. 249 * 250 * @return 251 * <i>true</i> if this baseband has a partner. 252 */ 253 public abstract boolean hasPartner(); 254 255 /** 256 * Returns the partner of this baseband, if any. 257 * In general baseband pairs do not have partners while baseband 258 * singlets do. 259 * <p> 260 * Even unpaired basebands have some coupling to one other baseband, due to 261 * the correlator hardware.</p> 262 * 263 * @return 264 * the partner of this baseband or <i>null</i> if this baseband has no 265 * partner. 266 */ 267 public abstract WidarBaseband getPartner(); 268 269 //============================================================================ 270 // SUBBANDS 271 //============================================================================ 272 273 /* (non-Javadoc) 274 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#makeNewSubband() 275 */ 276 public WidarSubband makeNewSubband() 277 { 278 return new WidarSubband(); 279 } 280 281 /* (non-Javadoc) 282 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#getMaxSubbandCount() 283 */ 284 public int getMaxSubbandCount() 285 { 286 return getInitialQuantization() == 8 ? 32 : 16; 287 } 288 289 /** 290 * WIDAR basebands have an array of slots for subbands. A subband 291 * must lie entirely within a single slot. This constant gives 292 * the width of these slots. 293 */ 294 static final Frequency SB_GRID_WIDTH = new Frequency("128.0", MEGAHERTZ); 295 296 /* (non-Javadoc) 297 * @see edu.nrao.sss.model.resource.CorrelatorBaseband#getSubbandGrid() 298 */ 299 public SortedSet<Frequency> getSubbandGrid() 300 { 301 SortedSet<Frequency> grid = new TreeSet<Frequency>(); 302 303 Frequency increment = SB_GRID_WIDTH; 304 Frequency gridLine = new Frequency("0.0", SB_GRID_WIDTH.getUnits()); 305 Frequency bbBw = getBandwidth(); 306 307 while (gridLine.compareTo(bbBw) < 0) 308 { 309 grid.add(gridLine.clone().normalize()); 310 gridLine.add(increment); 311 } 312 313 //Add high frequency of this baseband, even if it's not a natural point 314 grid.add(bbBw.normalize()); 315 316 return grid; 317 } 318 319 /** 320 * Returns a frequency range that represents the grid cell of this baseband 321 * that contains the given frequency. This baseband contains boundary lines 322 * that break it up into a group of cells. No subband may straddle a boundary 323 * line and occupy multiple cells. 324 * <p> 325 * If the given frequency is below the lowest frequency of this baseband, 326 * the lowest grid cell is returned. If it is above the highest frequency, 327 * the highest cell is returned. If the given frequency is exactly equal 328 * to one of the inner boundaries, the higher of the two cells that use 329 * that boundary is returned.</p> 330 * 331 * @param point 332 * the frequency used to find a grid cell. 333 * 334 * @return 335 * a frequency range that represents one subband grid cell of this baseband. 336 */ 337 FrequencyRange getGridCellContaining(Frequency point) 338 { 339 Frequency[] boundaries = getSubbandGrid().toArray(new Frequency[0]); 340 341 //Any frequency beyond grid will be said to be in highest cell of grid. 342 int highIndex = boundaries.length - 1; 343 344 //Any frequency below grid will be said to be in lowest cell of grid, 345 //thus i=1 and not i=0 as loop start. 346 for (int i=1; i < boundaries.length; i++) 347 { 348 if (point.compareTo(boundaries[i]) < 0) 349 { 350 highIndex = i; 351 break; 352 } 353 } 354 355 int lowIndex = Math.max(0, highIndex - 1); 356 357 return new FrequencyRange(boundaries[lowIndex], boundaries[highIndex]); 358 } 359 360 public void addSubband(CorrelatorSubband newSubband) 361 { 362 WidarSubband sb = (WidarSubband)newSubband; 363 364 addNewSubband(sb); 365 366 //TODO sb's bw and center freq might not be legal. Probably want: 367 //sb.setCentralFrequency(sb.getCentralFrequency()); 368 //sb.setBandwidth(sb.getBandwidth()); 369 370 setSubbandId(sb); 371 } 372 373 @Override 374 public boolean removeSubband(CorrelatorSubband unwantedSubband) 375 { 376 boolean removed = super.removeSubband(unwantedSubband); 377 378 if (removed) 379 freeSubbandId((WidarSubband)unwantedSubband); 380 381 return removed; 382 } 383 384 @XmlElementWrapper(name="subbands") 385 @XmlElement(name="widarSubband") 386 @SuppressWarnings("unused") //JAXB use 387 private void setWidarSubbands(WidarSubband[] replacements) 388 { 389 subbands.clear(); 390 freeAllSubbandIds(); 391 392 for (WidarSubband subband : replacements) 393 { 394 subband.setBaseband(this); 395 subbands.add(subband); 396 397 //Here we're assuming xml schema guarantees unique, valid, values 398 sbIdInUse[subband.getSbId()] = true; 399 } 400 } 401 402 @SuppressWarnings("unused") //JAXB use 403 private WidarSubband[] getWidarSubbands() 404 { 405 return subbands.toArray(new WidarSubband[subbands.size()]); 406 } 407 408 //---------------------------------------------------------------------------- 409 // Managing SB ID 410 //---------------------------------------------------------------------------- 411 412 //TODO need to get straight: 18 or 16? 413 private boolean[] sbIdInUse = new boolean[18]; 414 415 private void setSubbandId(WidarSubband sb) 416 { 417 //Give 1st available. If found, exit 418 for (int i=0; i < sbIdInUse.length; i++) 419 { 420 if (!sbIdInUse[i]) 421 { 422 sb.setSbId(i); 423 sbIdInUse[i] = true; 424 return; 425 } 426 } 427 428 //If we got this far we have problems 429 throwSbIdSettingError(); 430 } 431 432 private void freeSubbandId(WidarSubband sb) 433 { 434 sbIdInUse[sb.getSbId()] = false; 435 } 436 437 private void freeAllSubbandIds() 438 { 439 for (int i=0; i < sbIdInUse.length; i++) 440 sbIdInUse[i] = false; 441 } 442 443 private void throwSbIdSettingError() 444 { 445 //If we got this far there are no available IDs. Since we expected calling 446 //methods to check for max SBs in this BB, we shouldn't get here. However, 447 //we need to notify if we did. 448 if (subbands.size() <= getMaxSubbandCount()) 449 { 450 throw new RuntimeException( 451 "PROGRAMMER ERROR: Ran out of subband IDs. Subband count = " + 452 subbands.size() + ", max SB count = " + getMaxSubbandCount()); 453 } 454 else //too many subbands 455 { 456 throw new RuntimeException( 457 "PROGRAMMER ERROR: ID-setting logic found too many subbands. SB count = " + 458 subbands.size() + ", max SB count = " + getMaxSubbandCount()); 459 } 460 } 461 462 //============================================================================ 463 // VCI ELEMENTS 464 //============================================================================ 465 466 //VCI element BaseBand 467 // bbA - see subclasses 468 // bbB - see subclasses 469 // bw - part of this class already 470 private TimeDuration delayModelsValid; 471 // inQuant - part of this class already 472 // name - using name of this instance 473 private PulsarGating pulsarGating; 474 // sid - an optional attribute that we won't use, at least for now 475 private boolean singlePhaseCenter; 476 // subband - part of this class already 477 private WideBandCorrelator wideBandCorrelator; 478 479 //VCI element BbParams - model in this class? 480 // Probably not. We might invent a non-public class to handle this. 481 // Any exposure to public that might be needed will probably be done 482 // in EvlaWidarConfiguration. 483 // --DMH, 2009-02-10 484 485 //VCI element BaseBandHw - model in this class? 486 // No. In fact, this element will not be handled by SSS software. 487 // --DMH, 2009-02-10 488 489 private void setVciDefaults() 490 { 491 singlePhaseCenter = true; 492 493 overridePulsarGating = false; 494 pulsarGating = null; 495 pulsarGatingCache = VciJaxbUtil.makePulsarGating(); 496 497 overrideWideBandCorr = false; 498 wideBandCorrelator = null; 499 wideBandCorrCache = new WideBandCorrelator(); 500 501 overrideDelayModels = false; 502 delayModelsValid = null; 503 delayModelsCache = new TimeDuration("1.0", SECOND); 504 } 505 506 /** 507 * Makes copies of the VCI elements of this baseband for <tt>other</tt> baseband. 508 */ 509 private void copyVciElementsInto(WidarBaseband other) 510 { 511 other.singlePhaseCenter = this.singlePhaseCenter; 512 513 other.overridePulsarGating = this.overridePulsarGating; 514 other.pulsarGating = VciJaxbUtil.clone(this.pulsarGating); 515 other.pulsarGatingCache = VciJaxbUtil.clone(this.pulsarGatingCache); 516 517 other.overrideWideBandCorr = this.overrideWideBandCorr; 518 other.wideBandCorrelator = VciJaxbUtil.clone(this.wideBandCorrelator); 519 other.wideBandCorrCache = VciJaxbUtil.clone(this.wideBandCorrCache); 520 521 other.overrideDelayModels = this.overrideDelayModels; 522 other.delayModelsValid = (this.delayModelsValid == null) ? null : this.delayModelsValid.clone(); 523 other.delayModelsCache = (this.delayModelsCache == null) ? null : this.delayModelsCache.clone(); 524 } 525 526 /** 527 * Expresses this baseband as either one or two VCI <tt>BaseBand</tt> objects. 528 * If the initial quantization of this baseband is 8, the returned array will 529 * be of length two (unless this baseband has only one subband). 530 * If the initial quantization of this baseband is 3, the returned array will 531 * be of length one. 532 * 533 * @return 534 * an array containing one or two VCI <tt>BaseBand</tt> objects. 535 */ 536 public BaseBand[] toVci() 537 { 538 //If this BB's IQ is 8-bit we'll split the subbands evenly over 2 WIDAR BBs 539 boolean needTwoBBs = (getInitialQuantization() == 8 && subbands.size() > 1); 540 541 //Create array of 1 or 2 elements 542 BaseBand[] vciBB = new BaseBand[needTwoBBs ? 2 : 1]; 543 vciBB[0] = new BaseBand(); 544 if (needTwoBBs) 545 vciBB[1] = new BaseBand(); 546 547 for (int i=0; i < vciBB.length; i++) 548 { 549 //Attributes modeled directly as VCI elements 550 if (delayModelsValid != null) 551 vciBB[i].setDelayModelsValid(delayModelsValid.toUnits(SECOND).intValue()); 552 553 vciBB[i].setSinglePhaseCenter(singlePhaseCenter ? YES : NO); 554 555 vciBB[i].setPulsarGating (VciJaxbUtil.clone(pulsarGating)); 556 vciBB[i].setWideBandCorrelator(VciJaxbUtil.clone(wideBandCorrelator)); 557 558 //Mapped from SSS objects 559 vciBB[i].setBw(bandwidth.toUnits(HERTZ).stripTrailingZeros().toPlainString()); 560 vciBB[i].setInQuant(getInitialQuantization()); 561 vciBB[i].setName(getName()); 562 563 setWidarBbIds(vciBB[i], i == 0); 564 } 565 566 int sbCount = subbands.size(); 567 int sbCountBb1 = needTwoBBs ? sbCount / 2 : sbCount; 568 569 //Put subbands into first BB 570 List<SubBand> vciSubbands = vciBB[0].getSubBand(); 571 for (int s = 0; s < sbCountBb1; s++) 572 vciSubbands.add(((WidarSubband)subbands.get(s)).toVci()); //see note below 573 574 //Put subbands into second BB, if applicable 575 if (needTwoBBs) 576 { 577 vciSubbands = vciBB[1].getSubBand(); 578 for (int s = sbCountBb1; s < sbCount; s++) 579 vciSubbands.add(((WidarSubband)subbands.get(s)).toVci()); //see note below 580 } 581 582 return vciBB; 583 584 //Note: this cast should be safe because this class is in control of 585 //making new subband objects for itself. 586 } 587 588 /** Sets bbA, and sometimes bbB, of widarBB. */ 589 abstract void setWidarBbIds(BaseBand widarBB, boolean primary); 590 591 /** Creates one or two BbParam objects and adds to list. */ 592 abstract void addBbParams(List<BbParams> bbParamList, int stationId); 593 594 /** Creates one or two BbParam objects and adds to list. */ 595 void addBbParams(List<BbParams> bbParamList, int stationId, DigitalSignal inputSignal) 596 { 597 //A0, B1, C2, etc. 598 String signalName = inputSignal.getName(); 599 600 BigDecimal sslo = inputSignal.getMappingIntercept().toUnits(MEGAHERTZ); 601 BigDecimal offset = calcLocOscOffset(stationId).toUnits(KILOHERTZ); 602 int[] bbIds = getVciBbIds(signalName); 603 604 //The 8-bit IQ signals will lead to two VCI BBs; the 3-bit to one 605 BbParams bbParams1 = new BbParams(); 606 607 bbParams1.setBbid(bbIds[0]); 608 bbParams1.setFshiftKHz(offset.doubleValue()); 609 bbParams1.setLoOMHz(sslo.doubleValue()); 610 bbParams1.setPolarization(VciJaxbUtil.getPolarization(inputSignal.getPolarization())); 611 bbParams1.setSideband(proxiedRangeIsReversed() ? LOWER : UPPER); 612 bbParams1.setSourceId(getVciBbParamSrcId(signalName)); 613 bbParams1.setSourceType(StbSourceType.FORM); 614 615 bbParamList.add(bbParams1); 616 617 //When the 8-bit IQ signals lead to two VCI BBs, the VCI BBs are identical 618 //with the exception of their ID numbers. 619 if (bbIds.length == 2) 620 { 621 BbParams bbParams2 = VciJaxbUtil.clone(bbParams1); 622 bbParams2.setBbid(bbIds[1]); 623 bbParamList.add(bbParams2); 624 } 625 } 626 627 /** Calculates the LO offset for this baseband for the given antenna. */ 628 Frequency calcLocOscOffset(int antennaId) 629 { 630 return new Frequency("0", FrequencyUnits.KILOHERTZ); //TODO code me 631 } 632 633 /** Returns a VCI baseband ID for one of our IF signals. */ 634 int[] getVciBbIds(String signalName) 635 { 636 //See Section 4.2 of EVLA Correlator System Numbering Plan 637 if (signalName.equals("A0")) return new int[] {0, 1}; 638 else if (signalName.equals("C0")) return new int[] {2, 3}; 639 else if (signalName.equals("B0")) return new int[] {4, 5}; 640 else if (signalName.equals("D0")) return new int[] {6, 7}; 641 else if (signalName.equals("A1")) return new int[] {0}; 642 else if (signalName.equals("C1")) return new int[] {1}; 643 else if (signalName.equals("A2")) return new int[] {2}; 644 else if (signalName.equals("C2")) return new int[] {3}; 645 else if (signalName.equals("B1")) return new int[] {4}; 646 else if (signalName.equals("D1")) return new int[] {5}; 647 else if (signalName.equals("B2")) return new int[] {6}; 648 else if (signalName.equals("D2")) return new int[] {7}; 649 else 650 throw new RuntimeException("Cannot map unexpected signal name, '" + 651 signalName + "' to a WIDAR BB ID."); 652 } 653 654 /** Picks a sourceId for bbParams element based on signalName. */ 655 private int getVciBbParamSrcId(String signalName) 656 { 657 //This code is based on Figures 5-3 and 5-4 of vers. 3.5 of the VCI 658 //specification. These figures are only examples; will need to 659 //check these assumptions w/ someone. 660 661 //8-bit IQ 662 if (signalName.endsWith("0")) return 0; 663 664 //3-bit IQ 665 if (signalName.startsWith("A")) return 0; 666 if (signalName.startsWith("B")) return 0; 667 if (signalName.startsWith("C")) return 1; 668 if (signalName.startsWith("D")) return 1; 669 670 throw new RuntimeException("Cannot map unexpected signal name, '" + 671 signalName + "' to a WIDAR BB Source ID."); 672 } 673 674 //---------------------------------------------------------------------------- 675 // Pulsar Gating 676 //---------------------------------------------------------------------------- 677 678 private boolean overridePulsarGating; 679 private PulsarGating pulsarGatingCache; 680 681 /** 682 * Tells this baseband to override, or restore, pulsar gating defaults. 683 * 684 * @param override 685 * instruction to override, or restore, pulsar gating defaults. 686 * 687 * @return 688 * <i>null</i> if {@code override} is <i>false</i>. 689 * If {@code override} is <i>true</i>, returns the <tt>PulsarGating</tt> 690 * held internally by this baseband. This means clients can operate 691 * directly on the returned object and impact this baseband. 692 */ 693 public PulsarGating overrideDefaultPulsarGating(boolean override) 694 { 695 //Changing state? 696 if (override != overridePulsarGating) 697 { 698 overridePulsarGating = override; 699 700 if (override) //user-specified 701 { 702 pulsarGating = pulsarGatingCache; 703 } 704 else //default setting 705 { 706 pulsarGatingCache = VciJaxbUtil.clone(pulsarGating); 707 pulsarGating = null; 708 } 709 } 710 711 return pulsarGating; 712 } 713 714 /** 715 * Returns the pulsar gating configuration, if any. 716 * The default value of this property is <i>null</i>. 717 * <p> 718 * This is a VCI property. 719 * The returned object was generated from VCI XML schema elements and 720 * is the actual instance held internally by this baseband.</p> 721 * 722 * @return the pulsar gating configuration, if any. 723 * 724 * @see #overrideDefaultPulsarGating(boolean) 725 */ 726 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 727 public PulsarGating getPulsarGating() { return pulsarGating; } 728 729 //This method is for persistence frameworks such as JAXB & Hibernate 730 @SuppressWarnings("unused") 731 private void setPulsarGating(PulsarGating newCfg) 732 { 733 pulsarGating = newCfg; 734 overridePulsarGating = (newCfg != null); 735 } 736 737 //---------------------------------------------------------------------------- 738 // Wide Band Correlator 739 //---------------------------------------------------------------------------- 740 741 private boolean overrideWideBandCorr; 742 private WideBandCorrelator wideBandCorrCache; 743 744 /** 745 * Tells this baseband to override, or restore, wide band correlator defaults. 746 * 747 * @param override 748 * instruction to override, or restore, wide band correlator defaults. 749 * 750 * @return 751 * <i>null</i> if {@code override} is <i>false</i>. 752 * If {@code override} is <i>true</i>, returns the <tt>WideBandCorrelator</tt> 753 * held internally by this baseband. This means clients can operate 754 * directly on the returned object and impact this baseband. 755 */ 756 public WideBandCorrelator overrideDefaultWideBandCorrelator(boolean override) 757 { 758 //Changing state? 759 if (override != overrideWideBandCorr) 760 { 761 overrideWideBandCorr = override; 762 763 if (override) //user-specified 764 { 765 wideBandCorrelator = wideBandCorrCache; 766 } 767 else //default setting 768 { 769 wideBandCorrCache = VciJaxbUtil.clone(wideBandCorrelator); 770 wideBandCorrelator = null; 771 } 772 } 773 774 return wideBandCorrelator; 775 } 776 777 /** 778 * Returns the wide band correlation configuration, if any. 779 * The default value of this property is <i>null</i>. 780 * <p> 781 * This is a VCI property. 782 * The returned object was generated from VCI XML schema elements and 783 * is the actual instance held internally by this baseband.</p> 784 * 785 * @return the wide band correlation configuration, if any. 786 * 787 * @see #overrideDefaultWideBandCorrelator(boolean) 788 */ 789 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 790 public WideBandCorrelator getWideBandCorrelator() { return wideBandCorrelator; } 791 792 //This method is for persistence frameworks such as JAXB & Hibernate 793 @SuppressWarnings("unused") 794 private void setWideBandCorrelator(WideBandCorrelator newCfg) 795 { 796 wideBandCorrelator = newCfg; 797 overrideWideBandCorr = (newCfg != null); 798 } 799 800 //---------------------------------------------------------------------------- 801 // Delay Models 802 //---------------------------------------------------------------------------- 803 804 private boolean overrideDelayModels; 805 private TimeDuration delayModelsCache; 806 807 /** 808 * Tells this baseband to override, or restore, the default value of the delay 809 * models' lifetime. 810 * 811 * @param override 812 * instruction to override, or restore, the default value of the delay 813 * models' lifetime. 814 * 815 * @return 816 * <i>null</i> if {@code override} is <i>false</i>. 817 * If {@code override} is <i>true</i>, returns the <tt>WideBandCorrelator</tt> 818 * held internally by this baseband. This means clients can operate 819 * directly on the returned object and impact this baseband. 820 */ 821 public TimeDuration overrideDefaultDelayModelLifespan(boolean override) 822 { 823 //Changing state? 824 if (override != overrideDelayModels) 825 { 826 overrideDelayModels = override; 827 828 if (override) //user-specified 829 { 830 delayModelsValid = delayModelsCache; 831 } 832 else //default setting 833 { 834 delayModelsCache = delayModelsValid.clone(); 835 delayModelsValid = null; 836 } 837 } 838 839 return delayModelsValid; 840 } 841 842 /** 843 * Returns the length of time for which this baseband's delay models 844 * may remain valid. 845 * The default value of this property is <i>null</i>. 846 * <p> 847 * This is a VCI property. 848 * The returned object 849 * is the actual instance held internally by this baseband.</p> 850 * 851 * @return 852 * the length of time for which this baseband's delay models 853 * may remain valid. 854 */ 855 @XmlElement 856 public TimeDuration getDelayModelLifespan() { return delayModelsValid; } 857 858 //This method is for persistence frameworks such as JAXB & Hibernate 859 @SuppressWarnings("unused") 860 private void setDelayModelLifespan(TimeDuration newSpan) 861 { 862 delayModelsValid = newSpan; 863 overrideDelayModels = (newSpan != null); 864 } 865 866 //---------------------------------------------------------------------------- 867 // Other 868 //---------------------------------------------------------------------------- 869 870 /** 871 * Determines whether or not all the subbands of this baseband are required 872 * to have the same phase center. 873 * <p> 874 * This is a VCI property. The default value is <i>true</i> or "yes".</p> 875 */ 876 public void setSinglePhaseCenter(boolean singleCenter) 877 { 878 singlePhaseCenter = singleCenter; 879 } 880 881 /** 882 * Returns <i>true</i> if all subbands of this baseband are required 883 * to have the same phase center. 884 * <p> 885 * This is a VCI property.</p> 886 * 887 * @return 888 * <i>true</i> if all subbands of this baseband are required 889 * to have the same phase center. 890 */ 891 public boolean getSinglePhaseCenter() { return singlePhaseCenter; } 892 893 //---------------------------------------------------------------------------- 894 // Deprecated 895 //---------------------------------------------------------------------------- 896 897 /** @deprecated Always returns <i>null</i>. */ 898 @Deprecated public InputStateCounts getInputStateCounts() { return null; } 899 900 /** @deprecated does nothing */ 901 @XmlTransient 902 @Deprecated public void setFringeRotation(boolean turnOn) { } 903 904 /** @deprecated Always returns <i>false</i>. */ 905 @Deprecated public boolean getFringeRotation() { return false; } 906 907 //============================================================================ 908 // 909 //============================================================================ 910 911 /** 912 * Returns an XML representation of this baseband. 913 * @return an XML representation of this baseband. 914 * @throws JAXBException if anything goes wrong during the conversion to XML. 915 * @see #writeAsXmlTo(Writer) 916 */ 917 public String toXml() throws JAXBException 918 { 919 return JaxbUtility.getSharedInstance().objectToXmlString(this); 920 } 921 922 /** 923 * Writes an XML representation of this baseband to {@code writer}. 924 * @param writer the device to which XML is written. 925 * @throws JAXBException if anything goes wrong during the conversion to XML. 926 */ 927 public void writeAsXmlTo(Writer writer) throws JAXBException 928 { 929 JaxbUtility.getSharedInstance().writeObjectAsXmlTo(writer, this, null); 930 } 931 932 //============================================================================ 933 // 934 //============================================================================ 935 936 /** 937 * Returns a copy of this baseband. 938 * <p> 939 * If anything goes wrong during the cloning procedure, 940 * a {@code RuntimeException} will be thrown.</p> 941 */ 942 @Override 943 public WidarBaseband clone() 944 { 945 WidarBaseband clone = null; 946 947 try 948 { 949 clone = (WidarBaseband)super.clone(); 950 951 clone.sbIdInUse = Arrays.copyOf(this.sbIdInUse, this.sbIdInUse.length); 952 953 copyVciElementsInto(clone); 954 } 955 catch (Exception ex) 956 { 957 throw new RuntimeException(ex); 958 } 959 960 return clone; 961 } 962 963 /** Returns <i>true</i> if {@code o} is equal to this baseband. */ 964 @Override 965 public boolean equals(Object o) 966 { 967 //Quick exit if super class says not equal 968 if (!super.equals(o)) 969 return false; 970 971 //A safe cast if we got this far 972 WidarBaseband other = (WidarBaseband)o; 973 974 //VCI Objects 975 return 976 other.singlePhaseCenter == this.singlePhaseCenter && 977 978 objectsAreEqual(other.delayModelsValid, this.delayModelsValid) && 979 980 VciJaxbUtil.testEquality(other.pulsarGating, this.pulsarGating) && 981 VciJaxbUtil.testEquality(other.wideBandCorrelator, this.wideBandCorrelator); 982 } 983 984 private boolean objectsAreEqual(Object thisOne, Object thatOne) 985 { 986 return (thisOne == null) ? (thatOne == null) : thisOne.equals(thatOne); 987 } 988 989 @Override 990 public int hashCode() 991 { 992 //Taken from the Effective Java book by Joshua Bloch. 993 //The constants 17 & 37 are arbitrary & carry no meaning. 994 int result = super.hashCode(); 995 996 //You MUST keep this method in sync w/ the equals method 997 998 result = 37 * result + (singlePhaseCenter ? 37 : 17); 999 1000 if (delayModelsValid != null) 1001 result = 37 * result + delayModelsValid.hashCode(); 1002 1003 result = 37 * result + VciJaxbUtil.makeHashCode(pulsarGating); 1004 result = 37 * result + VciJaxbUtil.makeHashCode(wideBandCorrelator); 1005 1006 return result; 1007 } 1008 1009 //============================================================================ 1010 // 1011 //============================================================================ 1012 /* 1013 public static void main(String... args) throws Exception 1014 { 1015 FrequencyRange freqRange = new FrequencyRange(new Frequency("0.0"), new Frequency("2.048")); 1016 DigitalSignal input = new DigitalSignal(freqRange, PolarizationType.L, new Frequency("2.0"), 2); 1017 WidarBaseband bb = new WidarBasebandSinglet(input); 1018 1019 for (Frequency g : bb.getSubbandGrid()) 1020 System.out.println(g); 1021 } 1022 */ 1023 }