bessel.tcl

Go to the documentation of this file.
00001 /*  bessel.tcl --*/
00002 /*     Evaluate the most common Bessel functions*/
00003 /* */
00004 /*  TODO:*/
00005 /*     Yn - finding decent approximations seems tough*/
00006 /*     Jnu - for arbitrary values of the parameter*/
00007 /*     J'n - first derivative (from recurrence relation)*/
00008 /*     Kn - forward application of recurrence relation?*/
00009 /* */
00010 
00011 /*  namespace special*/
00012 /*     Create a convenient namespace for the "special" mathematical functions*/
00013 /* */
00014 namespace ::math::special {
00015     /* */
00016     /*  Define a number of common mathematical constants*/
00017     /* */
00018     ::math::constants::constants pi
00019 
00020     /* */
00021     /*  Export the functions*/
00022     /* */
00023     namespace export J0 J1 Jn J1/2 J-1/2 I_n
00024 }
00025 
00026 /*  J0 --*/
00027 /*     Zeroth-order Bessel function*/
00028 /* */
00029 /*  Arguments:*/
00030 /*     x         Value of the x-coordinate*/
00031 /*  Result:*/
00032 /*     Value of J0(x)*/
00033 /* */
00034 ret  ::math::special::J0 (type x) {
00035     Jn 0 $x
00036 }
00037 
00038 /*  J1 --*/
00039 /*     First-order Bessel function*/
00040 /* */
00041 /*  Arguments:*/
00042 /*     x         Value of the x-coordinate*/
00043 /*  Result:*/
00044 /*     Value of J1(x)*/
00045 /* */
00046 ret  ::math::special::J1 (type x) {
00047     Jn 1 $x
00048 }
00049 
00050 /*  Jn --*/
00051 /*     Compute the Bessel function of the first kind of order n*/
00052 /*  Arguments:*/
00053 /*     n       Order of the function (must be integer)*/
00054 /*     x       Value of the argument*/
00055 /*  Result:*/
00056 /*     Jn(x)*/
00057 /*  Note:*/
00058 /*     This relies on the integral representation for*/
00059 /*     the Bessel functions of integer order:*/
00060 /*              1     I pi*/
00061 /*     Jn(x) = --     I   cos(x sin t - nt) dt*/
00062 /*             pi   0 I*/
00063 /* */
00064 /*     For this kind of integrands the trapezoidal rule is*/
00065 /*     very efficient according to Davis and Rabinowitz*/
00066 /*     (Methods of numerical integration, 1984).*/
00067 /* */
00068 ret  ::math::special::Jn (type n , type x) {
00069     variable pi
00070 
00071     if { ![string is integer -strict $n] } {
00072          return -code error "Order argument must be integer"
00073     }
00074 
00075     #
00076     # Integrate over the interval [0,pi] using a small
00077     # enough step - 40 points should do a good job
00078     # with |x| < 20, n < 20 (an accuracy of 1.0e-8
00079     # is reported by Davis and Rabinowitz)
00080     #
00081     set number 40
00082     set step   [expr {$pi/double($number)}]
00083     set result 0.0
00084 
00085     for { set i 0 } { $i <= $number } { incr i } {
00086         set t [expr {double($i)*$step}]
00087         set f [expr {cos($x * sin($t) - $n * $t)}]
00088         if { $i == 0 || $i == $number } {
00089             set f [expr {$f/2.0}]
00090         }
00091         set result [expr {$result+$f}]
00092     }
00093 
00094     expr {$result*$step/$pi}
00095 }
00096 
00097 /*  J1/2 --*/
00098 /*     Half-order Bessel function*/
00099 /* */
00100 /*  Arguments:*/
00101 /*     x         Value of the x-coordinate*/
00102 /*  Result:*/
00103 /*     Value of J1/2(x)*/
00104 /* */
00105 ret  ::math::special::J1/2 (type x) {
00106     variable pi
00107     #
00108     # This Bessel function can be expressed in terms of elementary
00109     # functions. Therefore use the explicit formula
00110     #
00111     if { $x != 0.0 } {
00112         expr {sqrt(2.0/$pi/$x)*sin($x)}
00113     } else {
00114         return 0.0
00115     }
00116 }
00117 
00118 /*  J-1/2 --*/
00119 /*     Compute the Bessel function of the first kind of order -1/2*/
00120 /*  Arguments:*/
00121 /*     x       Value of the argument (!= 0.0)*/
00122 /*  Result:*/
00123 /*     J-1/2(x)*/
00124 /* */
00125 ret  ::math::special::J-1/2 (type x) {
00126     variable pi
00127     if { $x == 0.0 } {
00128         return -code error "Argument must not be zero (singularity)"
00129     } else {
00130         return [expr {-cos($x)/sqrt($pi*$x/2.0)}]
00131     }
00132 }
00133 
00134 /*  I_n --*/
00135 /*     Compute the modified Bessel function of the first kind*/
00136 /* */
00137 /*  Arguments:*/
00138 /*     n            Order of the function (must be positive integer or zero)*/
00139 /*     x            Abscissa at which to compute it*/
00140 /*  Result:*/
00141 /*     Value of In(x)*/
00142 /*  Note:*/
00143 /*     This relies on Miller's algorithm for finding minimal solutions*/
00144 /* */
00145 namespace ::math::special {}
00146 
00147 ret  ::math::special::I_n (type n , type x) {
00148     if { ! [string is integer $n] || $n < 0 } {
00149         error "Wrong order: must be positive integer or zero"
00150     }
00151 
00152     set n2 [expr {$n+8}]  ;# Note: just a guess that this will be enough
00153 
00154     set ynp1 0.0
00155     set yn   1.0
00156     set sum  1.0
00157 
00158     while { $n2 > 0 } {
00159         set ynm1 [expr {$ynp1+2.0*$n2*$yn/$x}]
00160         set sum  [expr {$sum+$ynm1}]
00161         if { $n2 == $n+1 } {
00162            set result $ynm1
00163         }
00164         set ynp1 $yn
00165         set yn   $ynm1
00166         incr n2 -1
00167     }
00168 
00169     set quotient [expr {(2.0*$sum-$ynm1)/exp($x)}]
00170 
00171     expr {$result/$quotient}
00172 }
00173 
00174 /* */
00175 /*  some tests --*/
00176 /* */
00177 if { 0 } {
00178  tcl = _precision 17
00179 foreach x {0.0 2.0 4.4 6.0 10.0 11.0 12.0 13.0 14.0} {
00180     puts "J0($x) = [::math::special::J0 $x] - J1($x) = [::math::special::J1 $x] \
00181 - J1/2($x) = [::math::special::J1/2 $x]"
00182 }
00183 foreach n {0 1 2 3 4 5} {
00184     puts [::math::special::I_n $n 1.0]
00185 }
00186 }
00187 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1