#NEWLINE# def simulateSNR( arg1 , osr , amp = None , f0 = 0 , nlev = 2 , f = None , k = 13 , quadrature = False ) : #NEWLINE# #INDENT# "Determine the SNR for a delta-sigma modulator by using simulations.\n\n    Simulate a delta-sigma modulator with sine wave inputs of various\n    amplitudes and calculate the signal-to-noise ratio (SNR) in dB for each \n    input.\n\n    Three alternative descriptions of the modulator can be used:\n\n     * The modulator is described by a noise transfer function (NTF), provided\n       as ``arg1`` and the number of quantizer levels (``nlev``).\n\n     * Alternatively, the first argument to simulateSNR may be an ABCD matrix. \n\n     * Lastly, ``arg1`` may be a function taking the input signal as its\n       sole argument.\n\n    The band of interest is defined by the oversampling ratio (``osr``)\n    and the center frequency (``f0``).\n\n    The input signal is characterized by the ``amp`` vector and the ``f`` variable.\n    A default value for ``amp`` is used if not supplied.\n\n    ``f`` is the input frequency, normalized such that 1 -> fs;\n    ``f`` is rounded to an FFT bin.\n\n    Using sine waves located in FFT bins, the SNR is calculated as the ratio\n    of the sine wave power to the power in all in-band bins other than those\n    associated with the input tone. Due to spectral smearing, the input tone\n    is not allowed to lie in bins 0 or 1. The length of the FFT is :math:`2^k`.\n\n    If the NTF is complex, :func:`simulateQDSM` (which is slow, also available\n    in a future release) is called.\n\n    If ABCD is complex, :func:`simulateDSM` is used with the real equivalent\n    of ABCD in order to speed up simulations.\n\n    Future versions may accommodate STFs.\n\n    **Parameters:**\n\n    arg1 : scipy 'lti' object, or ndarray\n        The first argument may be one of the various supported representations\n        for an NTF or an ABCD matrix. Quadrature modulators are supported both\n        with quadrature TFs or with quadrature ABCD matrices, the latter being\n        the recommended description.\n\n    osr : int\n        The over-sampling ratio.\n\n    amp : sequence, optional\n        The amplitudes in dB, referred to the FS, for which the SNR is to be \n        evaluated. ``amp`` defaults to [-120 -110...-20 -15 -10 -9 -8 ... 0]dB,\n        where 0 dB means a full-scale (peak value = nlev-1) sine wave.\n\n    f0 : float, optional\n        The center frequency. Normalized. Defaults to 0.\n\n    nlev : int, optional\n        Number of quantizer levels, defaults to 2.\n\n    f : float, optional\n        Test signal input frequency. Normalized. Rounded to an FFT bin.\n        Defaults to:\n\n    .. math::\n\n        f = \\frac{1}{4\\ \\mathrm{OSR}}\n\n    k : int, optional\n        The number of samples used to compute the FFT is set by the integer\n        ``k`` - default value 13 - through the relationship:\n\n    .. math::\n\n        N_{samples} = 2^k\n\n    quadrature : boolean, optional\n        Whether the delta-sigma modulator is a quadrature modulator or not.\n        Defaults to ``False``.\n\n    **Returns:**\n\n    snr : ndarray\n        The SNR, from simulation.\n\n    amp : ndarray\n        The amplitudes corresponding to the SNR values.\n\n    .. seealso:: :func:`predictSNR`.\n\n    .. rubric:: Example:\n\n    Compare the SNR vs input amplitude curve for a fifth-order modulator, as \n    computed by the describing function method (:func:`predictSNR`) with\n    that determined by simulation (:func:`simulateSNR`).::\n\n        import pylab as plt\n        from deltasigma import *\n        OSR = 32\n        H = synthesizeNTF(5, OSR, 1)\n        snr_pred, amp, _, _, _ = predictSNR(H,OSR)\n        snr, amp = simulateSNR(H, OSR)\n        plt.plot(amp, snr_pred, 'b', label='Predicted')\n        plt.hold(True)\n        plt.plot(amp, snr, 'go', label='Simulated')\n        plt.grid(True)\n        figureMagic([-100, 0], 10, None,\n                    [0, 100], 10, None)\n        plt.xlabel('Input Level, dB')\n        plt.ylabel('SNR, dB')\n        s = 'peak SNR = %4.1fdB\\n' % max(snr)\n        plt.text(-65, 15, s, horizontalalignment='left')\n        plt.legend(loc='best')\n\n    .. plot::\n\n        import pylab as plt\n        from deltasigma import *\n        OSR = 32\n        H = synthesizeNTF(5, OSR, 1)\n        snr_pred, amp, _, _, _ = predictSNR(H,OSR)\n        snr, amp = simulateSNR(H, OSR)\n        plt.plot(amp, snr_pred, 'b', label='Predicted')\n        plt.hold(True)\n        plt.plot(amp, snr, 'go', label='Simulated')\n        plt.grid(True)\n        figureMagic([-100, 0], 10, None,\n                    [0, 100], 10, None)\n        plt.xlabel('Input Level, dB')\n        plt.ylabel('SNR, dB')\n        s = 'peak SNR = %4.1fdB\\n' % max(snr)\n        plt.text(-65, 15, s, horizontalalignment='left')\n        plt.legend(loc='best')\n\n    " #NEWLINE# quadrature_ntf = False #NEWLINE# if callable ( arg1 ) : #NEWLINE# #INDENT# raise ValueError ( ( 'There is no support for NTFs described through ' + 'a function.' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( not isinstance ( arg1 , np . ndarray ) ) : #NEWLINE# #INDENT# for roots in _get_zpk ( arg1 ) [ : 2 ] : #NEWLINE# #INDENT# if np . any ( ( np . abs ( np . imag ( np . poly ( roots ) ) ) > 0.0001 ) ) : #NEWLINE# #INDENT# quadrature = True #NEWLINE# quadrature_ntf = True #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# arg1 = np . real_if_close ( arg1 ) #NEWLINE# if ( not np . all ( ( np . imag ( arg1 ) == 0 ) ) ) : #NEWLINE# #INDENT# quadrature = True #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if ( amp is None ) : #NEWLINE# #INDENT# amp = np . concatenate ( ( np . arange ( ( - 120 ) , ( ( - 20 ) + 1 ) , 10 ) , np . array ( ( ( - 15 ) , ) ) , np . arange ( ( - 10 ) , 1 ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( not isinstance ( amp , collections . Iterable ) ) : #NEWLINE# #INDENT# amp = np . array ( ( amp , ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# amp = np . asarray ( amp ) #NEWLINE# #UNINDENT# #UNINDENT# osr_mult = 2 #NEWLINE# if ( ( f0 != 0 ) and ( not quadrature ) ) : #NEWLINE# #INDENT# osr_mult = ( 2 * osr_mult ) #NEWLINE# #UNINDENT# if ( ( f is None ) or np . isnan ( f ) ) : #NEWLINE# #INDENT# f = ( f0 + ( 0.5 / ( osr * osr_mult ) ) ) #NEWLINE# #UNINDENT# M = ( nlev - 1 ) #NEWLINE# if ( quadrature and ( not quadrature_ntf ) ) : #NEWLINE# #INDENT# nlev = np . array ( [ nlev , nlev ] ) #NEWLINE# arg1 = mapQtoR ( arg1 ) #NEWLINE# #UNINDENT# if ( abs ( ( f - f0 ) ) > ( 1.0 / ( osr * osr_mult ) ) ) : #NEWLINE# #INDENT# warn ( 'The input tone is out-of-band.' ) #NEWLINE# #UNINDENT# N = ( 2 ** k ) #NEWLINE# if ( N < ( ( 8 * 2 ) * osr ) ) : #NEWLINE# #INDENT# warn ( 'Increasing k to accommodate a large oversampling ratio.' ) #NEWLINE# k = np . array ( np . ceil ( np . log2 ( ( ( 8 * 2 ) * osr ) ) ) , dtype = np . int64 ) #NEWLINE# N = ( 2 ** k ) #NEWLINE# #UNINDENT# F = np . round ( ( f * N ) ) #NEWLINE# if ( np . abs ( F ) <= 1 ) : #NEWLINE# #INDENT# warn ( 'Increasing k to accommodate a low input frequency.' ) #NEWLINE# k = np . ceil ( np . log2 ( ( 1.0 / f ) ) ) #NEWLINE# N = ( 2 ** k ) #NEWLINE# F = 2 #NEWLINE# #UNINDENT# Ntransient = 100 #NEWLINE# soft_start = ( 0.5 * ( 1 - np . cos ( ( ( ( 2 * np . pi ) / Ntransient ) * np . arange ( ( Ntransient / 2 ) ) ) ) ) ) #NEWLINE# if ( not quadrature ) : #NEWLINE# #INDENT# tone = ( M * np . sin ( ( ( ( ( 2 * np . pi ) * F ) / N ) * np . arange ( ( N + Ntransient ) ) ) ) ) #NEWLINE# tone [ : ( Ntransient / 2 ) ] = ( tone [ : ( Ntransient / 2 ) ] * soft_start ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# tone = ( M * np . exp ( ( ( ( ( 2j * np . pi ) * F ) / N ) * np . arange ( ( N + Ntransient ) ) ) ) ) #NEWLINE# tone [ : ( Ntransient / 2 ) ] = ( tone [ : ( Ntransient / 2 ) ] * soft_start ) #NEWLINE# if ( not quadrature_ntf ) : #NEWLINE# #INDENT# tone = tone . reshape ( ( 1 , ( - 1 ) ) ) #NEWLINE# tone = np . vstack ( ( np . real ( tone ) , np . imag ( tone ) ) ) #NEWLINE# #UNINDENT# #UNINDENT# window = ( 0.5 * ( 1 - np . cos ( ( ( ( 2 * np . pi ) * np . arange ( N ) ) / N ) ) ) ) #NEWLINE# if ( f0 == 0 ) : #NEWLINE# #INDENT# inBandBins = ( int ( ( N / 2 ) ) + np . arange ( 3 , ( np . round ( ( ( N / osr_mult ) / osr ) ) + 1 ) , dtype = np . int32 ) ) #NEWLINE# F = ( F - 2 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# f1 = np . round ( ( N * ( f0 - ( ( 1.0 / osr_mult ) / osr ) ) ) ) #NEWLINE# inBandBins = ( int ( ( N / 2 ) ) + np . arange ( f1 , ( np . round ( ( N * ( f0 + ( ( 1.0 / osr_mult ) / osr ) ) ) ) + 1 ) , dtype = np . int32 ) ) #NEWLINE# F = ( ( F - f1 ) + 1 ) #NEWLINE# #UNINDENT# snr = np . zeros ( amp . shape ) #NEWLINE# for ( i , A ) in enumerate ( np . power ( 10.0 , ( amp / 20 ) ) ) : #NEWLINE# #INDENT# if quadrature_ntf : #NEWLINE# #INDENT# ( v , _ , _ , _ ) = simulateQDSM ( ( A * tone ) , arg1 , nlev ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# ( v , _ , _ , _ ) = simulateDSM ( ( A * tone ) , arg1 , nlev ) #NEWLINE# if quadrature : #NEWLINE# #INDENT# v = ( v [ 0 , : ] + ( 1j * v [ 1 , : ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# hwfft = fftshift ( fft ( ( window * v [ Ntransient : ( N + Ntransient ) ] ) ) ) #NEWLINE# snr [ i ] = calculateSNR ( hwfft [ ( inBandBins - 1 ) ] , F ) #NEWLINE# #UNINDENT# return ( snr , amp )