/* BipolarReferenceMontageGenerator.java created 2007-11-29 * */ package org.signalml.domain.montage.generators; import java.util.ArrayList; import java.util.List; import org.signalml.app.model.components.validation.ValidationErrors; import org.signalml.domain.montage.system.ChannelType; import org.signalml.domain.montage.Montage; import org.signalml.domain.montage.MontageException; import org.signalml.domain.montage.SourceChannel; import org.signalml.domain.montage.SourceMontage; import org.signalml.domain.montage.system.ChannelFunction; import org.springframework.validation.Errors; /** * This class represents the generator for a bipolar montage. * In bipolar montage each channel (i.e., waveform) represents the difference * between two adjacent electrodes. The entire montage consists of a series * of these channels. * For example, the channel "Fp1-F3" represents the difference in voltage * between the Fp1 electrode and the F3 electrode. The next channel in the montage, * "F3-C3," represents the voltage difference between F3 and C3, and so on through * the entire array of electrodes. * (source: {@code http://en.wikipedia.org/wiki/Electroencephalography}) * * It generates montage of that type from given "raw" montage and checks * if {@link SourceMontage montages} are valid bipolar montages. * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class BipolarReferenceMontageGenerator extends AbstractMontageGenerator { private static final long serialVersionUID = 1L; /** * An array of pairs of channels (channels {@link Channel functions}) * that will be used to create montage channels. * Each pair is used to create one {@link MontageChannel montage channel}. * First element as primary channel, second as reference. */ protected transient String[][] channelPairs; /** * Constructor. Creates a generator for an bipolar reference montage * based on <i>refChannels</i> array * @param channelPairs an array of pairs of {@link Channel channels} * (channels functions) that will be used to create montage channels. * Each pair is used to create one {@link MontageChannel montage channel}. * First element as primary channel, second as reference. */ public BipolarReferenceMontageGenerator(String[][] channelPairs) { if (channelPairs == null || channelPairs.length == 0) { throw new NullPointerException("Definition cannot be null or empty"); } this.channelPairs = channelPairs; } /** * Creates a bipolar montage from the given montage. * @param montage the montage to be used * @throws MontageException if two channels have the same function * (in the given montage) or there is no channel with some function */ @Override public void createMontage(Montage montage) throws MontageException { List<SourceChannel> primaryChannels = new ArrayList<SourceChannel>(); List<SourceChannel> referenceChannels = new ArrayList<SourceChannel>(); for (int i = 0; i < channelPairs.length; i++) { String channelName = channelPairs[i][0]; SourceChannel sourceChannel = montage.getSourceChannelByLabel(channelName); if (sourceChannel == null) { throw new MontageException("Cannot find primary channel " + channelName); } primaryChannels.add(sourceChannel); channelName = channelPairs[i][1]; sourceChannel = montage.getSourceChannelByLabel(channelName); if (sourceChannel == null) { throw new MontageException("Cannot find reference channel " + channelName); } referenceChannels.add(sourceChannel); } String token = "-1"; boolean oldMajorChange = montage.isMajorChange(); try { montage.setMajorChange(true); montage.reset(); int index; for (int i=0; i<primaryChannels.size(); i++) { int primaryChannelIndex = primaryChannels.get(i).getChannel(); int referenceChannelIndex = referenceChannels.get(i).getChannel(); index = montage.addMontageChannel(primaryChannelIndex); montage.setReference(index, referenceChannelIndex, token); montage.setMontageChannelLabelAt(index, montage.getSourceChannelLabelAt(primaryChannelIndex) + "-" + montage.getSourceChannelLabelAt(referenceChannelIndex)); } int size = montage.getSourceChannelCount(); for (int i=0; i<size; i++) { SourceChannel sourceChannel = montage.getSourceChannelAt(i); if (sourceChannel.getFunction() != ChannelFunction.EEG || (sourceChannel.getFunction() == ChannelFunction.EEG && !sourceChannel.isChannelType(ChannelType.PRIMARY))) { index = montage.addMontageChannel(i); } } } finally { montage.setMajorChange(oldMajorChange); } montage.setMontageGenerator(this); montage.setChanged(false); } /** * Checks if the montage is a valid bipolar montage. * @param sourceMontage the montage to be checked * @param errors Errors object used to report errors * @return true if the montage is a valid bipolar montage, false otherwise */ @Override public boolean validateSourceMontage(SourceMontage sourceMontage, ValidationErrors errors) { boolean ok = true; for (int i=0; i<channelPairs.length; i++) { for (int j = 0; j < 2; j++) { SourceChannel sourceChannel = sourceMontage.getSourceChannelByLabel(channelPairs[i][j]); if (sourceChannel == null) { onNotFound(channelPairs[i][j], errors); ok = false; } } } return ok; } }