public Basic_Material(double[] ABS, double[] Phase_Delay) { Abs = ABS; PD = Phase_Delay; for (int i = 0; i < ABS.Length; i++) { Ref[i] = 1 - ABS[i]; } //Interpolate a transfer function... this will probably be clumsy at first... double rt2 = Math.Sqrt(2); List <double> f = new List <double>(); f.Add(0); f.Add(31.25 * rt2); for (int oct = 0; oct < 9; oct++) { f.Add(62.5 * Math.Pow(2, oct)); f.Add(rt2 * 62.5 * Math.Pow(2, oct)); } f.Add(24000); List <double> pr = new List <double>(); pr.Add(0); pr.Add(Math.Sqrt(1 - Abs[0])); for (int oct = 0; oct < 7; oct++) { pr.Add(Math.Sqrt(1 - Abs[oct])); pr.Add(Math.Sqrt((2 - Abs[oct] - Abs[oct + 1]) / 2)); } if (pr.Count < f.Count) { pr.Add(Math.Sqrt(1 - Abs[7])); //8k } if (pr.Count < f.Count) { pr.Add(Math.Sqrt((1 - Abs[7] + (1 - Abs[7])) / 2)); //10k } if (pr.Count < f.Count) { pr.Add(Math.Sqrt(1 - Abs[7])); //12k } if (pr.Count < f.Count) { pr.Add(Math.Sqrt(1 - Abs[7])); //16k } while (pr.Count < f.Count) { pr.Add(1 - Abs[7]); } Transfer_Function = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkimaSorted(f.ToArray(), pr.ToArray()); }
public void ISO9613_1_Spline(double Tk, double Pa, double Hr) { double[] freq = new double[1024]; double df = 22050 / 1024; for (int i = 1; i < 1025; i++) { freq[i - 1] = df * i; } Spectrum = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(freq, ISO9613_1_attencoef(freq, Tk, Pa, Hr)); }
public void Populate_EigenFrequencies(double[] mag, double[] freq, string functiontype) { MathNet.Numerics.Interpolation.CubicSpline CS = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(freq, mag); for (double f = freq[0]; f < freq[freq.Length / 10]; f += 10) { double f_ = f + 10; double v = CS.Differentiate(f); double vf = CS.Differentiate(f_); if (v > 0 && vf < 0) { //Look closer - find the exact frequency. for (double f1 = f; f1 < f_; f1 += 1) { double v1 = CS.Differentiate(f1); double v1f = CS.Differentiate(f1 + 1); if (v1 > 0 && v1f < 0) { double eigen = v1 < -v1f?Math.Ceiling(f1) : Math.Floor(f1 + 1); string s = ""; if (eigen < 100) { s = "00"; } else if (eigen < 1000) { s = "0"; } s = s + string.Format("{0} hz. {1}", eigen, functiontype); EigenFrequencies.Items.Add(s); } } } } }
public static void Initialize_filter_functions() { int n = 100; double[] A = new double[n]; double[] ph = new double[n]; for (int i = 0; i < 100; i++) { ph[i] = Math.PI / 2 * i; A[i] = 0.25 * (ph[i] - Math.Cos(ph[i])) / (Math.PI * 2); } RCos_Integral = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(A, ph); }
public Basic_Material(double[] ABS, double[] Phase_Delay) { Abs = ABS; PD = Phase_Delay; for (int i = 0; i < ABS.Length; i++) Ref[i] = 1 - ABS[i]; //Interpolate a transfer function... this will probably be clumsy at first... double rt2 = Math.Sqrt(2); List<double> f = new List<double>(); f.Add(0); f.Add(31.25 * rt2); for (int oct = 0; oct < 9; oct++) { f.Add(62.5 * Math.Pow(2, oct)); f.Add(rt2 * 62.5 * Math.Pow(2, oct)); } f.Add(24000); List<double> pr = new List<double>(); pr.Add(0); pr.Add(Math.Sqrt(1 - Abs[0])); for (int oct = 0; oct < 7; oct++) { pr.Add(Math.Sqrt(1 - Abs[oct])); pr.Add(Math.Sqrt((2 - Abs[oct] - Abs[oct + 1]) / 2)); } if (pr.Count < f.Count) pr.Add(Math.Sqrt(1 - Abs[7]));//8k if (pr.Count < f.Count) pr.Add(Math.Sqrt((1 - Abs[7] + (1 - Abs[7])) / 2));//10k if (pr.Count < f.Count) pr.Add(Math.Sqrt(1 - Abs[7]));//12k if (pr.Count < f.Count) pr.Add(Math.Sqrt(1 - Abs[7]));//16k while (pr.Count < f.Count) pr.Add(1 - Abs[7]); Transfer_Function = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkimaSorted(f.ToArray(), pr.ToArray()); }
public Finite_Material(Smart_Material Mat, Rhino.Geometry.Brep Br, Rhino.Geometry.Mesh M, int face_id, Medium_Properties med) { //Strictly for the flat X,Y case - oversimplified for now. Inf_Mat = Mat; Azimuth = new double[36]; Altitude = new double[Mat.Angles.Length/2]; alpha = new double[Altitude.Length][][]; for(int i = 0; i < Altitude.Length; i++) Altitude[i] = Mat.Angles[i].Magnitude; for(int i = 0; i < Azimuth.Length; i++) Azimuth[i] = i * 360f / Azimuth.Length; //Set up a frequency interpolated Zr for each direction individually. Rhino.Geometry.Point3d pt = M.Faces.GetFaceCenter(face_id); double[][][] ZrR = new double[Altitude.Length][][], ZrI = new double[Altitude.Length][][]; double[] fr = new double[9]; for (int k = 0; k < Altitude.Length; k++) { ZrR[k] = new double[Azimuth.Length][]; ZrI[k] = new double[Azimuth.Length][]; alpha[k] = new double[Azimuth.Length][]; for (int j = 0; j < Azimuth.Length; j++) { ZrR[k][j] = new double[9]; ZrI[k][j] = new double[9]; alpha[k][j] = new double[8]; } } for (int oct = 0; oct < 9; oct++) { fr[oct] = 62.5 * Math.Pow(2, oct) / Utilities.Numerics.rt2; System.Numerics.Complex[][] Zr = AbsorptionModels.Operations.Finite_Radiation_Impedance_Rect_Longhand(pt.X, pt.Y, Br, fr[oct], Altitude, Azimuth, med.Sound_Speed(pt)); for (int k = 0; k < Zr.Length; k++) { for (int j = 0; j < Zr[k].Length; j++) { ZrR[k][j][oct] = Zr[k][j].Real; ZrI[k][j][oct] = Zr[k][j].Imaginary; } } } MathNet.Numerics.Interpolation.CubicSpline[][] Zr_r = new MathNet.Numerics.Interpolation.CubicSpline[Altitude.Length][]; MathNet.Numerics.Interpolation.CubicSpline[][] Zr_i = new MathNet.Numerics.Interpolation.CubicSpline[Altitude.Length][]; for (int k = 0; k < Zr_r.Length; k++) { Zr_r[k] = new MathNet.Numerics.Interpolation.CubicSpline[Azimuth.Length]; Zr_i[k] = new MathNet.Numerics.Interpolation.CubicSpline[Azimuth.Length]; for (int j = 0; j < Zr_r[k].Length; j++) { //Interpolate over curve real and imaginary Zr here... Zr_r[k][j] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(fr, ZrR[k][j]); Zr_i[k][j] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(fr, ZrI[k][j]); } } for (int k = 0; k < Zr_r.Length; k++) { for (int j = 0; j < Zr_r[k].Length; j++) { List<double> freq = new List<double>(); List<double> alpha_interp = new List<double>(); for (int l = 0; l < Mat.frequency.Length; l++) { if (Mat.frequency[l] > 10000) break; freq.Add(Mat.frequency[l]); alpha_interp.Add(AbsorptionModels.Operations.Finite_Unit_Absorption_Coefficient(Mat.Z[k][j], new System.Numerics.Complex(Zr_r[k][j].Interpolate(Mat.frequency[l]), Zr_i[k][j].Interpolate(Mat.frequency[l])), med.Rho(Utilities.PachTools.RPttoHPt(pt)), med.Sound_Speed(pt))); } MathNet.Numerics.Interpolation.CubicSpline a = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(freq, alpha_interp); for (int oct = 0; oct < 8; oct++) { alpha[k][j][oct] = 1 - a.Integrate(fr[oct], fr[oct + 1]) / (fr[oct + 1] - fr[oct]); } } } }
private void Record_Line_Segment(ref List<double> t, ref List<double[]> I, ref List<Vector> d, int rec_id) { if (t.Count > 4) { double[] t_dump = new double[t.Count]; double[][] I_dump = new double[8][]; double[][] xp_dump = new double[8][]; double[][] xn_dump = new double[8][]; double[][] yp_dump = new double[8][]; double[][] yn_dump = new double[8][]; double[][] zp_dump = new double[8][]; double[][] zn_dump = new double[8][]; double dt = 1d / (double)SampleFreq; double tmin = double.PositiveInfinity; double tmax = double.NegativeInfinity; for (int oct = 0; oct < 8; oct++) { I_dump[oct] = new double[t.Count]; xp_dump[oct] = new double[t.Count]; xn_dump[oct] = new double[t.Count]; yp_dump[oct] = new double[t.Count]; yn_dump[oct] = new double[t.Count]; zp_dump[oct] = new double[t.Count]; zn_dump[oct] = new double[t.Count]; } for (int i = 0; i < t.Count; i++) { Vector v = d[i]; t_dump[i] = t[i]; tmin = Math.Min(t[i], tmin); tmax = Math.Max(t[i], tmax); double log10Eps = Math.Log10(1E-12); for (int oct = 0; oct < 8; oct++) { I_dump[oct][i] = Math.Log10(I[i][oct]); if (v.x > 0) { xp_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.x)); xn_dump[oct][i] = log10Eps; } else { xn_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.x)); xp_dump[oct][i] = log10Eps; } if (v.y > 0) { yp_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.y)); yn_dump[oct][i] = log10Eps; } else { yn_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.y)); yp_dump[oct][i] = log10Eps; } if (v.z > 0) { zp_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.z)); zn_dump[oct][i] = log10Eps; } else { zn_dump[oct][i] = Math.Log10(Math.Abs(I[i][oct] * v.z)); zp_dump[oct][i] = log10Eps; } } } MathNet.Numerics.Interpolation.CubicSpline[] I_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] xp_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] xn_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] yp_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] yn_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] zp_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; MathNet.Numerics.Interpolation.CubicSpline[] zn_Spline = new MathNet.Numerics.Interpolation.CubicSpline[8]; for (int oct = 0; oct < 8; oct++) { I_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, I_dump[oct]); xp_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, xp_dump[oct]); xn_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, xn_dump[oct]); yp_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, yp_dump[oct]); yn_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, yn_dump[oct]); zp_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(t_dump, zp_dump[oct]); zn_Spline[oct] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkimaSorted(t_dump, zn_dump[oct]); } int taumin = (int)Math.Ceiling(tmin / dt); int taumax = (int)Math.Floor(tmax / dt); if (Io[rec_id][0].Length < taumax) { int tau_present = Io[rec_id][0].Length; //resize the intensity histograms... for (int oct = 0; oct < 8; oct++) { Array.Resize(ref Io[rec_id][oct], taumax); for (int j = tau_present; j < Io[rec_id][oct].Length; j++) { Dir_Rec_Pos[rec_id][oct][j] = new float[3]; Dir_Rec_Neg[rec_id][oct][j] = new float[3]; } } Array.Resize(ref Io[rec_id][8], taumax); } //Adjust for energy differential between what might be two different sample rates... double mod = (double)(taumax - taumin) / t.Count; for (int tau = taumin; tau < taumax; tau++) { for (int oct = 0; oct < 8; oct++) { double tdbl = (double)tau * dt; double spl = I_Spline[oct].Interpolate(tdbl); Io[rec_id][oct][tau] += Math.Pow(10, spl);// * mod; if (Io[rec_id][oct][tau] < 0 || double.IsInfinity(Io[rec_id][oct][tau]) || double.IsNaN(Io[rec_id][oct][tau])) { Rhino.RhinoApp.Write("MEEP"); } this.Dir_Rec_Pos[rec_id][oct][tau][0] += (float)(Math.Pow(10, xp_Spline[oct].Interpolate(tdbl)) * mod); this.Dir_Rec_Neg[rec_id][oct][tau][0] += (float)(Math.Pow(10, xn_Spline[oct].Interpolate(tdbl)) * mod); this.Dir_Rec_Pos[rec_id][oct][tau][1] += (float)(Math.Pow(10, yp_Spline[oct].Interpolate(tdbl)) * mod); this.Dir_Rec_Neg[rec_id][oct][tau][1] += (float)(Math.Pow(10, yn_Spline[oct].Interpolate(tdbl)) * mod); this.Dir_Rec_Pos[rec_id][oct][tau][2] += (float)(Math.Pow(10, zp_Spline[oct].Interpolate(tdbl)) * mod); this.Dir_Rec_Neg[rec_id][oct][tau][2] += (float)(Math.Pow(10, zn_Spline[oct].Interpolate(tdbl)) * mod); } } } else { Rhino.RhinoApp.Write("MEEP"); } t = new List<double>(); I = new List<double[]>(); d = new List<Vector>(); }
public Finite_Material(Smart_Material Mat, Rhino.Geometry.Brep Br, Rhino.Geometry.Mesh M, int face_id, Medium_Properties med) { //Strictly for the flat X,Y case - oversimplified for now. Inf_Mat = Mat; Azimuth = new double[36]; Altitude = new double[Mat.Angles.Length / 2]; alpha = new double[Altitude.Length][][]; for (int i = 0; i < Altitude.Length; i++) { Altitude[i] = Mat.Angles[i].Magnitude; } for (int i = 0; i < Azimuth.Length; i++) { Azimuth[i] = i * 360f / Azimuth.Length; } //Set up a frequency interpolated Zr for each direction individually. Rhino.Geometry.Point3d pt = M.Faces.GetFaceCenter(face_id); double[][][] ZrR = new double[Altitude.Length][][], ZrI = new double[Altitude.Length][][]; double[] fr = new double[9]; for (int k = 0; k < Altitude.Length; k++) { ZrR[k] = new double[Azimuth.Length][]; ZrI[k] = new double[Azimuth.Length][]; alpha[k] = new double[Azimuth.Length][]; for (int j = 0; j < Azimuth.Length; j++) { ZrR[k][j] = new double[9]; ZrI[k][j] = new double[9]; alpha[k][j] = new double[8]; } } for (int oct = 0; oct < 9; oct++) { fr[oct] = 62.5 * Math.Pow(2, oct) / Utilities.Numerics.rt2; System.Numerics.Complex[][] Zr = AbsorptionModels.Operations.Finite_Radiation_Impedance_Rect_Longhand(pt.X, pt.Y, Br, fr[oct], Altitude, Azimuth, med.Sound_Speed(pt)); for (int k = 0; k < Zr.Length; k++) { for (int j = 0; j < Zr[k].Length; j++) { ZrR[k][j][oct] = Zr[k][j].Real; ZrI[k][j][oct] = Zr[k][j].Imaginary; } } } MathNet.Numerics.Interpolation.CubicSpline[][] Zr_r = new MathNet.Numerics.Interpolation.CubicSpline[Altitude.Length][]; MathNet.Numerics.Interpolation.CubicSpline[][] Zr_i = new MathNet.Numerics.Interpolation.CubicSpline[Altitude.Length][]; for (int k = 0; k < Zr_r.Length; k++) { Zr_r[k] = new MathNet.Numerics.Interpolation.CubicSpline[Azimuth.Length]; Zr_i[k] = new MathNet.Numerics.Interpolation.CubicSpline[Azimuth.Length]; for (int j = 0; j < Zr_r[k].Length; j++) { //Interpolate over curve real and imaginary Zr here... Zr_r[k][j] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(fr, ZrR[k][j]); Zr_i[k][j] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(fr, ZrI[k][j]); } } for (int k = 0; k < Zr_r.Length; k++) { for (int j = 0; j < Zr_r[k].Length; j++) { List <double> freq = new List <double>(); List <double> alpha_interp = new List <double>(); for (int l = 0; l < Mat.frequency.Length; l++) { if (Mat.frequency[l] > 10000) { break; } freq.Add(Mat.frequency[l]); alpha_interp.Add(AbsorptionModels.Operations.Finite_Unit_Absorption_Coefficient(Mat.Z[k][j], new System.Numerics.Complex(Zr_r[k][j].Interpolate(Mat.frequency[l]), Zr_i[k][j].Interpolate(Mat.frequency[l])), med.Rho(Utilities.PachTools.RPttoHPt(pt)), med.Sound_Speed(pt))); } MathNet.Numerics.Interpolation.CubicSpline a = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(freq, alpha_interp); for (int oct = 0; oct < 8; oct++) { alpha[k][j][oct] = 1 - a.Integrate(fr[oct], fr[oct + 1]) / (fr[oct + 1] - fr[oct]); } } } }
/// <summary> /// This function calculates the actual path of the specular reflection. /// </summary> /// <param name="Images">The list of images.</param> /// <param name="Sequence">The list of surface indices for reflection.</param> /// <param name="Threadid">The id of the calling thread.</param> private void ProcessImages(Hare.Geometry.Point[][] Images, int[] Sequence, int Threadid) { for (int rec_id = 0; rec_id < Rec.Length; rec_id++) { double c_sound = Room.Sound_speed(Rec[rec_id]); double[][] Trans_Mod = new double[Images.Length][]; int[] Seq_Polys = new int[Sequence.Length]; List<Hare.Geometry.Point[]> PathVertices = new List<Hare.Geometry.Point[]>(); Hare.Geometry.Point S = Src.H_Origin(); Hare.Geometry.Point E = Rec[rec_id]; double df = SampleRate * .5 / 4096; //Find all Path Legs from Receiver to Source for (int r = 0; r < Images.Length; r++) { Trans_Mod[r] = new double[8]; for (int t_oct = 0; t_oct < 8; t_oct++) Trans_Mod[r][t_oct] = 1; Hare.Geometry.Point[] path = new Hare.Geometry.Point[Sequence.Length + 2]; path[0] = S; path[path.Length - 1] = E; for (int q = Sequence.Length - 1; q >= 0; q--) { if (Sequence[q] > Room.PlaneCount - 1) { //It's an edge! int EdgeID = Sequence[q] - Room.PlaneCount; //for (int i = 1; i < Room.Edge_Nodes[EdgeID].EdgeSources.Count; i++) if (!OcclusionIntersectED(path[q + 2], Images[r][q], Sequence[q], ref Trans_Mod[r], ref path[q + 1], Threadid))// ref Trans_Mod, , ref Seq_Polys[q], { path = null; break; } } else { if (!OcclusionIntersect(path[q + 2], Images[r][q], Sequence[q], ref Trans_Mod[r], ref path[q + 1], ref Seq_Polys[q], Threadid)) { path = null; break; } } } PathVertices.Add(path); } //Check that any path was unoccluded... if so, then record this entry. If not, move on... if (PathVertices.Count(item => item != null) == 0) continue; //goto Next; //Final Occlusion Check: for (int r = 0; r < PathVertices.Count; r++) { if (PathVertices[r] == null) continue; if (Sequence[0] < Room.PlaneCount) { if (FinalOcclusion(PathVertices[r][0], PathVertices[r][1], Sequence[0], ref Trans_Mod[r], Threadid)) PathVertices[r] = null; } else { int edge_id = Sequence[0] - Room.PlaneCount; if (FinalOcclusion(PathVertices[r][0], PathVertices[r][1], 0.00001, Room.Edge_Nodes[edge_id].ParentBreps[0], Room.Edge_Nodes[edge_id].ParentBreps[1], ref Trans_Mod[r], Threadid)) PathVertices[r] = null; } } //Check again for null(occluded) paths... if (PathVertices.Count(item => item != null) == 0) continue; //goto Next; ///Process all paths for pulse entry... if (PathVertices.Count == 0) continue;//goto Next; if (PathVertices.Count == 1) { ThreadPaths[rec_id, Threadid].Add(new Specular_Path(PathVertices[0], Sequence, Seq_Polys, Room, Src, Speed_of_Sound, Trans_Mod[0], ref Direct_Time[rec_id], Threadid, Rnd[Threadid].Next())); continue; } //Process Compound Path before storing it. double[] H = new double[0]; Environment.Material[] M = new Environment.Material[Sequence.Length]; for (int i = 0; i < M.Length; i++) M[i] = (Sequence[i] < Room.PlaneCount) ? Room.Surface_Material(Sequence[i]) : null; //Arrange all information to build filtered response... List<List<double>> Times = new List<List<double>>(); List<List<double>> Pr = new List<List<double>>(); List<double> Time = new List<double>(); List<double> Bs = new List<double>(); List<double> X = new List<double>(); List<double> Y = new List<double>(); List<double> Z = new List<double>(); List<List<double>> Xe = new List<List<double>>(); List<List<double>> Ye = new List<List<double>>(); List<List<double>> Ze = new List<List<double>>(); List<double> X_ = new List<double>(); List<double> Y_ = new List<double>(); List<double> Z_ = new List<double>(); List<List<double>> Xs = new List<List<double>>(); List<List<double>> Ys = new List<List<double>>(); List<List<double>> Zs = new List<List<double>>(); double deltaS = 0; double dt = 1.0f / SampleRate; List<double[]> t_limits = new List<double[]>(); for (int i = 0; i < PathVertices.Count; i++) { if (PathVertices[i] == null) { if (Bs.Count > 0) { t_limits.Add(new double[2] { Time.Min(), Time.Max() }); Pr.Add(Bs); Bs = new List<double>(); Times.Add(Time); Time = new List<double>(); Xe.Add(X); X = new List<double>(); Ye.Add(Y); Y = new List<double>(); Ze.Add(Z); Z = new List<double>(); Xs.Add(X_); X_ = new List<double>(); Ys.Add(Y_); Y_ = new List<double>(); Zs.Add(Z_); Z_ = new List<double>(); } continue; } double l = 0; double[] dm = null, dl = null; double length1 = 0, length2 = 0; double Pres = 1; int s, c, e; for (s = 0, c = 1, e = 2; e < PathVertices[i].Length; s++, c++, e++) { if (Sequence[s] < Room.PlaneCount) { length1 += (PathVertices[i][1] - PathVertices[i][c]).Length(); length2 = length1; dl = new double[2] { (PathVertices[i][c] - PathVertices[i][e]).Length(), (PathVertices[i][c] - PathVertices[i][e]).Length() }; } else if (Sequence[s] >= Room.PlaneCount) { double m = 0; double B = Room.Edge_Nodes[Sequence[s] - Room.PlaneCount].EdgeSources[i].Flex_Solve(PathVertices[i][s], PathVertices[i][e], ref m, ref l, ref dm, ref dl); Pres *= B; length1 += dm[0]; length2 += dm[1]; } else { throw new NotImplementedException("...well isn't that novel..."); } } length1 += dl[0]; length2 += dl[1]; double duration_s = SampleRate * Math.Abs(length2 - length1) / c_sound; Vector DIR; DIR = PathVertices[i][c-1] - PathVertices[i][e-1]; DIR.Normalize(); Pres /= duration_s; double Tn = 0.5 * (length1 + length2) / c_sound; if (Time.Count > 2) { double dtnew = Time[Time.Count - 2] - Tn; if (deltaS != 0 && (dtnew > 0) != (deltaS > 0)) { //Break it... t_limits.Add(new double[2] { Time.Min(), Time.Max() }); if (Bs.Last() < Pres) { t_limits[t_limits.Count - 1][0] += dt; } else { t_limits[t_limits.Count - 1][1] -= dt; } Pr.Add(Bs); Bs = new List<double>(); Times.Add(Time); Time = new List<double>(); Xe.Add(X); X = new List<double>(); Ye.Add(Y); Y = new List<double>(); Ze.Add(Z); Z = new List<double>(); Xs.Add(X_); X_ = new List<double>(); Ys.Add(Y_); Y_ = new List<double>(); Zs.Add(Z_); Z_ = new List<double>(); ///Ensure Continuity... //Time.Add(Times[Times.Count - 1].Last()); //Bs.Add(Pr[Pr.Count - 1].Last()); //X.Add(Xe[Xe.Count - 1].Last()); //Y.Add(Ye[Ye.Count - 1].Last()); //Z.Add(Ze[Ze.Count - 1].Last()); //X_.Add(Xs[Xs.Count - 1].Last()); //Y_.Add(Ys[Ys.Count - 1].Last()); //Z_.Add(Zs[Zs.Count - 1].Last()); //dtnew *= -1; } deltaS = dtnew; } Vector DIRs = PathVertices[i][1] - PathVertices[i][0]; DIRs.Normalize(); X_.Add(DIRs.x); Y_.Add(DIRs.y); Z_.Add(DIRs.z); Bs.Add(Pres); Time.Add(Tn); X.Add(DIR.x); Y.Add(DIR.y); Z.Add(DIR.z); } if (Bs.Count > 0) { t_limits.Add(new double[2] { Time.Min(), Time.Max() }); Pr.Add(Bs); Times.Add(Time); Xe.Add(X); Ye.Add(Y); Ze.Add(Z); Xs.Add(X_); Ys.Add(Y_); Zs.Add(Z_); } MathNet.Numerics.Interpolation.CubicSpline[] Pr_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Pr.Count]; MathNet.Numerics.Interpolation.CubicSpline[] X_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Xe.Count]; MathNet.Numerics.Interpolation.CubicSpline[] Y_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Ye.Count]; MathNet.Numerics.Interpolation.CubicSpline[] Z_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Ze.Count]; MathNet.Numerics.Interpolation.CubicSpline[] Xs_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Xs.Count]; MathNet.Numerics.Interpolation.CubicSpline[] Ys_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Ys.Count]; MathNet.Numerics.Interpolation.CubicSpline[] Zs_Spline = new MathNet.Numerics.Interpolation.CubicSpline[Zs.Count]; double min = double.PositiveInfinity; for (int i = 0; i < Times.Count; i++) { Pr_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Pr[i]); X_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Xe[i]); Y_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Ye[i]); Z_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Ze[i]); Xs_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Xs[i]); Ys_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Ys[i]); Zs_Spline[i] = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(Times[i], Zs[i]); min = Math.Min(min, t_limits[i][1]); } //TODO: Find a way to include absorption/transmission effects... which will not affect the entire multipath reflection... Dictionary<int, double> H_d = new Dictionary<int, double>(); Dictionary<int, double>[] H_directional = new Dictionary<int, double>[6]; for (int i = 0; i < 6; i++) H_directional[i] = new Dictionary<int, double>(); for (int i = 0; i < t_limits.Count; i++) { for (double t = t_limits[i][0]; t < t_limits[i][1]; t += dt) { Vector dir = new Vector(Xs_Spline[i].Interpolate(t), Ys_Spline[i].Interpolate(t), Zs_Spline[i].Interpolate(t)); ////Compose Impulse Response... //double T_current = (lengths[p_id] + dl[0]) / Room.Sound_speed(new Hare.Geometry.Point(0, 0, 0)); //double T_duration = (length2 + dl[1]) / Room.Sound_speed(new Hare.Geometry.Point(0, 0, 0)) - T_current; ///Apply TransMod to TF... ///Each sample will have it's own unique air attenuation and occlusion conditions, which means that it needs to be treated individually for input signal (for air attenuation and absorption). //double[] TF = Audio.Pach_SP.Magnitude_Filter(new double[8] { Math.Sqrt(Trans_Mod[p_id][0] * SW[0]), Math.Sqrt(Trans_Mod[p_id][1] * SW[1]), Math.Sqrt(Trans_Mod[p_id][2] * SW[2]), Math.Sqrt(Trans_Mod[p_id][3] * SW[3]), Math.Sqrt(Trans_Mod[p_id][4] * SW[4]), Math.Sqrt(Trans_Mod[p_id][5] * SW[5]), Math.Sqrt(Trans_Mod[p_id][6] * SW[6]), Math.Sqrt(Trans_Mod[p_id][7] * SW[7]) }, 44100, 4096, Threadid); double[] SW = Src.DirPower(Threadid, this.Rnd[Threadid].Next(), dir); foreach (Environment.Material m in M) { if (m is Environment.Basic_Material) for (int oct = 0; oct < 8; oct++) { SW[oct] *= 1 - m.Coefficient_A_Broad(oct); //SW[oct] *= Trans_Mod[j][oct]; } } System.Numerics.Complex[] TF = Audio.Pach_SP.Filter.Spectrum(new double[8] { Math.Sqrt(SW[0]), Math.Sqrt(SW[1]), Math.Sqrt(SW[2]), Math.Sqrt(SW[3]), Math.Sqrt(SW[4]), Math.Sqrt(SW[5]), Math.Sqrt(SW[6]), Math.Sqrt(SW[7]) }, 44100, 4096, Threadid); //double[] ms = Audio.Pach_SP.Magnitude_Spectrum(new double[8] { Math.Sqrt(SW[0]), Math.Sqrt(SW[1]), Math.Sqrt(SW[2]), Math.Sqrt(SW[3]), Math.Sqrt(SW[4]), Math.Sqrt(SW[5]), Math.Sqrt(SW[6]), Math.Sqrt(SW[7]) }, 44100, 4096, Threadid); //double[] ms = Audio.Pach_SP.Magnitude_Spectrum(new double[8] { Math.Sqrt(SW[0]), Math.Sqrt(SW[1]), Math.Sqrt(SW[2]), Math.Sqrt(SW[3]), Math.Sqrt(SW[4]), Math.Sqrt(SW[5]), Math.Sqrt(SW[6]), Math.Sqrt(SW[7]) }, 88200, 8096, Threadid); //System.Numerics.Complex[] TF = new System.Numerics.Complex[ms.Length]; // for (int j = 0; j < TF.Length; j++) TF[j] = ms[j]; //Array.Resize(ref TF, TF.Length / 2); ///Apply Air attenuation to TF... double[] atten = new double[0]; double[] freq = new double[0]; Room.AttenuationFilter(4096, 44100, t * c_sound, ref freq, ref atten, Rec[rec_id]);//sig is the magnitude response of the air attenuation filter... //Room.AttenuationFilter(4096, 88200, t * c_sound, ref freq, ref atten, Rec[rec_id]);//sig is the magnitude response of the air attenuation filter... for (int j = 0; j < TF.Length; j++) TF[j] *= atten[j]; for (int j = 0; j < M.Length; j++) { if (!(M[j] is Environment.Basic_Material)) { if (Sequence[j] < Room.PlaneCount) { System.Numerics.Complex[] spec = M[j].Reflection_Spectrum(44100, 4096 / 2, Room.Normal(Sequence[j]), PathVertices[i][j] - PathVertices[i][j - 1], Threadid); for (int k = 0; k < TF.Length; k++) TF[k] *= spec[k]; } } } //Audio.Pach_SP.Filter.Response(TF, SampleRate, Threadid); double[] pulse = Audio.Pach_SP.IFFT_Real4096(Audio.Pach_SP.Mirror_Spectrum(TF), Threadid); //double[] pulse = new double[prepulse.Length]; Audio.Pach_SP.Scale(ref pulse); //for (int j = 0; j < prepulse.Length; j++) //{ // pulse[j] = prepulse[(j + prepulse.Length/2) % prepulse.Length]; //} //////////////////////////////////////////////////////// //Pachyderm_Acoustic.Audio.Pach_SP.resample(ref pulse); //////////////////////////////////////////////////////// //Audio.Pach_SP.Raised_Cosine_Window(ref pulse); //Manual convolution of each distinct contribution of edge... int index = (int)Math.Floor(t * SampleRate); double omni_pr = Pr_Spline[i].Interpolate(t); dir = new Vector(X_Spline[i].Interpolate(t), Y_Spline[i].Interpolate(t), Z_Spline[i].Interpolate(t)); double[] dir_c = new double[6]; if (dir.x > 0) dir_c[0] = dir.x; else dir_c[1] = -dir.x; if (dir.y > 0) dir_c[2] = dir.y; else dir_c[3] = -dir.y; if (dir.z > 0) dir_c[4] = dir.z; else dir_c[5] = -dir.z; for (int j = 0; j < pulse.Length; j++) { //Todo: confirm that pulse comes in at right times... int t_c = index + j; double p_t = omni_pr * pulse[j] / 4096; if (!H_d.Keys.Contains<int>(index + j)) { H_d.Add(t_c, p_t); H_directional[0].Add(t_c, p_t * dir_c[0]); H_directional[1].Add(t_c, p_t * dir_c[1]); H_directional[2].Add(t_c, p_t * dir_c[2]); H_directional[3].Add(t_c, p_t * dir_c[3]); H_directional[4].Add(t_c, p_t * dir_c[4]); H_directional[5].Add(t_c, p_t * dir_c[5]); } else { H_d[t_c] += (float)(p_t); H_directional[0][t_c] += p_t * dir_c[0]; H_directional[1][t_c] += p_t * dir_c[1]; H_directional[2][t_c] += p_t * dir_c[2]; H_directional[3][t_c] += p_t * dir_c[3]; H_directional[4][t_c] += p_t * dir_c[4]; H_directional[5][t_c] += p_t * dir_c[5]; } } } } int minsample = H_d.Keys.Min(); int maxsample = H_d.Keys.Max(); double T0 = (double)minsample / SampleRate; H = new double[maxsample - minsample]; double[][] Hdir = new double[6][]; for(int j = 0; j < 6; j++) Hdir[j] = new double[maxsample - minsample]; for (int j = minsample; j < maxsample; j++) if (H_d.Keys.Contains<int>(j)) { H[j - minsample] = H_d[j]; Hdir[0][j - minsample] = H_directional[0][j]; Hdir[1][j - minsample] = H_directional[1][j]; Hdir[2][j - minsample] = H_directional[2][j]; Hdir[3][j - minsample] = H_directional[3][j]; Hdir[4][j - minsample] = H_directional[4][j]; Hdir[5][j - minsample] = H_directional[5][j]; } ///Enter the reflection PathVertices.RemoveAll(item => item == null); ThreadPaths[rec_id, Threadid].Add(new Compound_Path(PathVertices.ToArray(), Sequence, Src.Source_ID(), H, Hdir, T0, Speed_of_Sound, ref Direct_Time[rec_id], Threadid)); } }
public void ISO9613_1_Spline(double Tk, double Pa, double Hr) { double[] freq = new double[1024]; double df = 22050/1024; for (int i = 1; i < 1025; i++) { freq[i-1] = df * i; } Spectrum = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(freq, ISO9613_1_attencoef(freq, Tk, Pa, Hr)); }