001 package edu.nrao.sss.measure; 002 003 import java.math.BigDecimal; 004 005 import static edu.nrao.sss.math.MathUtil.MC_INTERM_CALCS; 006 007 import static edu.nrao.sss.measure.DistanceUnits.KILOMETER; 008 import static edu.nrao.sss.measure.DistanceUnits.METER; 009 import static edu.nrao.sss.measure.FrequencyUnits.GIGAHERTZ; 010 import static edu.nrao.sss.measure.FrequencyUnits.KILOHERTZ; 011 import static edu.nrao.sss.measure.FrequencyUnits.HERTZ; 012 import static edu.nrao.sss.measure.LinearVelocityUnits.KILOMETERS_PER_SECOND; 013 014 /** 015 * A wave with properties of velocity, wavelength, and frequency. 016 * <p> 017 * <b>Version Info:</b> 018 * <table style="margin-left:2em"> 019 * <tr><td>$Revision: 1490 $</td></tr> 020 * <tr><td>$Date: 2008-08-13 16:38:27 -0600 (Wed, 13 Aug 2008) $</td></tr> 021 * <tr><td>$Author: dharland $</td></tr> 022 * </table></p> 023 * 024 * @author David M. Harland 025 * @since 2006-12-05 026 */ 027 public class Wave 028 { 029 private LinearVelocity velocity; 030 private Frequency frequency; 031 private Distance wavelength; 032 033 private boolean needToUpdateFrequency; 034 private boolean needToUpdateWavelength; 035 036 /** 037 * The speed of light in a vacuum, expressed in kilometers per second. 038 * The value used is <tt>299,792.458 km/s</tt>. 039 */ 040 public static final BigDecimal LIGHT_SPEED_VACUUM_KM_PER_SEC = 041 new BigDecimal("2.99792458e5"); 042 043 /** 044 * Creates a new wave with velocity equal to that of light in a vacuum. 045 * The default frequency of this wave is one gigahertz. 046 */ 047 public Wave() 048 { 049 this(new LinearVelocity(LIGHT_SPEED_VACUUM_KM_PER_SEC, 050 KILOMETERS_PER_SECOND)); 051 } 052 053 /** 054 * Creates a new wave with the given velocity. 055 * The default frequency of this wave is one gigahertz. 056 * 057 * @param speedOfWave the velocity of this wave. 058 * 059 * @throws IllegalArgumentException if {@code speedOfWave} is <i>null</i> 060 * or has a non-positive value. 061 */ 062 public Wave(LinearVelocity speedOfWave) 063 { 064 validateVelocity(speedOfWave); 065 066 velocity = speedOfWave.clone(); 067 frequency = new Frequency("1.0", GIGAHERTZ); 068 wavelength = new Distance(); //a dummy value 069 070 needToUpdateFrequency = false; 071 needToUpdateWavelength = true; 072 } 073 074 //============================================================================ 075 // VELOCITY 076 //============================================================================ 077 078 /** 079 * Sets this wave's velocity so that it is equal to {@code newVelocity}. 080 * Changing this wave's velocity will force a corresponding change in its 081 * wavelength while its frequency will be held constant. 082 * 083 * @param newVelocity a new velocity for this wave. 084 * @return this wave 085 * @throws IllegalArgumentException if {@code newVelocity} is <i>null</i> 086 * or has a non-positive value. 087 */ 088 public Wave setVelocity(LinearVelocity newVelocity) 089 { 090 validateVelocity(newVelocity); 091 092 velocity = newVelocity.clone(); 093 094 needToUpdateWavelength = true; 095 096 return this; 097 } 098 099 /** 100 * Returns a copy of the velocity of this wave. 101 * @return a copy of the velocity of this wave. 102 */ 103 public LinearVelocity getVelocity() 104 { 105 //Can't provide reference because clients could alter it 106 return velocity.clone(); 107 } 108 109 /** 110 * Returns the velocity of this wave in the given units. 111 * This method will be faster than calling 112 * {@code getVelocity().toUnits(units)} because {@link #getVelocity()} 113 * makes a copy of this wave's velocity, while this method does not. 114 * 115 * @param units units of velocity. 116 * @return the velocity of this wave in the given units. 117 */ 118 public BigDecimal getVelocityValueIn(LinearVelocityUnits units) 119 { 120 return velocity.toUnits(units); 121 } 122 123 /** Ensures velocity value is valid. */ 124 private void validateVelocity(LinearVelocity v) 125 { 126 if (v == null) 127 throw new IllegalArgumentException("May not use NULL velocity."); 128 129 if (v.getValue().signum() <= 0) 130 throw new IllegalArgumentException("Velocity must be positive."); 131 } 132 133 //============================================================================ 134 // FREQUENCY 135 //============================================================================ 136 137 /** 138 * Sets this wave's frequency so that it is equal to {@code newFrequency}. 139 * Changing this wave's frequency will result in a corresponding change 140 * in its wavelength while its velocity will be held constant. 141 * 142 * @param newFrequency a new frequency for this wave. 143 * @return this wave. 144 * @throws IllegalArgumentException if {@code newFrequency} is <i>null</i> 145 * or has a non-positive value. 146 */ 147 public Wave setFrequency(Frequency newFrequency) 148 { 149 validateFrequency(newFrequency); 150 151 //Can't save reference because clients could alter it 152 frequency = newFrequency.clone(); 153 154 needToUpdateFrequency = false; 155 needToUpdateWavelength = true; 156 157 return this; 158 } 159 160 /** 161 * Returns a copy of this wave's frequency. 162 * @return a copy of this wave's frequency. 163 */ 164 public Frequency getFrequency() 165 { 166 if (needToUpdateFrequency) 167 updateFrequency(); 168 169 //Can't provide reference because clients could alter it 170 return frequency.clone(); 171 } 172 173 /** 174 * Returns the frequency of this wave in the given units. 175 * This method will be faster than calling 176 * {@code getFrequency().asUnitsOf(units)} because {@link #getFrequency()} 177 * makes a copy of this wave's frequency, while this method does not. 178 * 179 * @param units units of frequency. 180 * @return the frequency of this wave in the given units. 181 */ 182 public BigDecimal getFrequencyValueIn(FrequencyUnits units) 183 { 184 if (needToUpdateFrequency) 185 updateFrequency(); 186 187 return frequency.toUnits(units); 188 } 189 190 /** Ensures frequency value is valid. */ 191 private void validateFrequency(Frequency f) 192 { 193 if (f == null) 194 throw new IllegalArgumentException("May not use NULL frequency."); 195 196 if (f.getValue().compareTo(BigDecimal.ZERO) <= 0) 197 throw new IllegalArgumentException("Frequency must be positive."); 198 } 199 200 /** Updates the frequency based on velocity & wavelength. */ 201 private void updateFrequency() 202 { 203 BigDecimal kms = velocity.toUnits(KILOMETERS_PER_SECOND); 204 BigDecimal km = wavelength.toUnits(KILOMETER); 205 206 BigDecimal hertz = kms.divide(km, MC_INTERM_CALCS); 207 208 frequency.set(hertz, HERTZ); 209 } 210 211 //============================================================================ 212 // WAVELENGTH 213 //============================================================================ 214 215 /** 216 * Sets this wave's wavelength so that it is equal to {@code newWavelength}. 217 * Changing this wave's wavelength will result in a corresponding change 218 * in its frequency while its velocity will be held constant. 219 * 220 * @param newWavelength a new wavelength for this wave. 221 * @return this wave. 222 * @throws IllegalArgumentException if {@code newWavelength} is <i>null</i> 223 * or has a non-positive length. 224 */ 225 public Wave setWavelength(Distance newWavelength) 226 { 227 validateWavelength(newWavelength); 228 229 //Can't save reference because clients could alter it 230 wavelength = newWavelength.clone(); 231 232 needToUpdateFrequency = true; 233 needToUpdateWavelength = false; 234 235 return this; 236 } 237 238 /** 239 * Returns a copy of this wave's wavelength. 240 * @return a copy of this wave's wavelength. 241 */ 242 public Distance getWavelength() 243 { 244 if (needToUpdateWavelength) 245 updateWavelength(); 246 247 //Can't provide reference because clients could alter it 248 return wavelength.clone(); 249 } 250 251 /** 252 * Returns the wavelength of this wave in the given units. 253 * This method will be faster than calling 254 * {@code getWavelength().toUnits(units)} because {@link #getWavelength()} 255 * makes a copy of this wave's wavelength, while this method does not. 256 * 257 * @param units units of wavelength. 258 * @return the wavelength of this wave in the given units. 259 */ 260 public BigDecimal getWavelengthValueIn(DistanceUnits units) 261 { 262 if (needToUpdateWavelength) 263 updateWavelength(); 264 265 return wavelength.toUnits(units); 266 } 267 268 /** Ensures frequency value is valid. */ 269 private void validateWavelength(Distance d) 270 { 271 if (d == null) 272 throw new IllegalArgumentException("May not use NULL wavelength."); 273 274 if (d.getValue().signum() <= 0) 275 throw new IllegalArgumentException("Wavelength must be positive."); 276 } 277 278 /** Updates the wavelength based on velocity & frequency. */ 279 private void updateWavelength() 280 { 281 BigDecimal kms = velocity.toUnits(KILOMETERS_PER_SECOND); 282 BigDecimal kHz = frequency.toUnits(KILOHERTZ); 283 284 BigDecimal meters = kms.divide(kHz, MC_INTERM_CALCS); 285 286 wavelength.set(meters, METER); 287 } 288 289 //============================================================================ 290 // 291 //============================================================================ 292 293 @Override 294 public String toString() 295 { 296 StringBuilder buff = new StringBuilder(); 297 298 buff.append(getVelocity()).append(", "); 299 buff.append(getFrequency().normalize()).append(", "); 300 buff.append(getWavelength()); 301 302 return buff.toString(); 303 } 304 }