001 package edu.nrao.sss.model.project.scan; 002 003 import java.util.ArrayList; 004 import java.util.Collections; 005 import java.util.List; 006 007 import javax.xml.bind.annotation.XmlElement; 008 import javax.xml.bind.annotation.XmlElementWrapper; 009 import javax.xml.bind.annotation.XmlRootElement; 010 011 import edu.nrao.sss.measure.TimeDuration; 012 013 /** 014 * A scan that is used to determine the timing delays needed to synchronize 015 * the incoming signals for antennas in an array. 016 * <p> 017 * <b>Version Info:</b> 018 * <table style="margin-left:2em"> 019 * <tr><td>$Revision: 931 $</td></tr> 020 * <tr><td>$Date: 2007-09-28 14:41:38 -0600 (Fri, 28 Sep 2007) $</td></tr> 021 * <tr><td>$Author: dharland $</td></tr> 022 * </table></p> 023 * 024 * @author David M. Harland 025 * @since 2006-07-18 026 */ 027 @XmlRootElement 028 public class DelayScan 029 extends Scan 030 { 031 private List<DelaySetting> delays; 032 033 /** Creates a new instance. */ 034 DelayScan() 035 { 036 super(); 037 038 delays = new ArrayList<DelaySetting>(); 039 } 040 041 /** 042 * Sets the collection of delay settings held by this scan. 043 * A <i>null</i> {@code replacementSet} will be interpreted 044 * as a new empty list. 045 * <p> 046 * This scan will hold a reference to {@code replacementSet} 047 * (unless it is <i>null</i>), so any changes made to the list 048 * after calling this method will be reflected in this object.</p> 049 * 050 * @param replacementSet a set of delay settings to be held by this scan. 051 */ 052 public void setDelays(List<DelaySetting> replacementSet) 053 { 054 delays = (replacementSet == null) ? new ArrayList<DelaySetting>() 055 : replacementSet; 056 } 057 058 /** 059 * Returns a set of delay settings. 060 * <p> 061 * The returned set, which is guaranteed to be non-null, 062 * is the actual set held by this scan, 063 * so changes made to the set will be reflected in this 064 * object.</p> 065 * 066 * @return a set of delay settings. 067 */ 068 @XmlElementWrapper 069 @XmlElement(name="delaySetting") 070 public List<DelaySetting> getDelays() 071 { 072 return delays; 073 } 074 075 /** 076 * Sorts the internal list of delays and returns it. 077 * <p> 078 * The returned list is the actual list held by this scan, 079 * so changes made to the list will be reflected in this 080 * object.</p> 081 * 082 * @return the list of delays settings held by this scan, after they have 083 * been sorted. 084 */ 085 public List<DelaySetting> sortDelays() 086 { 087 Collections.sort(delays); 088 return delays; 089 } 090 091 /** 092 * Adds a series of delays to this scan's list. 093 * The number of new delays added is equal to 094 * <tt>1 + 2 * numberOfPositiveDelays</tt>. 095 * If we call the <tt>numberOfPositiveDelays</tt> "<tt>n</tt>" 096 * and the <tt>incrementalNanosecondDelay</tt> "<tt>t</tt>", delays 097 * of the following durations will be added to this scan: 098 * <p> 099 * <tt> -nt,...,-2t,-t,0,+t,+2t,...,+nt</tt>.</p> 100 * <p> 101 * Note that these delays are relative to the current value of the delay 102 * and are, therefore, allowed to be negative.</p> 103 * 104 * @param numberOfPositiveDelays 105 * the number of positive delays to be added. The total number of delays 106 * added is equal to one plus two times this amount. An {@code 107 * IllegalArgumentException} will be thrown if this value is negative. 108 * 109 * @param incrementalNanosecondDelay 110 * the spacing between the delays added by this method. 111 * An {@code IllegalArgumentException} will be 112 * thrown if this value less than or equal to zero. 113 * 114 * @param timeAtSetting 115 * the amount of time the delay should be placed at this setting. 116 * 117 * @throws IllegalArgumentException 118 * if any of the parameters violate the rules listed above. 119 */ 120 public void addDelays(int numberOfPositiveDelays, 121 double incrementalNanosecondDelay, 122 TimeDuration timeAtSetting) 123 { 124 validateParameters(numberOfPositiveDelays, 125 incrementalNanosecondDelay, timeAtSetting); 126 127 double ns = -numberOfPositiveDelays * incrementalNanosecondDelay; 128 129 int offsetCount = 1 + 2 * numberOfPositiveDelays; 130 131 for (int i=1; i <= offsetCount; i++) 132 { 133 DelaySetting setting = new DelaySetting(); 134 135 setting.setNanoseconds(ns); 136 setting.getTimeAtSetting().set(timeAtSetting); 137 138 delays.add(setting); 139 140 ns += incrementalNanosecondDelay; 141 } 142 } 143 144 /** 145 * Adds a series of delays to this scan's list. 146 * The number of new delays added is {@code numberOfDelays}. 147 * The smallest new delay is {@code minNanosecondDelay}, the largest is 148 * {@code maxNanosecondDelay}. The other delays are spread evenly between 149 * these two endpoints. 150 * <p> 151 * Note that these delays are relative to the current value of the delay 152 * and are, therefore, allowed to be negative.</p> 153 * 154 * @param minNanosecondDelay 155 * the smallest delay. This value is often negative, 156 * 157 * @param maxNanosecondDelay 158 * the largest delay. An {@code IllegalArgumentException} will be thrown if 159 * this value is less than or equal to the {@code minNanosecondDelay}. 160 * 161 * @param numberOfDelays 162 * the number of new delays to be added. 163 * Special cases:<ul> 164 * <li>numberOfDelays < 1: No new delays will be added.</li> 165 * <li>numberOfDelays == 1: Only the {@code minNanosecondDelay} 166 * will be added.</li> 167 * <li>numberOfDelays == 2: Only the {@code minNanosecondDelay} 168 * and {@code maxNanosecondDelay} 169 * will be added.</li> 170 * </ul> 171 * 172 * @param timeAtSetting 173 * the amount of time the delay should be placed at this setting. 174 * 175 * @throws IllegalArgumentException 176 * if any of the parameters violate the rules listed above. 177 */ 178 public void addDelays(double minNanosecondDelay, double maxNanosecondDelay, 179 int numberOfDelays, TimeDuration timeAtSetting) 180 { 181 validateParameters(minNanosecondDelay, maxNanosecondDelay, 182 numberOfDelays, timeAtSetting); 183 184 //Special cases 185 if (numberOfDelays < 1) //No action 186 { 187 return; 188 } 189 else if (numberOfDelays <= 2) //Add only min (& possibly max) 190 { 191 DelaySetting minDelay = new DelaySetting(); 192 minDelay.setNanoseconds(minNanosecondDelay); 193 minDelay.getTimeAtSetting().set(timeAtSetting); 194 delays.add(minDelay); 195 196 if (numberOfDelays == 2) //Add only min & max delays 197 { 198 DelaySetting maxDelay = new DelaySetting(); 199 maxDelay.setNanoseconds(maxNanosecondDelay); 200 maxDelay.getTimeAtSetting().set(timeAtSetting); 201 delays.add(maxDelay); 202 } 203 } 204 //Normal logic 205 else 206 { 207 double ns = minNanosecondDelay; 208 double increment = (maxNanosecondDelay - minNanosecondDelay) / 209 (numberOfDelays - 1); 210 211 for (int i=1; i <= numberOfDelays; i++) 212 { 213 DelaySetting setting = new DelaySetting(); 214 215 setting.getTimeAtSetting().set(timeAtSetting); 216 setting.setNanoseconds(ns); 217 218 delays.add(setting); 219 220 ns += increment; 221 } 222 } 223 } 224 225 /** Helps addOffsets(...). */ 226 private void validateParameters(int numberOfPositiveDelays, 227 double incrementalNanosecondDelay, 228 TimeDuration timeAtSetting) 229 { 230 final String errMsgStart = "Illegal value for "; 231 232 if (numberOfPositiveDelays < 0) 233 { 234 StringBuilder errMsg = new StringBuilder(errMsgStart); 235 errMsg.append("numberOfPositiveDelays (") 236 .append(numberOfPositiveDelays) 237 .append("): value may not be negative."); 238 throw new IllegalArgumentException(errMsg.toString()); 239 } 240 241 if (incrementalNanosecondDelay <= 0.0) 242 { 243 StringBuilder errMsg = new StringBuilder(errMsgStart); 244 errMsg.append("incrementalNanosecondDelay (") 245 .append(incrementalNanosecondDelay) 246 .append("): value must be positive."); 247 throw new IllegalArgumentException(errMsg.toString()); 248 } 249 } 250 251 /** Helps addOffsets(...). */ 252 private void validateParameters(double minNanosecondDelay, 253 double maxNanosecondDelay, 254 int numberOfOffsets, 255 TimeDuration timeAtOffset) 256 { 257 if (minNanosecondDelay >= maxNanosecondDelay) 258 { 259 StringBuilder errMsg = new StringBuilder("The minimum delay ("); 260 errMsg.append(minNanosecondDelay) 261 .append(") must be less than the maximum delay (") 262 .append(maxNanosecondDelay).append(")."); 263 throw new IllegalArgumentException(errMsg.toString()); 264 } 265 } 266 267 //============================================================================ 268 // TEXT 269 //============================================================================ 270 271 /* (non-Javadoc) 272 * @see edu.nrao.sss.model.project.scan.ScanLoopElement#toString() 273 */ 274 public String toSummaryString() 275 { 276 StringBuilder buff = new StringBuilder(super.toSummaryString()); 277 278 buff.append(", delayCnt=").append(delays.size()); 279 280 return buff.toString(); 281 } 282 283 //============================================================================ 284 // 285 //============================================================================ 286 287 /** 288 * Returns a delay scan that is a copy of this one. 289 * <p> 290 * The returned scan is, for the most part, a deep copy of this one. 291 * However, there are a few exceptions noted in the 292 * {@link ScanLoop#clone() clone method} of this class's parent.</p> 293 * <p> 294 * If anything goes wrong during the cloning procedure, 295 * a {@code RuntimeException} will be thrown.</p> 296 */ 297 public DelayScan clone() 298 { 299 DelayScan clone = null; 300 301 try 302 { 303 clone = (DelayScan)super.clone(); 304 305 //Need to clone set AND contained elements. 306 clone.delays = new ArrayList<DelaySetting>(); 307 for (DelaySetting ds : this.delays) 308 clone.delays.add(ds.clone()); 309 } 310 catch (Exception ex) 311 { 312 throw new RuntimeException(ex); 313 } 314 315 return clone; 316 } 317 318 /** 319 * Returns <i>true</i> if {@code o} is equal to this delay scan. 320 * <p> 321 * In order for {@code o} to be equal to this scan, it must have 322 * equal delay settings in the same order as those of this scan. 323 * It must also follow the rules set forth in the 324 * {@link ScanLoop#equals(Object) equals method} of this class's parent.</p> 325 */ 326 public boolean equals(Object o) 327 { 328 //Quick exit if o is this object 329 if (o == this) 330 return true; 331 332 //Not equal if super class says not equal 333 if (!super.equals(o)) 334 return false; 335 336 //Super class tested for Class equality, so cast is safe 337 DelayScan other = (DelayScan)o; 338 339 //Compare attributes 340 return other.delays.equals(this.delays); 341 } 342 343 /* (non-Javadoc) 344 * @see edu.nrao.sss.model.project.scan.Scan#hashCode() 345 */ 346 public int hashCode() 347 { 348 //Taken from the Effective Java book by Joshua Bloch. 349 //The constant 37 is arbitrary & carries no meaning. 350 int result = 37 * super.hashCode(); 351 352 result = 37 * result + delays.hashCode(); 353 354 return result; 355 } 356 357 //============================================================================ 358 // 359 //============================================================================ 360 /* 361 public static void main(String[] args) throws Exception 362 { 363 DelayScan scan1 = new DelayScan(); 364 DelayScan scan2 = new DelayScan(); 365 366 scan1.addDelays(5, 367 1.5, 368 new TimeDuration(5.0, edu.nrao.sss.measure.TimeUnits.MINUTE)); 369 370 scan2.addDelays(-7.5, 371 +7.5, 372 11, 373 new TimeDuration(5.0, edu.nrao.sss.measure.TimeUnits.MINUTE)); 374 375 System.out.println("SCAN 1:"); 376 for (DelaySetting setting : scan1.getDelays()) 377 System.out.println(" " + setting); 378 379 System.out.println(); 380 381 System.out.println("SCAN 2:"); 382 for (DelaySetting setting : scan2.getDelays()) 383 System.out.println(" " + setting); 384 } 385 */ 386 }