com.github.mrstampy.esp.dsp.PowerInstance Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esp Show documentation
Show all versions of esp Show documentation
ESP - An EEG Signal Processing Library
/*
* Copyright (C) 2008 - 2013 Burton Alexander
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.github.mrstampy.esp.dsp;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
/**
* This class is a convenience class to assist in aggregation of the power of
* the {@link SignalInstance}s produced by the {@link SignalProcessor} over
* time. It is of use when monitoring a set of frequencies. Only power
* information for the specified frequencies is extracted. Should another
* frequency be specified an exception will be thrown.
*
* @author burton
*
*/
public class PowerInstance extends DspInstance {
private static final long serialVersionUID = -5379475359721093457L;
private double[] frequencies;
private SignalInstance signalInstance;
private ConcurrentNavigableMap powers;
/**
* Creates an instance for the specified {@link SignalInstance} and extracts
* the power of the signal at the specified frequencies.
*
* @param signalInstance
* @param frequencies
*/
public PowerInstance(SignalInstance signalInstance, double... frequencies) {
super(signalInstance.getNanos(), signalInstance.getSampleRate());
this.frequencies = frequencies;
this.signalInstance = signalInstance;
init();
}
/**
* Powers are calculated as a weighted average of powers in the PowerInstance
* list supplied. The last (most recent) PowerInstance has a weight of
* list.size, the next last a weight of list.size - 1 etc. It is assumed that
* the same array of frequencies was used to create all instances in the list. An
* exception is thrown if otherwise.
*
* @param nanos
* @param sampleRate
* @param instances
* @throws IllegalArgumentException
* if a key specified in one instance does not exist for all
* instances
*/
public PowerInstance(long nanos, double sampleRate, List instances) {
super(nanos, sampleRate);
if (instances != null && !instances.isEmpty()) createMap(instances);
}
/**
* Returns the map of frequency:power pairs
*
* @return
*/
public ConcurrentNavigableMap getPowers() {
if (powers == null) createMap();
return powers;
}
/**
* Returns the power at the specified frequency, or throws an exception if a
* frequency different from one used to create this instance is specified.
*
* @param frequency
* @return
*/
public Double getPowerAt(double frequency) {
Double power = powers.get(frequency);
if (power == null) throw new IllegalArgumentException("No power for frequency " + frequency);
return power;
}
private void createMap(List instances) {
Set frequencies = instances.get(0).getPowers().keySet();
createMap();
int arraySize = getWeightedAverageArraySize(instances.size());
for (Double freq : frequencies) {
powers.put(freq, aggregatePower(freq, instances, arraySize));
}
}
private Double aggregatePower(Double freq, List instances, int arraySize) {
double[] powers = new double[arraySize];
int powersIdx = 0;
for (int i = instances.size() - 1; i >= 0; i--) {
Double val = instances.get(i).getPowers().get(freq);
if (val == null) throw new IllegalArgumentException("Value missing for frequency " + freq);
powersIdx = populateArray(powers, val, powersIdx, i + 1);
}
double rms = getRMS(powers);
return rms;
}
private int populateArray(double[] powers, Double val, int powersIdx, int weighting) {
int idx = powersIdx;
for (int i = 0; i < weighting; i++) {
powers[idx] = val;
idx++;
}
return idx;
}
private int getWeightedAverageArraySize(int listSize) {
int size = 0;
for (int i = 1; i <= listSize; i++) {
size += i;
}
return size;
}
private double getRMS(double... vals) {
double sum = 0;
for (double d : vals) {
sum += d * d;
}
return Math.sqrt(sum / vals.length);
}
private void init() {
check();
createMap();
signalInstance.setNormalizeAgainst(frequencies);
for (double freq : frequencies) {
powers.put(freq, signalInstance.getPowerAt(freq));
}
}
private void createMap() {
powers = new ConcurrentSkipListMap();
}
private void check() {
if (signalInstance == null) throw new IllegalArgumentException("No SignalInstance specified");
if (frequencies == null || frequencies.length == 0) throw new IllegalArgumentException("No frequencies specified");
frequencyCheck(frequencies);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy