Browse Source

Generate: Periodic; LinearSpacedMap, LinearRangeMap

pull/184/head
Christoph Ruegg 13 years ago
parent
commit
f83d6469fe
  1. 5
      src/Examples/Interpolation/AkimaSpline.cs
  2. 4
      src/Examples/Interpolation/LinearBetweenPoints.cs
  3. 4
      src/Examples/Interpolation/RationalWithPoles.cs
  4. 4
      src/Examples/Interpolation/RationalWithoutPoles.cs
  5. 20
      src/Examples/Signals/Equidistant.cs
  6. 9
      src/Examples/SpecialFunctions/ErrorFunction.cs
  7. 6
      src/Examples/Statistics.cs
  8. 272
      src/Numerics/Generate.cs
  9. 166
      src/Numerics/Signals/SignalGenerator.Equidistant.cs
  10. 26
      src/UnitTests/GenerateTests.cs
  11. 3
      src/UnitTests/IntegralTransformsTests/FourierTest.cs
  12. 5
      src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs

5
src/Examples/Interpolation/AkimaSpline.cs

@ -25,6 +25,7 @@
// </copyright>
using System;
using MathNet.Numerics;
using MathNet.Numerics.Interpolation;
using MathNet.Numerics.Random;
using MathNet.Numerics.Signals;
@ -67,8 +68,8 @@ namespace Examples.InterpolationExamples
{
// 1. Generate 10 samples of the function x*x-2*x on interval [0, 10]
Console.WriteLine(@"1. Generate 10 samples of the function x*x-2*x on interval [0, 10]");
double[] points;
var values = SignalGenerator.EquidistantInterval(TargetFunction, 0, 10, 10, out points);
double[] points = Generate.LinearSpaced(10, 0, 10);
var values = Generate.Map(points, TargetFunction);
Console.WriteLine();
// 2. Create akima spline interpolation

4
src/Examples/Interpolation/LinearBetweenPoints.cs

@ -67,8 +67,8 @@ namespace Examples.InterpolationExamples
{
// 1. Generate 20 samples of the function x*x-2*x on interval [0, 10]
Console.WriteLine(@"1. Generate 20 samples of the function x*x-2*x on interval [0, 10]");
double[] points;
var values = SignalGenerator.EquidistantInterval(TargetFunction, 0, 10, 20, out points);
double[] points = Generate.LinearSpaced(20, 0, 10);
var values = Generate.Map(points, TargetFunction);
Console.WriteLine();
// 2. Create a linear spline interpolation based on arbitrary points

4
src/Examples/Interpolation/RationalWithPoles.cs

@ -66,8 +66,8 @@ namespace Examples.InterpolationExamples
{
// 1. Generate 20 samples of the function f(x) = x on interval [-5, 5]
Console.WriteLine(@"1. Generate 20 samples of the function f(x) = x on interval [-5, 5]");
double[] points;
var values = SignalGenerator.EquidistantInterval(TargetFunction, -5, 5, 20, out points);
double[] points = Generate.LinearSpaced(20, -5, 5);
var values = Generate.Map(points, TargetFunction);
Console.WriteLine();
// 2. Create a burlish stoer rational interpolation based on arbitrary points

4
src/Examples/Interpolation/RationalWithoutPoles.cs

@ -67,8 +67,8 @@ namespace Examples.InterpolationExamples
{
// 1. Generate 10 samples of the function 1/(1+x*x) on interval [-5, 5]
Console.WriteLine(@"1. Generate 10 samples of the function 1/(1+x*x) on interval [-5, 5]");
double[] points;
var values = SignalGenerator.EquidistantInterval(TargetFunction, -5, 5, 10, out points);
double[] points = Generate.LinearSpaced(10, -5, 5);
var values = Generate.Map(points, TargetFunction);
Console.WriteLine();
// 2. Create a floater hormann rational pole-free interpolation based on arbitrary points

20
src/Examples/Signals/Equidistant.cs

@ -25,6 +25,7 @@
// </copyright>
using System;
using MathNet.Numerics;
using MathNet.Numerics.Signals;
namespace Examples.SignalsExamples
@ -62,7 +63,7 @@ namespace Examples.SignalsExamples
public void Run()
{
// 1. Get 11 samples of f(x) = (x * x) / 2 equidistant within interval [-5, 5]
var result = SignalGenerator.EquidistantInterval(Function, -5, 5, 11);
var result = Generate.LinearSpacedMap(11, -5, 5, Function);
Console.WriteLine(@"1. Get 11 samples of f(x) = (x * x) / 2 equidistant within interval [-5, 5]");
for (var i = 0; i < result.Length; i++)
{
@ -73,8 +74,8 @@ namespace Examples.SignalsExamples
Console.WriteLine();
// 2. Get 10 samples of f(x) = (x * x) / 2 equidistant starting at x=1 with step = 0.5 and retrieve sample points
double[] samplePoints;
result = SignalGenerator.EquidistantStartingAt(Function, 1, 0.5, 10, out samplePoints);
double[] samplePoints = Generate.LinearSpaced(10, 1.0, 5.5);
result = Generate.Map(samplePoints, Function);
Console.WriteLine(@"2. Get 10 samples of f(x) = (x * x) / 2 equidistant starting at x=1 with step = 0.5 and retrieve sample points");
Console.Write(@"Points: ");
for (var i = 0; i < samplePoints.Length; i++)
@ -93,24 +94,13 @@ namespace Examples.SignalsExamples
Console.WriteLine();
// 3. Get 10 samples of f(x) = (x * x) / 2 equidistant within period = 10 and period offset = 5
result = SignalGenerator.EquidistantPeriodic(Function, 10, 5, 10);
result = Generate.PeriodicMap(10, Function, 10, 1.0, 10, 5);
Console.WriteLine(@"3. Get 10 samples of f(x) = (x * x) / 2 equidistant within period = 10 and period offset = 5");
for (var i = 0; i < result.Length; i++)
{
Console.Write(result[i].ToString("N") + @" ");
}
Console.WriteLine();
Console.WriteLine();
// 4. Sample f(x) = (x * x) / 2 equidistant to an integer-domain function starting at x = 0 and step = 2
var equidistant = SignalGenerator.EquidistantToFunction(Function, 0, 2);
Console.WriteLine(@" 4. Sample f(x) = (x * x) / 2 equidistant to an integer-domain function starting at x = 0 and step = 2");
for (var i = 0; i < 10; i++)
{
Console.Write(equidistant(i).ToString("N") + @" ");
}
Console.WriteLine();
}

9
src/Examples/SpecialFunctions/ErrorFunction.cs

@ -26,7 +26,6 @@
using System;
using MathNet.Numerics;
using MathNet.Numerics.Signals;
namespace Examples.SpecialFunctionsExamples
{
@ -70,7 +69,7 @@ namespace Examples.SpecialFunctionsExamples
// 2. Sample 10 values of the error function in [-1.0; 1.0]
Console.WriteLine(@"2. Sample 10 values of the error function in [-1.0; 1.0]");
var data = SignalGenerator.EquidistantInterval(SpecialFunctions.Erf, -1.0, 1.0, 10);
var data = Generate.LinearSpacedMap(10, -1.0, 1.0, SpecialFunctions.Erf);
for (var i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("N") + @" ");
@ -86,7 +85,7 @@ namespace Examples.SpecialFunctionsExamples
// 4. Sample 10 values of the complementary error function in [-1.0; 1.0]
Console.WriteLine(@"4. Sample 10 values of the complementary error function in [-1.0; 1.0]");
data = SignalGenerator.EquidistantInterval(SpecialFunctions.Erfc, -1.0, 1.0, 10);
data = Generate.LinearSpacedMap(10, -1.0, 1.0, SpecialFunctions.Erfc);
for (var i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("N") + @" ");
@ -102,7 +101,7 @@ namespace Examples.SpecialFunctionsExamples
// 6. Sample 10 values of the inverse error function in [-1.0; 1.0]
Console.WriteLine(@"6. Sample 10 values of the inverse error function in [-1.0; 1.0]");
data = SignalGenerator.EquidistantInterval(SpecialFunctions.ErfInv, -1.0, 1.0, 10);
data = Generate.LinearSpacedMap(10, -1.0, 1.0, SpecialFunctions.ErfInv);
for (var i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("N") + @" ");
@ -118,7 +117,7 @@ namespace Examples.SpecialFunctionsExamples
// 8. Sample 10 values of the complementary inverse error function in [-1.0; 1.0]
Console.WriteLine(@"8. Sample 10 values of the complementary inverse error function in [-1.0; 1.0]");
data = SignalGenerator.EquidistantInterval(SpecialFunctions.ErfcInv, -1.0, 1.0, 10);
data = Generate.LinearSpacedMap(10, -1.0, 1.0, SpecialFunctions.ErfcInv);
for (var i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("N") + @" ");

6
src/Examples/Statistics.cs

@ -25,8 +25,8 @@
// </copyright>
using System;
using MathNet.Numerics;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.Signals;
using MathNet.Numerics.Statistics;
namespace Examples
@ -124,8 +124,8 @@ namespace Examples
Console.WriteLine();
// 6. Correlation coefficient between 1000 samples of f(x) = x * 2 and f(x) = x * x
data = SignalGenerator.EquidistantInterval(x => x * 2, 0, 100, 1000);
dataB = SignalGenerator.EquidistantInterval(x => x * x, 0, 100, 1000);
data = Generate.LinearSpacedMap(1000, 0, 100, x => x * 2);
dataB = Generate.LinearSpacedMap(1000, 0, 100, x => x * x);
Console.WriteLine(@"7. Correlation coefficient between 1000 samples of f(x) = x * 2 and f(x) = x * x is {0}", Correlation.Pearson(data, dataB).ToString("N04"));
Console.WriteLine(@"8. Ranked correlation coefficient between 1000 samples of f(x) = x * 2 and f(x) = x * x is {0}", Correlation.Spearman(data, dataB).ToString("N04"));
Console.WriteLine();

272
src/Numerics/Generate.cs

@ -43,6 +43,53 @@ namespace MathNet.Numerics
public static class Generate
{
/// <summary>
/// Generate samples by sampling a function at the provided points.
/// </summary>
public static T[] Map<TA, T>(TA[] points, Func<TA, T> map)
{
var res = new T[points.Length];
for (int i = 0; i < points.Length; i++)
{
res[i] = map(points[i]);
}
return res;
}
/// <summary>
/// Generate a sample sequence by sampling a function at the provided point sequence.
/// </summary>
public static IEnumerable<T> MapSequence<TA, T>(IEnumerable<TA> points, Func<TA, T> map)
{
return points.Select(map);
}
/// <summary>
/// Generate samples by sampling a function at the provided points.
/// </summary>
public static T[] Map2<TA, TB, T>(TA[] pointsA, TB[] pointsB, Func<TA, TB, T> map)
{
if (pointsA.Length != pointsB.Length)
{
throw new ArgumentException(Resources.ArgumentArraysSameLength, "pointsB");
}
var res = new T[pointsA.Length];
for (int i = 0; i < res.Length; i++)
{
res[i] = map(pointsA[i], pointsB[i]);
}
return res;
}
/// <summary>
/// Generate a sample sequence by sampling a function at the provided point sequence.
/// </summary>
public static IEnumerable<T> Map2Sequence<TA, TB, T>(IEnumerable<TA> pointsA, IEnumerable<TB> pointsB, Func<TA, TB, T> map)
{
return pointsA.Zip(pointsB, map);
}
/// <summary>
/// Generate a linearly spaced sample vector of the given length between the specified values (inclusive).
/// Equivalent to MATLAB linspace but with the length as first instead of last argument.
@ -63,6 +110,25 @@ namespace MathNet.Numerics
return data;
}
/// <summary>
/// Generate samples by sampling a function at linearly spaced points between the specified values (inclusive).
/// </summary>
public static T[] LinearSpacedMap<T>(int length, double start, double stop, Func<double, T> map)
{
if (length <= 0) return new T[0];
if (length == 1) return new[] { map(stop) };
double step = (stop - start)/(length - 1);
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(start + i*step);
}
data[data.Length - 1] = map(stop);
return data;
}
/// <summary>
/// Generate a base 10 logarithmically spaced sample vector of the given length between the specified decade exponents (inclusive).
/// Equivalent to MATLAB logspace but with the length as first instead of last argument.
@ -152,12 +218,149 @@ namespace MathNet.Numerics
return data;
}
/// <summary>
/// Generate samples by sampling a function at linearly spaced points within the inclusive interval (start, stop) and the provide step.
/// The start value is aways included as first value, but stop is only included if it stop-start is a multiple of step.
/// </summary>
public static T[] LinearRangeMap<T>(double start, double step, double stop, Func<double, T> map)
{
if (start == stop) return new T[] { map(start) };
if (start < stop && step < 0 || start > stop && step > 0 || step == 0d)
{
return new T[0];
}
var data = new T[(int)Math.Floor((stop - start)/step + 1d)];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(start + i*step);
}
return data;
}
/// <summary>
/// Create a periodic sample vector.
/// </summary>
/// <param name="length">The number of samples to generate.</param>
/// <param name="samplingRate">Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion.</param>
/// <param name="frequency">Frequency in periods per time unit (Hz).</param>
/// <param name="amplitude">The lenght of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions.</param>
/// <param name="phase">Optional phase offset.</param>
/// <param name="delay">Optional delay, relative to the phase.</param>
public static double[] Periodic(int length, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0)
{
double step = frequency/samplingRate*amplitude;
phase = Euclid.Modulus(phase - delay*step, amplitude);
var data = new double[length];
for (int i = 0, k = 0; i < data.Length; i++, k++)
{
var x = phase + k*step;
if (x >= amplitude)
{
x %= amplitude;
phase = x;
k = 0;
}
data[i] = x;
}
return data;
}
/// <summary>
/// Create a periodic sample vector.
/// </summary>
/// <param name="length">The number of samples to generate.</param>
/// <param name="map"></param>
/// <param name="samplingRate">Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion.</param>
/// <param name="frequency">Frequency in periods per time unit (Hz).</param>
/// <param name="amplitude">The lenght of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions.</param>
/// <param name="phase">Optional phase offset.</param>
/// <param name="delay">Optional delay, relative to the phase.</param>
public static T[] PeriodicMap<T>(int length, Func<double, T> map, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0)
{
double step = frequency/samplingRate*amplitude;
phase = Euclid.Modulus(phase - delay*step, amplitude);
var data = new T[length];
for (int i = 0, k = 0; i < data.Length; i++, k++)
{
var x = phase + k*step;
if (x >= amplitude)
{
x %= amplitude;
phase = x;
k = 0;
}
data[i] = map(x);
}
return data;
}
/// <summary>
/// Create an infinite periodic sample sequence.
/// </summary>
/// <param name="samplingRate">Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion.</param>
/// <param name="frequency">Frequency in periods per time unit (Hz).</param>
/// <param name="amplitude">The lenght of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions.</param>
/// <param name="phase">Optional phase offset.</param>
/// <param name="delay">Optional delay, relative to the phase.</param>
public static IEnumerable<double> PeriodicSequence(double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0)
{
double step = frequency/samplingRate*amplitude;
phase = Euclid.Modulus(phase - delay*step, amplitude);
int k = 0;
while (true)
{
var x = phase + (k++)*step;
if (x >= amplitude)
{
x %= amplitude;
phase = x;
k = 1;
}
yield return x;
}
}
/// <summary>
/// Create an infinite periodic sample sequence.
/// </summary>
/// <param name="samplingRate">Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion.</param>
/// <param name="frequency">Frequency in periods per time unit (Hz).</param>
/// <param name="amplitude">The lenght of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions.</param>
/// <param name="phase">Optional phase offset.</param>
/// <param name="delay">Optional delay, relative to the phase.</param>
public static IEnumerable<T> PeriodicMapSequence<T>(Func<double, T> map, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0)
{
double step = frequency/samplingRate*amplitude;
phase = Euclid.Modulus(phase - delay*step, amplitude);
int k = 0;
while (true)
{
var x = phase + (k++)*step;
if (x >= amplitude)
{
x %= amplitude;
phase = x;
k = 0;
}
yield return map(x);
}
}
/// <summary>
/// Create a Sine sample vector.
/// </summary>
/// <param name="length">The number of samples to generate.</param>
/// <param name="samplingRate">Samples per unit.</param>
/// <param name="frequency">Frequency in samples per unit.</param>
/// <param name="samplingRate">Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion.</param>
/// <param name="frequency">Frequency in periods per time unit (Hz).</param>
/// <param name="amplitude">The maximal reached peak.</param>
/// <param name="mean">The mean, or dc part, of the signal.</param>
/// <param name="phase">Optional phase offset.</param>
@ -168,7 +371,7 @@ namespace MathNet.Numerics
phase = (phase - delay*step)%Constants.Pi2;
var data = new double[length];
for (int i = 0; i < length; i++)
for (int i = 0; i < data.Length; i++)
{
data[i] = mean + amplitude*Math.Sin(phase + i*step);
}
@ -306,64 +509,17 @@ namespace MathNet.Numerics
}
}
/// <summary>
/// Generate samples by sampling a function at the provided points.
/// </summary>
public static TR[] Map<T, TR>(T[] points, Func<T, TR> map)
{
var res = new TR[points.Length];
for (int i = 0; i < points.Length; i++)
{
res[i] = map(points[i]);
}
return res;
}
/// <summary>
/// Generate a sample sequence by sampling a function at the provided point sequence.
/// </summary>
public static IEnumerable<TR> MapSequence<T, TR>(IEnumerable<T> points, Func<T, TR> map)
{
return points.Select(map);
}
/// <summary>
/// Generate samples by sampling a function at the provided points.
/// </summary>
public static TR[] Map2<TA, TB, TR>(TA[] pointsA, TB[] pointsB, Func<TA, TB, TR> map)
{
if (pointsA.Length != pointsB.Length)
{
throw new ArgumentException(Resources.ArgumentArraysSameLength, "pointsB");
}
var res = new TR[pointsA.Length];
for (int i = 0; i < res.Length; i++)
{
res[i] = map(pointsA[i], pointsB[i]);
}
return res;
}
/// <summary>
/// Generate a sample sequence by sampling a function at the provided point sequence.
/// </summary>
public static IEnumerable<TR> Map2Sequence<TA, TB, TR>(IEnumerable<TA> pointsA, IEnumerable<TB> pointsB, Func<TA, TB, TR> map)
{
return pointsA.Zip(pointsB, map);
}
/// <summary>
/// Generate samples by sampling a function at samples from a probability distribution.
/// </summary>
public static T[] RandomMap<T>(int length, IContinuousDistribution distribution, Func<double, T> map)
{
var res = new T[length];
for (int i = 0; i < res.Length; i++)
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
res[i] = map(distribution.Sample());
data[i] = map(distribution.Sample());
}
return res;
return data;
}
/// <summary>
@ -379,12 +535,12 @@ namespace MathNet.Numerics
/// </summary>
public static T[] RandomMap2<T>(int length, IContinuousDistribution distribution, Func<double, double, T> map)
{
var res = new T[length];
for (int i = 0; i < res.Length; i++)
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
res[i] = map(distribution.Sample(), distribution.Sample());
data[i] = map(distribution.Sample(), distribution.Sample());
}
return res;
return data;
}
/// <summary>

