Commit 2c25660f authored by Hurstel's avatar Hurstel

Git init

parents
Project components details:
/Alpha
-> precompiled executable for Windows with a x86 architecture
/FIC_scripts
-> python scripts to help analyze the OscilloPic2's signal data output.
/libOscilloPic2
-> C++ library that provides functions to interact with the OscilloPic2 device. Optionnally
used by the program SeriesProtcol
/SeriesDoc
-> quick documenation about the programs
/SeriesGenerator
-> a program that is a Qt User Interface to generate 'Feel In Controls' series description files.
/SeriesProtocol
-> a program that interepret and runs 'Feel In Controls' series description files.
Make sure to check the SeriesDoc and each component's individual README.txt files
\ No newline at end of file
<config>
<curve_display>
<curve_view_width>5.0</curve_view_width>
<curve_view_min>-35.0</curve_view_min>
<curve_view_max>100.0</curve_view_max>
</curve_display>
<global_params>
<gl_update_delay>500</gl_update_delay>
<save_results>true</save_results>
<phantom_sampling_rate>1600</phantom_sampling_rate>
<auto_seed>true</auto_seed>
<save_path>data</save_path>
</global_params>
<device active='yes'>
<threshold>10</threshold>
<timeout>500</timeout>
<com_port>14</com_port>
<baudrate>115200</baudrate>
</device>
</config>
<signal_config>
<img_path>[default display]</img_path>
<default_color red="255" blue="0" green="0"/>
<size width="100" height="100"/>
<snd_path>[default sound]</snd_path>
</signal_config>
<config>
<curve_display>
<curve_view_width>5.0</curve_view_width>
<curve_view_min>-35.0</curve_view_min>
<curve_view_max>100.0</curve_view_max>
</curve_display>
<global_params>
<gl_update_delay>500</gl_update_delay>
<save_results>true</save_results>
<phantom_sampling_rate>1600</phantom_sampling_rate>
<auto_seed>true</auto_seed>
<save_path>data</save_path>
</global_params>
<device active='yes'>
<threshold>10</threshold>
<timeout>500</timeout>
<com_port>14</com_port>
<baudrate>115200</baudrate>
</device>
</config>
To use the 'SignalAnalyze' script you'll need python in its 2.7 version.
Check /install/README.txt to install the python2.7 dependencies before you can
use the scripts.
SignalAnalzye.py is for a GUI version.
SignalAnalyze_cmd.py is for a console version.
# python SignalAnalyze.py -h
'''
Created on 27 august 2014
@author: hurstel
'''
import sys
import os.path
from argparse import ArgumentParser
from argparse import RawDescriptionHelpFormatter
from gooey.gooey_decorator import Gooey
from dev.CSVFileLooker import CSVFileLooker
from dev.HapticAnalyzer import HapticAnalyzer
from dev.AuditiveAnalyzer import AuditiveAnalyzer
from dev.VisualAnalyzer import VisualAnalyzer
def writeReport(reportPath, sigConf, clusters):
print "Writing report"
path= reportPath
i=1
while ( os.path.isfile(path) ) :
i+=1
path_split= reportPath.split('.')
if len(path_split)>1:
path= ('.'.join(path_split[:-1]))+("_{0}".format(i))+'.'+path_split[-1:][0]
else:
path= reportPath+("_{0}".format(i))
reportFile= open(path, 'w')
print "---- writing at: "+path
l1= len(clusters[0])
l2= len(clusters[1])
if (l1 != l2) :
reportFile.write("# (W) The same amount of clusters hasn't been detected in both entries\n\n")
reportFile.write("signal ; cluster_detect_position ; time\n")
groupClust= [ (c,e) for e in [0,1] for c in clusters[e] ]
groupClust.sort()
print "fuu: %s" % str(groupClust)
lg= len(groupClust)
for i in range(0, lg):
if i<(lg-1) and groupClust[i][0]==groupClust[i+1][1]:
w_s= sigConf[0]+sigConf[1]
else :
w_s= str(sigConf[groupClust[i][1]])
p= groupClust[i][0]
reportFile.write("{0} ; {1} ; {2}\n".format(w_s, p, float(p)/4000.0))
reportFile.close()
@Gooey
def main(argv=None):
if (argv is None):
argv= sys.argv
else:
sys.argv.extend(argv)
parser= ArgumentParser(description="Test", formatter_class=RawDescriptionHelpFormatter)
parser.add_argument("csvFilePath", help="path to the csv file to analyze")
parser.add_argument("signalConfig", help="signal configuration for both entries (ex: 'HV' for haptic on entry\
1 and visual on entry; 'AH' for auditive on entry 1 and haptic on entry 2)")
parser.add_argument("--report", dest="report", help="print a report file (give path)")
args= parser.parse_args()
looker= CSVFileLooker(args.csvFilePath)
looker.read()
sigConf= args.signalConfig[:2].upper()
print "\n\n\n"
print "---------"
print "This is a help script."
print "Its goal is to find quickly the signals occurence in the given sampled dataSet."
print "There are no warranty nor reliability for the results."
print "(especially regarding the auditive signal which is highly unstable)"
print "You'll probably want to (and should) double check manually the dataSet."
print "Feel free to edit and improve this script."
print "---------\n\n"
class SignalConfigError(Exception):
def __init__(self):
Exception.__init__(self)
def __str__(self):
return "The script's 'signalConfig' argument is invalid."
analyzers= [None,None]
if (len(sigConf)>=2):
data1= [v[0] for v in looker.data]
data2= [v[1] for v in looker.data]
if sigConf[0]=='A':
analyzers[0]= AuditiveAnalyzer(data1)
elif sigConf[0]=='V':
analyzers[0]= VisualAnalyzer(data1)
else:
analyzers[0]= HapticAnalyzer(data1)
if sigConf[1]=='H':
analyzers[1]= HapticAnalyzer(data2)
elif sigConf[1]=='V':
analyzers[1]= VisualAnalyzer(data2)
else:
analyzers[1]= AuditiveAnalyzer(data2)
foundClusters= [None, None]
for i in [0,1]:
analyzers[i].compute()
foundClusters[i]= analyzers[i].findCluster()
ev= [None,None]
for i in [0,1]:
print '%c signal:' % sigConf[i]
print '---- foundClusters: %s' % foundClusters[i]
v= []
for clust in foundClusters[i]:
v.append(analyzers[i].probableSignalClusterSignificantPos(clust))
print '---- signal occurences in dataset: %s' % v
print '---- signal times occurence in sampling: %s' % str([ float(p)/4000.0 for p in v])
ev[i]=v
if args.report is not None :
writeReport(args.report, sigConf, ev)
else :
raise SignalConfigError
return 0
if __name__ == "__main__":
sys.exit(main())
'''
Created on 27 august 2014
@author: hurstel
'''
import sys
import os.path
from argparse import ArgumentParser
from argparse import RawDescriptionHelpFormatter
from dev.CSVFileLooker import CSVFileLooker
from dev.HapticAnalyzer import HapticAnalyzer
from dev.AuditiveAnalyzer import AuditiveAnalyzer
from dev.VisualAnalyzer import VisualAnalyzer
def writeReport(reportPath, sigConf, clusters):
print "Writing report"
path= reportPath
i=1
while ( os.path.isfile(path) ) :
i+=1
path_split= reportPath.split('.')
if len(path_split)>1:
path= ('.'.join(path_split[:-1]))+("_{0}".format(i))+'.'+path_split[-1:][0]
else:
path= reportPath+("_{0}".format(i))
reportFile= open(path, 'w')
print "---- writing at: "+path
l1= len(clusters[0])
l2= len(clusters[1])
if (l1 != l2) :
reportFile.write("# (W) The same amount of clusters hasn't been detected in both entries\n\n")
reportFile.write("signal ; cluster_detect_position ; time\n")
groupClust= [ (c,e) for e in [0,1] for c in clusters[e] ]
groupClust.sort()
print "fuu: %s" % str(groupClust)
lg= len(groupClust)
for i in range(0, lg):
if i<(lg-1) and groupClust[i][0]==groupClust[i+1][1]:
w_s= sigConf[0]+sigConf[1]
else :
w_s= str(sigConf[groupClust[i][1]])
p= groupClust[i][0]
reportFile.write("{0} ; {1} ; {2}\n".format(w_s, p, float(p)/4000.0))
reportFile.close()
def main(argv=None):
if (argv is None):
argv= sys.argv
else:
sys.argv.extend(argv)
parser= ArgumentParser(description="Test", formatter_class=RawDescriptionHelpFormatter)
parser.add_argument("csvFilePath", help="path to the csv file to analyze")
parser.add_argument("signalConfig", help="signal configuration for both entries (ex: 'HV' for haptic on entry\
1 and visual on entry; 'AH' for auditive on entry 1 and haptic on entry 2)")
parser.add_argument("--report", dest="report", help="print a report file (give path)")
args= parser.parse_args()
looker= CSVFileLooker(args.csvFilePath)
looker.read()
sigConf= args.signalConfig[:2].upper()
print "\n\n\n"
print "---------"
print "This is a help script."
print "Its goal is to find quickly the signals occurence in the given sampled dataSet."
print "There are no warranty nor reliability for the results."
print "(especially regarding the auditive signal which is highly unstable)"
print "You'll probably want to (and should) double check manually the dataSet."
print "Feel free to edit and improve this script."
print "---------\n\n"
class SignalConfigError(Exception):
def __init__(self):
Exception.__init__(self)
def __str__(self):
return "The script's 'signalConfig' argument is invalid."
analyzers= [None,None]
if (len(sigConf)>=2):
data1= [v[0] for v in looker.data]
data2= [v[1] for v in looker.data]
if sigConf[0]=='A':
analyzers[0]= AuditiveAnalyzer(data1)
elif sigConf[0]=='V':
analyzers[0]= VisualAnalyzer(data1)
else:
analyzers[0]= HapticAnalyzer(data1)
if sigConf[1]=='H':
analyzers[1]= HapticAnalyzer(data2)
elif sigConf[1]=='V':
analyzers[1]= VisualAnalyzer(data2)
else:
analyzers[1]= AuditiveAnalyzer(data2)
foundClusters= [None, None]
for i in [0,1]:
analyzers[i].compute()
foundClusters[i]= analyzers[i].findCluster()
ev= [None,None]
for i in [0,1]:
print '%c signal:' % sigConf[i]
print '---- foundClusters: %s' % foundClusters[i]
v= []
for clust in foundClusters[i]:
v.append(analyzers[i].probableSignalClusterSignificantPos(clust))
print '---- signal occurences in dataset: %s' % v
print '---- signal times occurence in sampling: %s' % str([ float(p)/4000.0 for p in v])
ev[i]=v
if args.report is not None :
writeReport(args.report, sigConf, ev)
else :
raise SignalConfigError
return 0
if __name__ == "__main__":
sys.exit(main())
'''
Created on 29 AUGUST 2014
@author: hurstel
'''
from DataAnalyzer import DataAnalyzer
import Precomputed
class AuditiveAnalyzer(DataAnalyzer):
"""
DataAnalyzer class specialisation
for processing data looking for
auditive signals.
"""
class Descriptor :
"""
A data descriptor provided by the
AuditiveAnalyzer class that give a naive and
subjective metrics to compare and eventually match
2 cluster. Used to compare and distinguish
some diffrent cluster types.
"""
class DescriptorNotDefinedException(Exception):
"""
A custom exception
to be raised is descriptor aren't created correctly
"""
def __init__(self):
"""
Constuctor - do not call directly
"""
Exception.__init__(self)
def __str__(self):
"""
str method overload - do not call directly, use str()
"""
return "The descriptor was not defined correctly. Maybe the original cluster was empty...?\
did you use static method Descriptor.fromCluster()?"
def __init__(self):
"""
Constuctor - do not call directly
In fact, this constructor doesn't create nor defines
a descriptor properly; the descriptor won't be usable.
Since a Descriptor is unique to a cluster, you should only
use the static method Descriptor.fromCluster() to create
a descriptor
"""
self._defined= False
"""
Boolean private attribute
Is the descriptor defined? No!
"""
self._length= 0
"""
Integer private attribute
The length of the cluster
"""
self._average= 0.0
"""
Floating private attribute
The average value of the cluster data values
"""
self._average_inf= 0.0
"""
Floating private attribute
The average value of all values that are under the
global average value
"""
self._average_sup= 0.0
"""
Floating private attribute
The average value of all values that are over the
global average value
"""
self._l_inf= 0
"""
Integer private attribute
How many values under the global average value
"""
self._l_sup= 0
"""
Integer private attribute
How many values over the gloabl average value
"""
self._evo_inf= []
"""
Float array private attribute
Contains the evolution of the under average value
That is to say, all the slope between successive
under average values
"""
self._evo_sup= []
"""
Float array private attribute
Contains the evolution of the over average value
That is to say, all the slope between successive
over average values
"""
def __str__(self):
"""
str method overload - do not call directly, use str()
"""
if not self._defined:
return "{ Descriptor undefined }"
else:
return "{\t L=%d\n\
\taverage=%f\n\
\taverage_inf=%f\n\
\taverage_sup=%f\n\
\tL_inf=%d\n\
\tl_sup=%d\n\
\tevo_inf=%s\n\
\tevo_sup=%s }" % (self._length,\
self._average,\
self._average_inf,\
self._average_sup,\
self._l_inf,\
self._l_sup,\
self._evo_inf,\
self._evo_sup)
@staticmethod
def fromCluster(cluster):
"""
Public static method
Creates and returns a Descriptor object associated
with the given data cluster
---WARNING---
The parameter 'cluster', here, is a dataCluster, meaning an array
containing all the data values composing a cluster!
"""
desc= AuditiveAnalyzer.Descriptor()
#length
desc._length= len(cluster)
if desc._length<=0 :
return desc
#computing average value
for d in cluster:
desc._average+= float(d)
desc._average= desc._average / float(desc._length)
#average of lower values
l_inf= 0
#average of upper values
l_sup= 0
prev_id_inf= -1
prev_id_sup= -1
i=0
for d in cluster:
if float(d) >= desc._average:
l_sup+=1
v= (float(d)-desc._average)
desc._average_sup+= v
#computing upper slopes
if(prev_id_sup>=0):
desc._evo_sup.append( (v-(float(cluster[prev_id_sup])-desc._average_sup))/2.0 )
prev_id_sup= i
else:
l_inf+=1
v= (float(d)-desc._average)
desc._average_inf+= v
#computing lower slopes
if(prev_id_inf>=0):
desc._evo_inf.append( (v-(float(cluster[prev_id_inf])-desc._average_inf))/2.0 )
prev_id_inf= i
i+=1
if(l_inf>0):
desc._average_inf= desc._average_inf/float(l_inf)
if(l_sup>0):
desc._average_sup= desc._average_sup/float(l_sup)
desc._l_inf= l_inf
desc._l_sup= l_sup
#calculations done, the descriptor is defined
desc._defined= True
return desc
@staticmethod
def computeScore(desc1, desc2):
"""
Static public method
Compute the 'matching score' between 2 given
data cluster descriptor
Returns a float that evaluate the similarity between
the 2 descriptors
"""
#-------
#local inner method - don't pay attention </