Commit 27e64854 by Juan David González Cobas

add signal processing code and new GUI

`Remove copyrighted docs and maciej program`
parent e8a3e159
 # To change this template, choose Tools | Templates # and open the template in the editor. __author__="Federico Asara" __date__ ="\$Jul 11, 2011 2:39:38 PM\$" __doc__= """This module offers the Signal class, which simple store the output signal of an ADC with some other useful informations. """ from Utilities import * from numpy import * import Sinefit class Signal(object): """A class that represent a time-domain sampled signal. """ def __init__(self, nbits = 0, rate = 1, data = []): """initialize a signal object nbits: bit width of the sample values rate: sampling rate of sample production data: an array of samples (usually nbits-long words, stored in a numpy array) """ self.nbits = nbits self.rate = rate self.fulldata = data = array(data, dtype=float) self.fullnsamples = len(data) self.data = self.fulldata self.nsamples = len(data) # remove DC component if self.fullnsamples > 0: self.fulldata -= (max(self.fulldata) +min(self.fulldata))/2. self.fulldft = abs(fft.fft(self.fulldata)) # useful names N = len(data) fdft = self.fulldft first = 1. + argmax(fdft[1:N/2]) second = first + (argmax(fdft[first-1:first+2:2])*2) -1 ratio = (fdft[second] / fdft[first]) self.first = first self.beta = N/pi * arctan(sin(pi/N)/(cos(pi/N)+1./ratio)) self.w0index = first+ self.beta freqSample = 2 * pi * self.rate w0 = freqSample * float(self.w0index)/self.nsamples print "Frequency initial guess ->", w0 self.w0, self.A, self.B, self.C = Sinefit.sinefit4(data, 1.0/rate, w0, 1e-7) print "Frequency fit ->", self.w0 # limit data self.w0index = self.w0 /freqSample * self.nsamples self.limit = floor(0.5 + N*int(self.w0index)/self.w0index) self.data = data[:self.limit] self.nsamples = len(self.data) print "limit is:", self.limit self.precalculateAll() def items(self): """Create a list of tuples that describes the signal. The structure of a tuple is""" output = [] output.append(('Number of bits', '%d b', self.nbits)) output.append(('Sampling rate', '%.2f Hz', self.rate)) output.append(('Number of samples', "%d samples", self.nsamples)) output.append(('Peak at', "%f", self.w0index)) output.append(('Input frequency', "%.6f Hz", self.w0/2/pi)) output.append(('Beta', "%f", self.beta)) return output def precalculateAll(self): return
 ... ... @@ -31,16 +31,47 @@ def sinefit3(samples, sample_t, w0): D0 = D0T.T x0 = (D0T * D0).I * D0T * matrix(samples).T return array(x0).reshape((3,)) def sinefit4matrix(samples, sample_t, w0, tol=1e-7): """fit a sampled wave to a sine of unknown frequency def sinefit4(data, Ts, w0): This routine implements the algorithm of IEEE 1241, sect. 4.1.4.3., fitting a sine wave the the samples given, which are assumed equally spaced in time by a sample period sample_t. a0 cos(w0 t + theta) + b0 sin(w0 t + theta) + c0 An initial frequency estimate w0 is required to start, and an optional relative error in frequency is admitted (1e-4 by default) The return value is the quadruple (w0, a0, b0, c0) """ a0, b0, c0 = sinefit3(samples, sample_t, w0) deltaw0 = 0 while True: w0 += deltaw0 n = samples.size t = arange(n) * sample_t w0t = w0 * t D0T = matrix(vstack([cos(w0t), sin(w0t), ones(n), -a0*t*sin(w0t) + b0*t*cos(w0t)])) D0 = D0T.T x0 = (D0T * D0).I * D0T * matrix(samples).T x0 = array(x0).reshape((4,)) a0, b0, c0, deltaw0 = x0 if abs(deltaw0/w0) < tol: return (w0+deltaw0, a0, b0, c0) def sinefit4scipy(data, Ts, w0, *args, **kwargs): # Target function # fitfunc = lambda p, x: p[0]*cos(p[3]*x) +p[1]*sin(p[3]*x) +p[2] # Distance to the target function errfunc = lambda p, x, y: p[0]*cos(p[3]*x) +p[1]*sin(p[3]*x) +p[2] - y errfunc = lambda p, x, y: y - (p[0]*cos(p[3]*x) +p[1]*sin(p[3]*x) +p[2]) # Initial guess for the parameters A, B, C = sinefit3(data, Ts, w0) A, B, C = sinefit3(data, Ts, w0) p0 = [A, B, C, w0]; # Time serie ... ... @@ -49,7 +80,7 @@ def sinefit4(data, Ts, w0): p1, success = optimize.leastsq(errfunc, p0[:], args=(Tx, data)) return p1 return p1[:4] def makesine(samples, periods, bits, amplitude=1, noise=0): t = arange(samples)/float(samples) ... ... @@ -60,6 +91,8 @@ def makesine(samples, periods, bits, amplitude=1, noise=0): place(sine, sine <= -2**bits, -2**bits) return sine sinefit4 = sinefit4matrix if __name__ == "__main__": sine = makesine(20000, 20, 12, 443, 10) print sine ... ...
