001 package edu.nrao.sss.model.resource.evla; 002 003 import static edu.nrao.sss.measure.TimeUnits.MICROSECOND; 004 import static edu.nrao.sss.measure.TimeUnits.SECOND; 005 006 import java.math.BigDecimal; 007 import java.math.RoundingMode; 008 009 import javax.xml.bind.annotation.XmlAttribute; 010 011 import ca.nrc.widar.jaxb.vci.BlbProdIntegration; 012 import edu.nrao.sss.math.MathUtil; 013 import edu.nrao.sss.measure.TimeDuration; 014 015 /** 016 * Components of integration time for WIDAR correlation products. 017 * <p> 018 * The VCI element to which this class is mapped is 019 * {@link ca.nrc.widar.jaxb.vci.BlbProdIntegration}. 020 * </p> 021 * <p> 022 * <b>Version Info:</b> 023 * <table style="margin-left:2em"> 024 * <tr><td>$Revision: 2133 $</td></tr> 025 * <tr><td>$Date: 2009-03-20 14:24:28 -0600 (Fri, 20 Mar 2009) $</td></tr> 026 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 027 * </table></p> 028 * 029 * @author David M. Harland 030 * @since 2008-11-26 031 */ 032 public class WidarIntegrationTime 033 { 034 private static final BigDecimal HW_NO_RECIRC_IDEAL_uS = new BigDecimal("400.0"); 035 private static final BigDecimal HW_RECIRC_IDEAL_uS = new BigDecimal("200.0"); 036 private static final BigDecimal LTA_IDEAL_uS = new BigDecimal("1000000.0"); //one second 037 038 private WidarCorrelationProductGroup group; 039 040 private TimeDuration minHwIntTime; 041 private int multCorrChip; 042 private int multLTA; 043 private int multCBE; 044 045 WidarIntegrationTime(WidarCorrelationProductGroup container) 046 { 047 if (container == null) 048 throw new IllegalArgumentException( 049 "WidarIntegrationTime may not be created for NULL group."); 050 051 group = container; 052 053 init(); 054 setTotalIntegrationTime(new TimeDuration("1.0", SECOND)); 055 } 056 057 //Used by copy mechanism, and also by things like jaxb & hibernate 058 private WidarIntegrationTime() { init(); } 059 060 private void init() 061 { 062 minHwIntTime = new TimeDuration("200.0", MICROSECOND); 063 } 064 065 //============================================================================ 066 // MINIMUM HARDWARE INTEGRATION TIME 067 //============================================================================ 068 069 /** 070 * Returns the smallest legal value for the concept called 071 * the <i>minimum hardware integration time</i>. 072 * 073 * @return 074 * the smallest legal value for the minimum hardware integration time. 075 */ 076 public TimeDuration getSmallestMinimumHardwareIntegrationTime() 077 { 078 //TODO temp code below. See table 4-18, VCI ver 3.3, p74. 079 // Missing from below is determination of # of CCCs dumped 080 // per CC per LTA frame. 081 int ccc = 16; 082 083 BigDecimal microSec = new BigDecimal("2.5"); 084 if (ccc <= 1) 085 { 086 if (multLTA > 1) 087 microSec = new BigDecimal("15"); 088 } 089 else //ccc > 1 090 { 091 if (multLTA > 1) 092 microSec = new BigDecimal("200"); 093 else 094 microSec = microSec.multiply(new BigDecimal(ccc)); 095 } 096 097 return new TimeDuration(microSec, MICROSECOND); 098 } 099 100 /** 101 * Returns the largest legal value for the concept called 102 * the <i>minimum hardware integration time</i>. 103 * 104 * @return 105 * the largest legal value for the minimum hardware integration time. 106 */ 107 public TimeDuration getLargestMinimumHardwareIntegrationTime() 108 { 109 return new TimeDuration("400.0", MICROSECOND); 110 } 111 112 private static BigDecimal TIME_MULT = 113 new BigDecimal("64000000.0", MathUtil.MC_INTERM_CALCS); 114 115 /** 116 * Sets the minimum hardware integration time for this group of 117 * correlation products. 118 * <p> 119 * The minimum hardware integration time can take on only certain 120 * values. The maximum value is 400µs. The minimum value 121 * depends on the number of correlator chip cells per correlator 122 * chip that are being dumped, and also depends on the value of 123 * the LTA multiplier. Values in between these limits must be 124 * equal to N / 64MHz, where N is some integer.</p> 125 * 126 * @param minHwTime 127 * the new minimum hardware integration time for this group of 128 * correlation products. 129 * 130 * @see #getLargestMinimumHardwareIntegrationTime() 131 * @see #getSmallestMinimumHardwareIntegrationTime() 132 */ 133 public void setMinimumHardwareIntegrationTime(TimeDuration minHwTime) 134 { 135 //Time must be N/64MHz, where N is an integer 136 BigDecimal N = minHwTime.toUnits(SECOND).multiply(TIME_MULT); 137 N = N.setScale(0, RoundingMode.HALF_UP); 138 BigDecimal seconds = N.divide(TIME_MULT, MathUtil.MC_FINAL_CALC); 139 140 minHwIntTime.set(seconds, SECOND); 141 142 //Test against min/max 143 TimeDuration min = getSmallestMinimumHardwareIntegrationTime(); 144 if (minHwIntTime.compareTo(min) < 0) 145 { 146 minHwIntTime = min; 147 } 148 else 149 { 150 TimeDuration max = getLargestMinimumHardwareIntegrationTime(); 151 if (minHwIntTime.compareTo(max) > 0) 152 minHwIntTime = max; 153 else 154 minHwIntTime.convertTo(MICROSECOND); 155 } 156 } 157 158 /** 159 * Returns the minimum hardware integration time setting for this group of 160 * correlation products. 161 * The returned value is a copy of the one held internally, so changes 162 * made to it will not be reflected in this object. 163 * 164 * @return 165 * the minimum hardware integration time setting for this group of 166 * correlation products. 167 */ 168 public TimeDuration getMinimumHardwareIntegrationTime() 169 { 170 return minHwIntTime.clone(); 171 } 172 173 //============================================================================ 174 // MULTIPLIERS 175 //============================================================================ 176 177 /** 178 * Sets the correlator chip multiplier component of this integration time. 179 * @param newMult 180 * the new correlator chip multiplier value. 181 */ 182 @XmlAttribute(name="ccMult", required=true) 183 public void setCorrelatorChipMultiplier(int newMult) 184 { 185 if (newMult < 1) 186 throw new IllegalArgumentException("Illegal corr chip mult value: " + 187 newMult + ". Must be >= 1."); 188 //TODO make sure LTA time is legal. Suggested=1.0s; max ~ 16.7s 189 190 multCorrChip = newMult; 191 } 192 193 194 /** 195 * Returns the correlator chip multiplier component of this integration time. 196 * @return the correlator chip multiplier component of this integration time. 197 * @see #getTotalIntegrationTime() 198 */ 199 public int getCorrelatorChipMultiplier() 200 { 201 return multCorrChip; 202 } 203 204 /** 205 * Sets the correlator back end multiplier component of this integration time. 206 * @param newMult 207 * the new CBE multiplier value. 208 */ 209 @XmlAttribute(name="cbeMult", required=true) 210 public void setBackEndMultiplier(int newMult) 211 { 212 if (newMult < 1) 213 throw new IllegalArgumentException("Illegal CBE mult value: " + 214 newMult + ". Must be >= 1."); 215 multCBE = newMult; 216 } 217 218 /** 219 * Returns the correlator back end multiplier component of this integration time. 220 * @return the CBE multiplier component of this integration time. 221 * @see #getTotalIntegrationTime() 222 */ 223 public int getBackEndMultiplier() 224 { 225 return multCBE; 226 } 227 228 /** 229 * Sets the long term accumulator multiplier component of this integration time. 230 * @param newMult 231 * the new LTA multiplier value. 232 */ 233 @XmlAttribute(name="ltaMult", required=true) 234 public void setLongTermAccumulatorMultiplier(int newMult) 235 { 236 if (newMult < 1) 237 throw new IllegalArgumentException("Illegal LTA mult value: " + 238 newMult + ". Must be >= 1."); 239 //TODO make sure LTA time is legal. Suggested=1.0s; max ~ 16.7s 240 241 multLTA = newMult; 242 } 243 244 /** 245 * Returns the long term accumulator multiplier component of this integration time. 246 * @return the LTA multiplier component of this integration time. 247 * @see #getTotalIntegrationTime() 248 */ 249 public int getLongTermAccumulatorMultiplier() 250 { 251 return multLTA; 252 } 253 254 //============================================================================ 255 // TOTAL INTEGRATION TIME 256 //============================================================================ 257 258 /** 259 * Returns the smallest total integration time that may be used for the 260 * containing group of correlation products. 261 * 262 * @return 263 * smallest allowable total integration time. 264 */ 265 public TimeDuration getMinimumTotalIntegrationTime() 266 { 267 return getSmallestMinimumHardwareIntegrationTime(); 268 } 269 270 /** 271 * Returns the total integration time for the 272 * containing group of correlation products. 273 * <p> 274 * The total integration time equals:</p> 275 * <pre> 276 * {@link #getMinimumHardwareIntegrationTime()} * 277 * {@link #getCorrelatorChipMultiplier()} * 278 * {@link #getLongTermAccumulatorMultiplier()} * 279 * {@link #getBackEndMultiplier()} 280 * </pre> 281 * <p> 282 * The returned duration is <i>not</i> held internally by this object, 283 * so changes made to it will not be reflected herein.</p> 284 * 285 * @return 286 * total integration time. 287 */ 288 public TimeDuration getTotalIntegrationTime() 289 { 290 TimeDuration intTime = getMinimumHardwareIntegrationTime(); //a clone 291 292 intTime.multiplyBy(new BigDecimal(multCorrChip)); 293 intTime.multiplyBy(new BigDecimal(multLTA)); 294 intTime.multiplyBy(new BigDecimal(multCBE)); 295 296 return intTime; 297 } 298 299 /** 300 * Sets the total integration time for the 301 * containing group of correlation products. 302 * 303 * @param totalDuration 304 * the new total integration time. 305 * If this value is <i>null</i> this method does nothing. 306 * 307 * @see #getTotalIntegrationTime() 308 */ 309 void setTotalIntegrationTime(TimeDuration totalDuration) 310 { 311 if (totalDuration == null) 312 return; 313 314 //We assume here that we are NOT free to change the group's 315 //minimum hardware integration time. 316 //TODO examine above assumption 317 318 BigDecimal desiredTotalMicroseconds = totalDuration.toUnits(MICROSECOND); 319 320 BigDecimal minHwMs = getMinimumHardwareIntegrationTime().toUnits(MICROSECOND); 321 322 //Set up the CC factor. We'll get as close as we can w/out going over ideal. 323 int rf = group.getRecirculationFactor(); 324 325 BigDecimal idealCcMs = (rf == 1) ? HW_NO_RECIRC_IDEAL_uS : HW_RECIRC_IDEAL_uS; 326 327 BigDecimal goal = idealCcMs.compareTo(desiredTotalMicroseconds) <= 0 ? 328 idealCcMs : desiredTotalMicroseconds; //Taking lesser 329 330 int factor = goal.divide(minHwMs, RoundingMode.HALF_UP).intValue(); 331 332 if (factor < 1) 333 factor = 1; 334 335 multCorrChip = factor; 336 337 //Set up the ideal LTA factor. We'll get as close as we can w/out going over. 338 BigDecimal ccMs = minHwMs.multiply(new BigDecimal(factor)); 339 340 boolean done = ccMs.compareTo(desiredTotalMicroseconds) >= 0; 341 342 if (!done) 343 { 344 goal = LTA_IDEAL_uS.compareTo(desiredTotalMicroseconds) <= 0 ? 345 LTA_IDEAL_uS : desiredTotalMicroseconds; //Taking lesser 346 347 factor = goal.divide(ccMs, RoundingMode.HALF_UP).intValue(); 348 349 if (factor < 1) 350 factor = 1; 351 } 352 else 353 { 354 factor = 1; 355 } 356 357 multLTA = factor; 358 359 //If we haven't reached the goal, put rest in CBE. Come as close as possible. 360 BigDecimal ltaMs = null; 361 362 if (!done) //Ie, if CC did not eat up everything, see if LTA did 363 { 364 ltaMs = ccMs.multiply(new BigDecimal(factor)); 365 366 done = ltaMs.compareTo(desiredTotalMicroseconds) >= 0; 367 } 368 369 if (!done) //Ie, if LTA did not eat up everything, put rest in CBE 370 { 371 goal = desiredTotalMicroseconds; 372 373 factor = (int)Math.round(goal.divide(ltaMs, RoundingMode.HALF_UP).doubleValue()); 374 375 if (factor < 1) 376 factor = 1; 377 } 378 else 379 { 380 factor = 1; 381 } 382 383 //TODO cut CBE factor down by subband.recircFactor? 384 385 multCBE = factor; 386 } 387 388 //============================================================================ 389 // VCI 390 //============================================================================ 391 392 /** 393 * Returns a <i>Virtual Correlator Interface</i> (VCI) representation of this 394 * object. 395 * 396 * @return 397 * a VCI object built from this one. 398 */ 399 public BlbProdIntegration toVci() 400 { 401 BlbProdIntegration vciObj = new BlbProdIntegration(); 402 403 vciObj.setMinIntegTime(minHwIntTime.toUnits(MICROSECOND).doubleValue()); 404 vciObj.setCcIntegFactor(multCorrChip); 405 vciObj.setLtaIntegFactor(multLTA); 406 vciObj.setCbeIntegFactor(multCBE); 407 408 vciObj.setRecirculation(group.getRecirculationFactor()); 409 410 return vciObj; 411 } 412 413 //============================================================================ 414 // 415 //============================================================================ 416 417 /** 418 * Creates a copy of this object. 419 * The new copy is identical to this one, except: 420 * <ol> 421 * <li>Its group is {@code otherGroup}.</li> 422 * </ol> 423 * Note that this method does <i>not</i> tell {@code otherGroup} about 424 * the new object. The link forged in this method is one-way; clients 425 * are responsible for the link in the other direction. 426 */ 427 WidarIntegrationTime makeCopyFor(WidarCorrelationProductGroup otherGroup) 428 { 429 WidarIntegrationTime newTiming = new WidarIntegrationTime(); 430 431 newTiming.group = otherGroup; 432 433 newTiming.minHwIntTime = this.minHwIntTime.clone(); 434 newTiming.multCorrChip = this.multCorrChip; 435 newTiming.multLTA = this.multLTA; 436 newTiming.multCBE = this.multCBE; 437 438 return newTiming; 439 } 440 441 /** Returns <i>true</i> if <tt>o</tt> is equal to this object. */ 442 @Override 443 public boolean equals(Object o) 444 { 445 //Quick exit if o is null 446 if (o == null) 447 return false; 448 449 //Quick exit if o is this 450 if (o == this) 451 return true; 452 453 //Quick exit if classes are different 454 if (!o.getClass().equals(this.getClass())) 455 return false; 456 457 WidarIntegrationTime other = (WidarIntegrationTime)o; 458 459 if (other.multCBE != this.multCBE || 460 other.multCorrChip != this.multCorrChip || 461 other.multLTA != this.multLTA) 462 return false; 463 464 return other.minHwIntTime.equals(this.minHwIntTime); 465 } 466 467 /** Returns a hash code for this object. */ 468 @Override 469 public int hashCode() 470 { 471 //Taken from the Effective Java book by Joshua Bloch. 472 //The constants 17 & 37 are arbitrary & carry no meaning. 473 int result = 17; 474 475 //You MUST keep this method in sync w/ the equals method 476 477 result = 37 * result + multCBE; 478 result = 37 * result + multCorrChip; 479 result = 37 * result + multLTA; 480 result = 37 * result + minHwIntTime.hashCode(); 481 482 return result; 483 } 484 }