166
src/Numerics/Signals/SignalGenerator.Equidistant.cs

@ -56,39 +56,7 @@ namespace MathNet.Numerics.Signals
double intervalEnd,
int sampleCount)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 0)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
if (sampleCount == 0)
{
return new T[0];
}
if (sampleCount == 1)
{
return new[] { function(0.5 * (intervalBegin + intervalEnd)) };
}
var samples = new T[sampleCount];
var step = (intervalEnd - intervalBegin) / (sampleCount - 1);
var current = intervalBegin;
for (int i = 0; i < samples.Length - 1; i++)
{
samples[i] = function(current);
current += step;
}
samples[samples.Length - 1] = function(intervalEnd);
return samples;
return Generate.LinearSpacedMap(sampleCount, intervalBegin, intervalEnd, function);
}
/// <summary>
@ -111,44 +79,8 @@ namespace MathNet.Numerics.Signals
int sampleCount,
out double[] samplePoints)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 0)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
if (sampleCount == 0)
{
samplePoints = new double[0];
return new T[0];
}
if (sampleCount == 1)
{
samplePoints = new[] { 0.5 * (intervalBegin + intervalEnd) };
return new[] { function(samplePoints[0]) };
}
var samples = new T[sampleCount];
samplePoints = new double[sampleCount];
var step = (intervalEnd - intervalBegin) / (sampleCount - 1);
var current = intervalBegin;
for (int i = 0; i < samples.Length - 1; i++)
{
samplePoints[i] = current;
samples[i] = function(current);
current += step;
}
samplePoints[samplePoints.Length - 1] = intervalEnd;
samples[samples.Length - 1] = function(intervalEnd);
return samples;
samplePoints = Generate.LinearSpaced(sampleCount, intervalBegin, intervalEnd);
return Generate.Map(samplePoints, function);
}
/// <summary>
@ -170,27 +102,7 @@ namespace MathNet.Numerics.Signals
double periodOffset,
int sampleCount)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 1)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
var samples = new T[sampleCount];
var step = periodLength / sampleCount;
var current = periodOffset;
for (int i = 0; i < samples.Length; i++)
{
samples[i] = function(current);
current += step;
}
return samples;
return Generate.PeriodicMap(sampleCount, function, sampleCount, 1.0, periodLength, periodOffset);
}
/// <summary>
@ -214,29 +126,8 @@ namespace MathNet.Numerics.Signals
int sampleCount,
out double[] samplePoints)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 1)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
var samples = new T[sampleCount];
samplePoints = new double[sampleCount];
var step = periodLength / sampleCount;
var current = periodOffset;
for (int i = 0; i < samples.Length; i++)
{
samplePoints[i] = current;
samples[i] = function(current);
current += step;
}
return samples;
samplePoints = Generate.Periodic(sampleCount, sampleCount, 1.0, periodLength, periodOffset);
return Generate.Map(samplePoints, function);
}
/// <summary>
@ -257,26 +148,7 @@ namespace MathNet.Numerics.Signals
double step,
int sampleCount)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 0)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
var samples = new T[sampleCount];
var current = start;
for (int i = 0; i < samples.Length; i++)
{
samples[i] = function(current);
current += step;
}
return samples;
return Generate.LinearSpacedMap(sampleCount, start, start + (sampleCount - 1)*step, function);
}
/// <summary>
@ -299,28 +171,8 @@ namespace MathNet.Numerics.Signals
int sampleCount,
out double[] samplePoints)
{
if (ReferenceEquals(function, null))
{
throw new ArgumentNullException("function");
}
if (sampleCount < 0)
{
throw new ArgumentOutOfRangeException("sampleCount");
}
var samples = new T[sampleCount];
samplePoints = new double[sampleCount];
var current = start;
for (int i = 0; i < samples.Length; i++)
{
samplePoints[i] = current;
samples[i] = function(current);
current += step;
}
return samples;
samplePoints = Generate.LinearSpaced(sampleCount, start, start + (sampleCount - 1)*step);
return Generate.Map(samplePoints, function);
}
/// <summary>

