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() );
  }
}
void
FFTFilter::DetermineSignalProperties( SignalProperties& ioProperties, int inFFTType ) const
{
  int numChannels = Parameter( "FFTInputChannels" )->NumValues(),
      fftWindowLength = static_cast<int>( ioProperties.Elements() * Parameter( "FFTWindowLength" ).InSampleBlocks() );
  if( numChannels > 0 && fftWindowLength == 0 )
    bcierr << "FFTWindowLength must exceed a single sample's duration" << endl;
  double freqRange = ioProperties.SamplingRate() / 2.0;

  switch( inFFTType )
  {
    case eInput:
      break;

    case ePower:
    {
      ioProperties.SetName( "FFT Power Spectrum" )
                  .SetChannels( numChannels )
                  .SetElements( fftWindowLength / 2 + 1 );
      ioProperties.ElementUnit().SetOffset( 0.0 )
                                .SetGain( freqRange / ( ioProperties.Elements() - 1 ) )
                                .SetSymbol( "Hz" );
      double amplitude = ioProperties.ValueUnit().RawMax() - ioProperties.ValueUnit().RawMin();
      ioProperties.ValueUnit().SetRawMin( 0 )
                              .SetRawMax( amplitude * amplitude );
      ioProperties.ElementUnit().SetRawMin( 0 )
                                .SetRawMax( ioProperties.Elements() - 1 );
    } break;

    case eHalfcomplex:
      ioProperties.SetName( "FFT Coefficients" )
                  .SetChannels( numChannels )
                  .SetElements( fftWindowLength );
      ioProperties.ElementUnit().SetRawMin( 0 )
                                .SetRawMax( fftWindowLength - 1 )
                                .SetOffset( 0 )
                                .SetGain( 1 )
                                .SetSymbol( "" );
      break;

    default:
      throw std_logic_error( "Unknown value of FFT type" );
  }
}
示例#3
0
void
FFTFilter::DetermineSignalProperties( SignalProperties& ioProperties, int inFFTType ) const
{
  int numChannels = Parameter( "FFTInputChannels" )->NumValues(),
      fftWindowLength = Parameter( "SampleBlockSize" )
                        * MeasurementUnits::ReadAsTime( Parameter( "FFTWindowLength" ) );
  if( numChannels > 0 && fftWindowLength == 0 )
    bcierr << "FFTWindowLength must exceed a single sample's duration" << endl;

  switch( inFFTType )
  {
    case eInput:
      break;

    case ePower:
    {
      ioProperties.SetName( "FFT Power Spectrum" )
                  .SetChannels( numChannels )
                  .SetElements( fftWindowLength / 2 + 1 );
      float freqScale = Parameter( "SamplingRate" ) / 2.0 / ioProperties.Elements();
      ioProperties.ElementUnit().SetOffset( freqScale / 2 )
                                .SetGain( freqScale )
                                .SetSymbol( "Hz" );
      float amplitude = ioProperties.ValueUnit().RawMax() - ioProperties.ValueUnit().RawMin();
      ioProperties.ValueUnit().SetRawMin( 0 )
                              .SetRawMax( amplitude * amplitude );
    } break;

    case eHalfcomplex:
      ioProperties.SetName( "FFT Coefficients" )
                  .SetChannels( numChannels )
                  .SetElements( fftWindowLength );
      break;

    default:
      assert( false );
  }
}
示例#4
0
void
ARFilter::Preflight( const SignalProperties& Input,
                           SignalProperties& Output ) const
{
  // Parameter consistency checks.
  float windowLength = MeasurementUnits::ReadAsTime( Parameter( "WindowLength" ) );
  int samplesInWindow = windowLength * Parameter( "SampleBlockSize" );
  if( samplesInWindow < Parameter( "ModelOrder" ) )
    bcierr << "WindowLength parameter must be large enough"
           << " for the number of samples to exceed the model order"
           << endl;

  Output = Input;
  switch( int( Parameter( "OutputType" ) ) )
  {
    case SpectralAmplitude:
    case SpectralPower:
    {
      float firstBinCenter = MeasurementUnits::ReadAsFreq( Parameter( "FirstBinCenter" ) ),
            lastBinCenter = MeasurementUnits::ReadAsFreq( Parameter( "LastBinCenter" ) ),
            binWidth = MeasurementUnits::ReadAsFreq( Parameter( "BinWidth" ) );

      if( firstBinCenter > 0.5 || firstBinCenter < 0
          || lastBinCenter > 0.5 || lastBinCenter < 0 )
        bcierr << "FirstBinCenter and LastBinCenter must be greater zero and"
               << " less than half the sampling rate"
               << endl;
      if( firstBinCenter >= lastBinCenter )
        bcierr << "FirstBinCenter must be less than LastBinCenter" << endl;
      if( binWidth <= 0 )
        bcierr << "BinWidth must be greater zero" << endl;
      else
      {
        int numBins = ::floor( ( lastBinCenter - firstBinCenter + eps ) / binWidth + 1 );
        Output.SetElements( numBins );
      }
      Output.ElementUnit().SetOffset( firstBinCenter / binWidth )
                          .SetGain( binWidth * Parameter( "SamplingRate" ) )
                          .SetSymbol( "Hz" );
      Output.ValueUnit().SetRawMin( 0 );
      float inputAmplitude = Input.ValueUnit().RawMax() - Input.ValueUnit().RawMin(),
            whiteNoisePowerPerBin = inputAmplitude * inputAmplitude / binWidth / 10;
      switch( int( Parameter( "OutputType" ) ) )
      {
        case SpectralAmplitude:
          Output.SetName( "AR Amplitude Spectrum" );
          Output.ValueUnit().SetOffset( 0 )
                            .SetGain( 1e-6 )
                            .SetSymbol( "V/sqrt(Hz)" )
                            .SetRawMax( ::sqrt( whiteNoisePowerPerBin ) );
          break;

        case SpectralPower:
        {
          Output.SetName( "AR Power Spectrum" );
          Output.ValueUnit().SetOffset( 0 )
                            .SetGain( 1 )
                            .SetSymbol( "(muV)^2/Hz" )
                            .SetRawMax( whiteNoisePowerPerBin );
        } break;
      }
    } break;

    case ARCoefficients:
      Output.SetName( "AR Coefficients" );
      Output.SetElements( Parameter( "ModelOrder" ) );
      Output.ElementUnit().SetOffset( 0 )
                          .SetGain( 1 )
                          .SetSymbol( "" );
      Output.ValueUnit().SetOffset( 0 )
                        .SetGain( 1 )
                        .SetSymbol( "" )
                        .SetRawMin( -1 )
                        .SetRawMax( 1 );
      break;

    default:
      bcierr << "Unknown OutputType" << endl;
  }
  Output.ElementUnit().SetRawMin( 0 )
                      .SetRawMax( Output.Elements() - 1 );
}
示例#5
0
void
LinearClassifier::Preflight( const SignalProperties& Input,
                                   SignalProperties& Output ) const
{
  // Determine the classifier matrix format:
  int controlSignalChannels = 0;
  const ParamRef& Classifier = Parameter( "Classifier" );
  if( Classifier->NumColumns() != 4 )
    bcierr << "Classifier parameter must have 4 columns "
           << "(input channel, input element, output channel, weight)"
           << endl;
  else
  {
    for( int row = 0; row < Classifier->NumRows(); ++row )
    {
      if( Classifier( row, 2 ) < 1 )
        bcierr << "Output channels must be positive integers"
               << endl;

      float ch = Input.ChannelIndex( Classifier( row, 0 ) );
      if( ch < 0 )
        bcierr << DescribeEntry( row, 0 )
               << " points to negative input index"
               << endl;
      else if( ::floor( ch ) > Input.Channels() )
        bcierr << "Channel specification in "
               << DescribeEntry( row, 0 )
               << " exceeds number of input channels"
               << endl;
      if( ::fmod( ch, 1.0f ) > 1e-2 )
        bciout << "Channel specification in physical units: "
               << DescribeEntry( row, 0 )
               << " does not exactly meet a single channel"
               << endl;

      float el = Input.ElementIndex( Classifier( row, 1 ) );
      if( el < 0 )
        bcierr << DescribeEntry( row, 1 )
               << " points to negative input index"
               << endl;
      if( ::floor( el ) > Input.Elements() )
        bcierr << "Element (bin) specification in "
               << DescribeEntry( row, 1 )
               << " exceeds number of input elements"
               << endl;
      if( ::fmod( el, 1.0f ) > 1e-2 )
        bciout << "Element (bin) specification in physical units: "
               << DescribeEntry( row, 1 )
               << " does not exactly meet a single element"
               << endl;

      int outputChannel =  Classifier( row, 2 );
      controlSignalChannels = max( controlSignalChannels, outputChannel );
    }
  }
  // Requested output signal properties.
  Output = SignalProperties( controlSignalChannels, 1, Input.Type() );
  // Output description.
  Output.ChannelUnit() = Input.ChannelUnit();
  Output.ValueUnit().SetRawMin( Input.ValueUnit().RawMin() )
                    .SetRawMax( Input.ValueUnit().RawMax() );

  float secsPerBlock = Parameter( "SampleBlockSize" ) / Parameter( "SamplingRate" );
  Output.ElementUnit().SetOffset( 0 ).SetGain( secsPerBlock ).SetSymbol( "s" );
  int visualizationTime = Output.ElementUnit().PhysicalToRaw( "15s" );
  Output.ElementUnit().SetRawMin( 0 ).SetRawMax( visualizationTime - 1 );
}
void
FFTFilter::Initialize( const SignalProperties& Input, const SignalProperties& /*Output*/ )
{
  mFFTOutputSignal = ( eFFTOutputSignal )( int )Parameter( "FFTOutputSignal" );
  mFFTWindowLength = static_cast<int>( Input.Elements() * Parameter( "FFTWindowLength" ).InSampleBlocks() );
  mFFTWindow = ( eFFTWindow )( int )Parameter( "FFTWindow" );

  mFFTInputChannels.clear();

  for( size_t i = 0; i < mVisualizations.size(); ++i )
    mVisualizations[ i ].Send( CfgID::Visible, false );
  mVisualizations.clear();
  mVisualizeFFT = int( Parameter( "VisualizeFFT" ) );
  if( mVisualizeFFT || mFFTOutputSignal == ePower )
  {
    mVisProperties = Input;
    DetermineSignalProperties( mVisProperties, ePower );
    PhysicalUnit elementUnit = mVisProperties.ElementUnit();
    mVisProperties.SetChannels( mVisProperties.Elements() );
    for( int i = 0; i < mVisProperties.Channels(); ++i )
      mVisProperties.ChannelLabels()[i] = elementUnit.RawToPhysical( mVisProperties.Channels() - i - 1 );
    mVisProperties.SetElements( 1 );
    mVisProperties.ElementUnit() = Input.ElementUnit();
    mVisProperties.ElementUnit().SetGain( mVisProperties.ElementUnit().Gain() * Input.Elements() );
    mPowerSpectrum = GenericSignal( mVisProperties );
  }
  for( int i = 0; i < Parameter( "FFTInputChannels" )->NumValues(); ++i )
  {
    size_t ch = static_cast<size_t>( Input.ChannelIndex( Parameter( "FFTInputChannels" )( i ) ) );
    mFFTInputChannels.push_back( ch );
    if( mVisualizeFFT )
    {
      ostringstream oss_i;
      oss_i << i + 1;
      mVisualizations.push_back( GenericVisualization( string( "FFT" ) + oss_i.str() ) );

      ostringstream oss_ch;
      oss_ch << "FFT for Ch ";
      if( Input.ChannelLabels().IsTrivial() )
        oss_ch << i + 1;
      else
        oss_ch << Input.ChannelLabels()[ch];

      mVisualizations.back().Send( mVisProperties )
                            .Send( CfgID::WindowTitle, oss_ch.str().c_str() )
                            .Send( CfgID::GraphType, CfgID::Field2d )
                            .Send( CfgID::Visible, true );
    }
  }

  mWindow.clear();
  mWindow.resize( mFFTWindowLength, 1.0 );
  float phasePerSample = static_cast<float>( M_PI ) / static_cast<float>( mFFTWindowLength );
  // Window coefficients: None Hamming Hann Blackman
  const float a1[] = {    0,   0.46f,  0.5f, 0.5f, },
              a2[] = {    0,   0,      0,    0.08f };

  for( int i = 0; i < mFFTWindowLength; ++i )
    mWindow[ i ] = 1.0f - a1[ mFFTWindow ] - a2[ mFFTWindow ]
                   + a1[ mFFTWindow ] * cos( static_cast<float>( i ) * phasePerSample )
                   + a2[ mFFTWindow ] * cos( static_cast<float>( i ) * 2.0f * phasePerSample );

  mValueBuffers.resize( mFFTInputChannels.size() );
  ResetValueBuffers( mFFTWindowLength );

  bool fftRequired = ( mVisualizeFFT || mFFTOutputSignal != eInput)
                     && mFFTInputChannels.size() > 0;
  if( !fftRequired )
    mFFTInputChannels.clear();
  else
    mFFT.Initialize( mFFTWindowLength );
}