/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.operator.generator; import com.rapidminer.example.Attribute; import com.rapidminer.operator.ports.metadata.AttributeMetaData; import com.rapidminer.operator.ports.metadata.ExampleSetMetaData; import com.rapidminer.operator.ports.metadata.SetRelation; import com.rapidminer.tools.Ontology; import com.rapidminer.tools.RandomGenerator; import com.rapidminer.tools.math.container.Range; /** * Generator for an artificial audio data set (based on real-world data from drilling processes). * * @author Sebastian Land */ public class DrillerOscillationFunction implements TargetFunction { private static final double SKEW_CATASTROPHY_EXPONENT = 1.2d; private double TURN_PERIODS = 16d; private static double GENERAL_NOISE = 0.02d; private static double INITIAL_SKEW_RATE_VARIANCE = 0.2d; private static double LAST_SKEW_CHANGE_PROBABILITY = 0.2d; private static double MAXIMAL_SKEW_CHANGE = 0.1d; private static double CRITICAL_FREQUENCY_SKEW = 2.7d; private static double SKEW_FASTER_PREFERENCE = 0.3d; private int periodLength; private int period = 0; private double[] frequencePeriod; private double[] skew; private double[] skewChangeDirection; private double[] crashed; private int numberOfAttributes; private int numberOfExamples; public DrillerOscillationFunction() {} @Override public double calculate(double[] args) throws FunctionException { return 0; } @Override public double[] createArguments(int dimension, RandomGenerator random) throws FunctionException { if (dimension < 3) { throw new FunctionException("Driller oscillation function", "needs at least 3 attributes!"); } if (skew == null) { skew = new double[dimension - 1]; for (int i = 0; i < dimension - 1; i++) { skew[i] = 1d + random.nextDoubleInRange(-INITIAL_SKEW_RATE_VARIANCE, INITIAL_SKEW_RATE_VARIANCE); } skewChangeDirection = new double[dimension - 1]; for (int i = 0; i < dimension - 1; i++) { skewChangeDirection[i] = random.nextDouble() - SKEW_FASTER_PREFERENCE; } crashed = new double[dimension]; frequencePeriod = new double[dimension - 1]; } double[] values = new double[dimension]; dimension--; // with later periods possible change in skewing will be more probable double neededProbability = Math.pow((((double) period) / periodLength), 1.5d) * LAST_SKEW_CHANGE_PROBABILITY; // now check against needed probability for (int i = 0; i < dimension; i++) { if (skew[i] > CRITICAL_FREQUENCY_SKEW) { skew[i] = Math.pow(skew[i], SKEW_CATASTROPHY_EXPONENT); crashed[i] = 1d; } else { double dice = random.nextDouble(); if (dice <= neededProbability) { // then change skew double skewChange = skew[i] * random.nextDoubleInRange(0, MAXIMAL_SKEW_CHANGE); if (random.nextDouble() <= skewChangeDirection[i]) { skew[i] = skew[i] - skewChange; } else { skew[i] = skew[i] + skewChange; } } } } // generating data for (int i = 0; i < dimension; i++) { frequencePeriod[i] = frequencePeriod[i] + ((Math.PI * skew[i]) / TURN_PERIODS); values[i] = Math.sin(frequencePeriod[i]); // adding noise values[i] = values[i] * random.nextDoubleInRange(1d - GENERAL_NOISE, 1d + GENERAL_NOISE); } values[1] = skew[0]; values[dimension] = period; period++; if (period == periodLength) { crashed[dimension] = period; return crashed; } return values; } @Override public Attribute getLabel() { return null; } @Override public void init(RandomGenerator random) {} @Override public void setUpperArgumentBound(double upper) {} @Override public void setLowerArgumentBound(double lower) {} @Override public void setTotalNumberOfAttributes(int number) { this.numberOfAttributes = number; } @Override public void setTotalNumberOfExamples(int number) { this.periodLength = number; this.numberOfExamples = number; } @Override public ExampleSetMetaData getGeneratedMetaData() { ExampleSetMetaData emd = new ExampleSetMetaData(); for (int i = 1; i <= numberOfAttributes; i++) { AttributeMetaData amd = new AttributeMetaData("att" + i, Ontology.REAL); if (i == numberOfAttributes) { amd.setValueRange(new Range(0, numberOfExamples), SetRelation.EQUAL); } else if (i == 2) { amd.setValueRange(new Range(0, Double.POSITIVE_INFINITY), SetRelation.SUBSET); } else { amd.setValueRange(new Range(-1d - GENERAL_NOISE, 1d + GENERAL_NOISE), SetRelation.EQUAL); } if (i < numberOfAttributes) { amd.getNumberOfMissingValues().increaseByUnknownAmount(); } emd.addAttribute(amd); } emd.setNumberOfExamples(numberOfExamples); return emd; } @Override public int getMinNumberOfAttributes() { return 3; } @Override public int getMaxNumberOfAttributes() { return Integer.MAX_VALUE; } }