CalcGM_Noise_LMU_multipleFiles.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Oct 05 15:49:46 2018
  4. @author: aemdlabs
  5. """
  6. from PhyREC.NeoInterface import NeoSegment#, ReadMCSFile
  7. import PhyREC.SignalAnalysis as Ran
  8. import PhyREC.PlotWaves as Rplt
  9. import quantities as pq
  10. import matplotlib.pyplot as plt
  11. import numpy as np
  12. import neo
  13. import deepdish as dd
  14. import csv
  15. from datetime import datetime
  16. from scipy import integrate
  17. def ReadMCSFile(McsFile, OutSeg=None, SigNamePrefix=''):
  18. import McsPy.McsData as McsData
  19. Dat = McsData.RawData(McsFile)
  20. Rec = Dat.recordings[0]
  21. NSamps = Rec.duration
  22. if OutSeg is None:
  23. OutSeg = NeoSegment()
  24. for AnaStrn, AnaStr in Rec.analog_streams.iteritems():
  25. if len(AnaStr.channel_infos) == 1:
  26. continue
  27. for Chn, Chinfo in AnaStr.channel_infos.iteritems():
  28. print 'Analog Stream ', Chinfo.label, Chinfo.sampling_frequency
  29. ChName = str(SigNamePrefix + Chinfo.label)
  30. print ChName
  31. Fs = Chinfo.sampling_frequency
  32. Var, Unit = AnaStr.get_channel_in_range(Chn, 0, NSamps)
  33. sig = neo.AnalogSignal(pq.Quantity(Var, Chinfo.info['Unit']),
  34. t_start=0*pq.s,
  35. sampling_rate=Fs.magnitude*pq.Hz,
  36. name=ChName)
  37. OutSeg.AddSignal(sig)
  38. return OutSeg
  39. def ReadLogFile(File):
  40. Fin = open(File)
  41. reader = csv.reader(Fin, delimiter='\t')
  42. LogVals = {}
  43. ValsPos = {}
  44. for il, e in enumerate(reader):
  45. if il == 0:
  46. for ih, v in enumerate(e):
  47. ValsPos[ih] = v
  48. LogVals[v] = []
  49. else:
  50. for ih, v in enumerate(e):
  51. par = ValsPos[ih]
  52. if (par=='Vgs') or (par=='Vds') or (par=='Vref'):
  53. LogVals[par].append(float(v.replace(',','.')))
  54. elif par == 'Date/Time':
  55. LogVals[par].append(datetime.strptime(v, '%d/%m/%Y %H:%M:%S'))
  56. else:
  57. LogVals[par].append(v)
  58. deltas = np.array(LogVals['Date/Time'])[:]-LogVals['Date/Time'][0]
  59. LogVals['Time'] = []
  60. for d in deltas:
  61. LogVals['Time'].append(d.total_seconds())
  62. Fin.close()
  63. return LogVals
  64. def GetSwitchTimes(Sig, Thres=-1e-4, Plot=True):
  65. s = Sig.GetSignal(None)
  66. ds = np.abs(np.diff(np.array(s), axis=0))
  67. if Plot:
  68. plt.figure()
  69. plt.plot(s.times, s)
  70. plt.plot(s.times[1:], ds)
  71. ds = Sig.duplicate_with_new_array(signal=ds)
  72. Times = Ran.threshold_detection(ds,
  73. threshold=Thres,
  74. RelaxTime=5*pq.s)
  75. return Times
  76. def MeanStd(Data, var):
  77. Arr = np.zeros([len(Data.keys()),len(Data[Data.keys()[0]][var])])
  78. for iT,TrtName in enumerate(Data.keys()):
  79. Arr[iT,:] = Data[TrtName][var][:,0]
  80. return np.mean(Arr,0), np.std(Arr,0)
  81. def MeanStdGM(Data):
  82. Arr = np.zeros([len(Data.keys()),len(Data[Data.keys()[0]])])
  83. for iT,TrtName in enumerate(Data.keys()):
  84. Arr[iT,:] = Data[TrtName]
  85. return np.mean(Arr,0), np.std(Arr,0)
  86. def Integrate(PSD, Freqs, Fmin, Fmax):
  87. indices = np.where((Freqs >= Fmin) & (Freqs<=Fmax))
  88. print( Freqs[indices])
  89. Irms = np.sqrt(integrate.trapz(PSD[indices], Freqs[indices]))
  90. return Irms
  91. MCSMapI={'SE1':'Ch03',
  92. 'SE2':'Ch05',
  93. 'SE3':'Ch01',
  94. 'SE4':'Ch02',
  95. 'SE5':'Ch22',
  96. 'SE6':'Ch06',
  97. 'SE7':'Ch16',
  98. 'SE8':'Ch37',
  99. 'SE9':'Ch20',
  100. 'SE10':'Ch10',
  101. 'SE11':'Ch24',
  102. 'SE12':'Ch08',
  103. 'SE13':'Ch14',
  104. 'SE14':'Ch04',
  105. 'SE15':'Ch18',
  106. 'SE16':'Ch33',
  107. 'SE17':'Ch34',
  108. 'SE18':'Ch60',
  109. 'SE19':'Ch38',
  110. 'SE20':'Ch64',
  111. 'SE21':'Ch40',
  112. 'SE22':'Ch56',
  113. 'SE23':'Ch42',
  114. 'SE24':'Ch70',
  115. 'SE25':'Ch66',
  116. 'SE26':'Ch65',
  117. 'SE27':'Ch68',
  118. 'SE28':'Ch67',
  119. 'SE29':'Ch55',
  120. 'SE30':'Ch62',
  121. 'SE31':'Ch58',
  122. 'SE32':'Ch69',
  123. 'ME1':'Ch57',
  124. 'ME2':'Ch61',
  125. 'ME3':'Ch53',
  126. 'ME4':'Ch63',
  127. 'ME5':'Ch52',
  128. 'ME6':'Ch41',
  129. 'ME7':'Ch49',
  130. 'ME8':'Ch51',
  131. 'ME9':'Ch46',
  132. 'ME10':'Ch45',
  133. 'ME11':'Ch44',
  134. 'ME12':'Ch39',
  135. 'ME13':'Ch54',
  136. 'ME14':'Ch43',
  137. 'ME15':'Ch50',
  138. 'ME16':'Ch47',
  139. 'ME17':'Ch32',
  140. 'ME18':'Ch27',
  141. 'ME19':'Ch30',
  142. 'ME20':'Ch29',
  143. 'ME21':'Ch28',
  144. 'ME22':'Ch25',
  145. 'ME23':'Ch26',
  146. 'ME24':'Ch07',
  147. 'ME25':'Ch21',
  148. 'ME26':'Ch11',
  149. 'ME27':'Ch17',
  150. 'ME28':'Ch15',
  151. 'ME29':'Ch13',
  152. 'ME30':'Ch31',
  153. 'ME31':'Ch19',
  154. 'ME32':'Ch09'}
  155. #Col, Row
  156. MCSMapFacingDown={'Ch58':(0,1),
  157. 'Ch57':(0,2),
  158. 'Ch56':(0,3),
  159. 'Ch55':(0,4),
  160. 'Ch54':(0,5),
  161. 'Ch53':(0,6),
  162. 'Ch52':(0,7),
  163. 'Ch51':(0,8),
  164. 'Ch50':(0,9),
  165. 'Ch49':(0,10),
  166. 'Ch60':(1,0),
  167. 'Ch61':(1,1),
  168. 'Ch62':(1,2),
  169. 'Ch63':(1,3),
  170. 'Ch64':(1,4),
  171. 'Ch65':(1,5),
  172. 'Ch43':(1,6),
  173. 'Ch44':(1,7),
  174. 'Ch45':(1,8),
  175. 'Ch46':(1,9),
  176. 'Ch47':(1,10),
  177. 'Ch70':(2,0),
  178. 'Ch69':(2,1),
  179. 'Ch68':(2,2),
  180. 'Ch67':(2,3),
  181. 'Ch66':(2,4),
  182. 'Ch42':(2,5),
  183. 'Ch41':(2,6),
  184. 'Ch40':(2,7),
  185. 'Ch39':(2,8),
  186. 'Ch38':(2,9),
  187. 'Ch37':(2,10),
  188. 'Ch01':(3,0),
  189. 'Ch02':(3,1),
  190. 'Ch03':(3,2),
  191. 'Ch04':(3,3),
  192. 'Ch05':(3,4),
  193. 'Ch06':(3,5),
  194. 'Ch30':(3,6),
  195. 'Ch31':(3,7),
  196. 'Ch32':(3,8),
  197. 'Ch33':(3,9),
  198. 'Ch34':(3,10),
  199. 'Ch11':(4,0),
  200. 'Ch10':(4,1),
  201. 'Ch09':(4,2),
  202. 'Ch08':(4,3),
  203. 'Ch07':(4,4),
  204. 'Ch29':(4,5),
  205. 'Ch28':(4,6),
  206. 'Ch27':(4,7),
  207. 'Ch26':(4,8),
  208. 'Ch25':(4,9),
  209. 'Ch24':(4,10),
  210. 'Ch12':None,
  211. 'Ch59':None,
  212. 'Ch13':(5,1),
  213. 'Ch14':(5,2),
  214. 'Ch15':(5,3),
  215. 'Ch16':(5,4),
  216. 'Ch17':(5,5),
  217. 'Ch18':(5,6),
  218. 'Ch19':(5,7),
  219. 'Ch20':(5,8),
  220. 'Ch21':(5,9),
  221. 'Ch22':(5,10)}
  222. if __name__ == '__main__':
  223. Path = 'C:/Users/RGarcia1/Dropbox (ICN2 AEMD - GAB GBIO)/TeamFolderLMU/Wireless/Characterization/'
  224. Files = [
  225. '28062019/B12142O30-T4/2019-06-29T17-07-11B12142O30-T4-1mVVgsSweep-ICN2-2',
  226. '28062019/B12142O37-T2/2019-06-29T18-00-36B12142O37-T2-1mVVgsSweep-ICN2-PostEthx2-Pt',
  227. '03072019/B12142O37-T5/2019-07-03T09-55-56B12142O37-T5-ACDC-1mVsine-Pt-PostEth',
  228. '03072019/B12142O37-T6/2019-07-03T10-18-36B12142O37-T6-ACDC-1mVsine-Pt-PostEth',
  229. '03072019/B12142O30-T6/2019-07-03T08-31-00B12142O30-T6-ACDC-1mVsine-Pt-PostEth',
  230. '03072019/B12142O30-T9/2019-07-03T10-43-12B12142O30-T9-ACDC-1mVsine-Pt-PostEth',
  231. '04072019/B12784O18-T1/2019-07-05T08-04-13B12784O18-T1-1mVVgsSweep-PostEth-ICN2',
  232. '23072019/B12784O18-T2/2019-07-23T16-18-20B12784O18-T2-ACDC-PostEth-1mV_2',
  233. '23072019/B12784O18-T3/2019-07-23T18-55-56B12784O18-T3-ACDC-PostEth-PostLong',]############
  234. LogFiles = [
  235. '28062019/B12142O30-T4/B12142O30-T4-PreEth-ACDC1mV-AgAgCl-2.txt',
  236. '28062019/B12142O37-T2/B12142O37-T2-ACDC-PostEthx2-Pt.txt',
  237. '03072019/B12142O37-T5/B12142O37-T5-ACDC-Pt-PostEth.txt',
  238. '03072019/B12142O37-T6/B12142O37-T6-ACDC-Pt-PostEth.txt',
  239. '03072019/B12142O30-T6/B12142O30-T6_Pt_PostEth-ACDC.txt',
  240. '03072019/B12142O30-T9/B12142o30-T9-ACDC-Pt-PostEth.txt',
  241. '04072019/B12784O18-T1/B12784O18-T1-ACdc-postTH.txt',
  242. '23072019/B12784O18-T2/B12784O18-T2-ACDC-PostEth_Cy2.txt',
  243. '23072019/B12784O18-T3/B12784O18-T3-ACDC-PostEth-PostLong.txt']
  244. UrmsTot = {}
  245. IrmsTot = {}
  246. GmTot = {}
  247. IdsTot = {}
  248. VGS = {}
  249. for iFile, File in enumerate(Files):
  250. StartCycle = -1
  251. LogFile = Path + LogFiles[iFile]
  252. InFileM = Path + File + '.h5'
  253. InFileS = Path + File + '_2.h5'
  254. LogVals = ReadLogFile(LogFile)
  255. delta = np.mean([t-LogVals['Time'][it] for it, t in enumerate(LogVals['Time'][1:])])*pq.s
  256. Delay = delta * StartCycle
  257. DCch = ('ME5', 'ME7', 'ME29', 'ME31', 'SE5', 'SE7', 'SE29', 'SE31')
  258. TrigChannel = 'SE29'
  259. TrigThres = 5e-5
  260. Vgs = np.array(LogVals['Vgs'])
  261. Vds = LogVals['Vds'][0]
  262. VGS[File] = Vgs
  263. ivgain1 = 12e3*pq.V
  264. ivgain2 = 101
  265. ACgain = 10*1
  266. DCgain = 1*pq.V
  267. Fsig = 10
  268. StabTime = 10*pq.s
  269. GuardTime = 1*pq.s
  270. BW = 100
  271. ivgainDC = 118.8*pq.V #the gain (1e6) is already applied to the saved signal ## Check this gain
  272. ivgainAC = 1188*pq.V
  273. Rec = ReadMCSFile(InFileM,
  274. OutSeg=None,
  275. SigNamePrefix='M')
  276. Rec = ReadMCSFile(InFileS,
  277. OutSeg=Rec,
  278. SigNamePrefix='S')
  279. # %% Detect Vgs switch time and arrange DC signals into SlotsDC
  280. plt.close('all')
  281. plt.ion()
  282. SwTimes = GetSwitchTimes(Sig=Rec.GetSignal(TrigChannel),
  283. Thres=TrigThres,
  284. Plot=False)
  285. SlotsDC = []
  286. for sig in Rec.Signals():
  287. if sig.name not in DCch:
  288. continue
  289. SlotsDC.append(Rplt.WaveSlot(sig,))
  290. SwTimes = LogVals['Time']*pq.s+SwTimes[0]+Delay
  291. #%% calc IV DC
  292. DevDCVals = {}
  293. Ids = {}
  294. for sl in SlotsDC:
  295. Ids[sl.name] = []
  296. for isw, (t, vg) in enumerate(zip(SwTimes, Vgs)):
  297. ts = SwTimes[isw]+delta
  298. TWind = (t+StabTime, ts-GuardTime)
  299. s = sl.GetSignal(TWind, Units='V')
  300. vio = np.mean(s).magnitude
  301. ids = (vio*101-(-vg+Vds))/12e3 #apply hardware gain calibration
  302. Ids[sl.name].append(ids)
  303. IdsTot[File.split('/')[1]] = Ids
  304. #%% Calc GM and integrated noise Irms
  305. GM = {}
  306. Irms = {}
  307. Urms = {}
  308. fig, (AxPsd, Axt) = plt.subplots(2,1)
  309. fig2, (AxPs, Axt) = plt.subplots(2,1)
  310. for sig in Rec.Signals():
  311. if sig.name[0:3] == 'SEn': #discard encoder channels
  312. continue
  313. GM[sig.name] = []
  314. Irms[sig.name] = []
  315. Urms[sig.name] = []
  316. for isw, (t, vg) in enumerate(zip(SwTimes, Vgs)):
  317. if isw == len(SwTimes)-1:
  318. ts = sl.Signal.t_stop
  319. else:
  320. ts = SwTimes[isw+1]
  321. TWind = (t+StabTime, ts-GuardTime)
  322. s = sig.GetSignal(TWind, Units ='V')
  323. if s.name in DCch:
  324. s = (s*ivgain2-(-vg+Vds)*pq.V)/ivgain1
  325. else:
  326. s = s/(ivgain1*ACgain/ivgain2)
  327. PS = Ran.PlotPSD((s,),
  328. Time = TWind,
  329. Ax=AxPs,
  330. FMin=1,
  331. Label=str(vg),
  332. scaling='spectrum')
  333. ps = PS[sig.name]['psd']
  334. Fps = PS[sig.name]['ff']
  335. indicesPeak = np.where( ((Fps >= Fsig-4) & (Fps<=Fsig+4)))
  336. IDSpeak = np.sqrt(ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]]+
  337. ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]+1]+
  338. ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]-1])
  339. gm = IDSpeak*1000/0.707
  340. GM[sig.name] = np.append(GM[sig.name],gm)
  341. PSD = Ran.PlotPSD((s,),
  342. Time = TWind,
  343. Ax=AxPsd,
  344. FMin=1,
  345. Label=str(vg),
  346. scaling='density')
  347. psd = PSD[sig.name]['psd'][:,0]
  348. Fpsd = PSD[sig.name]['ff']
  349. irms = Integrate(psd, Fpsd, 1.9, 1.9*3.3)
  350. Irms[sig.name] = np.append(Irms[sig.name],irms*2) #
  351. # square root of 2 adjusts the 1/f integrated noise to a 1 order of magnitude frequency range
  352. Irms[sig.name] = Irms[sig.name]
  353. Urms[sig.name] = Irms[sig.name]/GM[sig.name]
  354. plt.close('all') #close psd figures created
  355. UrmsTot[File.split('/')[1]] = Urms
  356. IrmsTot[File.split('/')[1]] = Irms
  357. GmTot[File.split('/')[1]] = GM
  358. plt.figure()
  359. GMmean, GMstd = MeanStdGM(GM)
  360. plt.plot(Vgs-0.70, GMmean*1000/0.1,'k',label = '1 metal layer')
  361. plt.fill_between(Vgs-0.70, GMmean*1000/0.1-GMstd*1000/0.1, GMmean*1000/0.1+GMstd*1000/0.1,color = 'k',alpha =0.3)
  362. plt.xlabel('V$_{gs}$ - V$_{CNP}$ (V)')
  363. plt.ylabel('G$_m$ (mS/V)')
  364. plt.legend()
  365. plt.figure()
  366. IrmsMean, IrmsStd = MeanStdGM(Irms)
  367. plt.semilogy(Vgs-0.70, IrmsMean,'k',label = 'rms')
  368. plt.fill_between(Vgs-0.70, IrmsMean-IrmsStd, IrmsMean+IrmsStd ,color = 'k',alpha =0.3)
  369. plt.figure()
  370. UrmsMean, UrmsStd = MeanStdGM(Urms)
  371. plt.semilogy(Vgs-0.70, UrmsMean,'k',label = '1 metal layer')
  372. plt.fill_between(Vgs-0.70, UrmsMean-UrmsStd, UrmsMean+UrmsStd ,color = 'k',alpha =0.3)
  373. plt.xlabel('V$_{gs}$ - V$_{CNP}$ (V)')
  374. plt.ylabel('U$_{rms}$ (A)')
  375. plt.legend()
  376. dd.io.save('GmIrmsUrmsIds10Probe_2.h5',(GmTot, IrmsTot, UrmsTot, IdsTot))
  377. #%% plot map Urms
  378. plt.figure()
  379. A=np.log10(np.ones((11,6))*5e-17)
  380. import matplotlib.colors as colors
  381. for Trt in Urms.keys():
  382. ch = MCSMapI[Trt]
  383. A[MCSMapFacingDown[ch][1],MCSMapFacingDown[ch][0]] = (Urms[Trt][9])*1e6
  384. plt.imshow(A, interpolation='nearest', vmin=3, vmax=30, norm=colors.LogNorm(vmin=3, vmax=30))
  385. plt.grid(True)
  386. cbar=plt.colorbar()
  387. plt.xlabel('column',fontsize=12)
  388. plt.ylabel('row',fontsize=12)
  389. cbar.set_label('U$_{gs-rms}$ ($\mu$V)', rotation=270, labelpad=15,fontsize=13)
  390. #%% plot map Gm
  391. plt.figure()
  392. A=np.log10(np.ones((11,6))*5e-17)
  393. import matplotlib.colors as colors
  394. for Trt in Urms.keys():
  395. ch = MCSMapI[Trt]
  396. A[MCSMapFacingDown[ch][1], MCSMapFacingDown[ch][0]] = (GM[Trt][9]*1000/0.1)
  397. plt.imshow(A, interpolation='nearest', vmin=1, vmax=3, norm=colors.LogNorm(vmin=1, vmax=3))
  398. plt.grid(True)
  399. cbar=plt.colorbar()
  400. plt.xlabel('column',fontsize=12)
  401. plt.ylabel('row',fontsize=12)
  402. cbar.set_label('G$_{m}$ (mS/V)', rotation=270, labelpad=15,fontsize=13)