%pylab inline
Populating the interactive namespace from numpy and matplotlib
from __future__ import division
from deltasigma import *
import warnings
from scipy.signal import ss2zpk
warnings.filterwarnings('ignore')
Demonstration of a low-pass, 3rd-order continuous-time delta sigma modulator, in a very similar fashion as as done in the MATLAB Delta Sigma Toolbox, albeit employing the Python port of the MATLAB package, deltasigma
.
order = 3
osr = 32
nlev = 2
f0 = 0.
Hinf = 1.5
tdac = [0, 1]
form = 'FB'
M = nlev - 1
#generic options
plotsize = (15, 8) #inches
print '\t\t\t %dth-Order Continuous-Time Lowpass Example\n' % order
print 'Doing NTF synthesis...',
ntf0 = synthesizeNTF(order, osr, 2, Hinf, f0) # 2: Optimized zero placement
print 'done.'
print "\nSynthesized a %d-order NTF, with roots:\n" % order
print " Zeros:\t\t\t Poles:"
for z, p in zip(ntf0[0], ntf0[1]):
print "(%f, %fj)\t(%f, %fj)" % (np.real(z), np.imag(z), np.real(p), np.imag(p))
print ""
3th-Order Continuous-Time Lowpass Example Doing NTF synthesis... done. Synthesized a 3-order NTF, with roots: Zeros: Poles: (0.997110, -0.075973j) (0.764515, -0.280052j) (0.997110, 0.075973j) (0.764515, 0.280052j) (1.000000, 0.000000j) (0.668460, 0.000000j)
figure(figsize=plotsize)
plotPZ(ntf0, showlist=True)
changeFig(10, 1.5, 7)
figure(figsize=plotsize)
DocumentNTF(ntf0, osr, f0)
<matplotlib.figure.Figure at 0xb019e7cc>
print 'Doing time-domain simulations...'
figure(figsize=plotsize)
PlotExampleSpectrum(ntf0, M, osr, f0)
title('Example Spectrum');
Doing time-domain simulations...
If we have a two level quantizer, we run the prediction routine predictSNR
, which employs the describing function method of Ardalan and Paulos.
Otherwise, we skip the prediction step and we move directly to time simulation of the NTF, to evaluate the SNR.
if nlev == 2:
snr_pred, amp_pred, k0, k1, se = predictSNR(ntf0, osr)
snr, amp = simulateSNR(ntf0, osr, None, f0, nlev)
figure(figsize=plotsize)
if nlev == 2:
plot(amp_pred, snr_pred, '-', label='Predicted')
hold(True)
plot(amp, snr,'o-.g', label='simulated')
#figureMagic(np.array([- 100,0]).reshape(1,-1),10,2,np.array([0,100]).reshape(1,-1),10,2,np.array([7,3]).reshape(1,-1),'Discrete-Time Simulation')
xlabel('Input Level (dBFS)')
ylabel('SQNR (dB)')
peak_snr, peak_amp = peakSNR(snr, amp)
msg = 'peak SQNR = %4.1fdB \n@ amp = %4.1fdB ' % (peak_snr, peak_amp)
text(peak_amp-10, peak_snr, msg, horizontalalignment='right', verticalalignment='center');
msg = 'OSR = %d ' % osr
text(-2, 5, msg, horizontalalignment='right');
hold(False)
figureMagic([-80, 0], 10, None, [0, 80], 10, None, [12, 6], 'Time-Domain Simulations')
legend(loc=2);
Performed in two steps:
We call realizeNTF_ct
to realize an NTF with a continuous-time loop filter, obtaining ABCD matrix and DAC timings.
We map the synthesized NTF to a discrete-time equivalent. The criterion for equivalence is set in mapCtoD
: the sampled pulse response of the CT system must be identical to the impulse response of the DT system.
print 'Mapping to continuous-time... ',
ABCDc, tdac2 = realizeNTF_ct(ntf0, form, tdac)
Ac, Bc, Cc, Dc = partitionABCD(ABCDc)
sys_c = []
for i in range(Bc.shape[1]):
sys_c.append(ss2zpk(Ac, Bc, Cc, Dc, input=i))
print 'done.'
print 'ABCD matrix:'
print ABCDc
print "DAC timing (tdac2):"
print tdac2
Mapping to continuous-time... done. ABCD matrix: [[ 0. 0. 0. 0.04440879 -0.04440879] [ 1. 0. -0.00578297 0. -0.23997611] [ 0. 1. 0. 0. -0.67004646] [ 0. 0. 1. 0. 0. ]] DAC timing (tdac2): [[-1. -1.] [ 0. 1.]]
figure(figsize=plotsize)
n_imp = 10
y = -impL1(ntf0, n_imp)
lollipop(np.arange(n_imp + 1), y)
hold(True)
grid(True)
dt = 1./16
tppulse = np.vstack((np.zeros((1, 2)), tdac2[1:, :])).tolist()
yy = -pulse(sys_c, tppulse, dt, n_imp).squeeze()
t = np.linspace(0, n_imp + dt, 10/dt + 1)
plot(t, yy, 'g', label='continuous-time')
legend()
title('Loop filter pulse/impulse responses (negated)');
sys_d, Gp = mapCtoD(ABCDc, tdac2)
ABCD = np.vstack((
np.hstack((sys_d[0], sys_d[1])),
np.hstack((sys_d[2], sys_d[3]))
))
ntf, G = calculateTF(ABCD)
ntf = cancelPZ(ntf)
figure(figsize=plotsize)
DocumentNTF(ntf0, osr, f0)
subplot(121)
plotPZ(ntf, 'c', 10)
hold(True)
plotPZ(ntf0, 'k')
hold(False)
L0 = sys_c[0]
f = linspace(0, 0.5)
G = evalTFP(L0, ntf, f)
subplot(122)
hold(True)
plot(f, dbv(G), 'm')
hold(False)
title('NTF and STF');
<matplotlib.figure.Figure at 0xb008fa2c>
print 'Re-evaluating the SNR... ',
snrR, ampR = simulateSNR(ABCD, osr, None, f0, nlev)
print 'done'
Re-evaluating the SNR... done
figure(figsize=plotsize)
plot(ampR, snrR, 'o-')
hold(True)
plot(amp, snr, '-')
peak_snrR, peak_ampR = peakSNR(snrR, ampR)
msg = 'Peak SNR %.1fdB at amp = %-.1fdB' % (peak_snrR, peak_ampR)
text(peak_ampR - 10, peak_snrR, msg, horizontalalignment='right', verticalalignment='center');
figureMagic([-100, 0], 10, 1, [0, 100], 10, 1, None,'SQNR vs. Input Amplitude')
xlabel('Input Amplitude (dBFS)')
ylabel('SNR (dB)')
title('Continuous-Time Implementation');
print 'Doing dynamic range scaling... ',
ABCDs, umax, S = scaleABCD(ABCD, nlev, f0, 1, None, None, 10000.0)
S = S[:order, :order]
Sinv = inv(S)
Acs = np.dot(np.dot(S, Ac), Sinv)
Bcs = np.dot(S, Bc)
Ccs = np.dot(Cc, Sinv)
ABCDcs = np.vstack((np.hstack((Acs, Bcs)),
np.hstack((Ccs, Dc))
))
sys_cs = (Acs, Bcs, Ccs, Dc)
print 'Done.'
print "During scaling, umax was found to be %g"% umax
print "Scaled ABCD matrix:"
print ABCDcs
Doing dynamic range scaling... Done. During scaling, umax was found to be 0.78 Scaled ABCD matrix: [[ 0. 0. 0. 0.16352917 -0.16352917] [ 0.29968154 0. -0.01756686 0. -0.26482215] [ 0. 0.32919785 0. 0. -0.24341548] [ 0. 0. 2.75268628 0. 0. ]]
The ADC parameters were found to be:
adc = {
'order':order,
'osr':osr,
'M':M,
'f0':f0,
'ntf':ntf,
'ABCD':ABCD,
'umax':umax,
'peak_snr':peak_snr,
'form':form,
'ABCDc':ABCDc,
'tdac':tdac,
'tdac2':tdac2,
'L0':L0,
'sys_c':sys_c,
'ABCDcs':ABCDcs,
'sys_cs':sys_cs
}
for k in sort(adc.keys()):
print "%s:" % k,
if str(adc[k]).count('\n'):
print ""
print adc[k]
ABCD: [[ 1. 0. 0. 0.04440879 -0.04440879] [ 0.99903645 0.99710991 -0.0057774 0.0221937 -0.26000208] [ 0.49975909 0.99903645 0.99710991 0.00739932 -0.79673041] [ 0. 0. 1. 0. 0. ]] ABCDc: [[ 0. 0. 0. 0.04440879 -0.04440879] [ 1. 0. -0.00578297 0. -0.23997611] [ 0. 1. 0. 0. -0.67004646] [ 0. 0. 1. 0. 0. ]] ABCDcs: [[ 0. 0. 0. 0.16352917 -0.16352917] [ 0.29968154 0. -0.01756686 0. -0.26482215] [ 0. 0.32919785 0. 0. -0.24341548] [ 0. 0. 2.75268628 0. 0. ]] L0: (array([], dtype=float64), array([-0.+0.07604585j, 0.-0.07604585j, 0.+0.j ]), 0.044408788405152069) M: 1 f0: 0.0 form: FB ntf: (array([ 0.99710991+0.07597258j, 0.99710991-0.07597258j, 1.00000000+0.j ]), array([ 0.76451468+0.28005204j, 0.76451468-0.28005204j, 0.66846004+0.j ]), 1.0) order: 3 osr: 32 peak_snr: [[ 70.50168227]] sys_c: [(array([], dtype=float64), array([-0.+0.07604585j, 0.-0.07604585j, 0.+0.j ]), 0.044408788405152069), (array([-0.17907423+0.18495837j, -0.17907423-0.18495837j]), array([-0.+0.07604585j, 0.-0.07604585j, 0.+0.j ]), -0.67004646290976189)] sys_cs: (array([[ 0. , 0. , 0. ], [ 0.29968154, 0. , -0.01756686], [ 0. , 0.32919785, 0. ]]), array([[ 0.16352917, -0.16352917], [ 0. , -0.26482215], [ 0. , -0.24341548]]), array([[ 0. , 0. , 2.75268628]]), array([[ 0., 0.]])) tdac: [0, 1] tdac2: [[-1. -1.] [ 0. 1.]] umax: 0.78
#%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py
%load_ext version_information
%reload_ext version_information
%version_information numpy, scipy, matplotlib, deltasigma
Software | Version |
---|---|
Python | 2.7.7 (default, Jun 3 2014, 23:36:29) [GCC 4.8.2] |
IPython | 2.1.0 |
OS | posix [linux2] |
numpy | 1.8.1 |
scipy | 0.14.0 |
matplotlib | 1.3.1 |
deltasigma | 0.1-4 |
Tue Jun 24 18:05:55 2014 CEST |