scripts/channelClasses/mock_ec/Sine.java
/////////////////////////////////////////////////////////////////
// This script generates pure sine waves, with different freqs at each site.
//
// Run with (for example)
// java -cp build:lib/derby.jar -Dserver.cache.enable=false -Djava.library.path=c frontendClasses/CLI -scriptChannel mock_ec/Sine -reviewSeries -paradigm ec -binZ site -transform power -display "TiledStack()" "Export(to=window, as=txt)" -v
/////////////////////////////////////////////////////////////////
package mock_ec;
import java.io.*;
import java.util.*;
import java.text.NumberFormat;
import epochClasses.*;
import generalClasses.*;
import recordingClasses.Recording;
import seriesClasses.*;
import seriesClasses.seriesGeneration.Erlang;
import channelClasses.ChannelScript;
import static channelClasses.Channel.*;
/////////////////////////////////////////////////////////////////
/** This script generates pure sine waves, with different freqs at each site.
*
* <p>The intended effect is:
* <ul><li>To check relation between amplitude and power: power should be
* 0.5*amplitude^2, irrespective of window size and overlap</li>
* <li>Demonstrate spectral leakage</li>
* </ul>
*/
public class Sine extends ChannelScript
{
/** Recording instance to be operated on */
Recording rec = null;
/** Time series */
ArrayList<SeriesAnalog> list = new ArrayList<SeriesAnalog>();
/** Events. May be left empty */
ArrayList<Event> ev = new ArrayList<Event>();
////////////////////////////////////////////////////////////////////
/** Initialize instance by setting its parameters to default values.
*/
public Sine(Recording rec) {
this.rec = rec;
} // Sine
////////////////////////////////////////////////////////////////////
/** Update recording data by performing channel-oriented operations.
*/
public void update() {
// Template - used to encapsulate all sampling characteristics
float x0 = 0.0f; // in seconds: times start at x0
float xDelta = 0.004f; // in seconds: times increment by xDelta
float duration = 120.0f; // in seconds: times end at x0+duration
int nIndexes = Math.round(duration/xDelta);
SeriesAnalog template = new SeriesAnalog(new SiteSet(), // sites
x0, // x0
xDelta, // xDelta
new Units(Unit.s), // xUnits
nIndexes, // # samples
new Units(Unit.uV), // yUnits
DataMode.EEG); // DataMode
// Channels containing frequencies in the range [f0,f1] Hz
int nChans = 20;
double f0 = 1.1;
double f1 = 80.0;
double step = Math.log(f1/f0)/(nChans-1);
String[] labels = new String[nChans];
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMaximumFractionDigits(1);
for(int i=0; i<nChans; i++) {
double f = Math.exp(Math.log(f0)+i*step);
labels[i] = formatter.format(f);
}
// Epochs will later be defined as 2.0 secs long, i.e. spectral
// res = 0.5 Hz. Accordingly, let's ensure that at least one
// channel contains an integer multiple of this
labels[3] = "2.0";
for(int site=0; site<labels.length; site++) {
// What modality?
DataMode mode = DataMode.EEG;
// Parameters of sine wave
float amplitude = (float)Math.sqrt(2.0);
float freq = Float.parseFloat(labels[site]);
float twoPiF = (float)(2*Math.PI*freq);
// Create time series, with general character matching template
SeriesAnalog series = template.clone().setRamp(0.0f,twoPiF);
series.transformSin().mul(amplitude);
series.setSites(new SiteSet(new Site(labels[site])));
// Append series to result
list.add(series);
}
// Add synthetic time series to the currently empty Recording
replaceAllSeries(rec, list);
replaceAllEvents(rec, ev);
} // update
////////////////////////////////////////////////////////////////////
/** Dump summary of this class or object
* @return String representation of this object
*/
public String toString() {
String s = "<<<"+this.getClass().toString()+">>>\n";
return s;
} // toString
}