4

下の図のグラフに似たグラフが欲しいです。cos/sinに似たグラフを実現したいのですが、少しランダムです。グラフは、制限を超えたり (100) も下回ったり (0) することもありません。ランダム性がなければ、次のような関数を書くことができます:

f(x)=cos(x)*50+50

ランダムグラフ

任意の言語での実装または簡単な説明を探しています。

4

5 に答える 5

4

いくつかの sin/cos をランダムな係数と周期で単純に合計できます。

実装例:

internal struct SineWave
{
    internal readonly double Amplitude;
    internal readonly double OrdinaryFrequency;
    internal readonly double AngularFrequency;
    internal readonly double Phase;
    internal readonly double ShiftY;

    internal SineWave(double amplitude, double ordinaryFrequency, double phase, double shiftY)
    {
        Amplitude = amplitude;
        OrdinaryFrequency = ordinaryFrequency;
        AngularFrequency = 2 * Math.PI * ordinaryFrequency;
        Phase = phase;
        ShiftY = shiftY;
    }
}

public class RandomCurve
{
    private SineWave[] m_sineWaves;

    public RandomCurve(int components, double minY, double maxY, double flatness)
    {
        m_sineWaves = new SineWave[components];

        double totalPeakToPeakAmplitude = maxY - minY;
        double averagePeakToPeakAmplitude = totalPeakToPeakAmplitude / components;

        int prime = 1;
        Random r = new Random();
        for (int i = 0; i < components; i++)
        {
            // from 0.5 to 1.5 of averagePeakToPeakAmplitude 
            double peakToPeakAmplitude = averagePeakToPeakAmplitude * (r.NextDouble() + 0.5d);

            // peak amplitude is a hald of peak-to-peak amplitude
            double amplitude = peakToPeakAmplitude / 2d;

            // period should be a multiple of the prime number to avoid regularities
            prime = Utils.GetNextPrime(prime);
            double period = flatness * prime;

            // ordinary frequency is reciprocal of period
            double ordinaryFrequency = 1d / period;

            // random phase
            double phase = 2 * Math.PI * (r.NextDouble() + 0.5d);

            // shiftY is the same as amplitude
            double shiftY = amplitude;

            m_sineWaves[i] =
                new SineWave(amplitude, ordinaryFrequency, phase, shiftY);
        }
    }

    public double GetY(double x)
    {
        double y = 0;
        for (int i = 0; i < m_sineWaves.Length; i++)
            y += m_sineWaves[i].Amplitude * Math.Sin(m_sineWaves[i].AngularFrequency * x + m_sineWaves[i].Phase) + m_sineWaves[i].ShiftY;

        return y;
    }
}

internal static class Utils
{
    internal static int GetNextPrime(int i)
    {
        int nextPrime = i + 1;
        for (; !IsPrime(nextPrime); nextPrime++) ;
        return nextPrime;
    }

    private static bool IsPrime(int number)
    {
        if (number == 1) return false;
        if (number == 2)  return true;

        for (int i = 2; i < number; ++i)
            if (number % i == 0) return false;

        return true;
    } 
}
于 2012-12-25T17:07:22.113 に答える
2

これは C# で書かれたコードで、ランダムな入力値でさらにランダム化できます。値を含む出力を提供して、問題がないかどうかを確認します。Amplite は余弦値と正弦値に対して変更できます。最後にオフセットが追加され (最小値は常に 0)、最大値が 100 になるようにスケーリングが行われます。ご覧のとおり、ノイズを追加できます (図 3、図 4)。

terr1: RandomTerrarain(1000, 4, 1, 10, 5, 0); 図1

terr2: RandomTerrarain(1000, 2, 3, -10, 5, 0); 図 2

お役に立てれば!

      private static Random rnd = new Random();
    private double[] RandomTerrarain(int length, int sinuses, int cosinuses, double amplsin, double amplcos, double noise)
    {
        if (length <= 0)
            throw new ArgumentOutOfRangeException("length", length, "Length must be greater than zero!");
        double[] returnValues = new double[length];

        for (int i = 0; i < length; i++)
        {
            // sin
            for (int sin = 1; sin <= sinuses; sin++)
            {
                returnValues[i] += amplsin * Math.Sin((2 * sin * i * Math.PI) / (double)length);
            }
            // cos
            for (int cos = 1; cos <= cosinuses; cos++)
            {
                returnValues[i] += amplcos * Math.Cos((2 * cos * i * Math.PI) / (double)length);
            }
            // noise
            returnValues[i] += (noise * rnd.NextDouble()) - (noise * rnd.NextDouble());
        }
        // give offset so it be higher than 0
        double ofs = returnValues.Min();
        if (ofs < 0)
        {
            ofs *= -1;
            for (int i = 0; i < length; i++)
            {
                returnValues[i] += ofs;
            }
        }
        // resize to be fit in 100
        double max = returnValues.Max();
        if (max >= 100)
        {
            double scaler = max / 100.0;
            for (int i = 0; i < length; i++)
            {
                returnValues[i] /= scaler;
            }
        }
        return returnValues;
    }
于 2012-12-25T17:54:06.007 に答える
0

これを忘れて....

terr3: RandomTerrarain(1000, 5, 5, -2, 5, 2); 図 3

terr4: RandomTerrarain(1000, 4, 1, 5, -20, 1); 図 4

于 2012-12-25T17:57:15.000 に答える
0

Math関数には、クラスとCos()メソッドを使用できます。

public static double GetCosFunction(double d)
{
     return Math.Cos(d) * 50 + 50;
}

グラフ ソリューションについては、これらのトピックを確認できます。

于 2012-12-25T17:16:19.573 に答える