diff --git a/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.pbxproj b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1ae8b0c --- /dev/null +++ b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.pbxproj @@ -0,0 +1,278 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1F93B5301D64DBEE00688FC6 /* ecg.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B5241D64DBEE00688FC6 /* ecg.c */; }; + 1F93B5311D64DBEE00688FC6 /* emg.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B5261D64DBEE00688FC6 /* emg.c */; }; + 1F93B5321D64DBEE00688FC6 /* exponential_moving_average.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B5281D64DBEE00688FC6 /* exponential_moving_average.c */; }; + 1F93B5331D64DBEE00688FC6 /* moving_average.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B52A1D64DBEE00688FC6 /* moving_average.c */; }; + 1F93B5341D64DBEE00688FC6 /* peak_to_peak.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B52C1D64DBEE00688FC6 /* peak_to_peak.c */; }; + 1F93B5351D64DBEE00688FC6 /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 1F93B52E1D64DBEE00688FC6 /* queue.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 1F93B5181D64DAFF00688FC6 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1F93B51A1D64DAFF00688FC6 /* ATLAS-DSP */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "ATLAS-DSP"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1F93B5241D64DBEE00688FC6 /* ecg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ecg.c; path = ../ecg.c; sourceTree = ""; }; + 1F93B5251D64DBEE00688FC6 /* ecg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ecg.h; path = ../ecg.h; sourceTree = ""; }; + 1F93B5261D64DBEE00688FC6 /* emg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = emg.c; path = ../emg.c; sourceTree = ""; }; + 1F93B5271D64DBEE00688FC6 /* emg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = emg.h; path = ../emg.h; sourceTree = ""; }; + 1F93B5281D64DBEE00688FC6 /* exponential_moving_average.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = exponential_moving_average.c; path = ../exponential_moving_average.c; sourceTree = ""; }; + 1F93B5291D64DBEE00688FC6 /* exponential_moving_average.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = exponential_moving_average.h; path = ../exponential_moving_average.h; sourceTree = ""; }; + 1F93B52A1D64DBEE00688FC6 /* moving_average.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = moving_average.c; path = ../moving_average.c; sourceTree = ""; }; + 1F93B52B1D64DBEE00688FC6 /* moving_average.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = moving_average.h; path = ../moving_average.h; sourceTree = ""; }; + 1F93B52C1D64DBEE00688FC6 /* peak_to_peak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = peak_to_peak.c; path = ../peak_to_peak.c; sourceTree = ""; }; + 1F93B52D1D64DBEE00688FC6 /* peak_to_peak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = peak_to_peak.h; path = ../peak_to_peak.h; sourceTree = ""; }; + 1F93B52E1D64DBEE00688FC6 /* queue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = queue.c; path = ../queue.c; sourceTree = ""; }; + 1F93B52F1D64DBEE00688FC6 /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queue.h; path = ../queue.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1F93B5171D64DAFF00688FC6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1F93B5111D64DAFF00688FC6 = { + isa = PBXGroup; + children = ( + 1F93B5241D64DBEE00688FC6 /* ecg.c */, + 1F93B5251D64DBEE00688FC6 /* ecg.h */, + 1F93B5261D64DBEE00688FC6 /* emg.c */, + 1F93B5271D64DBEE00688FC6 /* emg.h */, + 1F93B5281D64DBEE00688FC6 /* exponential_moving_average.c */, + 1F93B5291D64DBEE00688FC6 /* exponential_moving_average.h */, + 1F93B52A1D64DBEE00688FC6 /* moving_average.c */, + 1F93B52B1D64DBEE00688FC6 /* moving_average.h */, + 1F93B52C1D64DBEE00688FC6 /* peak_to_peak.c */, + 1F93B52D1D64DBEE00688FC6 /* peak_to_peak.h */, + 1F93B52E1D64DBEE00688FC6 /* queue.c */, + 1F93B52F1D64DBEE00688FC6 /* queue.h */, + 1F93B51C1D64DAFF00688FC6 /* ATLAS-DSP */, + 1F93B51B1D64DAFF00688FC6 /* Products */, + ); + sourceTree = ""; + }; + 1F93B51B1D64DAFF00688FC6 /* Products */ = { + isa = PBXGroup; + children = ( + 1F93B51A1D64DAFF00688FC6 /* ATLAS-DSP */, + ); + name = Products; + sourceTree = ""; + }; + 1F93B51C1D64DAFF00688FC6 /* ATLAS-DSP */ = { + isa = PBXGroup; + children = ( + ); + path = "ATLAS-DSP"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1F93B5191D64DAFF00688FC6 /* ATLAS-DSP */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1F93B5211D64DAFF00688FC6 /* Build configuration list for PBXNativeTarget "ATLAS-DSP" */; + buildPhases = ( + 1F93B5161D64DAFF00688FC6 /* Sources */, + 1F93B5171D64DAFF00688FC6 /* Frameworks */, + 1F93B5181D64DAFF00688FC6 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ATLAS-DSP"; + productName = "ATLAS-DSP"; + productReference = 1F93B51A1D64DAFF00688FC6 /* ATLAS-DSP */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1F93B5121D64DAFF00688FC6 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Jeremy Malloch"; + TargetAttributes = { + 1F93B5191D64DAFF00688FC6 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = 1F93B5151D64DAFF00688FC6 /* Build configuration list for PBXProject "ATLAS-DSP" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 1F93B5111D64DAFF00688FC6; + productRefGroup = 1F93B51B1D64DAFF00688FC6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1F93B5191D64DAFF00688FC6 /* ATLAS-DSP */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 1F93B5161D64DAFF00688FC6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F93B5311D64DBEE00688FC6 /* emg.c in Sources */, + 1F93B5321D64DBEE00688FC6 /* exponential_moving_average.c in Sources */, + 1F93B5341D64DBEE00688FC6 /* peak_to_peak.c in Sources */, + 1F93B5351D64DBEE00688FC6 /* queue.c in Sources */, + 1F93B5331D64DBEE00688FC6 /* moving_average.c in Sources */, + 1F93B5301D64DBEE00688FC6 /* ecg.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1F93B51F1D64DAFF00688FC6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 1F93B5201D64DAFF00688FC6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 1F93B5221D64DAFF00688FC6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 1F93B5231D64DAFF00688FC6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1F93B5151D64DAFF00688FC6 /* Build configuration list for PBXProject "ATLAS-DSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F93B51F1D64DAFF00688FC6 /* Debug */, + 1F93B5201D64DAFF00688FC6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1F93B5211D64DAFF00688FC6 /* Build configuration list for PBXNativeTarget "ATLAS-DSP" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F93B5221D64DAFF00688FC6 /* Debug */, + 1F93B5231D64DAFF00688FC6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1F93B5121D64DAFF00688FC6 /* Project object */; +} diff --git a/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ea3d45a --- /dev/null +++ b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/xcuserdata/jeremymalloch.xcuserdatad/UserInterfaceState.xcuserstate b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/xcuserdata/jeremymalloch.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..edd4fd2 Binary files /dev/null and b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/project.xcworkspace/xcuserdata/jeremymalloch.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/ATLAS-DSP.xcscheme b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/ATLAS-DSP.xcscheme new file mode 100644 index 0000000..c8b7dd0 --- /dev/null +++ b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/ATLAS-DSP.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/xcschememanagement.plist b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..6f5d652 --- /dev/null +++ b/C/ATLAS-DSP/ATLAS-DSP.xcodeproj/xcuserdata/jeremymalloch.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + ATLAS-DSP.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 1F93B5191D64DAFF00688FC6 + + primary + + + + + diff --git a/C/exponential_moving_average.c b/C/exponential_moving_average.c new file mode 100644 index 0000000..2a0366d --- /dev/null +++ b/C/exponential_moving_average.c @@ -0,0 +1,90 @@ +include +#include +#include + +#include "exponential_moving_average.h" + +struct Exponential_moving_average_ { + + Queue *data; + int data_sum; + int data_avg; + uint16_t cur_length; + uint16_t max_length; + +}; + +Exponential_Moving_Average *new_exponential_moving_average(uint16_t max_length_) { + Exponential_Moving_Average *to_return; + to_return = (Exponential_Moving_Average *) malloc(sizeof(Exponential_Moving_Average)); + if (to_return == NULL) { + puts("Not enough memory to allocate for MA"); + return NULL; + } + to_return->data = queue_new(); //puts("Creating queue"); + if (to_return->data == NULL) { + puts("Not enough memory for MA internal data structures"); + return NULL; + } + to_return->data_sum = 0; //puts("Initializing members"); + to_return->data_avg = 0; + to_return->cur_length = 0; + to_return->max_length = max_length_; + //printf("%d %d %d %d \n", to_return->data_sum, to_return->data_avg, to_return->cur_length, to_return->max_length); + //puts("returning constructed MA"); + return to_return; +} + +void free_exponential_moving_average(Exponential_Moving_Average *self) { + puts("freeing MA"); + queue_free(self->data); + free(self); + self = NULL; +} + +int get_exponential_moving_average(Exponential_Moving_Average *self, int data_entry_) { + int *data_entry; //puts("created variable"); + data_entry = (int *) malloc(sizeof(int)); //puts("allocated memory"); + *data_entry = data_entry_; //printf("Set to %d", *data_entry); + queue_push_head(self->data, data_entry); //puts("push to head successful"); + self->data_sum += data_entry_; + self->cur_length += 1; + + if (self->cur_length > self->max_length) { + int *popped = (int *)queue_pop_tail(self->data); + self->data_sum -= *popped; + free(popped); + self->cur_length -= 1; + } + + self->data_avg = self->data_sum / self->cur_length; + + if (self->cur_length < (self->max_length / 8)) { + //printf("%d\n", data_entry_); + return data_entry_; + } else { + //printf("%d\n", self->data_avg); + return self->data_avg; + } +} + +int newest_entry_exponential_moving_average(Exponential_Moving_Average *self) { + return *((int *)queue_peek_head(self->data)); +} + +int oldest_entry_exponential_moving_average(Exponential_Moving_Average *self){ + return *((int *)queue_peek_tail(self->data)); +} + +bool is_empty_exponential_moving_average(Exponential_Moving_Average *self) { + return queue_is_empty(self->data); +} + +void test_print_MA(Exponential_Moving_Average *self) { + puts("test print"); + printf("%d %d %d %d\n", self->data_sum, self->data_avg, self->cur_length, self->max_length); + puts("end test print"); +} + + + diff --git a/C/exponential_moving_average.h b/C/exponential_moving_average.h new file mode 100644 index 0000000..5500603 --- /dev/null +++ b/C/exponential_moving_average.h @@ -0,0 +1,21 @@ +#ifndef EXPONENTIAL_MOVING_AVERAGE_H +#define EXPONENTIAL_MOVING_AVERAGE_H + +#include +#include + +#include "queue.h" + +typedef struct Exponential_Moving_Average_ Exponential_Moving_Average; + +Exponential_Moving_Average *new_exponential_moving_average(uint16_t max_length_); +void free_moving_average(Exponential_Moving_Average *self); +int get_moving_average(Exponential_Moving_Average *self, int data_entry_); + +int newest_entry_moving_average(Exponential_Moving_Average *self); +int oldest_entry_moving_average(Exponential_Moving_Average *self); +bool is_empty_moving_average(Exponential_Moving_Average *self); + +void test_print_MA(Exponential_Moving_Average *self); + +#endif diff --git a/Python/Filter_Visualization/__init__.py b/Python/Filter_Visualization/__init__.py new file mode 100644 index 0000000..15b2463 --- /dev/null +++ b/Python/Filter_Visualization/__init__.py @@ -0,0 +1 @@ +__author__ = 'Jeremy Malloch' \ No newline at end of file diff --git a/Python/Filter_Visualization/filter_prototype_test.py b/Python/Filter_Visualization/filter_prototype_test.py new file mode 100644 index 0000000..738812e --- /dev/null +++ b/Python/Filter_Visualization/filter_prototype_test.py @@ -0,0 +1,90 @@ +import csv +import datetime +import os.path +import post_filter_data_normalization as data_norm +import matplotlib.pyplot as plt +import Python.Filters.emg as emg + +plt.style.use("ggplot") + +# Define the sample frequency as a global variable to make filtering consistent between filter methods, as well as +# allow a labeled x-axis for the plot +sample_frequency = 1000 + +# Open the sample emg signal file +basepath = os.path.dirname(__file__) +filepath = os.path.abspath(os.path.join(basepath, '..', '..', 'Sample Signals', 'emg_raw_values.csv')) +inputFile = open(filepath) +inputReader = csv.reader(inputFile) + +# Set up the list of filters to test out +filters = [] +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.5)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.75)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.9)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.925)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.95)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.975)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.985)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.99)) +filters.append(emg.EMGFilterEMA(sample_frequency=1000, exponential_factor_=0.999)) +filters.append(emg.EMGFilter(sample_frequency=1000)) + +filter_names = ["Unfiltered Data", "EMA 0.5", "EMA 0.75", "EMA 0.9", "EMA 0.925", "EMA 0.95", "EMA 0.975", "EMA 0.985", + "EMA 0.99", "EMA 0.999", "MA"] + + +def call_filter(filter_object, unfiltered_value): + return_value_ = filter_object.filter(unfiltered_value) + return return_value_ + + +def filtered_values(filters, unfiltered_value): + """ + Takes a list of EMG filter objects from filter parameter, passes the latest value from the unfiltered data into the + objects filter method, and then returns a list of the return values of all of the filters. The first entry in the + list returned is the unfiltered value so that it can be compared to the original value + """ + return_value = [call_filter(filters[x], unfiltered_value) for x in range(len(filters))] + return_value.insert(0, unfiltered_value) + return return_value + +# Create list of the values being filtered so they can be plotted +values_to_plot = [] +for row in inputReader: + value = float(row[0]) + values_to_plot.append(filtered_values(filters, value)) +# Transpose the values to be plotted +values_to_plot = list(zip(*values_to_plot)) + +print("Filtered data has been successfully input") + +# Trim first 100 entries from file as the moving average based filters are building up a window, and then normalize the +# data +for count, dataset in enumerate(values_to_plot): + dataset = dataset[100:] + values_to_plot[count] = data_norm.normalize(dataset) + +print("Data has been trimmed and normalized") + +x_axis = [x/sample_frequency for x in range(len(values_to_plot[0]))] + +num_plots = len(values_to_plot) + +fig, axarr = plt.subplots(num_plots, sharex=True) + +for i in range(num_plots): + axarr[i].set_title(filter_names[i], fontsize=24) + axarr[i].scatter(x_axis, values_to_plot[i], s=125) + axarr[i].set_xlim([0, 7.5]) + axarr[i].set_ylim([-4, 4]) + +fig.suptitle('EMG Filter Comparison', fontsize=36, fontweight='bold') + +axarr[num_plots-1].set_xlabel('Time (s)') +fig.set_size_inches(80, num_plots*5) +figure_path = os.path.abspath(os.path.join(basepath, '..', '..', 'Sample Signals', 'Plotted Filters', + 'Filter Comparison ' + str(datetime.datetime.now()) + '.png')) +fig.savefig(figure_path, bbox_inches='tight', dpi=100) + +print("Plot is finished and saved") diff --git a/Python/Filter_Visualization/post_filter_data_normalization.py b/Python/Filter_Visualization/post_filter_data_normalization.py new file mode 100644 index 0000000..f7c1b4c --- /dev/null +++ b/Python/Filter_Visualization/post_filter_data_normalization.py @@ -0,0 +1,26 @@ +import numpy as np + + +def normalize_mean(dataset): + """ + Modifies a dataset so that the mean is 0. Dataset is a list, return value is a numpy array. + """ + normalized_dataset = np.array(dataset) + return normalized_dataset - np.mean(normalized_dataset) + + +def normalize_standard_deviation(dataset): + """ + Modifies a dataset so that the standard deviation is 1, so that 99.7% of data should be between -3 and 3, + assuming that normalize_mean has been called first. Dataset is assumed to be a numpy array since the mean should + be normalized before the standard deviation is. Return value is a numpy array. + """ + return dataset*(1/np.std(dataset)) + + +def normalize(dataset): + """ + Normalizes a dataset's mean (makes it equal to zero), normalizes the standard deviation (sets it equal to one) + Dataset is assumed to be an interable, and the return value is a numpy array + """ + return normalize_standard_deviation(normalize_mean(dataset)) \ No newline at end of file diff --git a/Python/Filters/__init__.py b/Python/Filters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Python/Filters/ecg.py b/Python/Filters/ecg.py new file mode 100644 index 0000000..ff0cf31 --- /dev/null +++ b/Python/Filters/ecg.py @@ -0,0 +1,88 @@ +from __future__ import print_function, division +import Python.Filters.signal_utilities as su + + +# PLAY AROUND WITH MIN_FREQUENCY UNTIL IT WORKS +class ECG(object): + def __init__(self, sample_frequency=200, pkpk_threshold_ratio=2.0, reference_available=False, + autodetect_threshold=True): # range_ = 0.1, + self.sample_frequency = sample_frequency + # self.range_ = range_ + self.reference_available = reference_available + self.initialization_period = self.sample_frequency * 3 + + self.samples_between_beats = su.BasicStats(length=3) # sized two or three, averaged to get BPM + # self.samples_between_beats.add_data(0) + self.signal_tracker = su.PeakToPeak(sample_frequency=sample_frequency, min_frequency=self.sample_frequency / 20, + max_frequency=self.sample_frequency / 8) # PLAY AROUND WITH MIN_FREQUENCY UNTIL IT WORKS + self.BPM = 0 + + self.data_points_received = 0 + self.initialization_data = su.BasicStats(length=self.initialization_period) + self.average_pkpk = -1 + self.pkpk_threshold_ratio = 2.0 + self.autodetect_ratio = 0.2 + self.data_samples_since_beat = 0 + self.first_beat = True + # self.just_detected_beat = False #if true, prevents another beat from being detected for 1/2 of last beat-to-beat time + + self.autodetect_threshold = autodetect_threshold + self.init_maxs = su.MovingAverage(length=sample_frequency / 40, return_int=True) + init_maxs_average = 0; + + # self.init_mins = su.Moving_Average(length = sample_frequency / 40, return_int = True) + # init_mins_average = 0; + + def initialize(self, data, reference_data=0): + if self.reference_available == True: + data = data - reference_data + current_pkpk = self.signal_tracker.get_pkpk(data)['pkpk'] + if self.average_pkpk == -1: + self.average_pkpk = current_pkpk + else: + self.average_pkpk = self.initialization_data.get_average(current_pkpk) + + if self.autodetect_threshold == True: + if len(self.init_maxs.data) == 0 or data >= self.init_maxs.data[-1]: + self.init_maxs_average = self.init_maxs.get_ma(data) + + # if len(self.init_mins.data) == 0 or data <= self.init_mins.data[-1]: + # self.init_mins_average = self.init_mins.get_ma(data) + + if self.data_points_received == self.initialization_period - 1: + self.pkpk_threshold_ratio = self.autodetect_ratio * self.init_maxs_average / self.average_pkpk # be able to set both thresholds + # print("CALCULATED THRESHOLD: {}".format(self.pkpk_threshold_ratio)) + + def get_bpm(self, data, reference_data=0): + if self.reference_available == True: + data = data - reference_data + average_delay = 0 + if self.data_points_received < self.initialization_period: + self.initialize(data) + self.data_points_received += 1 + else: + # print("not initializing anymore") + current_pkpk = self.signal_tracker.get_pkpk(data)['pkpk'] + self.data_samples_since_beat += 1 + if (current_pkpk > self.average_pkpk * self.pkpk_threshold_ratio) and ( + self.first_beat == True or self.data_samples_since_beat > 0.75 * + self.samples_between_beats.data_points[0]): + # self.just_detected_beat = True + # if self.first_beat == True: + # self.samples_between_beats.add_data(self.data_samples_since_beat) + # self.first_beat = False + + average_delay = self.samples_between_beats.get_average(self.data_samples_since_beat) + + # beat detected, disable detection for next ... seconds (fraction of time between most recent beat intervals) + if self.first_beat == True: + self.BPM = 60.0 * self.sample_frequency / self.data_samples_since_beat + self.first_beat = False + else: + self.BPM = 60.0 * self.sample_frequency / average_delay + + self.data_samples_since_beat = 0 + + return self.BPM + +print("End of ECG module") diff --git a/Python/Filters/emg.py b/Python/Filters/emg.py new file mode 100644 index 0000000..d73505e --- /dev/null +++ b/Python/Filters/emg.py @@ -0,0 +1,161 @@ +from __future__ import print_function, division +import Python.Filters.signal_utilities as su +from collections import deque + + +class EMGFilterBasic(object): + """ + Simple moving average filter class that assumes no low-frequency noise and data centred at 0. + More complex filters inherit from this. + """ + + def __init__(self, sample_frequency=200, range_=0.1, reference_available=False): + self.log = deque([]) # Used to store filtered data + self.reference_available = reference_available + self.MA = su.MovingAverage(length=sample_frequency * range_, return_int=False) + + if reference_available: + self.LPF_data = su.LowPassFilter(cutoff_frequency=150, sample_frequency=sample_frequency) + self.LPF_reference = su.LowPassFilter(cutoff_frequency=150, sample_frequency=sample_frequency) + + def log_data(self, to_log): + """ + Input filtered data + """ + self.log.appendleft(to_log) + + def pop_log(self, num_to_pop=1): + """ + Since you can't slice in a deque list a list, when popping more than one entries in a list you must repeatedly + call the pop deque method. + """ + if num_to_pop_ema == 1: + return self.log.pop() + to_return = [] + for _ in range(min(num_to_pop, len(self.log))): + to_return.append(self.log.pop()) + return to_return + + def rectify(self, to_rectify): + """ + Rectifies data, assuming low frequency noise already removed (reference point of 0) + """ + return abs(to_rectify) + + def filter(self, data, reference_data=0): + """ + This function is called to input raw data. It returns a filtered value if it has enough samples, and also logs it + """ + if not self.reference_available: + filtered_value = self.MA.get_ma(self.rectify(data)) + if filtered_value: # If get_ma returned a value, log it and return it + self.log_data(filtered_value) + return filtered_value + return + + else: + clean_data = self.LPF_data.filter(data) + clean_reference = self.LPF_reference.filter(reference_data) + filtered_value = self.MA.get_ma(self.rectify(clean_data - clean_reference)) + self.log_data(filtered_value) + # ("Reference used") + return filtered_value + + +class EMGFilter(EMGFilterBasic): + """ + Extension of EMGFilterBasic that has tools to remove low-frequency noise and normalize the data + """ + + def __init__(self, sample_frequency=200, range_=0.5, min_EMG_frequency=25, max_EMG_frequency=150, + reference_available=False): + EMGFilterBasic.__init__(self, sample_frequency=sample_frequency, range_=range_, + reference_available=reference_available) + # self.reference_available = reference_available + self.PkPk = su.PeakToPeak(sample_frequency=sample_frequency, min_frequency=min_EMG_frequency, + max_frequency=max_EMG_frequency) + + def filter(self, data, reference_data=0): + """ + This function is called to input raw data and return a filtered value, accounting for low-frequency noise and un-normalized data + """ + if self.reference_available == True: + clean_data = self.LPF_data.filter(data) + clean_reference = self.LPF_reference.filter(reference_data) + data = clean_data - clean_reference + + neutral_value = self.PkPk.get_pkpk(data)['neutral'] + filtered_value = self.MA.get_ma(self.rectify(data - neutral_value)) + self.log_data(filtered_value) + return filtered_value + + # return super(EMG_filter, self).filter(data - neutral_value) + + +class EMGFilterBasicEMA(object): + """ + Simple exponential moving average filter class that assumes no low-frequency noise and data centred at 0. + """ + + def __init__(self, sample_frequency=200, range_=0.1, reference_available=False, exponential_factor_=0.5): + self.reference_available = reference_available + self.ema = su.ExpMovingAverage(frame_length=sample_frequency * range_, exponential_factor=exponential_factor_) + + if reference_available: + self.LPF_data = su.LowPassFilter(cutoff_frequency=150, sample_frequency=sample_frequency) + self.LPF_reference = su.LowPassFilter(cutoff_frequency=150, sample_frequency=sample_frequency) + + def pop_log(self, num_to_pop=1): + """ + Pop and return either one data point or a set of data points + """ + return self.ema.pop_log(num_to_pop_ema=num_to_pop) + + def rectify(self, to_rectify): + """ + Rectifies data, assuming low frequency noise already removed (reference point of 0) + """ + return abs(to_rectify) + + def filter(self, data, reference_data=0): + """ + This function is called to input raw data. It returns a filtered value if it has enough samples, and also logs + it + """ + if not self.reference_available: + return self.ema.get_ema(self.rectify(data)) + + else: + clean_data = self.LPF_data.filter(data) + clean_reference = self.LPF_reference.filter(reference_data) + return self.ema.get_ema(self.rectify(clean_data - clean_reference)) + + +class EMGFilterEMA(EMGFilterBasicEMA): + """ + Extension of EMGFilterBasic that has tools to remove low-frequency noise and normalize the data + """ + + def __init__(self, sample_frequency=200, range_=0.5, min_EMG_frequency=25, max_EMG_frequency=150, + reference_available_=False, exponential_factor=0.5): + EMGFilterBasicEMA.__init__(self, sample_frequency=sample_frequency, range_=range_, + reference_available=reference_available, exponential_factor_=exponential_factor)) + self.reference_available = reference_available_ + self.PkPk = su.PeakToPeak(sample_frequency=sample_frequency, min_frequency=min_EMG_frequency, + max_frequency=max_EMG_frequency) + + def filter(self, data, reference_data=0): + """ + This function is called to input raw data and return a filtered value, accounting for low-frequency noise and + un-normalized data + """ + if self.reference_available: + clean_data = self.LPF_data.filter(data) + clean_reference = self.LPF_reference.filter(reference_data) + data = clean_data - clean_reference + + neutral_value = self.PkPk.get_pkpk(data)['neutral'] + return self.ema.get_ema(self.rectify(data - neutral_value)) + + +print("End of EMG module") diff --git a/Python/Filters/signal_utilities.py b/Python/Filters/signal_utilities.py new file mode 100644 index 0000000..b82eb47 --- /dev/null +++ b/Python/Filters/signal_utilities.py @@ -0,0 +1,181 @@ +from __future__ import print_function, division +from collections import deque + + +class MovingAverage(object): + """ + Encapsulation of a key function that some filters require + Note: MA stands for moving average + """ + def __init__(self, length, return_int=False): + self.data = deque([]) + self.data_sum = -1 + self.length = length + self.value = -1 + self.return_int = return_int + + def get_ma(self, data): + self.data.appendleft(data) + self.data_sum += data + + if len(self.data) > self.length: + self.data_sum -= self.data.pop() + + if self.return_int: + self.value = self.data_sum // self.length # preserves integer form + else: + self.value = self.data_sum / self.length + + if len(self.data) < (self.length / 2): + return -1 + else: + return self.value + + +class ExpMovingAverage(object): + """ + An exponential moving average filter with variable exponentiating factors. + Does not return an exponential moving average while the log is being populated at first (it would be too + computationally expensive calculate the sum for each step to the end of the frame in order to have the weighting + factors sum to 1) + Note: As above, MA stands for moving average, and EMA stands for Exponential Moving Average + """ + def __init__(self, exponential_factor=0.5, frame_length=50): + """ + expFactor is what each term is multiplied by each time it is shift right in the current frame + window is the number of samples that are taken into account when calculating the EMA + In order for this to work, two conditions must be met: + 0 < expFactor < 1 + 1 < window + """ + if 0 < exponential_factor < 1: + self.expFactor = exponential_factor + else: + raise ValueError("expFactor must be between 0 and 1") + if frame_length <= 1: + raise ValueError("window must be greater than 1") + self.window = int(frame_length) # Number of samples that are factored into calculation + self.sumEMA = 0 # Initialize the sum of the EMA as zero + self.EMA = deque([], maxlen=self.window) # Initialize an empty deque iterable to contain the EMA calculated + # for the past + self.log = deque([], maxlen=self.window) # Initialize an empty deque iterable of the unfiltered datapoints + self.finalFactor = self.expFactor ** self.window # Precomputed weighting factor applied to the last entry in the + # EMA sum + self.weightFactor = sum(self.expFactor ** x for x in range(1, self.window)) * 1.0 # Value sumEMA is divided + # by so that sum of EMA weights is normalized to 1 + + def get_ema(self, data_point): + """ + Calculates the exponential moving average for the most recent points + """ + if len(self.log) < self.window - 1: + # If the log will not be as long as the full window after the new dataPoint is added, no EMA will be + # calculated or returned + self.sumEMA = self.expFactor * (data_point + self.sumEMA) + self.log.appendleft(data_point) + return + else: + self.sumEMA = ((self.sumEMA - self.finalFactor * self.log[-1]) + data_point) * self.expFactor + self.log.appendleft(data_point) + return_value = self.sumEMA / self.weightFactor + self.EMA.appendleft(return_value) + return return_value + + def pop_log(self, num_to_pop_ema=1): + """ + Since you can't slice in a deque list a list, when popping more than one entries in a list you must repeatedly + call the pop deque method. + """ + if num_to_pop_ema == 1: + return self.log.pop() + to_return = [] + for _ in range(min(num_to_pop_ema, len(self.log))): + to_return.append(self.log.pop()) + return to_return + + +class LowPassFilter(MovingAverage): + """ + Simplifies the creation of a moving average-based low pass filter + """ + + def __init__(self, cutoff_frequency, sample_frequency, return_int=False): + length = int(0.125 * sample_frequency / cutoff_frequency) + MovingAverage.__init__(self, length, return_int=return_int) + + def filter(self, to_filter): + if self.length < 2: + return to_filter + else: + return self.get_ma(to_filter) + + +class BasicStats(object): + def __init__(self, length): + self.length = length + self.data_points = deque([]) + self.total_sum = -1 + self.average = -1 + self.stddev = -1 + + def add_data(self, data): + self.data_points.appendleft(data) + self.total_sum += data + + if len(self.data_points) > self.length: + self.total_sum -= self.data_points.pop() + + def get_average(self, data): + self.add_data(data) + self.average = 1.0 * self.total_sum / len(self.data_points) + return self.average + + +class PeakToPeak(object): + """ + Peak to peak filter + """ + + def __init__(self, sample_frequency, min_frequency, max_frequency): + self.for_pkpk = deque([]) + self.min_frequency = min_frequency + self.max_frequency = max_frequency + self.min_pk_gap = sample_frequency / max_frequency + self.max_pk_gap = sample_frequency / min_frequency + + # self.neutral = -1 #signal is shifted so that point point is zero + # self.min_EMG_frequency = min_EMG_frequency #signals below this frequency do not influence the peak to peak measurements + # self.max_EMG_frequency = max_EMG_frequency #signals above this frequency do not influence the peak to peak measurements + # self.min_pk_gap = 1.0/self.max_EMG_frequency * sample_frequency #the minimun distance in data points that two registered peaks can be + # self.max_pk_gap = 1.0/self.min_EMG_frequency * sample_frequency #the maximum distance two consecutive peaks can be without the calculated neutral-point shifting significantly + + # self.pk_indices = deque([]) + # self.pk_is_convex = deque([]) + + def get_pkpk(self, data): + self.for_pkpk.appendleft(data) + + # discards any data beyond two periods of the lowest-frequency wave + if len(self.for_pkpk) > (self.max_pk_gap * 2): + self.for_pkpk.pop() + + highest = max(self.for_pkpk) + lowest = min(self.for_pkpk) + self.neutral = (highest + lowest) / 2 + + to_return = {'max': highest, 'min': lowest, 'pkpk': highest - lowest, 'neutral': self.neutral} + + if len(self.for_pkpk) < self.min_pk_gap * 2: + return {'max': -1, 'min': -1, 'pkpk': -1, 'neutral': -1} + else: + return to_return + + def find_peaks(self): + # cannot find another peak of oposite concavity until min_pk_gap data points past? + pass + + def advanced_get_pkpk(self): + pass + + +print("End") diff --git a/Python/README.md b/Python/README.md new file mode 100644 index 0000000..38e459f --- /dev/null +++ b/Python/README.md @@ -0,0 +1,19 @@ +# EMG/ECG Signal Processing Library Python Documentation + +- This is used to prototype new filter types and experiment with different parameters, such as frame length for moving average based filters +- Raw filters are implemented in the Filters/signal_utilities.py +- The filters are then combined together to work in emg.py and ecg.py, building off on another +- The library is compatible with Python 2 & 3 +- The only dependencies for this project are Matplotlib for visualizing the effectiveness of filters, and Pytest for running unit tests +- Plots of the filters tested on EMG data so far can be found [here.](https://drive.google.com/open?id=0ByaKikG9muWTbHRWeFFlZ0J1WTQ) + +Creating a new filter: +---------------------- + +##### 1) Write the filter as a class in the signal_utilities.py file +##### 2) Test your filter, and verifying it performs correctly +##### 3) Implement your filter in the emg.py and ecg.py files +##### 4) Edit filter_prototype_test.py to test how your filter performs on raw EMG data compared to the pre-existing filters +##### 5) If your filter performs well, save the Matplotlib figure as *your_filter_name.png* + + diff --git a/Python/Tests/test_exponential_moving_average.py b/Python/Tests/test_exponential_moving_average.py new file mode 100644 index 0000000..0a0fe06 --- /dev/null +++ b/Python/Tests/test_exponential_moving_average.py @@ -0,0 +1,88 @@ +import pytest +import Python.Filters.signal_utilities as su + +__author__ = 'Jeremy Malloch' + + +def is_close(a, b, rel_tol=1e-09, abs_tol=0.0): + """ + Determines if two floats are 'close', so that it can be used in place of the comparison operator + Is a default function in the Python 3.5 math library, but we're using Python 2 for the project -_____- + """ + return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + +class TestEMADefaults: + """ + Testing the ExpMovingAverage class using the default parameters + """ + @classmethod + def setup_class(cls): + self.Two = su.ExpMovingAverage() + self.Zero = su.ExpMovingAverage() + for _ in range (self.Two.window + 5): + self.Two.get_EMA(2) + self.Zero.get_EMA(0) + + def test_constant_value(self): + assert isclose(self.Two.get_EMA(2), 2) + + def test_zero_value(self): + assert isclose(self.Zero.get_EMA(0), 0) + + def test_one_nonzero_term(self): + assert isclose(self.Zero.get_EMA(250), 125) + + def test_two_nonzero_term(self): + assert isclose(self.Zero.get_EMA(250), 187.5) + + def test_zeros_after_nonzero_values(self): + for _ in range(self.Two.window - 1): + self.Two.get_EMA(0) + assert isclose(self.Two.get_EMA(0), 0) + + +class TestEMADifferentWindow: + """ + Testing the ExpMovingAverage class using varying window values + """ + @classmethod + def setup_class(cls): + self.Window1 = su.ExpMovingAverage(window_ = 1) + self.Window100 = su.ExpMovingAverage(window_ = 100) + + def test_window_length_1(self): + assert isclose(self.Window1.get_EMA(1), 1) + assert isclose(self.Window1.get_EMA(2), 1) + + def test_window_length_100(self): + for _ in range(99): + self.Window100.get_EMA(10) + assert isclose(self.Window100.get_EMA(10), 10) + + def test_single_zero_value(self): + assert isclose(self.Window100.get_EMA(0), 5) + + +class TestEMADifferentExponentialFactors: + """ + Testing with varying Exponential Factors + """ + @classmethod + def setup_class(cls): + self.FactorQuarter = su.ExpMovingAverage(expFactor_= 0.25) + self.FactorFourFifths = su.ExpMovingAverage(expFactor_= 0.8) + + def test_constant_value_four_fifths(self): + for _ in range(self.FactorFourFifths.window - 1): + self.FactorFourFifths.get_EMA(10) + assert isclose(self.FactorQuarter.get_EMA(10), 10) + + def test_constant_value_quarter(self): + for _ in range(self.FactorFourFifths.window - 1): + self.FactorQuarter.get_EMA(10) + assert isclose(self.FactorFourFifths.get_EMA(10), 10) + + +if __name__ == '__main__': + pytest.main() diff --git a/Python/Tests/test_moving_average.py b/Python/Tests/test_moving_average.py new file mode 100644 index 0000000..9288d43 --- /dev/null +++ b/Python/Tests/test_moving_average.py @@ -0,0 +1,26 @@ +import pytest +import Python.Filters.signal_utilities as su + +__author__ = 'Jeremy Malloch' + + +def is_close(a, b, rel_tol=1e-09, abs_tol=0.0): + """ + Determines if two floats are 'close', so that it can be used in place of the comparison operator + Is a default function in the Python 3.5 math library, but we're using Python 2 for the project -_____- + """ + return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + +class TestMovingAverageReturnInt: + """ + Testing the moving average algorithm returning an integer + """ + @classmethod + def setup_class(cls): + su.MovingAverage + + + + + diff --git a/Python/__init__.py b/Python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Python/ecg.py b/Python/ecg.py deleted file mode 100644 index f467d26..0000000 --- a/Python/ecg.py +++ /dev/null @@ -1,82 +0,0 @@ -import signal_utilities as su - -#PLAY AROUND WITH MIN_FREQUENCY UNTIL IT WORKS -class ECG(object): - def __init__(self, sample_frequency = 200, pkpk_threshold_ratio = 2.0, reference_available = False, autodetect_threshold = True): #range_ = 0.1, - self.sample_frequency = sample_frequency - #self.range_ = range_ - self.reference_available = reference_available - self.initialization_period = self.sample_frequency * 3 - - self.samples_between_beats = su.Basic_Stats(length = 3) #sized two or three, averaged to get BPM - #self.samples_between_beats.add_data(0) - self.signal_tracker = su.PkPk(sample_frequency = sample_frequency, min_frequency = self.sample_frequency / 20, max_frequency = self.sample_frequency / 8) #PLAY AROUND WITH MIN_FREQUENCY UNTIL IT WORKS - self.BPM = 0 - - self.data_points_received = 0 - self.initialization_data = su.Basic_Stats(length = self.initialization_period) - self.average_pkpk = -1 - self.pkpk_threshold_ratio = 2.0 - self.autodetect_ratio = 0.2 - self.data_samples_since_beat = 0 - self.first_beat = True - #self.just_detected_beat = False #if true, prevents another beat from being detected for 1/2 of last beat-to-beat time - - self.autodetect_threshold = autodetect_threshold - self.init_maxs = su.Moving_Average(length = sample_frequency / 40, return_int = True) - init_maxs_average = 0; - #self.init_mins = su.Moving_Average(length = sample_frequency / 40, return_int = True) - #init_mins_average = 0; - - def initialize(self, data, reference_data = 0): - if self.reference_available == True: - data = data - reference_data - current_pkpk = self.signal_tracker.get_pkpk(data)['pkpk'] - if self.average_pkpk == -1: - self.average_pkpk = current_pkpk - else: - self.average_pkpk = self.initialization_data.get_average(current_pkpk) - - if self.autodetect_threshold == True: - if len(self.init_maxs.data) == 0 or data >= self.init_maxs.data[-1]: - self.init_maxs_average = self.init_maxs.get_movingAvg(data) - - #if len(self.init_mins.data) == 0 or data <= self.init_mins.data[-1]: - # self.init_mins_average = self.init_mins.get_movingAvg(data) - - if self.data_points_received == self.initialization_period - 1: - self.pkpk_threshold_ratio = self.autodetect_ratio * self.init_maxs_average / self.average_pkpk #be able to set both thresholds - #print "CALCULATED THRESHOLD: ", self.pkpk_threshold_ratio - - def get_BPM(self, data, reference_data = 0): - if self.reference_available == True: - data = data - reference_data - average_delay = 0 - if self.data_points_received < self.initialization_period: - self.initialize(data) - self.data_points_received += 1 - else: - #print "not initializing anymore" - current_pkpk = self.signal_tracker.get_pkpk(data)['pkpk'] - self.data_samples_since_beat += 1 - if (current_pkpk > self.average_pkpk * self.pkpk_threshold_ratio) and (self.first_beat == True or self.data_samples_since_beat > 0.75 * self.samples_between_beats.data_points[0]): - #self.just_detected_beat = True - #if self.first_beat == True: - # self.samples_between_beats.add_data(self.data_samples_since_beat) - # self.first_beat = False - - average_delay = self.samples_between_beats.get_average(self.data_samples_since_beat) - - - #beat detected, disable detection for next ... seconds (fraction of time between most recent beat intervals) - if self.first_beat == True: - self.BPM = 60.0 * self.sample_frequency / self.data_samples_since_beat - self.first_beat = False - else: - self.BPM = 60.0 * self.sample_frequency / average_delay - - self.data_samples_since_beat = 0 - - return self.BPM - -#print "End of ECG module" diff --git a/Python/emg.py b/Python/emg.py deleted file mode 100644 index 18a09ee..0000000 --- a/Python/emg.py +++ /dev/null @@ -1,70 +0,0 @@ -import signal_utilities as su - -#Simple filter class assumes no low-frequency noise and data centred at 0. More complex filteres inherit from this. -class EMG_filter_basic(object): - def __init__(self, sample_frequency = 200, range_ = 0.1, reference_available = False): - self.log = [] #used to store filtered data - self.reference_available = reference_available - self.MA = su.Moving_Average(length = sample_frequency * range_, return_int = True) - - if reference_available == True: - self.LPF_data = su.LPF(cutoff_frequency = 150, sample_frequency = sample_frequency) - self.LPF_reference = su.LPF(cutoff_frequency = 150, sample_frequency = sample_frequency) - - #input filtered data - def log_data(self, to_log): - self.log.insert(0, to_log) - - #pop and return either one data point or a set of data points - def pop_log(self, num_to_pop = 1): - if len(self.log) < 1 or num_to_pop > len(self.log): - return - elif num_to_pop <= 1: - return self.log.pop() - elif num_to_pop > 1 and num_to_pop <= len(self.log): - to_return = self.log[-num_to_pop:] - self.log = self.log[:-num_to_pop] - return to_return - - #rectifies data, assuming low frequency noise already removed (reference point of 0) - def rectify(self, to_rectify): - return abs(to_rectify) - - #this function is called to input raw data. It returns a filtered value if it has enough samples, and also logs it - def filter(self, data, reference_data = 0): - if not self.reference_available: - filtered_value = self.MA.get_movingAvg(self.rectify(data)) - self.log_data(filtered_value) - return filtered_value - - else: - clean_data = self.LPF_data.filter(data) - clean_reference = self.LPF_reference.filter(reference_data) - filtered_value = self.MA.get_movingAvg(self.rectify(clean_data - clean_reference)) - self.log_data(filtered_value) - #print "Reference used" - return filtered_value - -#extension of EMG_filter_basic that has tools to remove low-frequency noise and normalize the data -class EMG_filter(EMG_filter_basic): - - def __init__(self, sample_frequency = 200, range_ = 0.5, min_EMG_frequency = 25, max_EMG_frequency = 150, reference_available = False): - EMG_filter_basic.__init__(self, sample_frequency = sample_frequency, range_ = range_, reference_available = reference_available) - #self.reference_available = reference_available - self.PkPk = su.PkPk(sample_frequency = sample_frequency, min_frequency = min_EMG_frequency, max_frequency = max_EMG_frequency) - - #this function is called to input raw data and return a filtered value, accounting for low-frequency noise and un-normalized data - def filter(self, data, reference_data = 0): - if self.reference_available == True: - clean_data = self.LPF_data.filter(data) - clean_reference = self.LPF_reference.filter(reference_data) - data = clean_data - clean_reference - - neutral_value = self.PkPk.get_pkpk(data)['neutral'] - filtered_value = self.MA.get_movingAvg(self.rectify(data - neutral_value)) - self.log_data(filtered_value) - return filtered_value - - #return super(EMG_filter, self).filter(data - neutral_value) - -#print "End of EMG module" diff --git a/Python/signal_utilities.py b/Python/signal_utilities.py deleted file mode 100644 index 13d5d17..0000000 --- a/Python/signal_utilities.py +++ /dev/null @@ -1,110 +0,0 @@ -#Encapsulation of a key function that some filters require -class Moving_Average(object): - def __init__(self, length, return_int = False): - self.data = [] - self.data_sum = -1 - #self.data_avg = -1 - self.length = length - self.value = -1 - self.return_int = return_int - - #self.sample_frequency = sample_frequency #in Hz - #self.range_ = range_ #in seconds - #self.scope = 1.0 * self.sample_frequency * self.range_ #in number of samples, limits the length of movingAvg - #self.sum_movingAvg = 0 #tracks the sum of the moving average - #self.val_movingAvg = -1 #the latest moving average value - #self.movingAvg = [] #used to store the datapoints for taking a moving average - - def get_movingAvg (self, data): - self.data.insert(0, data) - self.data_sum += data - - if len(self.data) > self.length: - self.data_sum -= self.data.pop() - - if self.return_int == True: - self.value = int(self.data_sum / self.length) #preserves integer form - else: - self.value = 1.0 * self.data_sum / self.length - - if len(self.data) < (self.length / 2): - return -1 - else: - return self.value - -#Simplifies the creation of a moving average-based LPF -class LPF(Moving_Average): - def __init__(self, cutoff_frequency, sample_frequency, return_int = False): - length = int(0.125 * sample_frequency / cutoff_frequency) - Moving_Average.__init__(self, length, return_int = return_int) - - def filter(self, to_filter): - if self.length < 2: - return to_filter - else: - return self.get_movingAvg(to_filter) - -class Basic_Stats(object): - def __init__(self, length): - self.length = length - self.data_points = [] - self.total_sum = -1 - self.average = -1 - self.stddev = -1 - - def add_data(self, data): - self.data_points.insert(0, data) - self.total_sum += data - - if len(self.data_points) > self.length: - self.total_sum -= self.data_points.pop() - - def get_average(self, data): - self.add_data(data) - self.average = 1.0 * self.total_sum / len(self.data_points) - return self.average - - -class PkPk(object): - def __init__(self, sample_frequency, min_frequency, max_frequency): - self.for_pkpk = [] - self.min_frequency = min_frequency - self.max_frequency = max_frequency - self.min_pk_gap = sample_frequency / max_frequency - self.max_pk_gap = sample_frequency / min_frequency - - #self.neutral = -1 #signal is shifted so that point point is zero - #self.min_EMG_frequency = min_EMG_frequency #signals below this frequency do not influence the peak to peak measurements - #self.max_EMG_frequency = max_EMG_frequency #signals above this frequency do not influence the peak to peak measurements - #self.min_pk_gap = 1.0/self.max_EMG_frequency * sample_frequency #the minimun distance in data points that two registered peaks can be - #self.max_pk_gap = 1.0/self.min_EMG_frequency * sample_frequency #the maximum distance two consecutive peaks can be without the calculated neutral-point shifting significantly - - #self.pk_indices = [] - #self.pk_is_convex = [] - - def get_pkpk(self, data): - self.for_pkpk.insert(0, data) - - #discards any data beyond two periods of the lowest-frequency wave - if len(self.for_pkpk) > (self.max_pk_gap * 2): - self.for_pkpk.pop() - - highest = max(self.for_pkpk) - lowest = min(self.for_pkpk) - self.neutral = (highest + lowest)/2 - - to_return = {'max' : highest, 'min' : lowest, 'pkpk' : highest - lowest, 'neutral' : self.neutral} - - if len(self.for_pkpk) < self.min_pk_gap * 2: - return {'max' : -1, 'min' : -1, 'pkpk' : -1, 'neutral' : -1} - else: - return to_return - - def find_peaks(self): - #cannot find another peak of oposite concavity until min_pk_gap data points past? - pass - - def advanced_get_pkpk(self): - pass - -print "End" \ No newline at end of file diff --git a/README.md b/README.md index d7da910..39c0f68 100644 --- a/README.md +++ b/README.md @@ -213,4 +213,5 @@ Python DOCUMENTATION - The Python implementation uses true objects with member functions, as opposed to structs - Most functions and variables have the same name as the C implementation - Constant time is not guaranteed in the Python implementation, since some native Python functions are used +- More details about prototyping with the Python implementation can be found in the README in the Python directory diff --git a/Sample Signals/emg_raw_values.csv b/Sample Signals/emg_raw_values.csv new file mode 100644 index 0000000..b2b1973 --- /dev/null +++ b/Sample Signals/emg_raw_values.csv @@ -0,0 +1,7378 @@ +314 +323 +333 +344 +334 +348 +350 +351 +348 +345 +331 +325 +318 +325 +318 +320 +334 +344 +349 +338 +365 +367 +327 +334 +346 +327 +331 +357 +329 +389 +358 +352 +321 +339 +342 +322 +321 +352 +359 +346 +351 +332 +297 +354 +334 +323 +344 +330 +382 +351 +340 +319 +331 +348 +322 +338 +345 +376 +340 +346 +338 +325 +340 +338 +321 +327 +324 +349 +350 +353 +344 +338 +351 +327 +327 +336 +384 +331 +345 +342 +327 +337 +340 +311 +332 +402 +345 +339 +353 +323 +319 +337 +332 +321 +340 +380 +331 +344 +343 +325 +334 +346 +340 +334 +413 +360 +321 +349 +337 +322 +338 +335 +323 +338 +401 +332 +339 +357 +331 +334 +353 +326 +329 +385 +350 +326 +341 +334 +317 +335 +341 +321 +361 +365 +340 +331 +353 +329 +316 +347 +335 +314 +382 +355 +322 +327 +346 +316 +327 +360 +321 +365 +364 +344 +330 +336 +334 +321 +341 +339 +322 +387 +348 +322 +341 +326 +341 +321 +350 +329 +361 +362 +340 +323 +340 +344 +334 +319 +342 +345 +355 +392 +330 +336 +346 +330 +330 +341 +334 +358 +348 +348 +321 +325 +343 +319 +342 +341 +370 +349 +364 +351 +312 +342 +333 +320 +337 +340 +376 +344 +349 +320 +332 +356 +326 +320 +336 +401 +345 +352 +333 +323 +337 +339 +318 +333 +344 +348 +357 +336 +335 +325 +350 +349 +309 +340 +410 +334 +339 +335 +317 +332 +342 +324 +331 +401 +343 +345 +346 +328 +316 +339 +333 +326 +339 +391 +328 +335 +346 +323 +340 +347 +340 +323 +372 +352 +326 +343 +341 +324 +355 +332 +322 +332 +379 +340 +331 +355 +328 +326 +341 +335 +318 +388 +356 +354 +328 +346 +319 +331 +343 +324 +354 +358 +342 +327 +348 +336 +319 +338 +338 +319 +392 +350 +339 +329 +340 +329 +327 +346 +338 +376 +354 +340 +322 +343 +342 +322 +333 +341 +321 +357 +357 +330 +337 +348 +331 +325 +350 +327 +353 +351 +345 +319 +337 +338 +318 +329 +347 +302 +361 +360 +334 +331 +349 +329 +320 +339 +343 +391 +352 +345 +333 +329 +347 +330 +321 +351 +390 +340 +346 +329 +322 +344 +339 +320 +332 +340 +360 +340 +342 +339 +326 +356 +330 +341 +337 +389 +337 +346 +342 +321 +336 +344 +321 +328 +352 +358 +343 +354 +343 +324 +347 +336 +330 +337 +417 +333 +340 +342 +326 +327 +342 +328 +322 +404 +353 +347 +346 +329 +321 +333 +338 +320 +331 +405 +339 +331 +344 +326 +334 +341 +359 +318 +403 +342 +302 +338 +342 +317 +338 +330 +319 +323 +399 +351 +332 +361 +338 +327 +336 +336 +315 +384 +351 +326 +333 +344 +315 +327 +346 +326 +324 +362 +342 +321 +333 +349 +315 +341 +342 +323 +343 +339 +312 +333 +350 +344 +320 +330 +330 +291 +355 +330 +337 +343 +363 +333 +272 +346 +306 +363 +333 +305 +342 +394 +365 +305 +335 +339 +314 +326 +336 +260 +302 +292 +381 +380 +387 +312 +393 +334 +354 +210 +226 +398 +548 +322 +364 +230 +292 +419 +463 +330 +304 +369 +345 +304 +253 +406 +357 +239 +360 +416 +392 +222 +353 +378 +360 +276 +281 +277 +516 +398 +339 +305 +326 +334 +318 +319 +435 +363 +389 +302 +170 +440 +365 +362 +278 +337 +432 +312 +283 +350 +257 +462 +304 +296 +302 +373 +482 +326 +318 +295 +328 +342 +362 +256 +522 +354 +253 +258 +425 +268 +234 +332 +344 +379 +240 +206 +381 +369 +309 +336 +352 +329 +292 +397 +384 +346 +376 +313 +328 +333 +317 +346 +345 +388 +329 +204 +419 +519 +271 +286 +279 +446 +335 +395 +309 +305 +385 +348 +315 +325 +198 +441 +391 +373 +279 +304 +405 +329 +328 +245 +258 +575 +273 +290 +262 +353 +402 +314 +325 +304 +397 +317 +356 +335 +366 +315 +342 +360 +329 +154 +419 +393 +334 +337 +441 +368 +294 +290 +317 +323 +338 +357 +332 +233 +414 +310 +445 +327 +293 +285 +348 +355 +373 +313 +297 +262 +373 +333 +383 +339 +348 +351 +296 +347 +329 +312 +283 +431 +362 +320 +316 +339 +339 +395 +326 +350 +343 +347 +314 +369 +336 +309 +343 +312 +355 +321 +391 +340 +236 +383 +376 +330 +295 +447 +338 +333 +368 +327 +352 +417 +297 +327 +245 +354 +306 +316 +357 +412 +325 +337 +325 +307 +342 +353 +333 +311 +335 +355 +406 +343 +324 +297 +293 +303 +351 +382 +333 +249 +448 +386 +310 +350 +312 +320 +443 +299 +305 +294 +348 +335 +343 +342 +281 +396 +380 +328 +356 +310 +397 +332 +398 +316 +306 +377 +350 +335 +340 +321 +307 +371 +372 +314 +340 +396 +381 +353 +353 +318 +274 +292 +399 +360 +355 +370 +314 +333 +360 +294 +303 +437 +349 +342 +330 +367 +374 +351 +372 +314 +344 +333 +416 +353 +363 +307 +343 +367 +295 +330 +338 +362 +354 +408 +322 +278 +380 +325 +298 +365 +367 +351 +378 +310 +301 +362 +361 +300 +357 +347 +313 +335 +373 +365 +320 +362 +301 +345 +322 +396 +325 +308 +398 +356 +335 +375 +319 +310 +362 +368 +324 +362 +320 +395 +354 +386 +307 +294 +401 +367 +344 +340 +362 +353 +346 +334 +305 +393 +329 +344 +354 +353 +322 +241 +370 +353 +301 +394 +320 +348 +353 +396 +342 +248 +414 +329 +327 +338 +312 +308 +358 +272 +322 +315 +345 +303 +401 +351 +380 +390 +343 +302 +312 +377 +277 +326 +363 +342 +311 +413 +297 +342 +364 +366 +396 +292 +435 +369 +336 +236 +300 +323 +297 +358 +290 +437 +306 +335 +364 +311 +285 +343 +377 +327 +305 +354 +294 +305 +391 +342 +291 +350 +375 +348 +320 +397 +327 +340 +392 +268 +354 +374 +369 +273 +332 +305 +340 +317 +398 +245 +344 +335 +340 +337 +397 +308 +366 +307 +298 +303 +322 +371 +317 +287 +363 +267 +453 +301 +448 +258 +387 +287 +365 +370 +294 +278 +339 +311 +310 +378 +378 +330 +347 +323 +322 +332 +298 +331 +260 +427 +366 +360 +313 +313 +339 +441 +387 +298 +409 +423 +344 +420 +346 +147 +146 +361 +527 +509 +128 +24 +231 +327 +436 +332 +475 +235 +450 +442 +458 +254 +274 +379 +420 +320 +305 +546 +279 +265 +479 +401 +246 +316 +373 +283 +309 +396 +386 +369 +337 +427 +348 +296 +496 +402 +153 +236 +348 +324 +387 +384 +385 +292 +297 +429 +302 +280 +363 +352 +304 +430 +300 +337 +301 +321 +302 +356 +420 +326 +257 +495 +271 +360 +358 +250 +478 +298 +406 +241 +326 +339 +346 +333 +368 +420 +339 +330 +201 +340 +460 +410 +222 +416 +383 +319 +138 +618 +379 +286 +346 +304 +388 +253 +316 +376 +360 +378 +233 +197 +579 +195 +321 +307 +355 +390 +347 +309 +260 +367 +310 +293 +398 +457 +387 +279 +296 +285 +370 +334 +371 +357 +406 +263 +252 +450 +348 +305 +293 +262 +385 +408 +299 +342 +357 +387 +305 +323 +330 +345 +277 +390 +350 +315 +312 +333 +342 +347 +314 +285 +329 +430 +366 +327 +368 +352 +282 +348 +350 +329 +345 +366 +300 +343 +340 +336 +271 +371 +378 +356 +344 +293 +356 +382 +317 +326 +288 +342 +325 +347 +364 +243 +445 +339 +379 +358 +364 +335 +326 +346 +315 +263 +374 +400 +326 +361 +247 +326 +334 +327 +337 +344 +335 +325 +289 +370 +346 +301 +334 +365 +322 +328 +335 +324 +278 +372 +345 +324 +340 +339 +324 +351 +328 +277 +345 +377 +326 +372 +283 +365 +339 +392 +239 +312 +339 +334 +320 +360 +360 +348 +332 +352 +341 +374 +385 +354 +343 +369 +358 +297 +342 +197 +321 +356 +346 +320 +340 +365 +335 +345 +386 +310 +343 +357 +338 +355 +367 +285 +493 +363 +277 +329 +322 +337 +290 +300 +334 +340 +333 +376 +328 +317 +342 +398 +343 +365 +371 +345 +372 +267 +355 +316 +355 +337 +341 +369 +321 +307 +386 +334 +287 +421 +385 +349 +398 +302 +324 +346 +310 +340 +348 +355 +324 +325 +402 +335 +323 +306 +335 +306 +400 +350 +336 +316 +353 +315 +313 +315 +334 +317 +347 +380 +343 +373 +360 +322 +279 +346 +313 +357 +368 +355 +341 +338 +314 +310 +434 +344 +320 +363 +386 +336 +348 +379 +353 +285 +365 +343 +336 +352 +342 +334 +339 +350 +326 +364 +360 +356 +343 +356 +344 +335 +361 +323 +245 +343 +316 +393 +404 +353 +348 +349 +353 +286 +337 +351 +354 +353 +330 +353 +349 +353 +346 +310 +352 +359 +330 +356 +361 +320 +391 +314 +296 +320 +361 +338 +344 +353 +334 +346 +356 +315 +323 +360 +352 +347 +345 +336 +361 +351 +364 +294 +328 +337 +341 +328 +346 +337 +326 +352 +324 +351 +336 +355 +335 +342 +339 +346 +328 +354 +314 +328 +345 +357 +349 +327 +328 +337 +328 +319 +349 +359 +362 +344 +328 +358 +351 +359 +325 +348 +348 +342 +349 +335 +341 +358 +325 +324 +303 +325 +347 +344 +328 +307 +348 +344 +343 +254 +348 +327 +342 +356 +348 +356 +326 +326 +355 +295 +356 +328 +345 +358 +264 +339 +346 +348 +307 +352 +339 +347 +349 +346 +337 +354 +299 +338 +336 +363 +321 +335 +343 +339 +340 +348 +340 +282 +347 +335 +337 +340 +349 +341 +294 +340 +299 +329 +347 +336 +335 +348 +343 +336 +351 +334 +288 +357 +364 +322 +369 +350 +328 +341 +345 +303 +345 +348 +339 +342 +342 +336 +332 +332 +319 +330 +368 +362 +316 +343 +340 +320 +336 +361 +281 +343 +351 +338 +328 +350 +341 +318 +358 +281 +326 +341 +344 +339 +295 +354 +337 +335 +349 +288 +345 +350 +343 +330 +340 +344 +329 +328 +308 +335 +341 +352 +328 +332 +353 +340 +342 +342 +344 +325 +336 +314 +342 +337 +348 +335 +351 +303 +338 +343 +350 +340 +322 +352 +335 +333 +317 +354 +340 +345 +358 +339 +336 +342 +327 +356 +317 +333 +314 +340 +329 +327 +335 +368 +330 +292 +352 +339 +342 +350 +349 +334 +354 +340 +336 +299 +350 +303 +349 +347 +329 +343 +352 +340 +295 +352 +348 +337 +346 +336 +359 +289 +333 +318 +348 +352 +340 +346 +348 +336 +336 +346 +344 +290 +346 +345 +334 +332 +346 +334 +354 +340 +271 +344 +348 +340 +340 +351 +343 +338 +348 +341 +302 +345 +339 +333 +334 +325 +337 +337 +346 +291 +343 +347 +342 +330 +350 +343 +334 +341 +336 +345 +343 +350 +338 +363 +329 +336 +333 +332 +268 +363 +302 +321 +441 +369 +342 +315 +351 +313 +344 +349 +342 +328 +331 +321 +276 +331 +411 +358 +328 +332 +345 +353 +344 +314 +278 +330 +375 +322 +234 +291 +464 +432 +341 +336 +313 +325 +347 +340 +325 +337 +322 +313 +309 +363 +413 +244 +328 +334 +449 +342 +307 +233 +242 +518 +418 +283 +233 +484 +417 +384 +265 +278 +471 +386 +316 +326 +320 +495 +438 +405 +298 +297 +431 +342 +348 +378 +314 +333 +408 +311 +312 +290 +253 +568 +378 +311 +246 +265 +476 +399 +378 +300 +203 +419 +389 +328 +261 +181 +470 +397 +361 +233 +227 +546 +380 +366 +319 +321 +302 +334 +352 +305 +351 +338 +313 +325 +271 +271 +483 +396 +287 +317 +295 +361 +343 +363 +339 +323 +355 +289 +239 +266 +358 +350 +372 +349 +259 +335 +425 +317 +352 +347 +241 +410 +401 +359 +265 +310 +314 +417 +293 +219 +407 +429 +383 +250 +173 +420 +348 +242 +372 +329 +276 +345 +239 +427 +347 +519 +247 +371 +366 +328 +402 +244 +221 +460 +474 +118 +321 +370 +512 +404 +232 +419 +326 +424 +308 +244 +381 +500 +376 +243 +430 +311 +403 +399 +273 +245 +668 +217 +294 +204 +389 +272 +349 +385 +162 +535 +278 +356 +537 +253 +575 +194 +170 +438 +254 +377 +318 +363 +288 +309 +405 +253 +505 +415 +369 +473 +377 +458 +434 +195 +286 +395 +234 +546 +222 +233 +363 +356 +283 +257 +349 +316 +668 +426 +280 +127 +470 +209 +375 +268 +281 +207 +321 +296 +356 +435 +239 +494 +367 +445 +147 +286 +281 +359 +511 +269 +238 +310 +405 +263 +402 +324 +321 +368 +339 +344 +366 +433 +215 +271 +338 +341 +321 +415 +341 +312 +321 +338 +334 +319 +324 +373 +381 +233 +389 +360 +301 +239 +373 +445 +323 +271 +302 +287 +352 +426 +338 +257 +384 +335 +482 +297 +347 +276 +447 +395 +307 +271 +348 +304 +396 +445 +336 +326 +330 +322 +296 +343 +339 +336 +285 +412 +349 +302 +340 +354 +355 +329 +297 +345 +309 +340 +347 +325 +321 +313 +312 +461 +331 +356 +286 +343 +274 +471 +402 +305 +325 +370 +310 +478 +361 +362 +287 +392 +331 +362 +284 +368 +342 +329 +383 +315 +323 +323 +469 +315 +344 +341 +333 +298 +371 +315 +313 +315 +322 +255 +436 +363 +307 +337 +312 +354 +329 +418 +263 +400 +282 +296 +495 +316 +238 +256 +269 +427 +327 +344 +411 +285 +349 +330 +225 +421 +394 +252 +324 +401 +382 +305 +360 +328 +363 +326 +329 +367 +362 +328 +349 +309 +365 +302 +326 +296 +432 +300 +336 +335 +333 +372 +282 +356 +365 +342 +263 +341 +344 +326 +324 +315 +309 +346 +360 +313 +389 +295 +391 +303 +314 +311 +389 +321 +334 +317 +358 +348 +335 +312 +335 +329 +340 +295 +422 +374 +331 +313 +374 +351 +162 +459 +293 +312 +289 +394 +399 +330 +333 +297 +332 +320 +380 +304 +364 +290 +372 +341 +339 +307 +330 +332 +292 +433 +297 +405 +282 +515 +293 +305 +312 +325 +403 +309 +327 +336 +361 +360 +350 +319 +299 +403 +332 +354 +354 +312 +324 +280 +339 +333 +299 +378 +323 +343 +349 +334 +318 +335 +367 +342 +358 +237 +476 +334 +332 +341 +283 +366 +326 +338 +316 +354 +304 +351 +435 +299 +326 +375 +329 +331 +346 +357 +331 +354 +302 +300 +346 +328 +267 +420 +367 +308 +387 +376 +302 +315 +390 +365 +366 +342 +340 +341 +384 +336 +347 +362 +284 +445 +338 +301 +305 +448 +295 +313 +381 +301 +363 +339 +341 +453 +303 +384 +285 +361 +416 +361 +325 +374 +338 +288 +381 +364 +272 +379 +348 +391 +301 +340 +345 +285 +286 +390 +342 +321 +403 +276 +397 +204 +485 +314 +552 +115 +185 +281 +384 +340 +393 +320 +279 +359 +285 +460 +354 +369 +323 +311 +281 +471 +329 +290 +358 +319 +475 +330 +346 +377 +338 +283 +419 +447 +237 +306 +323 +335 +310 +465 +448 +153 +186 +414 +260 +356 +474 +332 +285 +488 +353 +216 +402 +332 +257 +326 +314 +379 +303 +256 +447 +262 +317 +344 +488 +362 +167 +393 +333 +261 +240 +374 +404 +246 +342 +426 +317 +350 +668 +289 +529 +215 +185 +457 +327 +522 +194 +326 +322 +359 +347 +301 +301 +334 +350 +438 +185 +345 +329 +439 +378 +194 +195 +362 +330 +384 +341 +394 +260 +460 +355 +226 +335 +373 +354 +274 +446 +336 +308 +343 +360 +354 +377 +299 +284 +391 +438 +255 +462 +388 +165 +338 +317 +330 +315 +310 +327 +235 +340 +260 +414 +297 +668 +552 +489 +119 +214 +300 +418 +197 +406 +317 +317 +386 +399 +245 +557 +304 +347 +333 +668 +125 +262 +417 +351 +596 +116 +233 +355 +381 +380 +302 +324 +329 +368 +402 +261 +350 +457 +312 +300 +299 +364 +391 +358 +285 +269 +354 +348 +374 +342 +293 +310 +313 +385 +365 +291 +354 +367 +342 +292 +306 +294 +330 +406 +374 +308 +381 +322 +326 +410 +318 +242 +460 +197 +304 +375 +353 +318 +360 +313 +299 +325 +293 +407 +342 +350 +318 +324 +427 +289 +402 +271 +304 +348 +347 +322 +377 +389 +318 +242 +345 +313 +360 +345 +400 +291 +340 +352 +289 +366 +372 +361 +321 +286 +396 +387 +349 +401 +185 +299 +337 +432 +324 +302 +343 +277 +377 +246 +437 +305 +325 +374 +257 +451 +280 +348 +292 +305 +340 +394 +346 +329 +378 +342 +318 +395 +298 +377 +340 +330 +298 +365 +360 +339 +377 +297 +323 +343 +397 +321 +361 +290 +381 +359 +346 +248 +481 +324 +326 +312 +288 +411 +267 +310 +272 +390 +292 +361 +352 +298 +312 +407 +324 +341 +333 +329 +338 +354 +303 +311 +337 +344 +251 +414 +332 +319 +298 +427 +232 +309 +397 +311 +313 +374 +357 +313 +316 +357 +296 +365 +352 +309 +289 +366 +335 +313 +347 +441 +363 +304 +327 +286 +343 +386 +328 +355 +295 +406 +408 +338 +296 +268 +466 +284 +290 +315 +404 +329 +320 +344 +276 +302 +313 +430 +331 +306 +323 +386 +314 +361 +329 +345 +289 +269 +432 +320 +306 +360 +288 +336 +384 +285 +224 +506 +331 +348 +283 +346 +273 +343 +288 +418 +333 +389 +369 +352 +331 +351 +288 +331 +403 +273 +309 +354 +276 +422 +318 +335 +326 +366 +328 +357 +337 +355 +279 +348 +301 +291 +332 +304 +373 +341 +331 +332 +329 +319 +322 +319 +379 +356 +321 +346 +342 +248 +504 +325 +347 +334 +360 +327 +344 +362 +347 +318 +339 +320 +345 +353 +315 +308 +382 +416 +333 +274 +270 +361 +361 +321 +322 +313 +358 +286 +380 +368 +317 +326 +309 +380 +351 +377 +373 +349 +335 +301 +349 +332 +356 +388 +253 +368 +343 +357 +359 +347 +333 +394 +375 +360 +303 +367 +341 +332 +320 +336 +340 +339 +364 +295 +344 +361 +349 +273 +353 +360 +362 +351 +326 +349 +353 +353 +328 +321 +358 +280 +374 +320 +312 +330 +339 +339 +297 +337 +326 +373 +358 +336 +342 +351 +369 +379 +267 +337 +333 +346 +322 +324 +313 +351 +290 +283 +370 +350 +358 +377 +266 +309 +359 +403 +285 +334 +368 +355 +342 +379 +337 +327 +350 +341 +288 +319 +337 +339 +327 +392 +356 +312 +338 +297 +357 +286 +334 +325 +335 +363 +330 +341 +359 +309 +350 +365 +337 +348 +354 +328 +385 +376 +314 +363 +341 +340 +364 +317 +342 +320 +331 +315 +355 +389 +408 +332 +329 +313 +296 +356 +333 +103 +306 +325 +360 +315 +329 +473 +357 +394 +260 +335 +266 +348 +484 +327 +351 +341 +341 +336 +325 +425 +300 +353 +306 +403 +388 +266 +342 +298 +358 +339 +353 +322 +338 +335 +316 +382 +377 +352 +342 +378 +385 +326 +284 +395 +359 +349 +297 +345 +221 +370 +456 +399 +409 +359 +333 +296 +387 +349 +381 +366 +354 +280 +295 +355 +296 +579 +391 +335 +331 +349 +372 +252 +377 +246 +300 +327 +338 +332 +344 +376 +334 +308 +375 +357 +383 +365 +333 +348 +362 +273 +363 +339 +356 +286 +333 +395 +347 +317 +295 +285 +465 +373 +315 +301 +357 +151 +327 +359 +355 +334 +302 +201 +279 +668 +360 +339 +335 +361 +387 +333 +370 +311 +343 +289 +342 +260 +320 +432 +351 +404 +385 +310 +376 +377 +311 +369 +373 +342 +308 +316 +321 +298 +313 +438 +379 +332 +348 +310 +303 +358 +373 +335 +301 +343 +290 +415 +365 +325 +349 +282 +313 +342 +338 +376 +387 +399 +344 +328 +289 +312 +358 +372 +356 +340 +328 +352 +308 +264 +334 +497 +335 +369 +335 +345 +329 +345 +308 +283 +340 +344 +341 +354 +319 +317 +385 +349 +303 +331 +368 +371 +364 +376 +312 +324 +347 +338 +289 +355 +336 +343 +355 +349 +335 +350 +338 +299 +353 +353 +368 +347 +338 +351 +346 +356 +335 +296 +367 +356 +344 +352 +333 +317 +368 +358 +274 +355 +348 +342 +378 +342 +345 +337 +305 +348 +296 +351 +349 +353 +351 +360 +327 +339 +351 +307 +287 +340 +317 +369 +359 +363 +316 +337 +322 +353 +339 +359 +334 +353 +335 +338 +349 +332 +253 +337 +352 +348 +355 +342 +336 +313 +329 +304 +347 +336 +276 +338 +344 +356 +333 +356 +328 +317 +338 +349 +335 +323 +359 +295 +317 +346 +253 +355 +341 +337 +319 +347 +366 +349 +348 +358 +339 +329 +335 +344 +306 +330 +332 +345 +373 +323 +337 +366 +323 +338 +353 +328 +359 +337 +288 +347 +337 +337 +353 +349 +328 +350 +334 +335 +314 +363 +345 +347 +344 +343 +345 +343 +340 +298 +349 +343 +344 +318 +315 +321 +362 +327 +336 +360 +340 +324 +344 +340 +338 +334 +346 +309 +297 +358 +340 +343 +348 +318 +311 +350 +338 +301 +353 +349 +351 +349 +301 +299 +317 +334 +338 +261 +352 +340 +349 +344 +328 +339 +355 +335 +314 +298 +351 +342 +332 +355 +345 +328 +339 +338 +325 +350 +341 +335 +331 +307 +367 +439 +352 +310 +331 +318 +337 +369 +343 +286 +258 +358 +435 +356 +315 +313 +345 +292 +305 +339 +320 +386 +234 +349 +329 +275 +515 +462 +335 +283 +167 +361 +436 +367 +323 +298 +280 +355 +349 +336 +283 +358 +342 +304 +434 +444 +323 +299 +347 +345 +329 +339 +300 +312 +345 +363 +294 +309 +494 +343 +366 +313 +354 +400 +328 +337 +275 +342 +369 +290 +315 +373 +413 +320 +363 +319 +281 +308 +367 +310 +302 +301 +277 +522 +340 +369 +292 +128 +266 +558 +337 +282 +338 +354 +336 +293 +351 +191 +549 +363 +309 +237 +233 +479 +331 +334 +249 +313 +524 +357 +250 +351 +508 +346 +329 +244 +283 +464 +370 +324 +293 +323 +291 +430 +312 +234 +266 +446 +346 +441 +296 +330 +437 +388 +342 +265 +345 +376 +348 +387 +237 +411 +450 +302 +146 +445 +463 +273 +291 +375 +325 +401 +412 +322 +314 +319 +305 +353 +288 +279 +405 +352 +379 +223 +395 +398 +321 +356 +350 +331 +360 +366 +324 +360 +370 +281 +397 +330 +399 +333 +507 +292 +169 +398 +379 +335 +294 +366 +326 +344 +427 +386 +347 +357 +325 +508 +352 +310 +246 +356 +379 +299 +346 +294 +451 +400 +264 +288 +498 +537 +295 +300 +373 +271 +439 +298 +345 +273 +418 +335 +510 +290 +402 +317 +365 +447 +241 +236 +402 +268 +387 +397 +292 +440 +203 +376 +367 +333 +363 +282 +306 +442 +482 +85 +304 +318 +239 +665 +359 +289 +221 +541 +310 +280 +499 +270 +277 +251 +489 +278 +293 +447 +229 +282 +304 +375 +337 +418 +285 +252 +603 +256 +436 +334 +309 +287 +225 +308 +265 +510 +295 +305 +409 +394 +307 +480 +227 +203 +668 +0 +242 +311 +268 +436 +344 +456 +327 +270 +412 +667 +146 +517 +197 +326 +112 +224 +329 +392 +381 +239 +417 +321 +301 +404 +179 +450 +233 +168 +361 +449 +196 +361 +413 +280 +322 +342 +215 +373 +318 +233 +413 +406 +597 +0 +23 +220 +434 +200 +465 +489 +314 +423 +227 +289 +486 +227 +526 +48 +52 +387 +230 +323 +597 +60 +246 +402 +531 +235 +326 +368 +452 +357 +307 +412 +308 +277 +396 +244 +443 +422 +224 +325 +291 +446 +377 +265 +469 +319 +516 +211 +285 +426 +252 +305 +336 +150 +460 +549 +146 +268 +346 +310 +349 +360 +444 +338 +387 +267 +243 +317 +367 +395 +224 +253 +374 +396 +158 +379 +341 +370 +345 +430 +272 +384 +243 +365 +364 +494 +353 +202 +329 +386 +368 +251 +330 +370 +379 +258 +342 +378 +374 +324 +304 +405 +281 +383 +386 +190 +112 +344 +337 +248 +424 +421 +423 +452 +294 +102 +491 +300 +206 +452 +204 +243 +397 +429 +213 +345 +363 +330 +386 +416 +186 +293 +320 +288 +415 +586 +238 +245 +296 +330 +429 +390 +142 +363 +318 +398 +319 +457 +236 +379 +302 +522 +91 +550 +356 +340 +521 +201 +330 +349 +360 +403 +304 +527 +360 +275 +304 +308 +199 +415 +294 +268 +26 +668 +254 +314 +299 +333 +234 +605 +342 +377 +381 +413 +291 +141 +496 +291 +331 +331 +325 +293 +376 +331 +322 +348 +342 +370 +332 +337 +334 +344 +319 +373 +326 +335 +352 +356 +317 +341 +330 +360 +260 +346 +370 +289 +382 +362 +368 +317 +363 +354 +373 +411 +373 +397 +400 +399 +371 +399 +368 +355 +367 +354 +328 +341 +345 +298 +281 +348 +323 +326 +336 +308 +310 +342 +315 +268 +342 +336 +309 +341 +346 +342 +349 +364 +316 +281 +344 +321 +326 +306 +307 +313 +340 +323 +266 +357 +363 +326 +299 +330 +351 +339 +281 +293 +436 +390 +346 +317 +308 +313 +294 +324 +334 +284 +350 +342 +327 +332 +320 +279 +452 +357 +320 +330 +348 +335 +329 +371 +312 +326 +319 +341 +342 +355 +448 +379 +358 +397 +352 +282 +313 +285 +319 +319 +320 +340 +337 +352 +333 +320 +432 +368 +387 +362 +339 +334 +316 +365 +317 +325 +378 +349 +343 +345 +303 +327 +342 +298 +319 +431 +373 +335 +324 +332 +315 +316 +335 +328 +339 +438 +336 +339 +339 +327 +328 +337 +339 +323 +358 +291 +144 +322 +337 +336 +326 +347 +313 +337 +444 +365 +338 +355 +334 +327 +344 +244 +328 +362 +411 +334 +368 +368 +347 +346 +361 +334 +354 +343 +371 +354 +295 +360 +168 +345 +209 +329 +401 +378 +377 +336 +351 +374 +311 +339 +349 +348 +193 +309 +328 +198 +346 +297 +347 +377 +323 +393 +370 +369 +342 +349 +359 +330 +360 +343 +408 +380 +346 +331 +331 +346 +334 +333 +331 +344 +362 +367 +375 +322 +343 +248 +328 +208 +352 +408 +374 +387 +353 +343 +348 +361 +352 +355 +384 +226 +296 +363 +277 +347 +293 +328 +348 +355 +469 +362 +371 +356 +328 +364 +362 +294 +352 +363 +345 +283 +357 +336 +340 +355 +341 +320 +356 +407 +374 +321 +367 +331 +250 +361 +183 +348 +366 +362 +346 +360 +339 +348 +354 +361 +337 +367 +307 +371 +357 +347 +308 +350 +355 +339 +345 +293 +345 +342 +357 +336 +331 +351 +331 +360 +298 +354 +350 +351 +357 +342 +348 +376 +338 +342 +444 +371 +356 +339 +345 +229 +350 +197 +330 +351 +387 +364 +339 +361 +341 +340 +351 +353 +334 +387 +335 +342 +360 +356 +248 +350 +308 +335 +359 +374 +354 +342 +360 +358 +167 +344 +356 +347 +262 +276 +355 +204 +360 +334 +353 +354 +343 +354 +388 +356 +341 +348 +351 +337 +350 +367 +293 +360 +358 +343 +340 +342 +345 +331 +350 +346 +285 +354 +342 +310 +331 +316 +350 +343 +359 +302 +345 +354 +341 +342 +355 +339 +335 +341 +336 +338 +356 +348 +347 +351 +345 +345 +343 +350 +326 +350 +357 +355 +329 +354 +356 +307 +354 +382 +369 +361 +359 +338 +349 +331 +333 +310 +348 +375 +367 +366 +337 +344 +341 +400 +257 +349 +363 +359 +379 +364 +347 +340 +361 +344 +331 +337 +251 +380 +349 +253 +347 +347 +358 +366 +363 +382 +377 +352 +362 +365 +348 +359 +262 +327 +398 +391 +309 +352 +373 +343 +322 +363 +335 +347 +320 +345 +344 +363 +357 +325 +367 +312 +342 +304 +341 +322 +334 +356 +347 +339 +355 +351 +332 +330 +352 +356 +338 +364 +346 +349 +350 +330 +404 +385 +360 +342 +347 +356 +327 +356 +350 +235 +355 +246 +369 +361 +368 +326 +321 +394 +349 +254 +391 +373 +354 +366 +311 +355 +235 +357 +261 +446 +369 +360 +350 +360 +346 +348 +361 +362 +198 +338 +381 +187 +366 +320 +342 +334 +345 +289 +339 +364 +349 +336 +350 +345 +336 +355 +319 +325 +339 +353 +336 +345 +356 +344 +339 +355 +273 +333 +361 +350 +344 +347 +356 +334 +358 +343 +366 +284 +368 +349 +340 +373 +352 +302 +353 +432 +346 +367 +346 +339 +75 +356 +254 +341 +366 +418 +366 +384 +377 +357 +368 +354 +326 +362 +467 +377 +380 +361 +345 +349 +331 +157 +325 +408 +392 +352 +344 +337 +334 +336 +351 +340 +343 +218 +235 +357 +277 +355 +356 +354 +381 +345 +360 +375 +341 +354 +353 +330 +338 +301 +333 +377 +369 +290 +343 +365 +352 +342 +346 +341 +333 +425 +358 +353 +338 +370 +230 +331 +202 +357 +410 +387 +362 +354 +352 +357 +334 +347 +339 +349 +339 +412 +344 +304 +351 +359 +335 +354 +348 +348 +370 +358 +332 +351 +379 +343 +316 +328 +360 +293 +286 +361 +352 +358 +370 +337 +341 +355 +401 +361 +380 +331 +349 +234 +351 +151 +354 +394 +390 +379 +358 +340 +359 +354 +356 +352 +372 +460 +370 +371 +361 +351 +351 +354 +324 +354 +378 +356 +351 +363 +349 +349 +364 +345 +351 +324 +361 +345 +360 +352 +343 +352 +351 +329 +341 +400 +358 +357 +353 +339 +298 +352 +256 +338 +430 +369 +294 +348 +354 +325 +342 +342 +325 +347 +472 +352 +364 +370 +341 +346 +352 +329 +338 +353 +370 +345 +346 +354 +330 +339 +352 +349 +300 +364 +354 +332 +374 +350 +337 +347 +352 +332 +349 +374 +344 +362 +342 +336 +349 +352 +352 +337 +365 +313 +340 +349 +352 +332 +341 +344 +336 +313 +360 +353 +327 +346 +346 +335 +330 +338 +286 +352 +357 +337 +345 +352 +334 +345 +350 +339 +336 +348 +325 +339 +368 +338 +328 +343 +346 +284 +329 +347 +341 +344 +356 +341 +338 +361 +309 +311 +342 +357 +329 +362 +344 +330 +345 +363 +285 +347 +340 +342 +339 +348 +351 +326 +352 +303 +346 +345 +361 +340 +342 +350 +338 +333 +357 +401 +359 +362 +351 +336 +358 +347 +316 +349 +431 +367 +336 +356 +335 +332 +343 +334 +335 +355 +287 +257 +327 +217 +338 +312 +348 +353 +341 +414 +360 +333 +361 +347 +323 +352 +195 +326 +408 +402 +292 +361 +388 +325 +344 +356 +333 +350 +402 +362 +355 +285 +355 +140 +356 +223 +309 +420 +391 +348 +370 +325 +348 +328 +347 +341 +337 +219 +266 +335 +191 +337 +272 +360 +368 +345 +464 +377 +326 +357 +364 +354 +355 +310 +359 +351 +416 +331 +355 +373 +373 +381 +366 +354 +371 +390 +401 +371 +355 +378 +313 +348 +461 +352 +203 +388 +415 +354 +350 +348 +340 +339 +358 +344 +278 +357 +377 +295 +352 +234 +322 +373 +362 +302 +371 +356 +365 +345 +355 +348 +325 +356 +369 +340 +283 +380 +314 +348 +362 +346 +354 +365 +408 +374 +361 +356 +341 +276 +352 +161 +340 +371 +351 +356 +339 +347 +323 +352 +340 +345 +359 +403 +364 +358 +347 +333 +347 +349 +334 +316 +382 +364 +338 +351 +348 +329 +351 +336 +334 +381 +256 +162 +341 +240 +330 +327 +351 +355 +330 +379 +277 +365 +366 +347 +333 +350 +201 +323 +419 +351 +357 +336 +359 +339 +332 +340 +355 +325 +344 +362 +346 +360 +350 +356 +345 +212 +328 +357 +389 +368 +359 +353 +346 +343 +356 +301 +315 +500 +298 +362 +234 +364 +303 +349 +362 +335 +439 +402 +374 +359 +324 +349 +338 +276 +349 +338 +388 +334 +348 +341 +358 +333 +332 +353 +328 +358 +410 +336 +362 +358 +178 +333 +179 +365 +348 +402 +364 +343 +345 +340 +336 +354 +327 +343 +211 +336 +327 +197 +349 +253 +339 +290 +356 +258 +388 +405 +358 +343 +351 +357 +326 +363 +302 +297 +413 +369 +219 +364 +364 +350 +362 +356 +360 +381 +366 +356 +354 +371 +377 +255 +350 +353 +418 +401 +374 +371 +344 +350 +350 +332 +350 +388 +396 +407 +336 +356 +308 +346 +389 +334 +253 +390 +387 +368 +346 +328 +345 +339 +327 +279 +249 +366 +351 +374 +330 +290 +350 +347 +329 +219 +382 +370 +370 +361 +337 +359 +326 +339 +350 +341 +305 +360 +332 +352 +349 +353 +354 +326 +422 +392 +354 +354 +379 +320 +337 +222 +324 +273 +397 +330 +346 +329 +348 +370 +351 +354 +327 +451 +373 +333 +326 +365 +356 +331 +381 +330 +254 +400 +381 +347 +344 +339 +324 +340 +346 +228 +494 +352 +318 +245 +358 +328 +317 +367 +345 +380 +399 +367 +344 +341 +356 +338 +323 +361 +264 +374 +267 +366 +319 +356 +359 +334 +352 +330 +408 +383 +359 +341 +336 +317 +336 +376 +368 +338 +424 +390 +355 +342 +348 +347 +323 +327 +290 +434 +385 +371 +370 +351 +327 +340 +368 +353 +266 +398 +367 +351 +326 +333 +342 +327 +341 +389 +230 +336 +360 +263 +325 +347 +350 +327 +340 +401 +381 +355 +363 +329 +333 +350 +369 +327 +326 +326 +226 +376 +325 +341 +364 +337 +342 +359 +430 +377 +347 +349 +338 +314 +356 +346 +330 +397 +383 +342 +342 +357 +328 +341 +352 +315 +427 +416 +362 +336 +355 +332 +249 +344 +350 +286 +399 +362 +332 +338 +340 +329 +335 +353 +337 +399 +299 +327 +327 +283 +321 +336 +339 +347 +335 +333 +358 +332 +339 +350 +339 +335 +180 +335 +363 +382 +315 +335 +351 +345 +320 +328 +347 +332 +360 +365 +347 +279 +342 +235 +333 +226 +343 +429 +378 +378 +336 +343 +345 +330 +325 +359 +416 +354 +360 +337 +333 +339 +343 +330 +330 +338 +306 +323 +341 +333 +357 +320 +335 +331 +347 +287 +316 +339 +343 +327 +333 +339 +332 +341 +344 +315 +310 +345 +351 +334 +354 +346 +349 +328 +299 +304 +335 +349 +345 +329 +358 +342 +350 +278 +327 +328 +347 +341 +323 +343 +349 +333 +340 +316 +331 +333 +353 +342 +343 +354 +349 +335 +317 +332 +331 +343 +347 +339 +344 +354 +333 +333 +346 +334 +339 +351 +343 +342 +339 +355 +325 +297 +353 +334 +344 +360 +333 +344 +362 +341 +325 +380 +365 +350 +340 +354 +341 +357 +368 +311 +425 +394 +363 +349 +395 +157 +349 +218 +357 +329 +407 +391 +351 +370 +361 +331 +344 +346 +336 +382 +359 +341 +336 +349 +336 +325 +345 +329 +371 +348 +336 +324 +342 +360 +361 +339 +370 +346 +354 +466 +364 +323 +359 +359 +335 +349 +341 +267 +391 +374 +347 +348 +313 +344 +330 +359 +144 +393 +390 +360 +332 +351 +345 +332 +330 +345 +360 +374 +385 +231 +349 +159 +343 +289 +355 +456 +369 +394 +356 +321 +342 +345 +330 +333 +293 +204 +326 +366 +107 +344 +312 +351 +343 +321 +298 +365 +350 +371 +340 +338 +349 +284 +341 +239 +372 +298 +375 +353 +346 +343 +343 +322 +336 +455 +374 +359 +305 +341 +260 +351 +271 +331 +256 +422 +338 +358 +357 +328 +337 +313 +350 +388 +439 +354 +346 +264 +356 +235 +346 +324 +333 +313 +366 +344 +348 +363 +340 +338 +340 +327 +292 +335 +136 +353 +300 +352 +355 +344 +360 +333 +396 +364 +328 +344 +355 +323 +335 +352 +329 +312 +356 +346 +330 +347 +363 +322 +324 +348 +328 +331 +356 +337 +339 +355 +344 +334 +350 +336 +310 +343 +342 +336 +329 +355 +339 +327 +352 +307 +329 +339 +342 +332 +346 +343 +330 +338 +348 +295 +281 +356 +340 +341 +355 +336 +334 +352 +317 +336 +351 +350 +336 +348 +362 +327 +353 +351 +335 +326 +359 +343 +333 +354 +346 +333 +356 +327 +325 +308 +373 +347 +346 +347 +345 +316 +333 +348 +331 +357 +355 +332 +348 +351 +330 +344 +318 +339 +343 +337 +345 +352 +363 +352 +342 +319 +349 +342 +346 +327 +360 +340 +345 +367 +343 +356 +341 +364 +357 +341 +343 +324 +348 +330 +350 +340 +249 +340 +397 +349 +339 +315 +380 +363 +392 +368 +330 +371 +335 +331 +334 +333 +320 +409 +364 +340 +331 +353 +316 +300 +319 +332 +416 +356 +372 +327 +343 +333 +307 +338 +333 +332 +388 +353 +335 +325 +335 +318 +338 +343 +322 +381 +364 +359 +311 +350 +345 +323 +322 +336 +339 +388 +371 +343 +338 +298 +276 +324 +397 +346 +376 +361 +386 +327 +306 +310 +265 +306 +379 +407 +376 +415 +391 +163 +280 +286 +401 +300 +316 +323 +325 +356 +343 +325 +354 +312 +361 +359 +404 +300 +328 +380 +356 +306 +308 +336 +319 +342 +387 +370 +371 +383 +348 +371 +331 +279 +384 +361 +339 +311 +340 +408 +334 +342 +326 +329 +345 +342 +327 +358 +339 +282 +290 +391 +316 +299 +317 +343 +332 +377 +337 +302 +338 +355 +360 +318 +355 +314 +323 +395 +353 +352 +288 +346 +335 +384 +357 +298 +374 +352 +318 +330 +337 +316 +320 +360 +325 +369 +357 +326 +330 +327 +312 +391 +337 +331 +303 +328 +379 +339 +340 +349 +325 +309 +361 +325 +331 +332 +374 +336 +352 +335 +348 +318 +373 +323 +343 +369 +330 +326 +386 +410 +260 +368 +370 +344 +339 +341 +303 +354 +355 +308 +382 +339 +330 +344 +376 +344 +358 +380 +326 +363 +329 +377 +345 +341 +342 +373 +332 +362 +293 +347 +365 +312 +369 +344 +347 +328 +341 +365 +346 +340 +352 +339 +330 +363 +362 +315 +347 +320 +378 +331 +352 +314 +337 +367 +352 +348 +295 +329 +347 +347 +343 +368 +379 +317 +328 +351 +322 +302 +311 +358 +318 +333 +357 +318 +344 +348 +333 +372 +355 +287 +328 +333 +334 +322 +321 +363 +337 +339 +353 +338 +330 +366 +335 +341 +358 +344 +324 +354 +334 +308 +331 +344 +342 +365 +270 +335 +320 +352 +356 +337 +333 +333 +328 +360 +365 +325 +344 +343 +322 +323 +337 +367 +343 +364 +349 +313 +349 +337 +316 +339 +351 +372 +365 +338 +323 +333 +354 +433 +207 +219 +303 +340 +347 +348 +338 +353 +353 +322 +328 +246 +313 +271 +317 +331 +215 +379 +272 +335 +315 +342 +380 +411 +312 +332 +330 +361 +333 +319 +355 +382 +335 +342 +346 +331 +379 +319 +290 +313 +360 +359 +356 +353 +305 +317 +207 +317 +227 +345 +416 +334 +348 +338 +318 +329 +324 +328 +330 +393 +204 +259 +360 +193 +322 +253 +354 +325 +351 +431 +334 +322 +345 +325 +344 +334 +310 +351 +431 +316 +256 +356 +298 +330 +354 +387 +277 +344 +403 +354 +329 +349 +320 +276 +352 +213 +352 +447 +352 +332 +361 +319 +336 +334 +365 +326 +379 +297 +334 +339 +235 +326 +214 +365 +323 +320 +448 +334 +318 +343 +337 +339 +331 +358 +331 +414 +289 +242 +337 +321 +346 +343 +361 +328 +339 +399 +361 +341 +352 +355 +299 +334 +262 +349 +388 +371 +338 +333 +356 +368 +352 +316 +303 +366 +300 +370 +351 +239 +351 +226 +335 +303 +356 +464 +365 +356 +347 +336 +345 +318 +348 +353 +395 +244 +228 +360 +238 +356 +257 +329 +309 +349 +356 +351 +323 +278 +327 +351 +304 +332 +354 +381 +334 +362 +343 +288 +351 +316 +326 +332 +359 +369 +308 +348 +307 +323 +362 +341 +310 +341 +445 +348 +324 +350 +303 +320 +329 +293 +331 +398 +378 +344 +352 +351 +311 +325 +324 +302 +336 +402 +342 +332 +310 +329 +278 +340 +330 +343 +363 +334 +303 +355 +367 +343 +315 +343 +312 +349 +378 +350 +328 +367 +329 +246 +370 +218 +322 +374 +356 +343 +358 +335 +345 +335 +361 +347 +364 +271 +332 +346 +252 +347 +331 +354 +345 +324 +406 +363 +335 +359 +359 +311 +341 +275 +344 +382 +372 +369 +345 +338 +330 +342 +338 +341 +334 +373 +377 +338 +307 +351 +301 +336 +347 +339 +381 +370 +353 +346 +317 +350 +314 +343 +368 +307 +290 +293 +349 +290 +364 +349 +339 +366 +342 +407 +381 +363 +358 +342 +353 +334 +297 +353 +409 +363 +331 +347 +354 +365 +350 +339 +327 +356 +369 +352 +341 +339 +326 +238 +328 +216 +364 +369 +347 +352 +354 +319 +350 +325 +345 +327 +376 +219 +275 +358 +176 +332 +288 +358 +335 +353 +492 +338 +327 +363 +327 +360 +349 +355 +327 +463 +333 +221 +366 +328 +335 +350 +338 +325 +361 +444 +325 +326 +376 +340 +329 +333 +223 +326 +438 +380 +338 +354 +347 +349 +313 +344 +327 +320 +404 +398 +336 +266 +323 +171 +343 +347 +313 +401 +341 +303 +343 +314 +349 +330 +295 +333 +385 +277 +123 +334 +289 +349 +335 +350 +335 +371 +439 +386 +338 +339 +349 +256 +352 +219 +346 +407 +388 +345 +352 +354 +358 +323 +360 +372 +366 +320 +322 +353 +252 +375 +290 +341 +339 +356 +358 +356 +363 +366 +324 +355 +346 +327 +346 +354 +415 +327 +351 +368 +336 +322 +336 +321 +350 +392 +319 +349 +338 +319 +315 +340 +258 +357 +396 +331 +333 +360 +293 +339 +324 +339 +324 +360 +373 +341 +331 +264 +320 +314 +346 +288 +356 +437 +352 +367 +367 +320 +350 +321 +345 +320 +379 +346 +300 +359 +314 +322 +312 +346 +330 +341 +470 +354 +339 +365 +315 +316 +334 +348 +319 +436 +366 +312 +335 +305 +326 +321 +362 +319 +320 +365 +353 +326 +308 +342 +258 +347 +308 +314 +387 +373 +315 +345 +339 +336 +363 +364 +305 +326 +349 +291 +329 +295 +346 +320 +347 +373 +355 +385 +366 +310 +351 +357 +360 +325 +295 +332 +363 +394 +329 +345 +339 +340 +280 +345 +316 +349 +442 +366 +346 +331 +348 +266 +343 +324 +315 +365 +363 +353 +342 +361 +344 +298 +346 +336 +362 +328 +317 +346 +275 +350 +317 +337 +364 +369 +392 +323 +296 +350 +306 +362 +343 +332 +350 +366 +350 +304 +358 +313 +341 +365 +336 +331 +362 +422 +364 +340 +359 +337 +304 +340 +272 +348 +412 +370 +358 +342 +326 +340 +310 +346 +310 +343 +368 +320 +359 +280 +339 +315 +342 +331 +317 +422 +329 +327 +374 +339 +304 +344 +365 +343 +354 +383 +365 +372 +370 +363 +368 +362 +359 +354 +364 +361 +357 +378 +348 +362 +370 +363 +353 +426 +393 +355 +347 +370 +358 +345 +364 +353 +334 +434 +360 +352 +358 +323 +322 +332 +275 +319 +402 +354 +350 +343 +343 +326 +352 +336 +318 +336 +396 +374 +342 +316 +342 +253 +340 +297 +334 +407 +370 +346 +338 +333 +336 +316 +370 +343 +397 +292 +230 +329 +243 +352 +306 +344 +350 +342 +425 +383 +340 +355 +357 +354 +326 +318 +354 +432 +325 +239 +348 +327 +349 +344 +339 +356 +377 +408 +377 +353 +350 +358 +339 +334 +266 +360 +426 +369 +311 +349 +332 +346 +342 +355 +360 +381 +369 +368 +358 +318 +347 +222 +320 +235 +337 +446 +366 +356 +366 +326 +393 +322 +336 +358 +494 +242 +269 +358 +161 +370 +279 +356 +325 +342 +416 +345 +347 +370 +302 +383 +354 +312 +333 +376 +356 +320 +351 +366 +365 +301 +345 +341 +388 +403 +374 +349 +367 +336 +359 +366 +320 +337 +465 +366 +331 +351 +347 +360 +361 +364 +327 +423 +341 +338 +348 +337 +364 +337 +334 +295 +315 +447 +340 +318 +331 +322 +388 +321 +334 +321 +421 +352 +266 +350 +334 +328 +332 +355 +337 +309 +370 +346 +313 +341 +373 +261 +317 +251 +333 +398 +369 +334 +351 +324 +335 +317 +365 +340 +375 +256 +330 +361 +237 +328 +220 +336 +318 +337 +476 +351 +332 +328 +345 +424 +314 +395 +317 +385 +275 +278 +345 +262 +345 +332 +358 +266 +337 +455 +433 +283 +356 +355 +344 +322 +307 +334 +445 +390 +311 +328 +322 +373 +312 +342 +349 +385 +348 +365 +336 +326 +327 +329 +383 +309 +331 +425 +336 +340 +350 +309 +380 +320 +407 +323 +411 +338 +349 +335 +303 +321 +327 +304 +291 +293 +458 +396 +317 +385 +332 +361 +301 +300 +311 +391 +339 +336 +358 +307 +313 +311 +357 +292 +368 +406 +391 +316 +331 +317 +288 +377 +299 +292 +440 +368 +301 +341 +322 +396 +363 +373 +311 +373 +302 +337 +332 +318 +300 +302 +351 +295 +320 +456 +372 +313 +397 +319 +353 +319 +349 +317 +450 +340 +294 +325 +299 +327 +312 +365 +309 +336 +411 +407 +317 +352 +312 +310 +321 +352 +299 +417 +354 +297 +315 +333 +345 +304 +411 +321 +372 +336 +348 +331 +274 +328 +290 +320 +304 +323 +436 +361 +333 +355 +333 +368 +313 +367 +309 +397 +318 +265 +321 +265 +329 +305 +320 +301 +346 +298 +258 +317 +266 +321 +332 +307 +318 +337 +418 +330 +319 +360 +323 +339 +320 +276 +319 +357 +362 +284 +358 +333 +334 +313 +344 +291 +343 +362 +345 +336 +317 +319 +250 +334 +241 +333 +381 +271 +304 +357 +293 +351 +329 +368 +324 +336 +287 +290 +337 +234 +324 +288 +369 +342 +349 +358 +326 +225 +348 +309 +346 +357 +355 +320 +350 +366 +268 +351 +355 +334 +340 +371 +323 +362 +402 +347 +306 +366 +333 +286 +349 +237 +333 +428 +405 +349 +359 +355 +335 +288 +368 +316 +354 +359 +363 +317 +274 +344 +248 +358 +331 +359 +440 +417 +352 +351 +374 +359 +342 +364 +356 +361 +278 +256 +337 +314 +363 +349 +352 +356 +373 +366 +373 +337 +349 +359 +337 +349 +240 +359 +404 +379 +326 +365 +362 +367 +355 +347 +302 +345 +389 +361 +323 +269 +331 diff --git a/Sample Signals/emgvalues.xlsx b/Sample Signals/emgvalues.xlsx deleted file mode 100644 index cae1a41..0000000 Binary files a/Sample Signals/emgvalues.xlsx and /dev/null differ diff --git a/Sample Signals/normality_test.png b/Sample Signals/normality_test.png new file mode 100644 index 0000000..1e63dae Binary files /dev/null and b/Sample Signals/normality_test.png differ diff --git a/Sample Signals/normality_test.py b/Sample Signals/normality_test.py new file mode 100644 index 0000000..4a3f749 --- /dev/null +++ b/Sample Signals/normality_test.py @@ -0,0 +1,27 @@ +import numpy as np +import matplotlib.mlab as mlab +import matplotlib.pyplot as plt +import csv +plt.style.use('seaborn-colorblind') + +inputFile = open("emg_raw_values.csv") +inputReader = csv.reader(inputFile) +x_values = [] +for row in inputReader: + x_values.append(float(row[0])) +mu = np.mean(x_values) +sigma = np.std(x_values) + +# the histogram of the data +n, bins, patches = plt.hist(x_values, 100, normed=True) + +# add a 'best fit' line +y = mlab.normpdf(bins, mu, sigma) +l = plt.plot(bins, y, linewidth=1.5) + +plt.xlabel('Intensity of Signal') +plt.ylabel('Probability') +plt.title("Distribution of Data Collected From an EMG Sensor") +plt.grid(True) + +plt.savefig("normality_test.png", dpi=300)