/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.sim; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Random; import org.diirt.util.array.ArrayDouble; import org.diirt.vtype.VDoubleArray; import static org.diirt.vtype.ValueFactory.*; /** * Function to simulate a waveform containing a gaussian that moves to the * left. * * @author carcassi */ public class GaussianWaveform extends SimFunction<VDoubleArray> { private Random rand = new Random(); private double[] buffer; private final double periodInSeconds; private VDoubleArray lastValue; private Instant initialRefernce; /** * Creates a gaussian wave of 100 samples, with period of 1 second, standard deviation of * 100 samples, updating every 100ms (10Hz). */ public GaussianWaveform() { this(1.0, 100.0, 100.0, 0.1); } /** * Creates a gaussian wave of given number of samples, with given period and standard, * updating at the given rate * * @param periodInSeconds the period measured in seconds * @param stdDev standard deviation of the gaussian distribution * @param nSamples number of elements in the waveform * @param updateRateInSeconds time between samples in seconds */ public GaussianWaveform(Double periodInSeconds, Double stdDev, Double nSamples, Double updateRateInSeconds) { super(updateRateInSeconds, VDoubleArray.class); int size = nSamples.intValue(); this.periodInSeconds = periodInSeconds; buffer = new double[size]; populateGaussian(buffer, stdDev); } static void populateGaussian(double[] array, double stdDev) { for (int i = 0; i < array.length; i++) { array[i] = gaussian(i, array.length / 2.0, stdDev); } } private double[] generateNewValue(double omega, double t) { double x = t * omega / (2 * Math.PI); double normalizedX = x - (double) (long) x; int offset = (int) (normalizedX * buffer.length); if (offset == buffer.length) { offset = 0; } int localCounter = offset; double[] newArray = new double[buffer.length]; for (int i = 0; i < newArray.length; i++) { newArray[i] = buffer[localCounter]; localCounter++; if (localCounter >= buffer.length) { localCounter -= buffer.length; } } return newArray; } /** * 1D gaussian, centered on centerX and with the specified width. * @param x coordinate x * @param centerX center of the gaussian on x * @param width width of the gaussian in all directions * @return the value of the function at the given coordinates */ public static double gaussian(double x, double centerX, double width) { return Math.exp((-Math.pow((x - centerX), 2.0)) / width); } @Override VDoubleArray nextValue() { if (lastTime == null) lastTime = Instant.now(); if (initialRefernce == null) { initialRefernce = lastTime; } double t = initialRefernce.until(lastTime, ChronoUnit.SECONDS); double omega = 2 * Math.PI / periodInSeconds; return newVDoubleArray(new ArrayDouble(generateNewValue(omega, t)), alarmNone(), newTime(lastTime), newDisplay(0.0, 0.0, 0.0, "x", Constants.DOUBLE_FORMAT, 1.0, 1.0, 1.0, 0.0, 1.0)); } }