void
WindowingThread::OnInitialize( const SignalProperties& Input,
                               const SignalProperties& Output )
{
  size_t numSamples = Output.Elements();
  mBuffers.clear();
  mBuffers.resize( Channels().size(), DataVector( numSamples ) );
  mInputElements = Input.Elements();

  mDetrend = Parameter( "Detrend" );
  if( mDetrend == None )
    mDetrendBuffer.resize( 0 );
  else
    mDetrendBuffer.resize( numSamples );

  mWindowFunction = Parameter( "WindowFunction" );
  mWindow.resize( numSamples );
  Real phasePerSample = M_PI / numSamples;
  // Window coefficients: Rect Hamming Hann Blackman
  const Real a1[] = {    0,   0.46,  0.5, 0.5, },
             a2[] = {    0,   0,     0,   0.08 };
  for( size_t i = 0; i < numSamples; ++i )
    mWindow[i] = 1 - a1[mWindowFunction] - a2[mWindowFunction]
                   + a1[mWindowFunction] * cos( i * phasePerSample )
                   + a2[mWindowFunction] * cos( i * 2 * phasePerSample );
}
void
TSWFilter::Preflight( const SignalProperties& Input,
                            SignalProperties& Output ) const
{
#if 0
  if( Parameter( "YMean" ) != 0 )
    bciout << "YMean should be set to zero for Slow Waves" << endl;
  if( Parameter( "YGain" ) < 300 || Parameter( "YGain" ) > 400 )
    bciout << "YGain should be set to 327.68 for Slow Waves" << endl;
#endif
  Parameter( "FeedbackEnd" );
  State( itiStateName );

  if( Parameter( "SWOutChList" )->NumValues() != Parameter( "SWInChList" )->NumValues() )
    bcierr << "The number of entries in SWOutChList must match that in SWInChList"
           << endl;
  for( int i = 0; i < Parameter( "SWInChList" )->NumValues(); ++i )
    PreflightCondition( Parameter( "SWInChList" )( i ) > 0 && Parameter( "SWInChList" )( i ) <= Input.Channels() );
  for( int i = 0; i < Parameter( "SWOutChList" )->NumValues(); ++i )
    PreflightCondition( Parameter( "SWOutChList" )( i ) > 0 && Parameter( "SWOutChList" )( i ) <= Input.Channels() );
  PreflightCondition( Parameter( "Tc" ).InSampleBlocks() >= 0.0 );
  PreflightCondition( Parameter( "SpatialFilteredChannels" ) == Input.Channels() );
  Output = SignalProperties( Input.Channels(), 1 );
  Output.SetName( "SWFiltered" );
}
void
TFBArteCorrection::Preflight( const SignalProperties& inSignalProperties,
                                    SignalProperties& outSignalProperties ) const
{
  for( int i = 0; i < Parameter( "ArteChList" )->NumValues(); ++i )
  {
    PreflightCondition( Parameter( "ArteChList" )( i ) >= 0 );
    PreflightCondition( Parameter( "ArteChList" )( i ) <= inSignalProperties.Channels() );
  }
  outSignalProperties = inSignalProperties;
  outSignalProperties.SetName( "Artifact Filtered" );
}
void
CustomFIRFilter::Initialize( const SignalProperties& Input, const SignalProperties& /*Output*/ )
{
  mBuffer.clear();

  ParamRef FIRCoefficients = Parameter( "FIRCoefficients" );
  int filterLength = FIRCoefficients->NumValues();
  mFilter.resize( filterLength, 0.0 );
  for( int sample = 0; sample < filterLength; ++sample )
    mFilter[sample] = FIRCoefficients( sample );

  int bufferLength = filterLength + Input.Elements() - 1;
  mBuffer.resize( Input.Channels(), DataVector( 0.0, bufferLength ) );
}
示例#5
0
bool
SignalProperties::Accommodates( const SignalProperties& sp ) const
{
  if( sp.IsEmpty() )
    return true;
  if( IsEmpty() )
    return false;
  if( !SignalType::ConversionIsSafe( sp.Type(), Type() ) )
    return false;
  if( Elements() < sp.Elements() )
    return false;
  if( Elements() < sp.Elements() )
    return false;
  return true;
}
void
ARThread::OnInitialize( const SignalProperties& Input, const SignalProperties& Output )
{
  mMEMPredictor.SetModelOrder( Parameter( "ModelOrder" ) );
  mOutputType = Parameter( "OutputType" );
  if( mOutputType != Coefficients )
  {
    mTransferSpectrum.SetFirstBinCenter( Parameter( "FirstBinCenter" ).InHertz() / Input.SamplingRate() );
    mTransferSpectrum.SetBinWidth( Parameter( "BinWidth" ).InHertz() / Input.SamplingRate() );
    mTransferSpectrum.SetNumBins( Output.Elements() );
    mTransferSpectrum.SetEvaluationsPerBin( Parameter( "EvaluationsPerBin" ) );
    mSpectrum.resize( Output.Elements() );
  }
  mInput.resize( Input.Elements() );
}
void
AverageDisplay::Preflight( const SignalProperties& Input, SignalProperties& Output ) const
{
  PreflightCondition( Parameter( "AvgDisplayCh" )->NumColumns() >= 2 );
  for( int i = 0; i < Parameter( "AvgDisplayCh" )->NumRows(); ++i )
    PreflightCondition
    (
      Parameter( "AvgDisplayCh" )( i, 0 ) > 0
      && Parameter( "AvgDisplayCh" )( i, 0 ) <= Input.Channels()
    );
  PreflightCondition( Parameter( "SamplingRate" ) > 0 );
  PreflightCondition( Input.Elements() > 0 );
  State( "TargetCode" );
  Output = Input;
}
void
ExpressionFilter::Preflight( const SignalProperties& Input,
                                   SignalProperties& Output ) const
{
  // Test whether configuration can be loaded.
  LCRandomGenerator rg;
  Expr startRunExpression( rg, Parameter( "StartRunExpression" ) ),
       stopRunExpression( rg, Parameter( "StopRunExpression" ) );
  ExpressionMatrix expressions;
  LoadExpressions( Parameter( "Expressions" ), expressions, rg );
  VariableContainer variables;
  // Request output signal properties:
  Output = Input;
  size_t numRows = expressions.size(),
         numCols = numRows ? expressions[0].size() : 0;
  if( numCols != 0 )
    Output.SetChannels( numRows )
          .SetElements( numCols )
          .ElementUnit().SetGain( 1.0 ).SetOffset( 0.0 ).SetSymbol( "" );
  // Try evaluating expressions.
  startRunExpression.Compile( variables );
  startRunExpression.Evaluate();
  GenericSignal preflightInput( Input ), preflightOutput( Output );
  CompileExpressions( expressions, variables );
  EvaluateExpressions( expressions, &preflightInput, &preflightOutput );
  stopRunExpression.Compile( variables );
  stopRunExpression.Evaluate();
}
示例#9
0
void
ARFilter::Initialize( const SignalProperties& Input,
                      const SignalProperties& /*Output*/ )
{
  int windowLength = MeasurementUnits::ReadAsTime( Parameter( "WindowLength" ) )
                     * Parameter( "SampleBlockSize" );
  mBuffer.clear();
  mBuffer.resize( Input.Channels(), DataVector( 0.0, windowLength ) );

  mOutputType = Parameter( "OutputType" );
  mDetrend = Parameter( "Detrend" );
  mMEMPredictor.SetModelOrder( Parameter( "ModelOrder" ) );

  switch( mOutputType )
  {
    case SpectralAmplitude:
    case SpectralPower:
    {
      float firstBinCenter = MeasurementUnits::ReadAsFreq( Parameter( "FirstBinCenter" ) ),
            lastBinCenter = MeasurementUnits::ReadAsFreq( Parameter( "LastBinCenter" ) ),
            binWidth = MeasurementUnits::ReadAsFreq( Parameter( "BinWidth" ) );
      int outputElements = ::floor( ( lastBinCenter - firstBinCenter + eps ) / binWidth + 1 );
      mTransferSpectrum
        .SetFirstBinCenter( firstBinCenter )
        .SetBinWidth( binWidth )
        .SetNumBins( outputElements )
        .SetEvaluationsPerBin( Parameter( "EvaluationsPerBin" ) );

    } break;

    case ARCoefficients:
      break;
  }
}
示例#10
0
void
ComplexDemodulator::Preflight( const SignalProperties& Input,
                                     SignalProperties& Output ) const
{
  ParamRef DemodulatorFrequencies = Parameter( "DemodulatorFrequencies" );
  bool error = false;
  for( int i = 0; i < DemodulatorFrequencies->NumValues(); ++i )
  {
    double frequency = MeasurementUnits::ReadAsFreq( DemodulatorFrequencies( i ) );
    error |= ( frequency < 0 );
    error |= ( frequency > 0.5 );
  }
  if( error )
    bcierr << "DemodulatorFrequencies must be greater 0 and less than half the "
           << "sampling rate "
           << "(currently " << Parameter( "SamplingRate" ) << "Hz)"
           << endl;
  double FrequencyResolution
    = MeasurementUnits::ReadAsFreq( Parameter( "FrequencyResolution" ) );
  PreflightCondition( FrequencyResolution > 0 );

  // Request output signal properties:
  Output = SignalProperties(
            Input.Channels(),
            DemodulatorFrequencies->NumValues(),
            SignalType::float32
           );
}
示例#11
0
void
SpatialFilter::Preflight( const SignalProperties& Input,
                                SignalProperties& Output ) const
{
  // Parameter/Input consistency.
  if( Input.Channels() != Parameter( "SpatialFilter" )->NumColumns() )
    bcierr << "The input signal's number of channels must match "
           << "the number of columns in the SpatialFilter parameter"
           << endl;

  // Output signal description.
  Output = Input;
  Output.SetChannels( 0 ).SetChannels( Parameter( "SpatialFilter" )->NumRows() );
  if( !Parameter( "SpatialFilter" )->RowLabels().IsTrivial() )
    for( int i = 0; i < Parameter( "SpatialFilter" )->NumRows(); ++i )
      Output.ChannelLabels()[ i ] = Parameter( "SpatialFilter" )->RowLabels()[ i ];
}
void
WindowingThread::OnPreflight( const SignalProperties& Input,
                                    SignalProperties& Output ) const
{
  Output = Input;
  double windowLength = Parameter( "WindowLength" ).InSampleBlocks();
  int numSamples = static_cast<int>( windowLength * Input.Elements() );
  if( numSamples < 0 )
  {
    bcierr << "WindowLength parameter must be >= 0" << endl;
    numSamples = 0;
  }
  Output.SetElements( numSamples )
        .SetIsStream( false )
        .ElementUnit().SetRawMin( 0 )
                      .SetRawMax( Output.Elements() - 1 );
}
void
ARThread::OnPreflight( const SignalProperties& Input,
                             SignalProperties& Output ) const
{
  if( Input.Elements() < Parameter( "ModelOrder" ) )
    bcierr << "WindowLength parameter must be large enough"
           << " for the number of samples to exceed the model order"
           << endl;

  if( Parameter( "OutputType" ) == Coefficients )
  {
    Output = Input;
    Output.SetName( "AR Coefficients" );
    Output.SetElements( Parameter( "ModelOrder" ) );
    Output.ElementUnit().SetSymbol( "" )
                        .SetOffset( 0 )
                        .SetGain( 1 )
                        .SetRawMin( 0 )
                        .SetRawMax( Output.Elements() - 1 );
  }
  else
  {
    SpectrumThread::OnPreflight( Input, Output );
    Output.SetName( "AR " + Output.Name() );
  }
}
示例#14
0
void
LinearClassifier::Initialize( const SignalProperties& Input,
                              const SignalProperties& /*Output*/ )
{
  const ParamRef& Classifier = Parameter( "Classifier" );
  size_t numEntries = Classifier->NumRows();
  mInputChannels.resize( numEntries );
  mInputElements.resize( numEntries );
  mOutputChannels.resize( numEntries );
  mWeights.resize( numEntries );
  for( size_t entry = 0; entry < numEntries; ++entry )
  {
    mInputChannels[ entry ] = Input.ChannelIndex( Classifier( entry, 0 ) );
    mInputElements[ entry ] = Input.ElementIndex( Classifier( entry, 1 ) );
    mOutputChannels[ entry ] = Classifier( entry, 2 ) - 1;
    mWeights[ entry ] = Classifier( entry, 3 );
  }
}
示例#15
0
void
FFTFilter::Preflight( const SignalProperties& Input, SignalProperties& Output ) const
{
  for( int i = 0; i < Parameter( "FFTInputChannels" )->NumValues(); ++i )
  {
    int channelIndex = Input.ChannelIndex( Parameter( "FFTInputChannels" )( i ) );
    if( channelIndex < 0 || channelIndex >= Input.Channels() )
      bcierr << "Invalid channel specification \""
             << Parameter( "FFTInputChannels" )( i )
             << "\" in FFTInputChannels, evaluates to "
             << channelIndex
             << endl;
  }

  bool fftRequired = ( ( int )Parameter( "FFTOutputSignal" ) != eInput
                       || ( int )Parameter( "VisualizeFFT" ) )
                     && ( Parameter( "FFTInputChannels" )->NumValues() > 0 );
  if( fftRequired )
  {
    if( mFFT.LibAvailable() )
    {
      FFTLibWrapper preflightFFT;
      int fftWindowLength = Parameter( "SampleBlockSize" )
                            * MeasurementUnits::ReadAsTime( Parameter( "FFTWindowLength" ) );
      if( !preflightFFT.Initialize( fftWindowLength ) )
        bcierr << "Requested parameters are not supported by FFT library" << endl;
    }
    else
      bcierr << "The FFT Filter could not find the " << mFFT.LibName() << " library. "
             << "For legal reasons, this library is not part of the BCI2000 distribution. "
             << "Please download the latest version of fftw3.dll from "
             << "http://www.fftw.org/install/windows.html"
             << endl;
  }

  if( int( Parameter( "VisualizeFFT" ) ) )
  {
    SignalProperties temp;
    DetermineSignalProperties( temp, ePower );
  }

  Output = Input;
  DetermineSignalProperties( Output, Parameter( "FFTOutputSignal" ) );
}
void
BCI2000OutputFormat::Preflight( const SignalProperties& inProperties,
                                const StateVector& ) const
{
  Parameter( "SourceCh" );

  switch( inProperties.Type() )
  {
    case SignalType::int16:
    case SignalType::int32:
    case SignalType::float32:
      /* These types are OK */
      break;

    default:
      bcierr << inProperties.Type().Name()
             << " data type unsupported for BCI2000 files"
             << endl;
  }
}
示例#17
0
void
FeedbackDemoTask::OnPreflight( const SignalProperties& Input ) const
{
  Parameter( "WindowHeight" );
  Parameter( "WindowWidth" );
  Parameter( "WindowLeft" );
  Parameter( "WindowTop" );

  if( RGBColor( Parameter( "CursorColor" ) ) == RGBColor::NullColor )
    bcierr << "Invalid RGB value in CursorColor" << endl;

  if( MeasurementUnits::ReadAsTime( Parameter( "FeedbackDuration" ) ) <= 0 )
    bcierr << "FeedbackDuration must be greater 0" << endl;

  if( Input.IsEmpty() )
    bcierr << "Requires at least one entry in control signal" << endl;

  if( Input.Channels() > 1 )
    bciout << "Will ignore additional channels in control signal" << endl;
}
示例#18
0
void
FFTFilter::Preflight( const SignalProperties& Input, SignalProperties& Output ) const
{
  for( int i = 0; i < Parameter( "FFTInputChannels" )->NumValues(); ++i )
  {
    double channelIndex = Input.ChannelIndex( Parameter( "FFTInputChannels" )( i ) );
    if( channelIndex < 0 || channelIndex >= Input.Channels() )
      bcierr << "Invalid channel specification \""
             << Parameter( "FFTInputChannels" )( i )
             << "\" in FFTInputChannels, evaluates to "
             << channelIndex
             << endl;
  }

  bool fftRequired = ( int( Parameter( "FFTOutputSignal" ) ) != eInput
                       || int( Parameter( "VisualizeFFT" ) ) )
                     && ( Parameter( "FFTInputChannels" )->NumValues() > 0 );
  if( fftRequired )
  {
    if( mFFT.LibAvailable() )
    {
      RealFFT preflightFFT;
      int fftWindowLength =
        static_cast<int>( Input.Elements() * Parameter( "FFTWindowLength" ).InSampleBlocks() );
      if( !preflightFFT.Initialize( fftWindowLength ) )
        bcierr << "Requested parameters are not supported by FFT library" << endl;
    }
    else
      bcierr << "The FFT Filter could not find the " << mFFT.LibName() << " library."
             << endl;
  }

  if( int( Parameter( "VisualizeFFT" ) ) || int( Parameter( "FFTOutputSignal" ) ) == ePower )
  {
    SignalProperties temp( Input );
    DetermineSignalProperties( temp, ePower );
  }

  Output = Input;
  DetermineSignalProperties( Output, Parameter( "FFTOutputSignal" ) );
}
示例#19
0
void
P3TemporalFilter::Preflight( const SignalProperties& Input,
                             SignalProperties& Output ) const
{
    // Required states.
    State( "Running" );
    State( "StimulusCode" );
    State( "StimulusType" );
    OptionalState( "StimulusBegin" );

    float outputSamples = MeasurementUnits::ReadAsTime( Parameter( "EpochLength" ) );
    outputSamples *= Input.Elements();
    outputSamples = ::ceil( outputSamples );
    // Requested output signal properties.
    Output = Input;
    Output.SetChannels( Input.Channels() )
    .SetElements( outputSamples )
    .SetType( SignalType::float32 )
    .ElementUnit().SetRawMin( 0 )
    .SetRawMax( outputSamples - 1 );
}
示例#20
0
// **************************************************************************
// Function:   Preflight
// Purpose:    Checks parameters for availability and consistency with
//             input signal properties; requests minimally needed properties for
//             the output signal; checks whether resources are available.
// Parameters: Input and output signal properties pointers.
// Returns:    N/A
// **************************************************************************
void FIRFilter::Preflight( const SignalProperties& inSignalProperties,
                                 SignalProperties& outSignalProperties ) const
{
  // Parameter consistency checks: Existence/Ranges and mutual Ranges.
  Parameter( "SamplingRate" );
  PreflightCondition(
    Parameter( "FIRFilteredChannels" ) == Parameter( "FIRFilterKernal" )->NumRows() );
 // PreflightCondition(
 //   Parameter( "SampleBlockSize" ) == Parameter( "FIRFilterKernal" )->GetNumValuesDimension2() );
  PreflightCondition(
     Parameter( "FIRFilterKernal" )->NumRows() <= MAX_M );
  PreflightCondition(
     Parameter( "FIRFilterKernal" )->NumColumns() <= MAX_N );

  // Resource availability checks.
  /* The FIR filter seems not to depend on external resources. */

  // Input signal checks.
  PreflightCondition( Parameter( "FIRFilteredChannels" ) <= inSignalProperties.Channels() );

  // Requested output signal properties.

  if( Parameter( "Integration" ) == 0 )
  {

         PreflightCondition( Parameter( "FIRFilterKernal" )->NumColumns() ==
           ( Parameter( "FIRWindows" ) -1 ) * Parameter( "SampleBlockSize" ) + 1 );

         outSignalProperties = SignalProperties( inSignalProperties.Channels(), Parameter( "SampleBlockSize" ) );
  }
  else
  {
        PreflightCondition( Parameter( "FIRFilterKernal" )->NumColumns() <=
           ( Parameter( "FIRWindows" ) -1 ) * Parameter( "SampleBlockSize" ) + 1 );

         outSignalProperties = SignalProperties( inSignalProperties.Channels(), 1 );
  }
}
void
EDFOutputFormat::Initialize( const SignalProperties& inProperties,
                             const StateVector& inStatevector )
{
  EDFOutputBase::Initialize( inProperties, inStatevector );
  // Adapt marker channels to EDF conventions.
  for( size_t i = inProperties.Channels(); i < Channels().size(); ++i )
  {
    Channels()[ i ].DigitalMinimum = 0;
    Channels()[ i ].DigitalMaximum = static_cast<int>( Channels()[ i ].DigitalMaximum - 1 ) & 0x7fff;
    Channels()[ i ].PhysicalMinimum = Channels()[ i ].DigitalMinimum;
    Channels()[ i ].PhysicalMaximum = Channels()[ i ].DigitalMaximum;
  }
}
示例#22
0
void
P3TemporalFilter::Initialize( const SignalProperties& /*Input*/,
                              const SignalProperties& Output )
{
    mEpochs.clear();
    mEpochSums.clear();

    mOutputProperties = Output;
    mEpochsToAverage = Parameter( "EpochsToAverage" );

    mVisualize = int( Parameter( "VisualizeP3TemporalFiltering" ) );
    if( mVisualize )
    {
        mTargetERPChannel = Parameter( "TargetERPChannel" );
        SignalProperties visProperties = Output;
        visProperties.SetChannels( 12 );
        mVisSignal = GenericSignal( visProperties );

        mVis.Send( CfgID::WindowTitle, "ERP" )
        .Send( mVisSignal.Properties() )
        .Send( mVisSignal );
    }
}
void
CoreModule::InitializeInputSignal( const SignalProperties& Input )
{
#ifdef TODO
# error The inputPropertiesFixed variable may be removed once property messages contain an UpdateRate field.
#endif // TODO
  SignalProperties inputFixed( Input );
  if( !Input.IsEmpty() )
  {
    MeasurementUnits::Initialize( mParamlist );
    inputFixed.SetUpdateRate( 1.0 / MeasurementUnits::SampleBlockDuration() );
  }
  mInputSignal = GenericSignal( inputFixed );
}
示例#24
0
void
EDFFileWriter::Initialize( const SignalProperties& Input,
                           const SignalProperties& Output )
{
    EDFFileWriterBase::Initialize( Input, Output );
    // Adapt marker channels to EDF conventions.
    for( size_t i = Input.Channels(); i < Channels().size(); ++i )
    {
        Channels()[ i ].DigitalMinimum = 0;
        Channels()[ i ].DigitalMaximum = int( Channels()[ i ].DigitalMaximum - 1 ) & 0x7fff;
        Channels()[ i ].PhysicalMinimum = Channels()[ i ].DigitalMinimum;
        Channels()[ i ].PhysicalMaximum = Channels()[ i ].DigitalMaximum;
    }
}
示例#25
0
void
EDFFileWriter::Preflight( const SignalProperties& Input,
                          SignalProperties& Output ) const
{
    EDFFileWriterBase::Preflight( Input, Output );
    if( Input.Type() != SignalType::int16 )
        bcierr << "Signal data type must be int16 for EDF files"
               << endl;

    Parameter( "SubjectYearOfBirth" );
    Parameter( "EquipmentID" );
    Parameter( "TechnicianID" );
    Parameter( "LabID" );
}
示例#26
0
void
AlignmentFilter::Initialize( const SignalProperties& Input,
                             const SignalProperties& /*Output*/ )
{
  mPrevSample.clear();
  mWeightPrev.clear();
  mWeightCur.clear();

  // Do we want to align the samples in time ?
  mAlign = ( Parameter( "AlignChannels" ) == 1 );
  if( mAlign )
  {
    mPrevSample.resize( Input.Channels(), 0.0 );
    mWeightPrev.resize( Input.Channels(), 0.0 );
    mWeightCur.resize( Input.Channels(), 1.0 );

    // Calculate weight values for linear interpolation if we do not use the default value.
    if( Parameter( "SourceChTimeOffset" )->NumValues() > 0 )
    {
      for( int i = 0; i < Input.Channels(); ++i ) // get original channel position
      {
        mWeightPrev[ i ] = Parameter( "SourceChTimeOffset" )( i );
        mWeightCur[ i ] = 1.0 - mWeightPrev[ i ];
      }
    }
    // If we do use the default value, assume that all sampled channels are evenly distributed in time.
    else
    {
      float delta = 1.0 / Input.Channels();
      for( int i = 0; i < Input.Channels(); ++i ) // get original channel position
      {
        mWeightPrev[ i ] = delta * i;
        mWeightCur[ i ] = 1.0 - mWeightPrev[ i ];
      }
    }
  }
}
void
Normalizer::Preflight( const SignalProperties& Input,
                             SignalProperties& Output ) const
{
  if( Parameter( "NormalizerOffsets" )->NumValues() < Input.Channels() )
    bcierr << "The number of entries in the NormalizerOffsets parameter must match "
           << "the number of input channels"
           << endl;
  if( Parameter( "NormalizerGains" )->NumValues() < Input.Channels() )
    bcierr << "The number of entries in the NormalizerGains parameter must match "
           << "the number of input channels"
           << endl;

  ParamRef Adaptation = Parameter( "Adaptation" );
  if( Adaptation->NumValues() < Input.Channels() )
    bcierr << "The number of entries in the Adaptation parameter must match "
           << "the number of input channels"
           << endl;

  bool adaptation = false;
  for( int channel = 0;
      channel < Input.Channels() && channel < Adaptation->NumValues();
      ++channel )
    adaptation |= ( Adaptation( channel ) != none );

  if( adaptation )
  {
    GenericSignal preflightSignal( Input );

    string UpdateTrigger = Parameter( "UpdateTrigger" );
    if( !UpdateTrigger.empty() )
      Expression( UpdateTrigger ).Evaluate( &preflightSignal );

    ParamRef BufferConditions = Parameter( "BufferConditions" );
    if( BufferConditions->NumColumns() > Input.Channels() )
      bcierr << "The number of columns in the BufferConditions parameter "
             << "may not exceed the number of input channels"
             << endl;

    // Evaluate all expressions to test for validity.
    for( int row = 0; row < BufferConditions->NumRows(); ++row )
      for( int col = 0; col < BufferConditions->NumColumns(); ++col )
        Expression( BufferConditions( row, col ) ).Evaluate( &preflightSignal );

    double bufferSize = Parameter( "BufferLength" ).InSampleBlocks();
    if( bufferSize < 1 )
      bciout << "The BufferLength parameter specifies a zero-sized buffer"
             << endl;
  }
  // Request output signal properties:
  Output = Input;
  // Describe output:
  if( adaptation )
    Output.ValueUnit().SetOffset( 0 ).SetGain( 1 ).SetSymbol( "" )
                      .SetRawMin( -2 ).SetRawMax( 2 );
}
void
BufferedADC::Preflight( const SignalProperties&,
                        SignalProperties& Output ) const
{
    if( Parameter( "SourceBufferSize" ).InSampleBlocks() < 2 )
        bcierr << "The SourceBufferSize parameter must be greater or"
               << " equal 2 sample blocks."
               << endl;
    State( "SourceTime" );
    State( "Running" );
    mAcquisitionProperties = Output;
    this->OnPreflight( mAcquisitionProperties );
    Output = mAcquisitionProperties;
    int numStateChannels = 0;
    for( int ch = 0; ch < Output.Channels(); ++ch )
    {
        bool isStateChannel = ( *Output.ChannelLabels()[ch].c_str() == StateMark );
        if( numStateChannels && !isStateChannel )
            bcierr_ << "State channels must be located at the end of the channel list";
        else if( isStateChannel )
            ++numStateChannels;
    }
    Output.SetChannels( Output.Channels() - numStateChannels );
}
void
EDFOutputFormat::Preflight( const SignalProperties& inProperties,
                            const StateVector& inStatevector ) const
{
  EDFOutputBase::Preflight( inProperties, inStatevector );
  if( inProperties.Type() != SignalType::int16 )
    bcierr << "Signal data type must be int16 for EDF files"
           << endl;

  Parameter( "SubjectYearOfBirth" );
  Parameter( "EquipmentID" );
  Parameter( "TechnicianID" );
  Parameter( "LabID" );
  Parameter( "SubjectName" );
}
void
Normalizer::Initialize( const SignalProperties& Input,
                        const SignalProperties& /*Output*/ )
{
  mOffsets.clear();
  mGains.clear();

  delete mpUpdateTrigger;
  mpUpdateTrigger = NULL;

  mBufferConditions.clear();
  mDataBuffers.clear();

  ParamRef Adaptation = Parameter( "Adaptation" ),
           NormalizerOffsets = Parameter( "NormalizerOffsets" ),
           NormalizerGains = Parameter( "NormalizerGains" );

  mAdaptation.clear();
  mDoAdapt = false;
  for( int channel = 0; channel < Input.Channels(); ++channel )
  {
    mOffsets.push_back( NormalizerOffsets( channel ) );
    mGains.push_back( NormalizerGains( channel ) );
    mAdaptation.push_back( int( Adaptation( channel ) ) );
    mDoAdapt |= ( Adaptation( channel ) != none );
  }
  if( mDoAdapt )
  {
    string UpdateTrigger = Parameter( "UpdateTrigger" );
    if( !UpdateTrigger.empty() )
      mpUpdateTrigger = new Expression( UpdateTrigger );

    size_t bufferSize = static_cast<size_t>( Parameter( "BufferLength" ).InSampleBlocks() * Input.Elements() );
    ParamRef BufferConditions = Parameter( "BufferConditions" );
    mBufferConditions.resize( BufferConditions->NumColumns() );
    for( int col = 0; col < BufferConditions->NumColumns(); ++col )
      for( int row = 0; row < BufferConditions->NumRows(); ++row )
        mBufferConditions[ col ].push_back( Expression( BufferConditions( row, col ) ) );
    mDataBuffers.resize(
      BufferConditions->NumColumns(),
      vector<RingBuffer>( BufferConditions->NumRows(), RingBuffer( bufferSize ) )
    );
    bcidbg << "Allocated " << mDataBuffers.size()
           << "x" << ( mDataBuffers.empty() ? 0 : mDataBuffers[ 0 ].size() )
           << " data buffers of size " << bufferSize << "."
           << endl;
  }
}