Example #1
0
        public FourierSeries(IEnumerable<double> samples)
        {
            _complexes = samples.Select(x => new Complex(x, 0))
                                .ToArray();

            var dft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform();
            dft.BluesteinForward(_complexes, FourierOptions.NoScaling);
        }
Example #2
0
 /// <summary>
 /// Perform a IFFT using Bluestein's algorithm
 /// </summary>
 /// <param name="input">Array of complex numbers</param>
 /// <returns></returns>
 public Complex[] IFFT(Complex[] input)
 {
     Complex[] output = new Complex[input.Length];
       Array.Copy(input, output, input.Length);
       var transform = new MN.Algorithms.DiscreteFourierTransform();
       transform.BluesteinInverse(output, MN.FourierOptions.Matlab);
       return output;
 }
Example #3
0
        /// <summary>
        /// Set the channel properties
        /// </summary>
        /// <param name="channel"></param>
        public static void SetChannel(Dict channel)
        {
            // validate channel's properties
              var data = new Complex[BlocksPerSymbol];
              foreach(var curr in channel.Keys())
              {
            int index;
            double value;

            if (!int.TryParse(curr, out index))
              throw new Exception(String.Format("Channel quality indexes must be integers. '{0}' is not a valid integer!", curr));

            if (index >= data.Length)
              throw new Exception("Key exceeds array length");

            if (!double.TryParse(channel.Get(curr), out value))
              throw new Exception(String.Format("Channel quality values must be floats. '{0}' is not a valid float!", curr));

            data[index] = new Complex(value, 0);
              }

              // reverse-transform to get SNRs
              var fft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform();
              fft.BluesteinInverse(data, MathNet.Numerics.IntegralTransforms.FourierOptions.Default);
              ChannelQuality = data.Select(p => p.Magnitude).ToArray();
        }
        public TraceFeatures(ICollection <Touch> touches)
        {
            var           trace      = touches.Where(t => t.FingerId == touches.First().FingerId);
            long          startTime  = trace.First().Time;
            List <double> timePoints = trace.Select(t => (double)(t.Time - startTime)).ToList();
            List <double> xValues    = trace.Select(t => (double)t.X).ToList();
            List <double> yValues    = trace.Select(t => (double)t.Y).ToList();


            var X = new double[trace.Count()];
            var Y = new double[trace.Count()];

            Time = new int[trace.Count()];
            var ind = 0;

            foreach (var touch in trace)
            {
                X[ind]    = (double)touch.X;
                Y[ind]    = (double)touch.Y;
                Time[ind] = (int)(touch.Time - startTime);
                ind++;
            }

            var isNotDistinct = timePoints.GroupBy(n => n).Any(c => c.Count() > 1);

            if (isNotDistinct)
            {
                return;
            }

            //do interpolation stuff
            var splineX = new MathNet.Numerics.Interpolation.Algorithms.AkimaSplineInterpolation(timePoints, xValues);
            var splineY = new MathNet.Numerics.Interpolation.Algorithms.AkimaSplineInterpolation(timePoints, yValues);

            var fft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform();

            //fft.BluesteinForward()

            //var splineX = new MathNet.Numerics.Interpolation.Algorithms.CubicSplineInterpolation(timePoints, xValues);
            //var splineY = new MathNet.Numerics.Interpolation.Algorithms.CubicSplineInterpolation(timePoints, yValues);

            /*
             * int nSteps = (int)timePoints.Last() / 10;
             *
             * var XInt = new double[nSteps];
             * var YInt = new double[nSteps];
             * var vX = new double[nSteps];
             * var vY = new double[nSteps];
             * TimeInterpolated = new int[nSteps];
             * //var aX = new double[nSteps];
             * //var aY = new double[nSteps];
             *
             *
             * for (int i = 0; i < nSteps; i++)
             * {
             *  XInt[i] = splineX.Interpolate(i * 10);
             *  YInt[i] = splineY.Interpolate(i * 10);
             *  vX[i] = splineX.Differentiate(i * 10);
             *  vY[i] = splineY.Differentiate(i * 10);
             *  TimeInterpolated[i] = (int)(i * 10);
             * }
             */

            /*
             * //init arrays
             * int n = touches.Count;
             * var dT = new int?[n];
             * var X = new decimal[n];
             * var Y = new decimal[n];
             * var dX = new decimal?[n];
             * var dY = new decimal?[n];
             * var ddX = new decimal?[n];
             * var ddY = new decimal?[n];
             * var StartDistance = new decimal[n];
             * var StartDirection = new decimal[n];
             * var Direction = new decimal?[n];
             * var Curvature = new decimal?[n];
             * var CurvX = new decimal?[n];
             * var CurvY = new decimal?[n];
             * var DirX = new decimal?[n];
             * var DirY = new decimal?[n];
             * var vX = new decimal?[n];
             * var vY = new decimal?[n];
             * var aX = new decimal?[n];
             * var aY = new decimal?[n];
             *
             * Time = new int[n];
             *
             * var startTime = touches.First().Time;
             *
             * int i = 0;
             * foreach(var t in touches)
             * {
             *  X[i] = t.X;
             *  Y[i] = t.Y;
             *
             *  Time[i] = (int)(t.Time - startTime);
             *
             *  dT[i] = (i == 0) ? null : (int?)(Time[i] - Time[i - 1]);
             *
             *  dX[i] = (i == 0) ? null : (decimal?)(X[i - 1] - X[i]);
             *  dY[i] = (i == 0) ? null : (decimal?)(Y[i - 1] - Y[i]);
             *
             *  ddX[i] = (i > 1) ? (decimal?)(dX[i-1] - dX[i]) : null;
             *  ddY[i] = (i > 1) ? (decimal?)(dY[i-1] - dY[i]) : null;
             *
             *  var dir = (dX[i].HasValue) ? (decimal?)Math.Atan2((double)dY[i], (double)dX[i]) : null;
             *  var curv = (ddX[i].HasValue) ? (decimal?)((double)(dX[i] * ddY[i] - dY[i] * ddX[i]) / ((dX[i] == 0 && dY[i] == 0) ? 0 : Math.Pow((double)(dX[i] * dX[i] + dY[i] * dY[i]), 1.5d))) : null;
             *
             *  var sdX = t.X - X[0];
             *  var sdY = t.Y - Y[0];
             *  var sdis = Math.Sqrt((double)(sdX * sdX + sdY * sdY));
             *  var sdir = Math.Atan2((double)sdY, (double)sdX);
             *
             *  Direction[i] = dir;
             *  Curvature[i] = curv;
             *  StartDistance[i] = (decimal)sdis;
             *  StartDirection[i] = (decimal)sdir;
             *
             *
             *  vX[i] = (i == 0) ? null : (decimal?)(dX[i] / dT[i]);
             *  vY[i] = (i == 0) ? null : (decimal?)(dY[i] / dT[i]);
             *
             *  aX[i] = (i < 2) ? null : (decimal?)(ddX[i] / dT[i]);
             *  aY[i] = (i < 2) ? null : (decimal?)(ddY[i] / dT[i]);
             *
             *  i++;
             * }
             */

            //create features and add to dictionary
            //var fX = new Feature("X", X);
            //var fY = new Feature("Y", Y);
            //var fXInt = new Feature("X interpolated", XInt);
            //var fYInt = new Feature("Y interpolated", YInt);
            //var fVx = new Feature("Velocity X", vX);
            //var fVy = new Feature("Velocity Y", vY);

            /*
             * var fStartDistance = new Feature("StartDistance", StartDistance);
             * var fStartDirection = new Feature("StartDirection", StartDirection);
             * var fDirection = new Feature("Direction", Direction.SkipWhile(d=>!d.HasValue).Cast<decimal>().ToArray());
             * var fCurvature = new Feature("Curvature", Curvature.SkipWhile(d => !d.HasValue).Cast<decimal>().ToArray());
             * var fVx = new Feature("Velocity X", vX.SkipWhile(d => !d.HasValue).Cast<decimal>().ToArray());
             * var fVy = new Feature("Velocity Y", vY.SkipWhile(d => !d.HasValue).Cast<decimal>().ToArray());
             * var fAx = new Feature("Acceleration X", aX.SkipWhile(d => !d.HasValue).Cast<decimal>().ToArray());
             * var fAy = new Feature("Acceleration Y", aY.SkipWhile(d => !d.HasValue).Cast<decimal>().ToArray());
             */

            this["X"] = new Feature("X", splineX);
            this["Y"] = new Feature("Y", splineY);

            //this[fX.Name] = fX;
            //this[fY.Name] = fY;
            //this[fXInt.Name] = fXInt;
            //this[fYInt.Name] = fYInt;
            //this[fVx.Name] = fVx;
            //this[fVy.Name] = fVy;

            /*
             * this[fAx.Name] = fAx;
             * this[fAy.Name] = fAy;
             * this[fStartDistance.Name] = fStartDistance;
             * this[fStartDirection.Name] = fStartDirection;
             * this[fDirection.Name] = fDirection;
             * this[fCurvature.Name] = fCurvature;
             */
        }
        public override void CalculateTransmissionLoss(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial)
        {
            var sourceDepth = platform.Depth;
            var frequency = (float)Math.Sqrt(mode.HighFrequency * mode.LowFrequency);
            if (mode.Depth.HasValue) sourceDepth += mode.Depth.Value;
            var directoryPath = Path.GetDirectoryName(radial.BasePath);
            if (directoryPath == null) throw new NullReferenceException("radial.BasePath does not point to a valid directory");
            if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath);

            // Derived Parameters
            // ==================
            // Note: All the specific calculations given in the comments below assume a frequency of 1kHz
            // lambda is wavelength, in meters
            var lambda = ReferenceSoundSpeed / frequency;
            // if dz < 1m round dz down to either [1/10, 1/5, 1/4 or 1/2] m  ... or multiples of 10^-n of these numbers
            //                                  = [1     2    2.5 or 5  ] x 0.1m  "   " ...
            // if dz > 1m round dz down to either [1     2    2.5    5  ] m  ... or multiples of 10^+n of these numbers
            // var fixpoints = new List<double> { 1, 2, 2.5, 5 };
            // dz = 0.1 * lambda
            var dz = RelativeDepthResolution * lambda;
            // make dz a 'pretty' number
            //dz = Fix2X10pN(dz, fixpoints);

            // ndz is the depth decimation factor
            // MinimumOutputDepthResolution is 10m
            // dz is 0.1 * lambda (dz = 0.15 for a 1 kHz signal, 'pretty' dz = 0.2 @ 1kHz)
            // so ndz = (10 / 0.2) = 50 @ 1kHz
            // this means that we will only output every 50 computational depth cells, giving us a depth
            // resolution of 50 * 0.2m = 10m @ 1kHz which is what we want it to be.  Outstanding.
            var ndz = (int)Math.Max(1.0, Math.Floor(MinimumOutputDepthResolution / dz));

            //  similar for dr and assoc. grid decimation
            // RelativeRangeResolution is 2, so with our 'pretty' dz = 0.2, dr = 0.4
            var dr = RelativeRangeResolution * dz;
            // make dr a 'pretty' number, in this case 0.25
            //dr = Fix2X10pN(dr, fixpoints);
            // ndr is the range decimation factor
            // MinimumOutputRangeResolution is 10m
            // dr is 0.25 * lambda, so (10 / 0.25) gives us an ndr of 40
            // this means that we will only output every 40 computational range cells, giving us a range
            // resolution of 40 * 0.25m = 10m @ 1kHz which is what we want it to be.  Outstanding.
            var ndr = (int)Math.Max(1, Math.Floor(MinimumOutputRangeResolution / dr));

            //  attenuation layer (round up to nearest dz)
            var sedimentLambda = sedimentType.CompressionWaveSpeed / frequency;
            var sedimentLayerDz = Math.Ceiling(LastLayerThickness * sedimentLambda / dz) * dz;
            var attenuationLayerDz = Math.Ceiling(AttenuationLayerThickness * sedimentLambda / dz) * dz;
            var maxSubstrateDepth = bottomProfile.MaxDepth + sedimentLayerDz;
            var zstep = dz * ndz;
            var zmplt = Math.Ceiling((bottomProfile.MaxDepth + 2 * zstep) / zstep) * zstep;
            // Maximum Depth for PE calc ->  zmax 
            //  zmax is the z-limit for the PE calc from top of the water column to the bottom of the last substrate layer 
            // (including the attentuation layer if, as recommended, this is included)
            var zmax = maxSubstrateDepth + attenuationLayerDz;
            var envFileName = radial.BasePath + ".env";
            //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}",
            //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
            //                radial.TransmissionLoss.AnalysisPoint.Geo,
            //                radial.TransmissionLoss.Modes[0].ModeName,
            //                radial.Bearing, zmplt);

            using (var envFile = new StreamWriter(envFileName, false))
            {
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}",
                                  radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
                                  radial.TransmissionLoss.AnalysisPoint.Geo,
                                  radial.TransmissionLoss.Modes[0].ModeName,
                                  radial.Bearing));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2:0.000000}\t\tf [Frequency (Hz)], zs [Source Depth (m)], zrec0 [First receiever depth (m)]",
                                  frequency,
                                  sourceDepth,
                                  0.1));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t\t\trmax[Max range (m)], dr [Range resolution (m)], ndr [Range grid decimation factor]",
                                  mode.MaxPropagationRadius + (dr * ndr),
                                  dr,
                                  ndr));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t{3:0.000000}\tzmax [Max computational depth (m)], dz [Depth resolution (m)], ndz [Depth grid decimation factor], zmplot [Maximum depth to plot (m)]",
                                  zmax,
                                  dz,
                                  ndz,
                                  zmplt));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1}\t{2}\t{3:0.000000}\t\tc0 [Reference sound speed (m/s)], np [Number of terms in Padé expansion], ns [Number of stability constraints], rs [Maximum range of stability constraints (m)]",
                                  ReferenceSoundSpeed,
                                  PadeExpansionTerms,
                                  StabilityConstraints,
                                  StabilityConstraintMaxRange));
                // todo: different stuff goes here for RAMSGeo

                // bathymetry data
                var first = true;
                foreach (var profilePoint in bottomProfile.Profile)
                {
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture,
                                                    "{0:0.000000}\t{1:0.000000}{2}",
                                                    profilePoint.Range * 1000,
                                                    profilePoint.Depth,
                                                    first ? "\t\t\t\t\tbathymetry data [range (m), depth (m)]" : ""));
                    first = false;
                }
                envFile.WriteLine("-1\t-1");

                // range-dependent environment profiles
                var firstRangeProfile = true;
                foreach (var rangeProfileTuple in soundSpeedProfilesAlongRadial)
                {
                    // Range of profile only written for second and subsequent profiles
                    if (!firstRangeProfile) envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.#}\t\t\t\t\t\t\tProfile range (m)", rangeProfileTuple.Item1 * 1000));

                    var firstSoundSpeedProfile = true;
                    foreach (var profilePoint in rangeProfileTuple.Item2.Data)
                    {
                        if (double.IsNaN(profilePoint.SoundSpeed)) break;
                        envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}{2}",
                                          profilePoint.Depth,
                                          profilePoint.SoundSpeed,
                                          firstSoundSpeedProfile ? "\t\t\t\t\tsound speed profile in water [depth (m), sound speed (m/s)]" : ""));
                        firstSoundSpeedProfile = false;
                    }
                    envFile.WriteLine("-1\t-1");

                    // todo: RAMGeo and RAMSGeo also support sediment layers, as well as range-dependent sediment, neither of which is not yet supported by ESME
                    // If sediment layers are ever supported, put a loop like for the sound speed profile above
                    // A sediment layer is analogous to a sound speed profile point
                    // For range-dependent sediment, the sediment samples have to be at the same ranges as the sound speed profiles
                    // so we might want to change the API to include sediment properties in what is the current range and sound speed profile tuple
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive sound speed profile in substrate [depth (m), sound speed (m/s)]", 0.0, sedimentType.CompressionWaveSpeed));
                    envFile.WriteLine("-1\t-1");
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tdensity profile in substrate [depth (m), rhob (g/cm³)]", 0.0, sedimentType.Density));
                    envFile.WriteLine("-1\t-1");
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive attenuation profile in substrate [depth (m), attnp (db/lambda)]", 0.0, 0.0));
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}", attenuationLayerDz, 40));
                    envFile.WriteLine("-1\t-1");
                    firstRangeProfile = false;
                }
            }
            var tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(envFileName));
            //Debug.WriteLine(string.Format("Env File: {0} temp path: {1}", envFileName, tempDirectory));
            if (Directory.Exists(tempDirectory))
            {
                var files = Directory.GetFiles(tempDirectory, "*.*");
                foreach (var file in files) File.Delete(file);
                Directory.Delete(tempDirectory, true);
            } else if (File.Exists(tempDirectory)) File.Delete(tempDirectory);
            Directory.CreateDirectory(tempDirectory);
            File.Copy(envFileName, Path.Combine(tempDirectory, "ramgeo.in"));
            using (var steerableArrayFile = new StreamWriter(Path.Combine(tempDirectory, "sra.in"), false))
            {
                // From http://www.activefrance.com/Antennas/Introduction%20to%20Phased%20Array%20Design.pdf
                // theta3 = 3dB beam width, in degrees
                // emitterSize = size of emitter array, in meters
                // theta3 = (0.886 * lambda / arrayLength) * 180 / pi
                // so, doing the algebra and solving for arrayLength, you get:
                // emitterSize = (0.886 * lambda) / (theta3 * (pi / 180))
                var emitterSize = (0.886 * lambda) / (mode.VerticalBeamWidth * (Math.PI / 180.0));
                var emitterCount = (int)(emitterSize / (dz * 2));
                var emitterSpacing = 1.0;
                var weights = new List<double> { 1 };
                if (emitterCount > 1)
                {
                    emitterSpacing = emitterSize / (emitterCount - 1);
                    // chebyshev window calculations for relative emitter strength across the array
                    var discreteFourierTransform = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform();
                    var r0 = Math.Pow(10, mode.SideLobeAttenuation / 20.0);
                    var n = emitterCount - 1;
                    var a = Complex.Cosh((1.0 / n) * Acosh(r0));
                    var am = new Complex[n];
                    for (var m = 0; m < n; m++) am[m] = a * Complex.Cos(Math.PI * m / n);
                    var wm = new Complex[n];
                    var sign = 1;
                    for (var i = 0; i < n; i++)
                    {
                        if (am[i].Magnitude > 1) wm[i] = sign * Complex.Cosh(n * Acosh(am[i]));
                        else wm[i] = sign * Complex.Cos(n * Complex.Acos(am[i]));
                        sign *= -1;
                    }
                    discreteFourierTransform.BluesteinInverse(wm, FourierOptions.Default);
                    weights = wm.Select(e => e.Real).ToList();
                    weights[0] /= 2;
                    weights.Add(weights[0]);
                    var maxWeight = weights.Max();
                    for (var i = 0; i < weights.Count; i++) weights[i] /= maxWeight;
                }
                steerableArrayFile.WriteLine("{0}\t{1}\t{2}", emitterCount, emitterSpacing, mode.DepressionElevationAngle);
                for (var i = 0; i < emitterCount; i++) steerableArrayFile.WriteLine("{0}", weights[i]);
            }
            //File.Copy(Path.Combine(AssemblyLocation, "sra.in"), Path.Combine(tempDirectory, "sra.in"));
            //Debug.WriteLine(string.Format("Env File: {0} copied to: {1}", envFileName, tempDirectory));
            // Now that we've got the files ready to go, we can launch bellhop to do the actual calculations
            var ramProcess = new Process
            {
                StartInfo = new ProcessStartInfo(Path.Combine(AssemblyLocation, "RAMGeo.exe"))
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardInput = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    WorkingDirectory = tempDirectory
                }
            };
            if (radial.IsDeleted) throw new RadialDeletedByUserException();
            ramProcess.Start();
            try
            {
                ramProcess.PriorityClass = ProcessPriorityClass.Idle;
            }
            catch (InvalidOperationException) { }
            //ramProcess.BeginOutputReadLine();
            while (!ramProcess.HasExited)
            {
                if (radial.IsDeleted)
                {
                    ramProcess.Kill();
                    throw new RadialDeletedByUserException();
                }
                Thread.Sleep(20);
            }
            var ramOutput = ramProcess.StandardOutput.ReadToEnd();
            var ramError = ramProcess.StandardError.ReadToEnd();
            if (ramProcess.ExitCode != 0)
            {
                Debug.WriteLine("RAMGeo process for radial {0} exited with error code {1:X}", radial.BasePath, ramProcess.ExitCode);
                Debug.WriteLine(ramError);
                Directory.Delete(tempDirectory, true);
                return;
            }
            //File.Delete(Path.Combine(tempDirectory, "ramgeo.in"));
            //File.Delete(radial.BasePath + ".grid");
            //File.Move(Path.Combine(tempDirectory, "tl.grid"), radial.BasePath + ".grid");
            //File.Delete(radial.BasePath + ".line");
            //File.Move(Path.Combine(tempDirectory, "tl.line"), radial.BasePath + ".line");
            //File.Delete(radial.BasePath + ".pgrid");
            //File.Move(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid");
            //File.Delete(radial.BasePath + ".sra");
            //File.Move(Path.Combine(tempDirectory, "sra.in"), radial.BasePath + ".sra");

            using (var writer = new StreamWriter(radial.BasePath + ".bty")) writer.Write(bottomProfile.ToBellhopString());
            if (File.Exists(Path.Combine(tempDirectory, "p.grid")))
            {
                var pressures = ReadPGrid(Path.Combine(tempDirectory, "p.grid"));
                File.Copy(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid", true);
                //File.Delete(radial.BasePath + ".pgrid");
                if (pressures.Count == 0)
                {
                    Debug.WriteLine("Temp directory: " + tempDirectory);
                    Debug.WriteLine("RAMGeo stdout: " + ramOutput);
                    Debug.WriteLine("RAMGeo stderr: " + ramError);
                    Directory.Delete(tempDirectory, true);
                    return;
                }
                var rangeCount = pressures.Count;
                var depthCount = pressures[0].Length;
                var rr = new double[rangeCount];
                var rd = new double[depthCount];
                for (var rangeIndex = 0; rangeIndex < rr.Length; rangeIndex++) rr[rangeIndex] = (rangeIndex + 1) * dr * ndr;
                for (var depthIndex = 0; depthIndex < rd.Length; depthIndex++) rd[depthIndex] = depthIndex * zstep;
                //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}, zstep: {5}, maxDepth: {6}, fileName: {7}, reqDepthCells: {8}, actualDepthCells: {9}",
                //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
                //                radial.TransmissionLoss.AnalysisPoint.Geo,
                //                radial.TransmissionLoss.Modes[0].ModeName,
                //                radial.Bearing,
                //                zmplt,
                //                zstep,
                //                rd.Last(),
                //                Path.GetFileNameWithoutExtension(radial.BasePath),
                //                zmplt / zstep,
                //                depthCount);
                var shadeFile = new ShadeFile(sourceDepth, frequency, rd, rr, pressures);
                shadeFile.Write(radial.BasePath + ".shd");
                //BellhopOutput.WriteShadeFile(radial.BasePath + ".shd", sourceDepth, frequency, rd, rr, pressures);
            }
            else
            {
                //Debug.WriteLine("Scenario: {0} Analysis point: {1} Mode {2} Bearing {3}",
                //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
                //                radial.TransmissionLoss.AnalysisPoint.Geo,
                //                radial.TransmissionLoss.Modes[0].ModeName,
                //                radial.Bearing);
                //Debug.WriteLine("p.grid file not found in RAMGeo output directory");
            }
            Directory.Delete(tempDirectory, true);
            //Debug.WriteLine(string.Format("Env File: {0} temp directory deleted: {1}", envFileName, tempDirectory));
        }