Christophe Favergeon | 53f828f | 2019-03-25 13:42:44 +0100 | [diff] [blame] | 1 | import cmsisdsp as dsp |
| 2 | import numpy as np |
| 3 | from scipy import signal |
| 4 | from pylab import figure, clf, plot, xlabel, ylabel, xlim, ylim, title, grid, axes, show,semilogx, semilogy |
| 5 | # Data file from https://www.physionet.org/pn3/ecgiddb/Person_87/rec_2.dat |
| 6 | |
| 7 | def q31sat(x): |
| 8 | if x > 0x7FFFFFFF: |
| 9 | return(np.int32(0x7FFFFFFF)) |
| 10 | elif x < -0x80000000: |
| 11 | return(np.int32(0x80000000)) |
| 12 | else: |
| 13 | return(np.int32(x)) |
| 14 | |
| 15 | q31satV=np.vectorize(q31sat) |
| 16 | |
| 17 | def toQ31(x): |
| 18 | return(q31satV(np.round(x * (1<<31)))) |
| 19 | |
| 20 | def Q31toF32(x): |
| 21 | return(1.0*x / 2**31) |
| 22 | |
| 23 | filename = 'rec_2.dat' |
| 24 | |
| 25 | f = open(filename,"r") |
| 26 | sig = np.fromfile(f, dtype=np.int16) |
| 27 | f.closed |
| 28 | |
| 29 | sig = 1.0*sig / (1 << 12) |
| 30 | |
| 31 | |
| 32 | p0 = np.exp(1j*0.05) * 0.98 |
| 33 | p1 = np.exp(1j*0.25) * 0.9 |
| 34 | p2 = np.exp(1j*0.45) * 0.97 |
| 35 | |
| 36 | z0 = np.exp(1j*0.02) |
| 37 | z1 = np.exp(1j*0.65) |
| 38 | z2 = np.exp(1j*1.0) |
| 39 | |
| 40 | g = 0.02 |
| 41 | |
| 42 | nb = 300 |
| 43 | |
| 44 | sos = signal.zpk2sos( |
| 45 | [z0,np.conj(z0),z1,np.conj(z1),z2,np.conj(z2)] |
| 46 | ,[p0, np.conj(p0),p1, np.conj(p1),p2, np.conj(p2)] |
| 47 | ,g) |
| 48 | |
| 49 | res=signal.sosfilt(sos,sig) |
| 50 | figure() |
| 51 | plot(sig[1:nb]) |
| 52 | figure() |
| 53 | plot(res[1:nb]) |
| 54 | |
| 55 | |
| 56 | |
| 57 | |
| 58 | biquadQ31 = dsp.arm_biquad_casd_df1_inst_q31() |
| 59 | numStages=3 |
| 60 | state=np.zeros(numStages*4) |
| 61 | # For use in CMSIS, denominator coefs must be negated |
| 62 | # and first a0 coef wihich is always 1 must be removed |
| 63 | coefs=np.reshape(np.hstack((sos[:,:3],-sos[:,4:])),15) |
| 64 | coefs = coefs / 4.0 |
| 65 | coefsQ31 = toQ31(coefs) |
| 66 | postshift = 2 |
| 67 | dsp.arm_biquad_cascade_df1_init_q31(biquadQ31,numStages,coefsQ31,state,postshift) |
| 68 | sigQ31=toQ31(sig) |
| 69 | nbSamples=sigQ31.shape[0] |
| 70 | # Here we demonstrate how we can process a long sequence of samples per block |
| 71 | # and thus check that the state of the biquad is well updated and preserved |
| 72 | # between the calls. |
Christophe Favergeon | 4128fac | 2019-03-26 09:29:06 +0100 | [diff] [blame^] | 73 | half = int(round(nbSamples / 2)) |
Christophe Favergeon | 53f828f | 2019-03-25 13:42:44 +0100 | [diff] [blame] | 74 | res2a=dsp.arm_biquad_cascade_df1_q31(biquadQ31,sigQ31[1:half]) |
| 75 | res2b=dsp.arm_biquad_cascade_df1_q31(biquadQ31,sigQ31[half+1:nbSamples]) |
| 76 | res2=Q31toF32(np.hstack((res2a,res2b))) |
| 77 | figure() |
| 78 | plot(res2[1:nb]) |
| 79 | show()# |