001 package edu.nrao.sss.model.resource.evla; 002 003 import java.io.FileNotFoundException; 004 import java.io.Reader; 005 import java.io.Writer; 006 import java.math.BigDecimal; 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.XmlAttribute; 013 import javax.xml.bind.annotation.XmlElement; 014 import javax.xml.bind.annotation.XmlElementWrapper; 015 import javax.xml.bind.annotation.XmlRootElement; 016 import javax.xml.bind.annotation.XmlTransient; 017 import javax.xml.stream.XMLStreamException; 018 019 import static ca.nrc.widar.jaxb.vci.YesNoType.NO; 020 import static ca.nrc.widar.jaxb.vci.YesNoType.YES; 021 import static edu.nrao.sss.measure.FrequencyUnits.HERTZ; 022 023 import ca.nrc.widar.jaxb.vci.AutoCorrMode; 024 import ca.nrc.widar.jaxb.vci.BurstMode; 025 import ca.nrc.widar.jaxb.vci.PhasedArray; 026 import ca.nrc.widar.jaxb.vci.PolProducts; 027 import ca.nrc.widar.jaxb.vci.PulsarBinning; 028 import ca.nrc.widar.jaxb.vci.RadarMode; 029 import ca.nrc.widar.jaxb.vci.SubBand; 030 import ca.nrc.widar.jaxb.vci.ToneExtraction; 031 import edu.nrao.sss.measure.Frequency; 032 import edu.nrao.sss.measure.FrequencyRange; 033 import edu.nrao.sss.model.resource.CorrelationProductGroupAbs; 034 import edu.nrao.sss.model.resource.CorrelatorBaseband; 035 import edu.nrao.sss.model.resource.CorrelatorSubband; 036 import edu.nrao.sss.model.resource.CorrelatorSubbandAbs; 037 import edu.nrao.sss.util.JaxbUtility; 038 039 /** 040 * A subband of a WIDAR correlator baseband. 041 * <p> 042 * <b>Version Info:</b> 043 * <table style="margin-left:2em"> 044 * <tr><td>$Revision: 2291 $</td></tr> 045 * <tr><td>$Date: 2009-05-08 11:09:46 -0600 (Fri, 08 May 2009) $</td></tr> 046 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 047 * </table></p> 048 * 049 * @author David M. Harland 050 * @since 2008-03-11 051 */ 052 @XmlRootElement 053 public class WidarSubband 054 extends CorrelatorSubbandAbs 055 { 056 private static final Frequency MIN_BW = new Frequency("31250.0", HERTZ); 057 058 private static final Frequency MAX_BW_4_BIT_RQ = new Frequency("128000000.0", HERTZ); 059 private static final Frequency MAX_BW_7_BIT_RQ = new Frequency( "64000000.0", HERTZ); 060 061 private SubbandChannelCalculator channelCalculator = 062 SubbandChannelCalculator.getInstance(); 063 064 /** Helps create a new WIDAR subband. */ 065 public WidarSubband() 066 { 067 super(); 068 setVciDefaults(); 069 070 Frequency center = WidarBaseband.SB_GRID_WIDTH.clone().divideBy("2.0"); 071 freqRange.setCenterAndWidth(center, WidarBaseband.SB_GRID_WIDTH); 072 setRequantization(4); 073 } 074 075 void setBaseband(WidarBaseband container) 076 { 077 setContainer(container); 078 } 079 080 @Override 081 @XmlTransient 082 public WidarBaseband getBaseband() 083 { 084 return (WidarBaseband)super.getBaseband(); 085 } 086 087 //============================================================================ 088 // FREQUENCY 089 //============================================================================ 090 091 /* (non-Javadoc) 092 * @see CorrelatorSubband#getMinimumBandwidth() 093 */ 094 public Frequency getMinimumBandwidth() 095 { 096 //2008-09-03 According to M.Rupen the algorithm in ver 3.3 of the VCI 097 //document stating that the minimum is the greater of below and 098 //BB_BW/4096 is incorrect. 099 return MIN_BW.clone(); 100 } 101 102 /* (non-Javadoc) 103 * @see CorrelatorSubband#getMaximumBandwidth() 104 */ 105 public Frequency getMaximumBandwidth() 106 { 107 Frequency max = (requantizationBits == 4) ? MAX_BW_4_BIT_RQ.clone() 108 : MAX_BW_7_BIT_RQ.clone(); 109 CorrelatorBaseband bb = getContainer(); 110 //max = lesser of MAX_BW_* and baseband's BW 111 if (bb != null) 112 { 113 Frequency bbBw = bb.getBandwidth(); //returns a clone 114 115 if (bbBw.compareTo(max) < 0) 116 max = bbBw; 117 } 118 119 return max; 120 } 121 122 /* (non-Javadoc) 123 * @see CorrelatorSubband#hasDiscreteBandwidths() 124 */ 125 public boolean hasDiscreteBandwidths() { return true; } 126 127 /* (non-Javadoc) 128 * @see CorrelatorSubband#getAllowableBandwidths() 129 */ 130 public SortedSet<Frequency> getAllowableBandwidths() 131 { 132 SortedSet<Frequency> bws = new TreeSet<Frequency>(); 133 134 double minHz = getMinimumBandwidth().toUnits(HERTZ).doubleValue(); 135 double maxHz = getMaximumBandwidth().toUnits(HERTZ).doubleValue(); 136 137 //Only non-negative powers-of-two multiples of min are allowed 138 for (double hertz = minHz; hertz <= maxHz; hertz *= 2.0) 139 { 140 bws.add(new Frequency(new BigDecimal(hertz), HERTZ).normalize()); 141 } 142 143 return bws; 144 } 145 146 /** 147 * Sets the bandwidth of this subband. 148 * <p> 149 * In addition to doing the work described in the 150 * {@link CorrelatorSubband#setBandwidth(Frequency) method specifications}, 151 * this WIDAR version also turns off the <i>stage 2 mixer</i>, if it 152 * happened to be on, and if the new width is 128 MHz.</p> 153 */ 154 public void setBandwidth(Frequency newWidth) 155 { 156 super.setBandwidth(newWidth); 157 158 //If we're not using the mixer, the super class's code already does correct thing. 159 //This code is here because super class things all frequencies are valid, but 160 //for widar we have the 128MHz boundaries. 161 if (useMixer) 162 keepWithinGridCell(); 163 164 //Turn off mixer if BW is 128MHz 165 if (useMixer && getBandwidth().equals(WidarBaseband.SB_GRID_WIDTH)) 166 useMixer = false; 167 } 168 169 /** 170 * Sets the central frequency of this subband. 171 * <p> 172 * In addition to the 173 * {@link CorrelatorSubband#setCentralFrequency(Frequency) side effects} 174 * mentioned in the specification of this method, this implementation 175 * will also snap the center frequency to an imaginary grid. 176 * If the <i>stage 2 filter</i> is not turned on, the center of this 177 * subband must be equal to <tt>BW / 2 + BW * n, n=0,1,2,...</tt>, 178 * where <tt>BW</tt> is the bandwidth of this subband.</p> 179 */ 180 @Override 181 public void setCentralFrequency(Frequency newCenter) 182 { 183 if (newCenter == null) 184 throw new IllegalArgumentException( 185 "Cannot set center of subband to NULL."); 186 187 //If the stage 2 mixer is off, the center of the subband must 188 //be in the center of a slot of an imaginary grid whose slots 189 //are the same width as the subband. 190 if (!useMixer) 191 { 192 BigDecimal mult = newCenter.dividedBy(getBandwidth()); 193 194 double goodMult = mult.intValue() + 0.5; 195 196 newCenter = getBandwidth().multiplyBy(BigDecimal.valueOf(goodMult)); 197 } 198 199 super.setCentralFrequency(newCenter); 200 201 //If we're not using the mixer, the super class's code already does correct thing. 202 //This code is here because super class things all frequencies are valid, but 203 //for widar we have the 128MHz boundaries. 204 if (useMixer) 205 keepWithinGridCell(); 206 } 207 208 /** 209 * Holds the bandwidth constant and moves center frequency if any part 210 * of this subband overlaps one of the boundary lines specified by the 211 * containing baseband. 212 */ 213 private void keepWithinGridCell() 214 { 215 WidarBaseband bb = getBaseband(); 216 217 if (bb != null) 218 { 219 Frequency sbCenter = getCentralFrequency(); 220 Frequency sbHalfWidth = getBandwidth().divideBy("2.0"); 221 FrequencyRange gridCell = bb.getGridCellContaining(sbCenter); 222 223 Frequency minCenter = gridCell.getLowFrequency().add(sbHalfWidth); 224 225 if (sbCenter.compareTo(minCenter) < 0) 226 { 227 super.setCentralFrequency(minCenter); 228 } 229 else 230 { 231 Frequency maxCenter = gridCell.getHighFrequency().subtract(sbHalfWidth); 232 233 if (sbCenter.compareTo(maxCenter) > 0) 234 super.setCentralFrequency(maxCenter); 235 } 236 } 237 } 238 239 //============================================================================ 240 // QUANTIZATION 241 //============================================================================ 242 243 /* (non-Javadoc) 244 * @see CorrelatorSubband#getAllowableRequantizations() 245 */ 246 public SortedSet<Integer> getAllowableRequantizations() 247 { 248 SortedSet<Integer> allowable = new TreeSet<Integer>(); 249 250 allowable.add(4); 251 252 if (getBandwidth().compareTo(MAX_BW_7_BIT_RQ) <= 0) 253 allowable.add(7); 254 255 return allowable; 256 } 257 258 /* (non-Javadoc) 259 * @see CorrelatorSubband#setRequantization(int) 260 */ 261 public void setRequantization(int bits) 262 { 263 requantizationBits = bits <= 5 ? 4 : 7; 264 } 265 266 //============================================================================ 267 // CHANNELS 268 //============================================================================ 269 // TODO: at one time methods such as those below were part of the 270 // CorrelatorSubband I/F. Consider making them so again. 271 272 public int getMaximumChannelCount() 273 { 274 //TODO BLBPs are now in a diff VCI element 275 return channelCalculator.getMaxChannels(this, 1 /*this.blbps.size()*/); 276 } 277 278 public int getChannelIncrementSize() 279 { 280 //TODO recirculation is now in a diff VCI element 281 return channelCalculator.getChannelIncrement( 1 /*recirculation*/); 282 } 283 284 //============================================================================ 285 // CORRELATION PRODUCT GROUPS 286 //============================================================================ 287 288 @Override 289 protected WidarCorrelationProductGroup makeCorrelationProductGroup() 290 { 291 return new WidarCorrelationProductGroup(this); 292 } 293 294 @XmlElementWrapper(name="correlationProductGroups") 295 @XmlElement(name="group") 296 @SuppressWarnings("unused") //JAXB use 297 private void setWidarProdGroupList(WidarCorrelationProductGroup[] replacements) 298 { 299 productGroups.clear(); 300 301 for (WidarCorrelationProductGroup prodGrp : replacements) 302 { 303 prodGrp.setSubband(this); 304 productGroups.add(prodGrp); 305 } 306 } 307 308 @SuppressWarnings("unused") //JAXB use 309 private WidarCorrelationProductGroup[] getWidarProdGroupList() 310 { 311 return productGroups.toArray(new WidarCorrelationProductGroup[productGroups.size()]); 312 } 313 314 //============================================================================ 315 // VCI ELEMENTS 316 //============================================================================ 317 318 //VCI element SubBand 319 private AutoCorrMode autoCorrMode; 320 private BurstMode burstMode; 321 // bw - part of this class already 322 // centralFreq - part of this class already 323 private boolean mixerPhaseErrorCorr; 324 // name - part of super class 325 private PhasedArray phasedArray; 326 // polProducts - part of super class 327 private PulsarBinning pulsarBinning; 328 private int pulsarGatingPhase; 329 private RadarMode radarMode; 330 // rqNumBits - part of this class already 331 private int sbId; 332 private int signalToNoise; 333 private ToneExtraction toneExtraction; 334 private boolean useMixer; 335 336 //VCI element SbParams 337 //TODO model in this class? 338 339 private void setVciDefaults() 340 { 341 sbId = 0; 342 343 mixerPhaseErrorCorr = true; 344 pulsarGatingPhase = 0; 345 signalToNoise = 0; 346 useMixer = false; 347 348 overrideAutoCorr = false; 349 autoCorrMode = null; 350 autoCorrCache = VciJaxbUtil.makeAutoCorrMode(); 351 352 overrideBurstMode = false; 353 burstMode = null; 354 burstModeCache = VciJaxbUtil.makeBurstMode(); 355 356 overridePhasedArray = false; 357 phasedArray = null; 358 phasedArrayCache = VciJaxbUtil.makePhasedArray(); 359 360 overridePulsarBinning = false; 361 pulsarBinning = null; 362 pulsarBinningCache = VciJaxbUtil.makePulsarBinning(); 363 364 overrideRadarMode = false; 365 radarMode = null; 366 radarModeCache = new RadarMode(); 367 368 overrideToneExtraction = false; 369 toneExtraction = null; 370 toneExtractionCache = new ToneExtraction(); 371 } 372 373 /** 374 * Makes copies of the VCI elements of this subband for <tt>other</tt> subband. 375 */ 376 private void copyVciElementsInto(WidarSubband other) 377 { 378 other.mixerPhaseErrorCorr = this.mixerPhaseErrorCorr; 379 other.pulsarGatingPhase = this.pulsarGatingPhase; 380 other.signalToNoise = this.signalToNoise; 381 other.useMixer = this.useMixer; 382 383 other.overrideAutoCorr = this.overrideAutoCorr; 384 other.autoCorrMode = VciJaxbUtil.clone(this.autoCorrMode); 385 other.autoCorrCache = VciJaxbUtil.clone(this.autoCorrCache); 386 387 other.overrideBurstMode = this.overrideBurstMode; 388 other.burstMode = VciJaxbUtil.clone(this.burstMode); 389 other.burstModeCache = VciJaxbUtil.clone(this.burstModeCache); 390 391 other.overridePhasedArray = this.overridePhasedArray; 392 other.phasedArray = VciJaxbUtil.clone(this.phasedArray); 393 other.phasedArrayCache = VciJaxbUtil.clone(this.phasedArrayCache); 394 395 other.overridePulsarBinning = this.overridePulsarBinning; 396 other.pulsarBinning = VciJaxbUtil.clone(this.pulsarBinning); 397 other.pulsarBinningCache = VciJaxbUtil.clone(this.pulsarBinningCache); 398 399 other.overrideRadarMode = this.overrideRadarMode; 400 other.radarMode = VciJaxbUtil.clone(this.radarMode); 401 other.radarModeCache = VciJaxbUtil.clone(this.radarModeCache); 402 403 other.overrideToneExtraction = this.overrideToneExtraction; 404 other.toneExtraction = VciJaxbUtil.clone(this.toneExtraction); 405 other.toneExtractionCache = VciJaxbUtil.clone(this.toneExtractionCache); 406 } 407 408 /** 409 * Returns true if this and other subband have equal VCI elements. 410 */ 411 private boolean vciElementsAreEqual(WidarSubband other) 412 { 413 //Intentionally NOT comparing: sbId 414 415 //Simple properties 416 if (other.mixerPhaseErrorCorr != this.mixerPhaseErrorCorr || 417 other.pulsarGatingPhase != this.pulsarGatingPhase || 418 other.signalToNoise != this.signalToNoise || 419 other.useMixer != this.useMixer) 420 return false; 421 422 //We're going to say that two SBs that have equal values for VCI property V 423 //are NOT equal if one has V in its default state and the other has overridden 424 //V's default with a value equal to the default. 425 426 //Default states 427 if (other.overrideAutoCorr != this.overrideAutoCorr || 428 other.overrideBurstMode != this.overrideBurstMode || 429 other.overridePhasedArray != this.overridePhasedArray || 430 other.overridePulsarBinning != this.overridePulsarBinning || 431 other.overrideRadarMode != this.overrideRadarMode || 432 other.overrideToneExtraction != this.overrideToneExtraction) 433 return false; 434 435 //We're going to say that if a VCI property V is in its default state for 436 //both subbands, then these subbands are equal with respect to V, even 437 //if their cached values for V are different. 438 439 //VCI objects 440 if (overrideAutoCorr && 441 !VciJaxbUtil.testEquality(other.autoCorrMode, this.autoCorrMode)) 442 return false; 443 444 if (overrideBurstMode && 445 !VciJaxbUtil.testEquality(other.burstMode, this.burstMode)) 446 return false; 447 448 if (overridePhasedArray && 449 !VciJaxbUtil.testEquality(other.phasedArray, this.phasedArray)) 450 return false; 451 452 if (overridePulsarBinning && 453 !VciJaxbUtil.testEquality(other.pulsarBinning, this.pulsarBinning)) 454 return false; 455 456 if (overrideRadarMode && 457 !VciJaxbUtil.testEquality(other.radarMode, this.radarMode)) 458 return false; 459 460 if (overrideToneExtraction && 461 !VciJaxbUtil.testEquality(other.toneExtraction, this.toneExtraction)) 462 return false; 463 464 return true; 465 } 466 467 /** Returns a hash code for the VCI elements of this subband. */ 468 private int vciElementsHashCode() 469 { 470 //Taken from the Effective Java book by Joshua Bloch. 471 //The constants 17 & 37 are arbitrary & carry no meaning. 472 int result = 17; 473 474 result = 37 * result + Boolean.valueOf(mixerPhaseErrorCorr).hashCode(); 475 result = 37 * result + pulsarGatingPhase; 476 result = 37 * result + signalToNoise; 477 result = 37 * result + Boolean.valueOf(useMixer).hashCode(); 478 479 if (overrideAutoCorr) 480 result = 37 * result + VciJaxbUtil.makeHashCode(autoCorrMode); 481 482 if (overrideBurstMode) 483 result = 37 * result + VciJaxbUtil.makeHashCode(burstMode); 484 485 if (overridePhasedArray) 486 result = 37 * result + VciJaxbUtil.makeHashCode(phasedArray); 487 488 if (overridePulsarBinning) 489 result = 37 * result + VciJaxbUtil.makeHashCode(pulsarBinning); 490 491 if (overrideRadarMode) 492 result = 37 * result + VciJaxbUtil.makeHashCode(radarMode); 493 494 if (overrideToneExtraction) 495 result = 37 * result + VciJaxbUtil.makeHashCode(toneExtraction); 496 497 return result; 498 } 499 500 public SubBand toVci() 501 { 502 SubBand vciObj = new SubBand(); 503 504 vciObj.setSbid(sbId); 505 506 //Modeled as VCI elements 507 vciObj.setAutoCorrMode (VciJaxbUtil.clone(autoCorrMode )); 508 vciObj.setBurstMode (VciJaxbUtil.clone(burstMode )); 509 vciObj.setPhasedArray (VciJaxbUtil.clone(phasedArray )); 510 vciObj.setPulsarBinning (VciJaxbUtil.clone(pulsarBinning )); 511 vciObj.setRadarMode (VciJaxbUtil.clone(radarMode )); 512 vciObj.setToneExtraction(VciJaxbUtil.clone(toneExtraction)); 513 514 vciObj.setMixerPhaseErrorCorr(mixerPhaseErrorCorr ? YES : NO); 515 vciObj.setPulsarGatingPhase (pulsarGatingPhase); 516 vciObj.setSignalToNoise (signalToNoise); 517 vciObj.setUseMixer (useMixer ? YES : NO); 518 519 //Mapped from SSS objects 520 if (name != null) 521 vciObj.setName(name); 522 523 vciObj.setBw(getBandwidth().toUnits(HERTZ).stripTrailingZeros().toPlainString()); 524 vciObj.setCentralFreq(getCentralFrequency().toUnits(HERTZ).intValue()); 525 vciObj.setRqNumBits(getRequantization()); 526 527 List<PolProducts> polProducts = vciObj.getPolProducts(); 528 for (CorrelationProductGroupAbs prodGrp : productGroups) 529 polProducts.add(((WidarCorrelationProductGroup)prodGrp).toVci()); //see note below 530 531 return vciObj; 532 533 //Note: this cast should be safe because this class is in control of 534 //making new product group objects for itself. 535 } 536 537 //---------------------------------------------------------------------------- 538 // ID 539 //---------------------------------------------------------------------------- 540 541 //Since this method is used only by trusted classes, we don't check newId value 542 void setSbId(int newId) { sbId = newId; } 543 544 @XmlAttribute(required=true) 545 public int getSbId() { return sbId; } 546 547 //---------------------------------------------------------------------------- 548 // Auto Correlation Mode 549 //---------------------------------------------------------------------------- 550 551 private boolean overrideAutoCorr; 552 private AutoCorrMode autoCorrCache; 553 554 /** 555 * Tells this subband to override, or restore, auto correlation mode defaults. 556 * 557 * @param override 558 * instruction to override, or restore, auto correlation mode defaults. 559 * 560 * @return 561 * <i>null</i> if {@code override} is <i>false</i>. 562 * If {@code override} is <i>true</i>, returns the <tt>AutoCorrMode</tt> 563 * held internally by this subband. This means clients can operate 564 * directly on the returned object and impact this subband. 565 */ 566 public AutoCorrMode overrideDefaultAutoCorrMode(boolean override) 567 { 568 //Changing state? 569 if (override != overrideAutoCorr) 570 { 571 overrideAutoCorr = override; 572 573 if (override) //user-specified 574 { 575 autoCorrMode = autoCorrCache; 576 } 577 else //default setting 578 { 579 autoCorrCache = VciJaxbUtil.clone(autoCorrMode); 580 autoCorrMode = null; 581 } 582 } 583 584 return autoCorrMode; 585 } 586 587 /** 588 * Returns the autocorrelation mode to use for this subband, if any. 589 * The default value of this property is <i>null</i>. 590 * <p> 591 * This is a VCI property. 592 * The returned object was generated from VCI XML schema elements and 593 * is the actual instance held internally by this subband.</p> 594 * 595 * @return the autocorrelation mode to use for this subband, if any. 596 * 597 * @see #overrideDefaultAutoCorrMode(boolean) 598 */ 599 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 600 public AutoCorrMode getAutoCorrMode() { return autoCorrMode; } 601 602 //This method is for persistence frameworks such as JAXB & Hibernate 603 @SuppressWarnings("unused") 604 private void setAutoCorrMode(AutoCorrMode newMode) 605 { 606 autoCorrMode = newMode; 607 overrideAutoCorr = (newMode != null); 608 } 609 610 //---------------------------------------------------------------------------- 611 // Burst Mode 612 //---------------------------------------------------------------------------- 613 614 private boolean overrideBurstMode; 615 private BurstMode burstModeCache; 616 617 /** 618 * Tells this subband to override, or restore, burst mode defaults. 619 * 620 * @param override 621 * instruction to override, or restore, burst mode defaults. 622 * 623 * @return 624 * <i>null</i> if {@code override} is <i>false</i>. 625 * If {@code override} is <i>true</i>, returns the <tt>BurstMode</tt> 626 * held internally by this subband. This means clients can operate 627 * directly on the returned object and impact this subband. 628 */ 629 public BurstMode overrideDefaultBurstMode(boolean override) 630 { 631 //Changing state? 632 if (override != overrideBurstMode) 633 { 634 overrideBurstMode = override; 635 636 if (override) //user-specified 637 { 638 burstMode = burstModeCache; 639 } 640 else //default setting 641 { 642 burstModeCache = VciJaxbUtil.clone(burstMode); 643 burstMode = null; 644 } 645 } 646 647 return burstMode; 648 } 649 650 /** 651 * Returns the burst mode to use for this subband, if any. 652 * The default value of this property is <i>null</i>. 653 * <p> 654 * This is a VCI property. 655 * The returned object was generated from VCI XML schema elements and 656 * is the actual instance held internally by this subband.</p> 657 * 658 * @return the autocorrelation mode to use for this subband, if any. 659 * 660 * @see #overrideDefaultBurstMode(boolean) 661 */ 662 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 663 public BurstMode getBurstMode() { return burstMode; } 664 665 //This method is for persistence frameworks such as JAXB & Hibernate 666 @SuppressWarnings("unused") 667 private void setBurstMode(BurstMode newMode) 668 { 669 burstMode = newMode; 670 overrideBurstMode = (newMode != null); 671 } 672 673 //---------------------------------------------------------------------------- 674 // Phased Array 675 //---------------------------------------------------------------------------- 676 677 private boolean overridePhasedArray; 678 private PhasedArray phasedArrayCache; 679 680 /** 681 * Tells this subband to override, or restore, phased array defaults. 682 * 683 * @param override 684 * instruction to override, or restore, phased array defaults. 685 * 686 * @return 687 * <i>null</i> if {@code override} is <i>false</i>. 688 * If {@code override} is <i>true</i>, returns the <tt>PhasedArray</tt> 689 * held internally by this subband. This means clients can operate 690 * directly on the returned object and impact this subband. 691 */ 692 public PhasedArray overrideDefaultPhasedArray(boolean override) 693 { 694 //Changing state? 695 if (override != overridePhasedArray) 696 { 697 overridePhasedArray = override; 698 699 if (override) //user-specified 700 { 701 phasedArray = phasedArrayCache; 702 } 703 else //default setting 704 { 705 phasedArrayCache = VciJaxbUtil.clone(phasedArray); 706 phasedArray = null; 707 } 708 } 709 710 return phasedArray; 711 } 712 713 /** 714 * Returns the phase array parameters to use for this subband, if any. 715 * The default value of this property is <i>null</i>. 716 * <p> 717 * This is a VCI property. 718 * The returned object was generated from VCI XML schema elements and 719 * is the actual instance held internally by this subband.</p> 720 * 721 * @return the phase array parameters to use for this subband, if any. 722 * 723 * @see #overrideDefaultPhasedArray(boolean) 724 */ 725 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 726 public PhasedArray getPhasedArray() { return phasedArray; } 727 728 //This method is for persistence frameworks such as JAXB & Hibernate 729 @SuppressWarnings("unused") 730 private void setPhasedArray(PhasedArray newArray) 731 { 732 phasedArray = newArray; 733 overridePhasedArray = (newArray != null); 734 } 735 736 //---------------------------------------------------------------------------- 737 // Pulsar Binning 738 //---------------------------------------------------------------------------- 739 740 private boolean overridePulsarBinning; 741 private PulsarBinning pulsarBinningCache; 742 743 /** 744 * Tells this subband to override, or restore, pulsar binning defaults. 745 * 746 * @param override 747 * instruction to override, or restore, pulsar binning defaults. 748 * 749 * @return 750 * <i>null</i> if {@code override} is <i>false</i>. 751 * If {@code override} is <i>true</i>, returns the <tt>PulsarBinning</tt> 752 * held internally by this subband. This means clients can operate 753 * directly on the returned object and impact this subband. 754 */ 755 public PulsarBinning overrideDefaultPulsarBinning(boolean override) 756 { 757 //Changing state? 758 if (override != overridePulsarBinning) 759 { 760 overridePulsarBinning = override; 761 762 if (override) //user-specified 763 { 764 pulsarBinning = pulsarBinningCache; 765 } 766 else //default setting 767 { 768 pulsarBinningCache = VciJaxbUtil.clone(pulsarBinning); 769 pulsarBinning = null; 770 } 771 } 772 773 return pulsarBinning; 774 } 775 776 /** 777 * Returns the pulsar binning parameters to use for this subband, if any. 778 * The default value of this property is <i>null</i>. 779 * <p> 780 * This is a VCI property. 781 * The returned object was generated from VCI XML schema elements and 782 * is the actual instance held internally by this subband.</p> 783 * 784 * @return the pulsar binning parameters to use for this subband, if any. 785 * 786 * @see #overrideDefaultPulsarBinning(boolean) 787 */ 788 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 789 public PulsarBinning getPulsarBinning() { return pulsarBinning; } 790 791 //This method is for persistence frameworks such as JAXB & Hibernate 792 @SuppressWarnings("unused") 793 private void setPulsarBinning(PulsarBinning newBinning) 794 { 795 pulsarBinning = newBinning; 796 overridePulsarBinning = (newBinning != null); 797 } 798 799 //---------------------------------------------------------------------------- 800 // Radar Mode 801 //---------------------------------------------------------------------------- 802 803 private boolean overrideRadarMode; 804 private RadarMode radarModeCache; 805 806 /** 807 * Tells this subband to override, or restore, radar mode defaults. 808 * 809 * @param override 810 * instruction to override, or restore, radar mode defaults. 811 * 812 * @return 813 * <i>null</i> if {@code override} is <i>false</i>. 814 * If {@code override} is <i>true</i>, returns the <tt>RadarMode</tt> 815 * held internally by this subband. This means clients can operate 816 * directly on the returned object and impact this subband. 817 */ 818 public RadarMode overrideDefaultRadarMode(boolean override) 819 { 820 //Changing state? 821 if (override != overrideRadarMode) 822 { 823 overrideRadarMode = override; 824 825 if (override) //user-specified 826 { 827 radarMode = radarModeCache; 828 } 829 else //default setting 830 { 831 radarModeCache = VciJaxbUtil.clone(radarMode); 832 radarMode = null; 833 } 834 } 835 836 return radarMode; 837 } 838 839 /** 840 * Returns the pulsar binning parameters to use for this subband, if any. 841 * The default value of this property is <i>null</i>. 842 * <p> 843 * This is a VCI property. 844 * The returned object was generated from VCI XML schema elements and 845 * is the actual instance held internally by this subband.</p> 846 * 847 * @return the pulsar binning parameters to use for this subband, if any. 848 * 849 * @see #overrideDefaultRadarMode(boolean) 850 */ 851 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 852 public RadarMode getRadarMode() { return radarMode; } 853 854 //This method is for persistence frameworks such as JAXB & Hibernate 855 @SuppressWarnings("unused") 856 private void setRadarMode(RadarMode newMode) 857 { 858 radarMode = newMode; 859 overrideRadarMode = (newMode != null); 860 } 861 862 //---------------------------------------------------------------------------- 863 // Tone Extraction 864 //---------------------------------------------------------------------------- 865 866 private boolean overrideToneExtraction; 867 private ToneExtraction toneExtractionCache; 868 869 /** 870 * Tells this subband to override, or restore, pulsar gating defaults. 871 * 872 * @param override 873 * instruction to override, or restore, pulsar gating defaults. 874 * 875 * @return 876 * <i>null</i> if {@code override} is <i>false</i>. 877 * If {@code override} is <i>true</i>, returns the <tt>ToneExtraction</tt> 878 * held internally by this subband. This means clients can operate 879 * directly on the returned object and impact this subband. 880 */ 881 public ToneExtraction overrideDefaultToneExtraction(boolean override) 882 { 883 //Changing state? 884 if (override != overrideToneExtraction) 885 { 886 overrideToneExtraction = override; 887 888 if (override) //user-specified 889 { 890 toneExtraction = toneExtractionCache; 891 } 892 else //default setting 893 { 894 toneExtractionCache = VciJaxbUtil.clone(toneExtraction); 895 toneExtraction = null; 896 } 897 } 898 899 return toneExtraction; 900 } 901 902 /** 903 * Returns the tone extraction parameters to use for this subband, if any. 904 * The default value of this property is <i>null</i>. 905 * <p> 906 * This is a VCI property. 907 * The returned object was generated from VCI XML schema elements and 908 * is the actual instance held internally by this subband.</p> 909 * 910 * @return the tone extraction parameters to use for this subband, if any. 911 * 912 * @see #overrideDefaultToneExtraction(boolean) 913 */ 914 @XmlElement(namespace="http://www.nrc.ca/namespaces/widar") 915 public ToneExtraction getToneExtraction() { return toneExtraction; } 916 917 //This method is for persistence frameworks such as JAXB & Hibernate 918 @SuppressWarnings("unused") 919 private void setToneExtraction(ToneExtraction newTone) 920 { 921 toneExtraction = newTone; 922 overrideToneExtraction = (newTone != null); 923 } 924 925 //---------------------------------------------------------------------------- 926 // 927 //---------------------------------------------------------------------------- 928 929 /** 930 * Returns <i>true</i> if the {@link #getUseStage2Mixer() stage 2 mixer} 931 * should update the phase error and model. 932 * If the stage 2 mixer is not being used, this value is irrelevant. 933 * The default value of this property is <i>true</i>. 934 * 935 * @return 936 * <i>true</i> if the stage 2 mixer should update the phase error and model. 937 */ 938 @XmlAttribute(required=false) 939 public boolean getMixerPhaseErrorCorr() { return mixerPhaseErrorCorr; } 940 941 /** 942 * Tells the correlator whether or not the stage 2 mixer should update the 943 * phase error and model. 944 * 945 * @param correct 946 * use a value of <i>true</i> 947 * if the stage 2 mixer should update the phase error and model. 948 */ 949 public void setMixerPhaseErrorCorr(boolean correct) { mixerPhaseErrorCorr = correct; } 950 951 /** 952 * Returns the shift of the pulsar gate in fractions of a cycle. 953 * 954 * @return 955 * the shift of the pulsar gate in fractions of a cycle. 956 * The returned value will be an integer from 0 through 100. 957 */ 958 @XmlAttribute(required=false) 959 public int getPulsarGatingPhase() { return pulsarGatingPhase; } 960 961 /** 962 * Sets the shift of the pulsar gate in fractions of a cycle 963 * 964 * @param newPhase 965 * fraction of a cycle. The value must be in the range 0 through 100. 966 * 967 * @throws IllegalArgumentException 968 * if {@code newPhase} is less than zero or greater than one hundred. 969 */ 970 public void setPulsarGatingPhase(int newPhase) 971 { 972 if (newPhase < 0 || newPhase > 100) 973 throw new IllegalArgumentException("Phase value of " + newPhase + 974 " is illegal. Value must be in range [0-100]."); 975 976 pulsarGatingPhase = newPhase; 977 } 978 979 /** 980 * Returns the percent of signal in the input data. 981 * 982 * @return 983 * the percent of signal in the input data. 984 * The returned value will be an integer from 0 through 100. 985 */ 986 @XmlAttribute(required=false) 987 public int getSignalToNoiseRatio() { return signalToNoise; } 988 989 /** 990 * Sets the percent of signal in the input data. 991 * 992 * @param newRatio 993 * percent of signal in the input data. 994 * The value must be in the range 0 through 100. 995 * 996 * @throws IllegalArgumentException 997 * if {@code newRatio} is less than zero or greater than one hundred. 998 */ 999 public void setSignalToNoiseRatio(int newRatio) 1000 { 1001 if (newRatio < 0 || newRatio > 100) 1002 throw new IllegalArgumentException("S/N ratio of " + newRatio + 1003 " is illegal. Value must be in range [0-100]."); 1004 1005 signalToNoise = newRatio; 1006 } 1007 1008 /** 1009 * Turns the stage 2 mixer on or off for this subband. 1010 * <p> 1011 * If the stage 2 mixer is off, this subband is restricted to certain slots 1012 * in its baseband. If this subband's bandwidth is W, and if the stage 2 1013 * mixer is off, then the low frequency of this subband's range must start 1014 * at 0, W, 2W, etc.</p> 1015 * 1016 * @param use 1017 * <i>true</i> if the stage 2 mixer should be used for this subband. 1018 */ 1019 @XmlAttribute(required=false) 1020 public void setUseStage2Mixer(boolean use) { useMixer = use; } 1021 1022 /** 1023 * Returns <i>true</i> if the stage 2 mixer is in use for this subband. 1024 * @return <i>true</i> if the stage 2 mixer is in use for this subband. 1025 * @see #setUseStage2Mixer(boolean) 1026 */ 1027 public boolean getUseStage2Mixer() { return useMixer; } 1028 1029 //============================================================================ 1030 // 1031 //============================================================================ 1032 1033 /** 1034 * Returns an XML representation of this subband. 1035 * @return an XML representation of this subband. 1036 * @throws JAXBException if anything goes wrong during the conversion to XML. 1037 * @see #writeAsXmlTo(Writer) 1038 */ 1039 public String toXml() throws JAXBException 1040 { 1041 return JaxbUtility.getSharedInstance().objectToXmlString(this); 1042 } 1043 1044 /** 1045 * Writes an XML representation of this subband to {@code writer}. 1046 * @param writer the device to which XML is written. 1047 * @throws JAXBException if anything goes wrong during the conversion to XML. 1048 */ 1049 public void writeAsXmlTo(Writer writer) throws JAXBException 1050 { 1051 JaxbUtility.getSharedInstance().writeObjectAsXmlTo(writer, this, null); 1052 } 1053 1054 /** 1055 * Creates a new subband from the XML data in the given file. 1056 * 1057 * @param xmlFile 1058 * the name of an XML file. This method will attempt to locate 1059 * the file by using {@link Class#getResource(String)}. 1060 * 1061 * @return 1062 * a new subband from the XML data in the given file. 1063 * 1064 * @throws FileNotFoundException 1065 * if the XML file cannot be found. 1066 * 1067 * @throws JAXBException 1068 * if the schema file used (if any) is malformed, if the XML file cannot be 1069 * read, or if the XML file is not schema-valid. 1070 * 1071 * @throws XMLStreamException 1072 * if there is a problem opening the XML file, if the XML is not well-formed, 1073 * or for some other "unexpected processing conditions". 1074 */ 1075 public static WidarSubband fromXml(String xmlFile) 1076 throws JAXBException, XMLStreamException, FileNotFoundException 1077 { 1078 return JaxbUtility.getSharedInstance() 1079 .xmlFileToObject(xmlFile, WidarSubband.class); 1080 } 1081 1082 /** 1083 * Creates a new subband based on the XML data read from {@code reader}. 1084 * 1085 * @param reader 1086 * the source of the XML data. 1087 * If this value is <i>null</i>, <i>null</i> is returned. 1088 * 1089 * @return 1090 * a new subband based on the XML data read from {@code reader}. 1091 * 1092 * @throws XMLStreamException 1093 * if the XML is not well-formed, 1094 * or for some other "unexpected processing conditions". 1095 * 1096 * @throws JAXBException 1097 * if anything else goes wrong during the transformation. 1098 */ 1099 public static WidarSubband fromXml(Reader reader) 1100 throws JAXBException, XMLStreamException 1101 { 1102 return JaxbUtility.getSharedInstance() 1103 .readObjectAsXmlFrom(reader, WidarSubband.class, null); 1104 } 1105 1106 //============================================================================ 1107 // 1108 //============================================================================ 1109 1110 /** 1111 * Returns a copy of this subband. 1112 * <p> 1113 * The returned subband is <i>nearly</i>, but not quite, a deep copy of this 1114 * subband. Properties that are not copied:</p> 1115 * <ol> 1116 * <li>Those properties not copied by the 1117 * {@link CorrelatorSubbandAbs#clone() super class}.</li> 1118 * <li><b>baseline board pairs</b> - this collection will be empty.</li> 1119 * </ol> 1120 * <p> 1121 * If anything goes wrong during the cloning procedure, 1122 * a {@code RuntimeException} will be thrown.</p> 1123 */ 1124 @Override 1125 public WidarSubband clone() 1126 { 1127 WidarSubband clone = null; 1128 1129 try 1130 { 1131 clone = (WidarSubband)super.clone(); 1132 1133 copyVciElementsInto(clone); 1134 } 1135 catch (Exception ex) 1136 { 1137 throw new RuntimeException(ex); 1138 } 1139 1140 return clone; 1141 } 1142 1143 /** Returns <i>true</i> if {@code o} is equal to this subband. */ 1144 @Override 1145 public boolean equals(Object o) 1146 { 1147 //Quick exit if super class says not equal 1148 if (!super.equals(o)) 1149 return false; 1150 1151 //A safe cast if we got this far 1152 WidarSubband other = (WidarSubband)o; 1153 1154 //Attributes that we INTENTIONALLY DO NOT COMPARE: 1155 // blbps 1156 1157 return vciElementsAreEqual(other); 1158 } 1159 1160 /** Returns a hash code for this subband. */ 1161 @Override 1162 public int hashCode() 1163 { 1164 //Taken from the Effective Java book by Joshua Bloch. 1165 //The constants 17 & 37 are arbitrary & carry no meaning. 1166 int result = super.hashCode(); 1167 1168 //You MUST keep this method in sync w/ the equals method 1169 1170 result = 37 * result + vciElementsHashCode(); 1171 1172 return result; 1173 } 1174 1175 //============================================================================ 1176 // 1177 //============================================================================ 1178 /* 1179 public static void main(String[] args) 1180 { 1181 WidarBuilder builder = new WidarBuilder(); 1182 1183 WidarSubband sb = builder.makeSubband(); 1184 1185 try 1186 { 1187 sb.writeAsXmlTo(new java.io.PrintWriter(System.out)); 1188 } 1189 catch (Exception ex) 1190 { 1191 System.out.println("Trouble w/ sb.toXml. Msg:"); 1192 System.out.println(ex.getMessage()); 1193 ex.printStackTrace(); 1194 1195 System.out.println("Attempting to write XML w/out schema verification:"); 1196 JaxbUtility.getSharedInstance().setLookForDefaultSchema(false); 1197 try 1198 { 1199 System.out.println(sb.toXml()); 1200 } 1201 catch (JAXBException ex2) 1202 { 1203 System.out.println("Still had trouble w/ sb.toXml. Msg:"); 1204 System.out.println(ex2.getMessage()); 1205 ex2.printStackTrace(); 1206 } 1207 } 1208 } 1209 */ 1210 /* 1211 public static void main(String... args) throws Exception 1212 { 1213 WidarBaseband bb = new WidarBasebandSinglet(); 1214 bb.setBandwidth(new Frequency("2.048")); 1215 1216 WidarSubband sb = (WidarSubband)bb.makeNewSubband(); 1217 bb.addSubband(sb); 1218 sb.setBandwidth(new Frequency("64.0", FrequencyUnits.MEGAHERTZ)); 1219 1220 sb.setCentralFrequency(new Frequency("200.0", FrequencyUnits.MEGAHERTZ)); 1221 System.out.println("Wanted 200, got " + sb.getCentralFrequency()); 1222 sb.setCentralFrequency(new Frequency("223.0", FrequencyUnits.MEGAHERTZ)); 1223 System.out.println("Wanted 223, got " + sb.getCentralFrequency()); 1224 sb.setCentralFrequency(new Frequency("224.0", FrequencyUnits.MEGAHERTZ)); 1225 System.out.println("Wanted 224, got " + sb.getCentralFrequency()); 1226 sb.setCentralFrequency(new Frequency("225.0", FrequencyUnits.MEGAHERTZ)); 1227 System.out.println("Wanted 225, got " + sb.getCentralFrequency()); 1228 sb.setCentralFrequency(new Frequency("255.0", FrequencyUnits.MEGAHERTZ)); 1229 System.out.println("Wanted 255, got " + sb.getCentralFrequency()); 1230 sb.setCentralFrequency(new Frequency("256.0", FrequencyUnits.MEGAHERTZ)); 1231 System.out.println("Wanted 256, got " + sb.getCentralFrequency()); 1232 sb.setCentralFrequency(new Frequency("257.0", FrequencyUnits.MEGAHERTZ)); 1233 System.out.println("Wanted 257, got " + sb.getCentralFrequency()); 1234 System.out.println(); 1235 sb.setCentralFrequency(new Frequency("20.0", FrequencyUnits.MEGAHERTZ)); 1236 System.out.println("Wanted 20, got " + sb.getCentralFrequency()); 1237 System.out.println(); 1238 sb.setCentralFrequency(new Frequency("2040.0", FrequencyUnits.MEGAHERTZ)); 1239 System.out.println("Wanted 2040, got " + sb.getCentralFrequency()); 1240 sb.setCentralFrequency(new Frequency("2050.0", FrequencyUnits.MEGAHERTZ)); 1241 System.out.println("Wanted 2050, got " + sb.getCentralFrequency()); 1242 sb.setCentralFrequency(new Frequency("2200.0", FrequencyUnits.MEGAHERTZ)); 1243 System.out.println("Wanted 2200, got " + sb.getCentralFrequency()); 1244 } 1245 */ 1246 }