1#!/usr/bin/python
2
3# Copyright (C) 2012 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from consts import *
18import numpy as np
19import scipy as sp
20import scipy.fftpack as fft
21import matplotlib.pyplot as plt
22import sys
23sys.path.append(sys.path[0])
24import calc_delay
25
26# check if amplitude ratio of DUT / Host signal
27#  lies in the given error boundary
28# input: host record
29#        device record,
30#        sampling rate
31#        low frequency in Hz,
32#        high frequency in Hz,
33#        allowed error in negative side for pass in %,
34#        allowed error ih positive side for pass
35# output: min value in negative side, normalized to 1.0
36#         max value in positive side
37#         calculated amplittude ratio in magnitude (DUT / Host)
38
39def do_check_spectrum(hostData, DUTData, samplingRate, fLow, fHigh, margainLow, margainHigh):
40    # reduce FFT resolution to have averaging effects
41    N = 512 if (len(hostData) > 512) else len(hostData)
42    iLow = N * fLow / samplingRate + 1 # 1 for DC
43    if iLow > (N / 2 - 1):
44        iLow = (N / 2 - 1)
45    iHigh = N * fHigh / samplingRate + 1 # 1 for DC
46    if iHigh > (N / 2 + 1):
47        iHigh = N / 2 + 1
48    print fLow, iLow, fHigh, iHigh, samplingRate
49
50    Phh, freqs = plt.psd(hostData, NFFT=N, Fs=samplingRate, Fc=0, detrend=plt.mlab.detrend_none,\
51        window=plt.mlab.window_hanning, noverlap=0, pad_to=None, sides='onesided',\
52        scale_by_freq=False)
53    Pdd, freqs = plt.psd(DUTData, NFFT=N, Fs=samplingRate, Fc=0, detrend=plt.mlab.detrend_none,\
54        window=plt.mlab.window_hanning, noverlap=0, pad_to=None, sides='onesided',\
55        scale_by_freq=False)
56    print len(Phh), len(Pdd)
57    print "Phh", abs(Phh[iLow:iHigh])
58    print "Pdd", abs(Pdd[iLow:iHigh])
59    amplitudeRatio = np.sqrt(abs(Pdd[iLow:iHigh]/Phh[iLow:iHigh]))
60    ratioMean = np.mean(amplitudeRatio)
61    amplitudeRatio = amplitudeRatio / ratioMean
62    print "Normialized ratio", amplitudeRatio
63    print "ratio mean for normalization", ratioMean
64    positiveMax = abs(max(amplitudeRatio))
65    negativeMin = abs(min(amplitudeRatio))
66    passFail = True if (positiveMax < (margainHigh / 100.0 + 1.0)) and\
67        ((1.0 - negativeMin) < margainLow / 100.0) else False
68    RatioResult = np.zeros(len(amplitudeRatio), dtype=np.int16)
69    for i in range(len(amplitudeRatio)):
70        RatioResult[i] = amplitudeRatio[i] * 1024 # make fixed point
71    print "positiveMax", positiveMax, "negativeMin", negativeMin
72    return (passFail, negativeMin, positiveMax, RatioResult)
73
74def toMono(stereoData):
75    n = len(stereoData)/2
76    monoData = np.zeros(n)
77    for i in range(n):
78        monoData[i] = stereoData[2 * i]
79    return monoData
80
81def check_spectrum(inputData, inputTypes):
82    output = []
83    outputData = []
84    outputTypes = []
85    # basic sanity check
86    inputError = False
87    if (inputTypes[0] != TYPE_MONO) and (inputTypes[0] != TYPE_STEREO):
88        inputError = True
89    if (inputTypes[1] != TYPE_MONO) and (inputTypes[1] != TYPE_STEREO):
90        inputError = True
91    if (inputTypes[2] != TYPE_I64):
92        inputError = True
93    if (inputTypes[3] != TYPE_I64):
94        inputError = True
95    if (inputTypes[4] != TYPE_I64):
96        inputError = True
97    if (inputTypes[5] != TYPE_DOUBLE):
98        inputError = True
99    if (inputTypes[6] != TYPE_DOUBLE):
100        inputError = True
101    if inputError:
102        print "input error"
103        output.append(RESULT_ERROR)
104        output.append(outputData)
105        output.append(outputTypes)
106        return output
107    hostData = inputData[0]
108    if inputTypes[0] == TYPE_STEREO:
109        hostData = toMono(hostData)
110    dutData = inputData[1]
111    if inputTypes[1] == TYPE_STEREO:
112        dutData = toMono(dutData)
113    samplingRate = inputData[2]
114    fLow = inputData[3]
115    fHigh = inputData[4]
116    margainLow = inputData[5]
117    margainHigh = inputData[6]
118    delay = 0
119    N = 0
120    hostData_ = hostData
121    dutData_ = dutData
122    if len(hostData) > len(dutData):
123        delay = calc_delay.calc_delay(hostData, dutData)
124        N = len(dutData)
125        hostData_ = hostData[delay:delay+N]
126    if len(hostData) < len(dutData):
127        delay = calc_delay.calc_delay(dutData, hostData)
128        N = len(hostData)
129        dutData_ = dutData[delay:delay+N]
130
131    print "delay ", delay, "deviceRecording samples ", N
132    (passFail, minError, maxError, TF) = do_check_spectrum(hostData_, dutData_,\
133        samplingRate, fLow, fHigh, margainLow, margainHigh)
134
135    if passFail:
136        output.append(RESULT_PASS)
137    else:
138        output.append(RESULT_OK)
139    outputData.append(minError)
140    outputTypes.append(TYPE_DOUBLE)
141    outputData.append(maxError)
142    outputTypes.append(TYPE_DOUBLE)
143    outputData.append(TF)
144    outputTypes.append(TYPE_MONO)
145    output.append(outputData)
146    output.append(outputTypes)
147    return output
148
149# test code
150if __name__=="__main__":
151    sys.path.append(sys.path[0])
152    mod = __import__("gen_random")
153    peakAmpl = 10000
154    durationInMSec = 1000
155    samplingRate = 44100
156    fLow = 500
157    fHigh = 15000
158    data = getattr(mod, "do_gen_random")(peakAmpl, durationInMSec, samplingRate, fHigh,\
159        stereo=False)
160    print len(data)
161    (passFail, minVal, maxVal, ampRatio) = do_check_spectrum(data, data, samplingRate, fLow, fHigh,\
162        1.0, 1.0)
163    plt.plot(ampRatio)
164    plt.show()
165