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