/** * 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 org.diirt.util.array.ArrayInt; import org.diirt.util.array.ListDouble; import org.diirt.vtype.VDoubleArray; import org.diirt.vtype.ValueFactory; import static org.diirt.vtype.ValueFactory.*; import java.time.Instant; import java.time.temporal.ChronoUnit; import org.diirt.vtype.ValueUtil; /** * Function to simulate a 2D waveform containing a sine wave. * * @author carcassi */ public class Square2DWaveform extends SimFunction<VDoubleArray> { private final double periodInSeconds; private final double wavelengthInSamples; private final int xSamples; private final int ySamples; private final double angle; private Instant initialReference; /** * Creates sine wave of 100 samples, with period of 1 second, wavelength of * 100 samples along the x axis, updating at 10 Hz. */ public Square2DWaveform() { this(1.0, 100.0, 0.1); } /** * Creates sine wave of 100 samples, with given period and given wavelength of * 100 samples along the x axis, updating at given rate. * * @param periodInSeconds the period measured in seconds * @param wavelengthInSamples the wavelength measured in samples * @param updateRateInSeconds the update rate in seconds */ public Square2DWaveform(Double periodInSeconds, Double wavelengthInSamples, Double updateRateInSeconds) { this(periodInSeconds, wavelengthInSamples, 100.0, updateRateInSeconds); } /** * Creates sine wave of 100 samples, with given period and given wavelength of * given number of samples along the x axis, updating at given rate. * * @param periodInSeconds the period measured in seconds * @param wavelengthInSamples the wavelength measured in samples * @param nSamples the number of samples * @param updateRateInSeconds the update rate in seconds */ public Square2DWaveform(Double periodInSeconds, Double wavelengthInSamples, Double nSamples, Double updateRateInSeconds) { this(periodInSeconds, wavelengthInSamples, 0.0, nSamples, nSamples, updateRateInSeconds); } /** * Creates sine wave with given parameters. * * @param periodInSeconds the period measured in seconds * @param wavelengthInSamples the wavelength measured in samples * @param angle the direction of propagation for the wave * @param xSamples number of samples on the x direction * @param ySamples number of samples on the y direction * @param updateRateInSeconds the update rate in seconds */ public Square2DWaveform(Double periodInSeconds, Double wavelengthInSamples, Double angle, Double xSamples, Double ySamples, Double updateRateInSeconds) { super(updateRateInSeconds, VDoubleArray.class); this.periodInSeconds = periodInSeconds; this.wavelengthInSamples = wavelengthInSamples; this.xSamples = xSamples.intValue(); this.ySamples = ySamples.intValue(); this.angle = angle; if (this.xSamples <= 0 || this.ySamples <= 0) { throw new IllegalArgumentException("Number of sample must be a positive integer."); } } private ListDouble generateNewValue(final double omega, final double t, double k) { final double kx = Math.cos(angle * Math.PI / 180.0) * k; final double ky = Math.sin(angle * Math.PI / 180.0) * k; return new ListDouble() { @Override public double getDouble(int index) { int x = index % xSamples; int y = index / xSamples; double length = (omega * t + kx* x + ky * y) / (2 * Math.PI); double normalizedPositionInPeriod = length - (double) (long) length; if (normalizedPositionInPeriod < 0.5) { return 1.0; } else if (normalizedPositionInPeriod < 1.0) { return -1.0; } else { return 1.0; } } @Override public int size() { return xSamples*ySamples; } }; } @Override VDoubleArray nextValue() { if (initialReference == null) { initialReference = lastTime; } double t = initialReference.until(lastTime, ChronoUnit.SECONDS); double omega = 2 * Math.PI / periodInSeconds; double k = 2 * Math.PI / wavelengthInSamples; double min = -1.0; double max = 1.0; double range = 0.0; return (VDoubleArray) ValueFactory.newVNumberArray(generateNewValue(omega, t, k), new ArrayInt(ySamples, xSamples), ValueUtil.defaultArrayDisplay(new ArrayInt(ySamples, xSamples)), alarmNone(), newTime(lastTime), newDisplay(min, min + range * 0.1, min + range * 0.2, "", Constants.DOUBLE_FORMAT, min + range * 0.8, min + range * 0.9, max, min, max)); } }