Introduction
Correlation Library is a C++ library implemented by Raul C. Muresan. The code is free for non-commercial purposes.
For details on the Scaled Correlation algorithm see paper on "Scaled Correlation Analysis" by Danko Nikolic, Raul C. Muresan, Weijia Feng, and Wolf Singer.
Description
The Correlation Library offers support for computing cross and scaled correlation between a pair of continuous valued, binary valued, or mixed signals.
For each method of computing the correlation and each combination of signals, there is one specialized class that can handle the respective operations.
In addition to C++ classes, the library also compiles into a Windows DLL that exports a number of functions as wrappers over the original classes.
C++ classes
Naming conventions
Each class is named as: C_descriptor_sufix, where
- descriptor - stands for CrossCorrelation or ScaledCorrelation
- sufix - denotes the combination type of data that the class accepts: B = Binary valued discrete signal (represented as a vector of time stamps corresponding to events with value "1"), C = Continuous valued discrete signal (represented as a vector of samples) => CC = Continuous-Continuos; BC = Binary-Continuous; BB = Binary-Binary.
List of classes
- CCrossCorrelationCC: A class that computes the cross-correlation for two continuous valued signals (Continuous - Continuous)
- CCrossCorrelationBC: A class that computes the cross-correlation for a vector of time stamps corresponding to events in a binary signal and a continuous valued signal (Binary - Continuous)
- CCrossCorrelationBB: A class that computes the cross-correlation for two vectors of time stamps corresponding to events in binary signals (Binary - Binary)
- CScaledCorrelationCC: A class that computes the scaled correlation for two continuous valued signals (Continuous - Continuous)
- CScaledCorrelationBC: A class that computes the scaled correlation for a vector of time stamps corresponding to events in a binary signal and a continuous valued signal (Binary - Continuous)
- CScaledCorrelationBB: A class that computes the scaled correlation for two vectors of time stamps corresponding to events in binary signals (Binary - Binary)
Input data formatting
All classes respect the same standard for accepting the input data. For a binary input, a vector of time stamps is expected as input while for a continuous valued input, a digitized vector of samples is expected as input.
When multiple measurements (trials) are available for the data, the classes can handle multiple trials. The length of the trial, in original sampling units, has to be specified in the constructor. Next, when the input signals are provided in the method call to ComputeCrossCorrelation or ComputeScaledCorrelation, the method determines how many trials are available, computes the correlogram on each trial and finally averages the correlograms into one single correlogram.
When multiple trials are available, the input should be structured as follows:
|.........Trial 1...........||.........Trial 2...........||.........Trial 3...........||.........Trial 4...........||.........Trial 5...........|
- For continuous valued signals, there must be as many samples in each trial as the previously specified trial length. In any case, the method only considers as many samples as specified in the call to ComputeCrossCorrelation or ComputeScaledCorrelation.
- For binary signals, the number of available trials is decided by taking into account the time stamp with the largest value. The method then searches, for each trial, the presence of valid time stamps. Time stamps for consecutive trials have to have increasing values. The trial to which a time stamp belongs is decided by taking into account the length of a trial in sampling units.
If the user cannot structure the trials as a contiguous series of datapoints, then the best option is to pass a single trial to the class, get the correlogram for each trial, and then the user should compute the average correlogram.
- Note:
- For the case of scaled correlation, the user can use the sum of coefficients of correlation for each bin of the correlogram and the count of coefficients to efficiently compute the average, smooth, scaled correlogram for all trials (see section Example). Averaging the sums of correlation coefficients gives a better and smoother estimate of the final scaled correlogram than averaging the individual scaled correlograms for each trial (see Example: Scaled correlogram example with only one trial passed at a time).
Method calls
For the two types of correlations the classes expose an interface to compute the CrossCorrelation and the ScaledCorrelation respectively. Depending on the type of the input data, the methods accept different parameter types. However, they have a general format:
- ComputeCrossCorrelation(VectorA, SizeOfVectorA, VectorB, SizeOfVectorB, pbNormalizeCorrelogram)
- ComputeScaledCorrelation(VectorA, SizeOfVectorA, VectorB, SizeOfVectorB, pbUseFisherZTransform)
The first four parameters specify the input vectors and their sizes (in number of elements). Each vector has a different type depending if the input signal is binary or continuous valued.
For binary data, the vectors are arrays of integers holding the time stamps. For continuous valued data, the vectors are arrays of floats, holding the samples.
The last parameter of each function model is a boolean. pbNormalizeCorrelogram - determines whether the cross-correlogram should be normalized. pbUseFisherZTransform - determines if the scaled correlogram should use the Fisher Z Transform to average the coefficients of correlation.
Output data
Each class exposes an interface that allows access to the computed cross or scaled correlogram. The correlogram is stored in the object as a vector of floats. The vector has a size of 2*CorrelationWindow+1.
The correlogram vector is stored such that the correlation at lag -CorrelationWindow is at position 0, the correlation at lag 0 is stored at position CorrelationWindow, and the correlation at lag +CorrelationWindow is stored at position 2*CorrelationWindow.
To retrieve the correlogram, call:
- GetCrossCorrelogram() - retrieves a pointer to the vector holding the cross-correlogram
- GetScaledCrossCorrelogram() - retrieves a pointer to the vector holding the scaled correlogram
The user should not write into the vectors!
- Attention:
- Very important: the cross and scaled correlation buffers might contain values of Not A Number (NAN = -100000000.0f) if there was no variance in the input signals and correlation was, as a consequence, not defined! Always check the output buffers for NAN values before using them! Otherwise results may be compromised.
Examples of usage
Let us consider we have two continuous valued signals that we want to correlate. The signals, we suppose, have been sampled at 1 kHz. Each signal has 2 trials recorded, with a length of 1000 ms each. We want to compute the cross-correlation and the scaled correlation.
#include "CrossCorrelation-CC.h"
float SignalA[2000];
float SignalB[2000];
float* CrossCorrelogram;
int iTrialLength = 1000;
int iCorrelationWindow = 100;
int isError = 0;
CCrossCorrelationCC ComputeClassicCC(iCorrelationWindow,iTrialLength,isError);
if(isError == 0)
{
ComputeClassicCC.ComputeCrossCorrelation(SignalA,2000,SignalB,2000,0);
CrossCorrelogram = ComputeClassicCC.GetCrossCorrelogram();
for(int j=0;j<2*iCorrelationWindow+1;j++)
{
if(CrossCorrelogram[j] != NAN)
{
}
}
}
#include "ScaledCorrelation-CC.h"
float SignalA[2000];
float SignalB[2000];
float* ScaledCorrelogram;
int iTrialLength = 1000;
int iCorrelationWindow = 100;
int iScaleWindow = 25;
int isError = 0;
CScaledCorrelationCC ComputeScaledCC(iScaleWindow,iCorrelationWindow,iTrialLength,isError);
if(isError == 0)
{
ComputeScaledCC.ComputeScaledCorrelation(SignalA,2000,SignalB,2000,0);
ScaledCorrelogram = ComputeScaledCC.GetScaledCrossCorrelogram();
for(int j=0;j<2*iCorrelationWindow+1;j++)
{
if(ScaledCorrelogram[j] != NAN)
{
}
}
}
Let us now assume we have again two signals each with two trials. This time however, we want to compute the correlogram manually by computing the sum of correlation coefficients for each trial and then computing the average in the end.
#include "ScaledCorrelation-CC.h"
#include "Constants.h"
float SignalA[2000];
float SignalB[2000];
float ScaledCorrelogram[201];
int SummedCoefficientsCount[201];
float *coeff_sum_buffer;
int *coeff_count_buffer;
int iTrialLength = 1000;
int iCorrelationWindow = 100;
int iScaleWindow = 25;
int iTrialNr = 2;
int isError = 0;
CScaledCorrelationCC ComputeScaledCC(iScaleWindow,iCorrelationWindow,iTrialLength,isError);
if(isError == 0)
{
for(int j=0;j<2*iCorrelationWindow+1;j++)
{
ScaledCorrelogram[j] = 0;
SummedCoefficientsCount[j] = 0;
}
for(int i=0;i<iTrialNr;i++)
{
ComputeScaledCC.ComputeScaledCorrelation(&(SignalA[i*iTrialLength]),iTrialLength,&(SignalB[i*iTrialLength]),iTrialLength,0);
coeff_sum_buffer = ComputeScaledCC.GetPearsonCoefficientSums();
coeff_count_buffer = ComputeScaledCC.GetPearsonCoefficientCounts();
for(j=0;j<2*iCorrelationWindow+1;j++)
{
if(coeff_sum_buffer[j] != NAN) ScaledCorrelogram[j] += coeff_sum_buffer[j];
SummedCoefficientsCount[j] += coeff_count_buffer[j];
}
}
for(j=0;j<2*iCorrelationWindow+1;j++) if(SummedCoefficientsCount[j]) ScaledCorrelogram[j] /= SummedCoefficientsCount[j];
}
Dll functions exported
The correlation library provides flexible means to interact with the classes that compute correlation. It exports a set of wrapper functions that can be used by an external caller to access the full class functionality.
Interfacing convention
To interface a given class method, the library exports a function with a similar name that has an additional parameter, which is an untyped pointer to an already created object of that class.
For example, let ClassA be the class of interest, and Method1 be a method of ClassA. To create an interface to ClassA functionality, one must first create an object of that class and then call a wrapper function to access the class method.
void* Wrapper_ObjectConstructor_ClassA()
{
return new ClassA();
}
void Wrapper_ObjectDestructor_ClassA(void* pObj)
{
delete ((ClassA*) pObj);
}
void Wrapper_Method1_Of_ClassA(void* pObj,int iSomeParam)
{
((ClassA*) pObj)->Method1(iSomeParam);
}
void main()
{
void *pObject;
pObject = Wrapper_ObjectConstructor_ClassA();
Wrapper_Method1_Of_ClassA(pObject,1);
Wrapper_ObjectDestructor_ClassA(pObject);
}
- Note:
- The wrapper constructors create untyped pointers to objects. The DLL caller can use these pointers as handles for the objects of a given class. All class operations have, as an additional parameter, the pointer to the object being handled. Depending on the wrapper function that is called, a corresponding method will be called from a corresponding class of the object whose handle is passed to the wrapper function.
Naming conventions
Each function is named as: prefix_name_sufix, where
- prefix - is optional and is usually added to avoid confusion, when a function with the same name is present in both Cross-Correlation and Scaled-Correlation classes. The prefix could be either CrossCorrelation or ScaledCorrelation
- name - is usually the name of the class method that is being interfaced
- sufix - denotes the combination type of data that the class accepts: B = Binary, C = Continuous => CC = Continuous-Continuos; BC = Binary-Continuous; BB = Binary-Binary.
List of wrapper functions
Cross-correlation for Continuous-Continuous data:
- void* CreateCrossCorrelationComputerCC(int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeCrossCorrelationComputerCC(void *pvObject)
- void ComputeCrossCorrelationCC(void *pvObject, float *pfaSamplesA, int piNrSamplesInA, float *pfaSamplesB, int piNrSamplesInB, int piNormalizationFlag)
- void ComputeWindowedCrossCorrelationPerTrialCC(void *pvObject, float *pfaSamplesA, int piNrSamplesInA, float *pfaSamplesB, int piNrSamplesInB, int piFromOffsetInTrial, int piToOffsetInTrial, int piNormalizationFlag)
- float* GetCrossCorrelogramCC(void *pvObject)
- int CrossCorrelationModifyCorrelationWindowCC(void *pvObject, int piNewCorrelationWindow)
- int CrossCorrelationModifyTrialLengthCC(void *pvObject, int piNewTrialLength)
- int CrossCorrelationModifyAllParametersCC(void *pvObject, int piNewCorrelationWindow, int piNewTrialLength)
- int CrossCorrelationGetCorrelationWindowCC(void *pvObject)
- int CrossCorrelationGetTrialLengthCC(void *pvObject)
Cross-correlation for Binary-Continuous data:
- void* CreateCrossCorrelationComputerBC(int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeCrossCorrelationComputerBC(void *pvObject)
- void ComputeCrossCorrelationBC(void *pvObject, int *piaTimeStampsA, int piNrTimeStampsInA, float *pfaSamplesB, int piNrSamplesInB, int pbNormalizeCorrelogram)
- float* GetCrossCorrelogramBC(void *pvObject)
- int CrossCorrelationModifyCorrelationWindowBC(void *pvObject, int piNewCorrelationWindow)
- int CrossCorrelationModifyTrialLengthBC(void *pvObject, int piNewTrialLength)
- int CrossCorrelationModifyAllParametersBC(void *pvObject, int piNewCorrelationWindow, int piNewTrialLength)
- int CrossCorrelationGetCorrelationWindowBC(void *pvObject)
- int CrossCorrelationGetTrialLengthBC(void *pvObject)
Cross-correlation for Binary-Binary data:
- void* CreateCrossCorrelationComputerBB(int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeCrossCorrelationComputerBB(void *pvObject)
- void ComputeCrossCorrelationBB(void *pvObject, int *piaTimeStampsA, int piNrTimeStampsInA, int *piaTimeStampsB, int piNrTimeStampsInB, int pbNormalizeCorrelogram)
- void ComputeWindowedCrossCorrelationPerTrialBB(void* pvObject,int *piaTimeStampsA,int piNrTimeStampsInA,int *piaTimeStampsB,int piNrTimeStampsInB,int piFromOffsetInTrial,int piToOffsetInTrial,int pbNormalizeCorrelogram)
- float* GetCrossCorrelogramBB(void *pvObject)
- int CrossCorrelationModifyCorrelationWindowBB(void *pvObject, int piNewCorrelationWindow)
- int CrossCorrelationModifyTrialLengthBB(void *pvObject, int piNewTrialLength)
- int CrossCorrelationModifyAllParametersBB(void *pvObject, int piNewCorrelationWindow, int piNewTrialLength)
- int CrossCorrelationGetCorrelationWindowBB(void *pvObject)
- int CrossCorrelationGetTrialLengthBB(void *pvObject)
Scaled correlation for Continuous-Continuous data:
- void* CreateScaledCorrelationComputerCC(int piScaleWindow, int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeScaledCorrelationComputerCC(void *pvObject)
- void ComputeScaledCorrelationCC(void *pvObject, float *pfaSamplesA, int piNrSamplesInA, float *pfaSamplesB, int piNrSamplesInB, int pbUseFisherZTransform)
- void ComputeWindowedScaledCorrelationPerTrialCC(void *pvObject, float *pfaSamplesA, int piNrSamplesInA, float *pfaSamplesB, int piNrSamplesInB, int piFromOffsetInTrial, int piToOffsetInTrial, int pbUseFisherZTransform)
- float* GetScaledCrossCorrelogramCC(void *pvObject)
- float* GetPearsonCoefficientSumsCC(void *pvObject)
- int* GetPearsonCoefficientCountsCC(void *pvObject)
- int* GetDistributionOfCorrelationCoefficientsCC(void *pvObject, int &piNumberOfBins, float &pfBinSize)
- int ScaledCorrelationModifyScaleWindowCC(void *pvObject, int piNewScale)
- int ScaledCorrelationModifyCorrelationWindowCC(void *pvObject, int piNewCorrelationWindow)
- int ScaledCorrelationModifyTrialLengthCC(void *pvObject, int piNewTrialLength)
- int ScaledCorrelationModifyAllParametersCC(void *pvObject, int piNewScale, int piNewCorrelationWindow, int piNewTrialLength)
- int ScaledCorrelationGetScaleWindowCC(void *pvObject)
- int ScaledCorrelationGetCorrelationWindowCC(void *pvObject)
- int ScaledCorrelationGetTrialLengthCC(void *pvObject)
- int GetDistributionOfCorrelationCoefficientsBinNrCC(void *pvObject)
- float GetDistributionOfCorrelationCoefficientsBinSizeCC(void *pvObject)
Scaled correlation for Binary-Continuous data:
- void* CreateScaledCorrelationComputerBC(int piScaleWindow, int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeScaledCorrelationComputerBC(void *pvObject)
- void ComputeScaledCorrelationBC(void *pvObject, int *piaTimeStampsA, int piNrTimeStampsInA, float *pfaSamplesB, int piNrSamplesInB, int pbUseFisherZTransform)
- float* GetScaledCrossCorrelogramBC(void *pvObject)
- float* GetPBsCoefficientSumsBC(void *pvObject)
- int* GetPBsCoefficientCountsBC(void *pvObject)
- int* GetDistributionOfCorrelationCoefficientsBC(void *pvObject, int &piNumberOfBins, float &pfBinSize)
- int ScaledCorrelationModifyScaleWindowBC(void *pvObject, int piNewScale)
- int ScaledCorrelationModifyCorrelationWindowBC(void *pvObject, int piNewCorrelationWindow)
- int ScaledCorrelationModifyTrialLengthBC(void *pvObject, int piNewTrialLength)
- int ScaledCorrelationModifyAllParametersBC(void *pvObject, int piNewScale, int piNewCorrelationWindow, int piNewTrialLength)
- int ScaledCorrelationGetScaleWindowBC(void *pvObject)
- int ScaledCorrelationGetCorrelationWindowBC(void *pvObject)
- int ScaledCorrelationGetTrialLengthBC(void *pvObject)
- int GetDistributionOfCorrelationCoefficientsBinNrBC(void *pvObject)
- float GetDistributionOfCorrelationCoefficientsBinSizeBC(void *pvObject)
Scaled correlation for Binary-Binary data:
- void* CreateScaledCorrelationComputerBB(int piScaleWindow, int piCorrelationWindow, int piTrialLength, int &piIsError)
- void FreeScaledCorrelationComputerBB(void *pvObject)
- void ComputeScaledCorrelationBB(void *pvObject, int *piaTimeStampsA, int piNrTimeStampsInA, int *piaTimeStampsB, int piNrTimeStampsInB, int pbUseFisherZTransform)
- void ComputeWindowedScaledCorrelationPerTrialBB(void *pvObject, int *piaTimeStampsA, int piNrTimeStampsInA, int *piaTimeStampsB, int piNrTimeStampsInB, int piFromOffsetInTrial, int piToOffsetInTrial, int pbUseFisherZTransform)
- float* GetScaledCrossCorrelogramBB(void *pvObject)
- float* GetFiCoefficientSumsBB(void *pvObject)
- int* GetFiCoefficientCountsBB(void *pvObject)
- int* GetDistributionOfCorrelationCoefficientsBB(void *pvObject, int &piNumberOfBins, float &pfBinSize)
- int ScaledCorrelationModifyScaleWindowBB(void *pvObject, int piNewScale)
- int ScaledCorrelationModifyCorrelationWindowBB(void *pvObject, int piNewCorrelationWindow)
- int ScaledCorrelationModifyTrialLengthBB(void *pvObject, int piNewTrialLength)
- int ScaledCorrelationModifyAllParametersBB(void *pvObject, int piNewScale, int piNewCorrelationWindow, int piNewTrialLength)
- int ScaledCorrelationGetScaleWindowBB(void *pvObject)
- int ScaledCorrelationGetCorrelationWindowBB(void *pvObject)
- int ScaledCorrelationGetTrialLengthBB(void *pvObject)
- int GetDistributionOfCorrelationCoefficientsBinNrBB(void *pvObject)
- float GetDistributionOfCorrelationCoefficientsBinSizeBB(void *pvObject)