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" ); } }
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 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 ); } }
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 ); }
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 ); }