This diff is collapsed.
 from Signal import * class TwoToneSignal(Signal): """A class that represent a time-domain sampled signal with two sinusoids with similiar frequenciess. """ def __init__(self, nbits = 0, rate = 1, data = []): """initialize a signal object nbits: bit width of the sample values rate: sampling rate of sample production data: an array of samples (usually nbits-long words, stored in a numpy array) """ super(TwoToneSignal, self).__init__(nbits, rate, data) def items(self): output = super(TwoToneSignal, self).items() output.append(('The cake is a lie', "%s ", True)) return output def precalculateAll(self): """Evaluates all the parameters of the signal, and also call the precalculate method for each window function we know.""" return
 from ConfigParser import RawConfigParser from numpy import max, abs, sum, sqrt, log10 from time import time # timeit decoratr def timeit(method): def timed(*args, **kw): ts = time() result = method(*args, **kw) te = time() print '%r (%r, %r) %2.3f sec' % (method.__name__, args, kw, te-ts) return result return timed # db converter def dB(x): return 20*log10(x) def norm(v): m = max(abs(v)) w = v/m return m * sqrt(sum(w*w)) # empty generator def fake(x, y): return (i for i in []) @timeit def readFile(path): config = RawConfigParser() config.read(path) nbits = config.getint('SIGNAL', 'nbits') rate = config.getint('SIGNAL', 'rate') dataString = config.get('SIGNAL', 'data').split('\n') data = map(int, dataString) return nbits, rate, data
 ... ... @@ -50,4 +50,4 @@ windows = { if __name__ == "__main__": for name in windows: print "Using window", name print windows[name][15] \ No newline at end of file print windows[name][15]
 from numpy import * class WindowedSignal: data = array([]) th = array([]) nsamples = 0 dft = array([]) udft = array([]) ldft = array([]) ludft = array([]) ratio = 0 maxPeak = 0 w0 = 0 w0index = 0 rate = 0 def adjust(self, data, fs): while data >= fs: data -= fs if data >= fs/2.: data = fs -data; return data def harmonicPeaksGenerator(self, start, end): indexes = (self.adjust(x * self.w0index, self.nsamples -1) for x in xrange(start , end)) return ((i, self.ratio*i, self.dft[i]) for i in indexes) def logHarmonicPeaksGenerator(self, start, end): indexes = (self.adjust(x * self.w0index, self.nsamples -1) for x in xrange(start , end)) return ((i, self.ratio*i, self.ldft[i]) for i in indexes) THD = 0 noiseFloor = 0 signalPower = 0 noisePower = 0 SNR = 0 SINAD = 0 ENOB = 0 maxPeak = 0 secondPeak = 0 SFDR = 0 def items(self): output = [] output.append(('Input frequency', '%.5f Hz', self.w0/(2*pi))) output.append(('Peak', '%d', self.w0index)) output.append(('THD', '%.2f dB', self.THD)) output.append(('Noise floor', "%g dB", self.noiseFloor)) output.append(('Signal power', "%.f ", self.signalPower)) output.append(('Noise power', "%.f ", self.noisePower)) output.append(('SNR', "%.2f dB", self.SNR)) output.append(('SINAD', "%.2f dB", self.SINAD)) output.append(('ENOB', "%.2f b", self.ENOB)) output.append(('SFDR', "%.2f dBc", self.SFDR)) return output def report(self): for i in self.items(): print "%s: %s" % (i[0], i[1] % i[2])
 __author__="federico" __date__ ="\$Jul 11, 2011 2:39:08 PM\$" import matplotlib matplotlib.use('Qt4Agg')