/// <summary> /// R/S анализ ряда (последовательные вычисления) /// </summary> /// <param name="A">Массив входных данных</param> /// <param name="periodLength">Стартовая длина периода</param> /// <param name="startGIndex">Начальный индекс в массиве, с которого берутся данные</param> /// <param name="endGIndex">Конечный индекс в массиве, до которого берутся данные (включительно)</param> /// <param name="maxPeriodLength">Максимальная длина периода, до которого ведется расчет</param> /// <returns>Таблицу полученных R/S-точек и коэффициенты регрессии (A - соответствет H)</returns> public static ResultRS RS_Analyse(float[] A, int periodLength, int startGIndex, int endGIndex, int maxPeriodLength) { //кол-во RS-результатов int resLength = maxPeriodLength - periodLength + 1; //результаты RS-анализа PointRS[] result = new PointRS[resLength]; //последний индекс в массиве int lastIndex = endGIndex; //первый индекс в массиве //конечный локальный индекс int startIndex, endIndex, startIndexNow; //ср. значение RS для данного периода float averageRS; int j = 0; //текущая длина периода int currentPeriodLength = periodLength; //Кол-во периодов int periodCount = (endGIndex - startGIndex + 1) / currentPeriodLength; //Устанавливаем длину прогресбара CalculateStart.CreateEvent(resLength + 1, "R/S analyse..."); do { startIndex = lastIndex; endIndex = lastIndex; averageRS = 0; for (int i = 1; i <= periodCount; i++) { startIndex = endIndex - currentPeriodLength + 1; averageRS += GetRS(A, startIndex, endIndex); endIndex -= startIndex - 1; } startIndexNow = startIndex; averageRS /= periodCount; result[j].n = Math.Log10((float)currentPeriodLength / 2); result[j].rs = Math.Log10(averageRS); result[j].h = result[j].rs / result[j].n; j++; currentPeriodLength++; //Кол-во периодов periodCount = (endGIndex - startGIndex + 1) / currentPeriodLength; //Увеличиваем прогресбар Calculus.CreateEvent(j); }while (currentPeriodLength <= maxPeriodLength); KRegression regression = MathProcess.SimpleRegression(result); ResultRS res; res.points = result; res.regression = regression; return(res); }
/// <summary> /// Простая линейная регрессия y=Ax+B /// </summary> /// <param name="A">Массив наблюдений</param> /// <returns>Коэффициенты A и B</returns> public static KRegression SimpleRegression(PointRS[] A) { double sumX = 0; double sumY = 0; double sumX2 = 0; double sumXY = 0; CalculateStart.CreateEvent(A.Length, "Simple regression ..."); for (int i = 0; i < A.Length; i++) { sumX += A[i].n; sumY += A[i].rs; sumX2 += A[i].n * A[i].n; sumXY += A[i].n * A[i].rs; Calculus.CreateEvent(i); } double nSumX2 = A.Length * sumX2; KRegression res; res.A = (A.Length * sumXY - sumX * sumY) / (nSumX2 - sumX * sumX); res.B = (sumX2 * sumY - sumX * sumXY) / (nSumX2 - sumX2 * sumX2); return(res); }
public static KRegression SimpleRegression(double[,] A, int startIndex, int endIndex) { double sumX = 0; double sumY = 0; double sumX2 = 0; double sumXY = 0; int len = endIndex - startIndex + 1; CalculateStart.CreateEvent(len, "Simple regression ..."); for (int i = startIndex; i < len; i++) { sumX += A[i, 0]; sumY += A[i, 1]; sumX2 += A[i, 0] * A[i, 0]; sumXY += A[i, 0] * A[i, 1]; Calculus.CreateEvent(i); } double nSumX2 = len * sumX2; KRegression res; res.A = (len * sumXY - sumX * sumY) / (nSumX2 - sumX * sumX); res.B = (sumX2 * sumY - sumX * sumXY) / (nSumX2 - sumX2 * sumX2); return(res); }
/// <summary> /// R/S анализ ряда (параллельные вычисления) /// </summary> /// <param name="A">Массив входных данных</param> /// <param name="periodLength">Стартовая длина периода</param> /// <param name="startGIndex">Начальный индекс в массиве, с которого берутся данные</param> /// <param name="endGIndex">Конечный индекс в массиве, до которого берутся данные (включительно)</param> /// <param name="maxPeriodLength">Максимальная длина периода, до которого ведется расчет</param> /// <param name="threadCount">Количество потоков (распараллеливание вычислений)</param> /// <returns>Таблицу полученных R/S-точек и коэффициенты регрессии (A - соответствет H)</returns> public static ResultRS RS_Analyse(float[] A, int currentPeriodLength, int startGIndex, int endGIndex, int maxPeriodLength, int threadCount) { //кол-во RS-результатов int resLength = maxPeriodLength - currentPeriodLength + 1; //результаты RS-анализа PointRS[] result = new PointRS[resLength]; //Длина периода на поток int periodIntervalLength = resLength / threadCount; //Остаток (т.к. длина может не поделится на цело на число потоков) int remainder = resLength - periodIntervalLength * threadCount; //Максимальный период для первого потока = общий интервал + остаток int maxPeriodLengthLocal = periodIntervalLength + remainder + currentPeriodLength - 1; //Потоки Thread[] threads = new Thread[threadCount]; //Потоковые экземпляры, проводящие R/S анализ RS_AnalyseThread[] rsat = new RS_AnalyseThread[threadCount]; //Первый поток пошел rsat[0] = new RS_AnalyseThread(A, currentPeriodLength, startGIndex, endGIndex, maxPeriodLengthLocal, 0); threads[0] = new Thread(new ThreadStart(rsat[0].RS_Analyse)); //Устанавливаем длину прогресбара для 1 процесса resLength = maxPeriodLengthLocal - currentPeriodLength + 1; CalculateStart.CreateEvent(resLength, "R/S analyse 1", 0); threads[0].Start(); //Запускаем остальные потоки int j = 2; for (int i = 1; i < threadCount; i++) { //с какого периода начинать считать currentPeriodLength = maxPeriodLengthLocal + 1; //до какого периода считать maxPeriodLengthLocal += periodIntervalLength; //Запуск потока rsat[i] = new RS_AnalyseThread(A, currentPeriodLength, startGIndex, endGIndex, maxPeriodLengthLocal, i); threads[i] = new Thread(new ThreadStart(rsat[i].RS_Analyse)); //Устанавливаем длину прогресбара для i процесса resLength = maxPeriodLengthLocal - currentPeriodLength + 1; CalculateStart.CreateEvent(resLength, "R/S analyse " + j.ToString(), i); threads[i].Start(); j++; } //Ждем выполнения всех потоков for (int i = 0; i < threadCount; i++) { threads[i].Join(); } //Сшиваем все результаты в один массив int indexResult = 0; for (int i = 0; i < threadCount; i++) { rsat[i].result.CopyTo(result, indexResult); indexResult += rsat[i].result.Length; } //Регрессия KRegression regression = MathProcess.SimpleRegression(result, (int)(result.Length / 2.5), result.Length - 1); //KRegression regression = MathProcess.SimpleRegression(result, 0, result.Length - 1); ResultRS res; res.points = result; res.regression = regression; GC.Collect(GC.GetGeneration(A)); GC.Collect(GC.GetGeneration(rsat)); GC.Collect(GC.GetGeneration(threads)); GC.Collect(GC.GetGeneration(result)); GC.WaitForPendingFinalizers(); GC.Collect(); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); return(res); }