// this method builds an R(rho, ft) array and then uses FFT to generate R(rho, t) private double[] DetermineROfTimeFromROfFtForFixedRho(double rho, IOpticalPropertyRegion[] regions, out double[] FFTTimeSequence) { // get ops of top tissue region var op0 = regions[0].RegionOP; var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op0.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op0.N); var diffusionParameters = GetDiffusionParameters(regions); var layerThicknesses = GetLayerThicknesses(regions); int numFreq = 512; // Kienle used 512 and deltaFreq = 0.1 // Kienle says deltaFrequency depends on source-detector separation var deltaFrequency = 0.1; // 100 MHz if (rho <= 3) { deltaFrequency = 0.5; // so far I've found this value works for smaller rho } var F = numFreq * deltaFrequency; // 51 GHz var deltaTime = 1.0 / (numFreq * deltaFrequency); // 0.02 ns => T = 10 ns // var homoSDA = new PointSourceSDAForwardSolver(); // debug with h**o SDA // var rOfTime = new Complex[numFreq]; // debug array // considerations: 2n datapoint and pad with 0s beyond (deltaTime * numFreq) var rOfFt = new Complex[numFreq]; double[] ft = Enumerable.Range(0, numFreq).Select(x => x * deltaFrequency).ToArray(); FFTTimeSequence = Enumerable.Range(0, numFreq).Select(x => x * deltaTime).ToArray(); for (int i = 0; i < numFreq; i++) { // normalize by F=(numFreq*deltaFrequency) rOfFt[i] = TemporalFrequencyReflectance(rho, ft[i], diffusionParameters, layerThicknesses, fr1, fr2) * F; // rOfTime[i] = homoSDA.ROfRhoAndTime(regions[1].RegionOP, rho, t[i]); // debug array } // to debug, use R(t) and FFT to see if result R(ft) is close to rOfFt //var dft2 = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); //dft2.Radix2Forward(rOfTime, FourierOptions.NoScaling); // convert to R(ft) to compare with rOfFt //var relDiffReal = Enumerable.Zip(rOfTime, rOfFt, (x, y) => Math.Abs((y.Real - x.Real) / x.Real)); //var relDiffImag = Enumerable.Zip(rOfTime, rOfFt, (x, y) => Math.Abs((y.Imaginary - x.Imaginary) / x.Imaginary)); //var maxReal = relDiffReal.Max(); //var maxImag = relDiffImag.Max(); //var dum1 = maxReal; //var dum2 = maxImag; //dft2.Inverse(rOfTime, FourierOptions.NoScaling); // debug convert to R(t) // end debug code // FFT R(ft) to R(t) //var dft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); //dft.Inverse(rOfFt, FourierOptions.NoScaling); // convert to R(t) Fourier.Inverse(rOfFt, FourierOptions.NoScaling); var rOfTime = new double[FFTTimeSequence.Length]; rOfTime = rOfFt.Select(r => r.Real / (numFreq / 2)).ToArray(); return(rOfTime); }
// protected methods /// <summary> /// Calculates the reflectance based on the integral of the radiance over the backward hemisphere... /// </summary> /// <param name="surfaceFluence">diffuse fluence at the surface</param> /// <param name="surfaceFlux">diffuse flux at the surface</param> /// <param name="mediaRefractiveIndex">refractive index of the medium</param> /// <returns></returns> protected static double GetBackwardHemisphereIntegralDiffuseReflectance( double surfaceFluence, double surfaceFlux, double mediaRefractiveIndex) { var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1( mediaRefractiveIndex); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2( mediaRefractiveIndex); return(GetBackwardHemisphereIntegralDiffuseReflectance(surfaceFluence, surfaceFlux, fr1, fr2)); }
public override IEnumerable <double> ROfRho( IEnumerable <OpticalProperties> ops, IEnumerable <double> rhos) { foreach (var op in ops) { DiffusionParameters dp = DiffusionParameters.Create(op, this.ForwardModel); var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op.N); foreach (var rho in rhos) { yield return(StationaryReflectance(dp, rho, fr1, fr2)); } } }
public override double ROfFx(IOpticalPropertyRegion[] regions, double fx) { // get ops of top tissue region var op0 = regions[0].RegionOP; var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op0.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op0.N); var diffusionParameters = GetDiffusionParameters(regions); var layerThicknesses = GetLayerThicknesses(regions); // check that embedded source is within top layer, otherwise solution invalid if (diffusionParameters[0].zp > layerThicknesses[0]) { throw new ArgumentException("Top layer thickness must be greater than l* = 1/(mua+musp)"); } return(SpatialFrequencyReflectance(2 * Math.PI * fx, diffusionParameters, layerThicknesses, fr1, fr2)); }
public override IEnumerable <Complex> ROfRhoAndFt(IEnumerable <OpticalProperties> ops, IEnumerable <double> rhos, IEnumerable <double> fts) { foreach (var op in ops) { DiffusionParameters dp = DiffusionParameters.Create(op, this.ForwardModel); var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op.N); foreach (var rho in rhos) { foreach (var ft in fts) { Complex k = ((op.Mua * dp.cn + Complex.ImaginaryOne * ft * 2 * Math.PI) / (dp.cn * dp.D)).SquareRoot(); yield return(TemporalFrequencyReflectance(dp, rho, k, fr1, fr2)); } } } }
// this method builds an R(fx, ft) array and then uses FFT to generate R(fx, t) private double[] DetermineROfTimeFromROfFtForFixedFx(double fx, IOpticalPropertyRegion[] regions, out double[] FFTTimeSequence) { // get ops of top tissue region var op0 = regions[0].RegionOP; var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op0.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op0.N); var diffusionParameters = GetDiffusionParameters(regions); var layerThicknesses = GetLayerThicknesses(regions); int numFreq = 512; // Kienle used 512 and deltaFreq = 0.1 // Kienle says deltaFrequency depends on source-detector separation var deltaFrequency = 0.5; // 500 MHz good for all fx var F = numFreq * deltaFrequency; // 51 GHz var deltaTime = 1.0 / (numFreq * deltaFrequency); // 0.02 ns => T = 10 ns // considerations: 2n datapoint and pad with 0s beyond (deltaTime * numFreq) var rOfFt = new Complex[numFreq]; double[] ft = Enumerable.Range(0, numFreq).Select(x => x * deltaFrequency).ToArray(); FFTTimeSequence = Enumerable.Range(0, numFreq).Select(x => x * deltaTime).ToArray(); for (int i = 0; i < numFreq; i++) { // normalize by F=(numFreq*deltaFrequency) rOfFt[i] = SpatialAndTemporalFrequencyReflectance(2 * Math.PI * fx, ft[i], diffusionParameters, layerThicknesses, fr1, fr2) * F; } // FFT R(ft) to R(t) //var dft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); //dft.Radix2Inverse(rOfFt, FourierOptions.NoScaling); // convert to R(t) Fourier.Radix2Inverse(rOfFt, FourierOptions.NoScaling); var rOfTime = new double[FFTTimeSequence.Length]; rOfTime = rOfFt.Select(r => r.Real / (numFreq / 2)).ToArray(); return(rOfTime); }