Calculate wave numbers and generate a CurveFit data set
for Experiment 15 - Sound Waves

Cavity dimensions

Edit the assignments to the Lx and Ly cavity dimensions (in millimeters)
and evaluate the following cell:

Clear[Lx, Ly];
Lx=152.4 (* Longer dimension in millimeters *)
Ly=114.3 (* Shorter dimension in millimeters *)

Function to calculate wave number (Subscript[k, n,m]) using Lx and Ly

The rectangular box implies that we should use Cartesian components for the wave vector (OverVector[k]). In each direction, the number of nodal lines for a mode times π gives the total phase change in that dimension. Dividing by the cavity length then gives the wave vector component in that direction. Thus:

 (Subscript[k, n,m]) = π(Sqrt[ (((n/Lx))^2) + (((m/Ly))^2)]) 

Dividing (Subscript[k, n,m]) by 2π gives the wave number in cycles/distance rather than radians/distance. This is the form most useful for comparing with the measured resonance frequencies in Hertz. Evaluate the following cell to define this function:

Clear[k];
k[n_Integer,m_Integer]:=0.5(Sqrt[(((n /Lx))^2)+(((m /Ly))^2)]) (* units: cycles/millimeter, if Lx and Ly in mm *)

Table of Wave Numbers (Subscript[k, n,m]) and corresponding n, m values

Use the function k[n,m] to generate a table of the (Subscript[k, n,m]) and the associated n, m nodal line counts. The result is in kvals.

kvals=Table[{k[n,m],{n,m}},{n,0,5},{m,0,5}];

Use Flatten[ ] to turn the matrix returned by Table[] into a list, then Sort by (Subscript[k, n,m]), then remove the first entry (n = m = 0) using Rest:

kvals=(Flatten[kvals,1]//Sort//Rest)

Evaluate the following cell to define the structure of a valid entry in kvals:
 {(Subscript[k, n,m]) > 0, {n_Integer/; n > 0, m_Integer/; m > 0}}

ValidPattern = {v_/;NumberQ[v]&&v>0,{n_Integer/;n>=0,m_Integer/;m>=0}};

(* check that all kvals entries are valid *)
If[And@@(MatchQ[#,ValidPattern]&/@kvals)===True,
Print["All "<>ToString[Length[kvals]]<>" entries are valid."],
Print["One or more invalid entries found in kvals:"];
Select[kvals,!MatchQ[#,ValidPattern]&]//Column
]

Create a table of resonant frequencies and (n, m) values

The Estimate Modes notebook on the Physics 6 website: 
http://sophphx.caltech.edu/Physics_6/Extras/Sound_Waves_Exp_15/Estimate%20Modes.nb
can be used to match mode index pairs (n,m) to your observed resonant frequencies. The table kvals then supplies wave numbers associated with the various  (n,m) pairs.

FreqModes below is an example of such a frequency-mode table returned by Estimate Modes.
Edit the frequencies in the FreqModes table to match the frequencies you measured for the modes you will include in your fit. Remove any {freq, {n,m}} entries which don’t correspond to frequencies you will include in the analysis. Make sure commas separate the remaining entries. 

Evaluate the following cell after you complete the edits and inspect the resulting output to make sure the entries are correct.

FreqModes={{1131.0,{1,0}},{1504.0,{0,1}},{1881.8,{1,1}},{2262.0,{2,0}},{2716.4,{2,1}},{3008.0,{0,2}},{3213.6,{1,2}},{3393.0,{3,0}},{3711.4,{3,1}},{3763.6,{2,2}},{4512.0,{0,3}},{4524.0,{4,0}},{4534.4,{3,2}},{4651.6,{1,3}},{4767.5,{4,1}},{5047.0,{2,3}},{5432.7,{4,2}}}

(* 
The next lines check that the FreqModes entries are valid. The offending entries, if any, will be displayed. 
*)
If[And@@(MatchQ[#,ValidPattern]&/@FreqModes)===True,
Print["All "<>ToString[Length[FreqModes]]<>" entries are valid."],
Print["One or more invalid entries found in FreqModes."];
Print["Note: Null entries such as \", ,\" display as empty rows:"];
Select[FreqModes,!MatchQ[#,ValidPattern]&]//Column
]

Match resonant frequencies with wave numbers and create a standard CurveFit data file

Evaluate the following cell to match frequencies (Subscript[f, n,m]) in FreqModes to  wavenumbers (Subscript[k, n,m]) in kvals.
The resulting ((Subscript[k, n,m]), (Subscript[f, n,m])) pairs are saved in the variable Data.

(* Select entries of FreqModes and kvals with matching {n,m} values *)
kvals=Select[kvals,MemberQ[FreqModes[[All,2]],Last[#]]&];
FreqModes=Select[FreqModes,MemberQ[kvals[[All,2]],Last[#]]&];
Data = Transpose[{kvals[[All,1]],FreqModes[[All,1]]}];   (* the ((Subscript[k, n,m]),(Subscript[f, n,m])) pairs *)

(* Plot the data points and confirm that the values are correct *)
ListPlot[ Data,ImageSize->Medium,PlotStyle->Darker[Red],
Frame->True, FrameLabel->{"Wave No. (Cycles/mm)","Freq (Hz)"}
]

The slope of a fit to the data should be Vs in mm/sec (if Lx and Ly were entered in mm).

Next, evaluate the following cell to create a text version of the ((Subscript[k, n,m]), (Subscript[f, n,m])) pairs, one pair per line, which will become the contents of a CurveFit-suitable data file. Check the frequency values for correctness.

(* Create a text version of the data *)
DataText=
(*"# Wave No.    Freq (Hz)\n# (Cycles/mm)\n"<>*)
"# Wave No.    Freq (Hz)\n# (Cycles/mm)\n"<>
ExportString[
{ToString[DecimalForm[First[#],{6,8}]],
ToString[DecimalForm[Last[#],{6,2}]]}&/@Data,
"Table"]<>"\n"

Finally, evaluate the next cell to create the CurveFit data file.

DispersionDataFile = 
SystemDialogInput["FileSave", "DispersionData.dat"];
  If[ DispersionDataFile =!= $Canceled, Export[DispersionDataFile,DataText,"Text"]]

DispersionDataFile=!=$Canceled&&Head[DispersionDataFile]=!=Symbol

Load the ((Subscript[k, n,m]), (Subscript[f, n,m])) data file into CurveFit

Evaluate the following cell to: 
1.  Ensure that CurveFit is loaded.
2.  Load the data file into CurveFit. 
The slope of a fit to the data should be Vs in mm/sec (if Lx and Ly were entered in mm).

(* Make sure CurveFit is loaded *)
Needs["CurveFit`"];

(* Attempt to load the dispersion data file into CurveFit using a file dialog box *)
With[  {name = SystemDialogInput["FileOpen",{DispersionDataFile,{"data files"->{"*.dat", "*.mca"},"all files"->{"*"}}}]},
  If[ name =!= $Canceled, 
    LoadFile[name]]
]