26
src/UnitTests/GenerateTests.cs

@ -130,6 +130,32 @@ namespace MathNet.Numerics.UnitTests
Assert.That(Generate.LinearRange(1d, -1.5d, -4d), Is.EqualTo(new[] { 1d, -0.5d, -2d, -3.5 }).AsCollection);
}
[Test]
public void Periodic()
{
Assert.That(Generate.Periodic(8, 2.0, 0.5), Is.EqualTo(new[] { 0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 1.0, delay: 1), Is.EqualTo(new[] { 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 1.0, delay: -1), Is.EqualTo(new[] { 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 1.0, phase: 0.7), Is.EqualTo(new[] { 0.7, 0.95, 0.2, 0.45, 0.7, 0.95, 0.2, 0.45 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 1.0, phase: -0.3), Is.EqualTo(new[] { 0.7, 0.95, 0.2, 0.45, 0.7, 0.95, 0.2, 0.45 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 2.0), Is.EqualTo(new[] { 0.0, 0.5, 1.0, 1.5, 0.0, 0.5, 1.0, 1.5 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.5, 2.0, phase: 1.9), Is.EqualTo(new[] { 1.9, 0.4, 0.9, 1.4, 1.9, 0.4, 0.9, 1.4 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 8.0, 1.0), Is.EqualTo(new[] { 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875 }).Within(1e-12).AsCollection);
// Angular over a full circle:
const double isq2 = Constants.Sqrt1Over2;
Assert.That(Generate.Periodic(8, 2.0, 0.5, Constants.Pi2).Select(Math.Sin), Is.EqualTo(new[] { 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0 }).Within(1e-12).AsCollection);
Assert.That(Generate.Periodic(8, 2.0, 0.25, Constants.Pi2).Select(Math.Sin), Is.EqualTo(new[] { 0.0, isq2, 1.0, isq2, 0.0, -isq2, -1.0, -isq2 }).Within(1e-12).AsCollection);
}
[Test]
public void PreiodicConsistentWithSequence()
{
Assert.That(
Generate.PeriodicSequence(16.0, 2.0, Constants.Pi2, Constants.PiOver4, 2).Take(1000).ToArray(),
Is.EqualTo(Generate.Periodic(1000, 16.0, 2.0, Constants.Pi2, Constants.PiOver4, 2)).Within(1e-12).AsCollection);
}
[Test]
public void SinusoidalConsistentWithSequence()
{

3
src/UnitTests/IntegralTransformsTests/FourierTest.cs

@ -28,7 +28,6 @@ using System;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.IntegralTransforms;
using MathNet.Numerics.IntegralTransforms.Algorithms;
using MathNet.Numerics.Signals;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
@ -58,7 +57,7 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
[Test]
public void NaiveTransformsRealSineCorrectly()
{
var samples = SignalGenerator.EquidistantPeriodic(w => new Complex(Math.Sin(w), 0), Constants.Pi2, 0, 16);
var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2);
// real-odd transforms to imaginary odd
var dft = new DiscreteFourierTransform();

5
src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs

@ -28,7 +28,6 @@ using System;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.IntegralTransforms;
using MathNet.Numerics.IntegralTransforms.Algorithms;
using MathNet.Numerics.Signals;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
@ -80,7 +79,7 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
public void FourierRadix2MatchesNaiveOnRealSine(FourierOptions options)
{
var dft = new DiscreteFourierTransform();
var samples = SignalGenerator.EquidistantPeriodic(w => new Complex(Math.Sin(w), 0), Constants.Pi2, 0, 16);
var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2);
VerifyMatchesNaiveComplex(
samples,
@ -130,7 +129,7 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
public void FourierBluesteinMatchesNaiveOnRealSineNonPowerOfTwo(FourierOptions options)
{
var dft = new DiscreteFourierTransform();
var samples = SignalGenerator.EquidistantPeriodic(w => new Complex(Math.Sin(w), 0), Constants.Pi2, 0, 14);
var samples = Generate.PeriodicMap(14, w => new Complex(Math.Sin(w), 0), 14, 1.0, Constants.Pi2);
VerifyMatchesNaiveComplex(
samples,

Loading…
Cancel
Save