CalcGM_Noise_LMU_multipleFiles.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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. Files = [
  224. 'B12142O30-T4/2019-06-29T17-07-11B12142O30-T4-1mVVgsSweep-ICN2-2',
  225. 'B12142O37-T2/2019-06-29T18-00-36B12142O37-T2-1mVVgsSweep-ICN2-PostEthx2-Pt',
  226. 'B12142O37-T5/2019-07-03T09-55-56B12142O37-T5-ACDC-1mVsine-Pt-PostEth',
  227. 'B12142O37-T6/2019-07-03T10-18-36B12142O37-T6-ACDC-1mVsine-Pt-PostEth',
  228. 'B12142O30-T6/2019-07-03T08-31-00B12142O30-T6-ACDC-1mVsine-Pt-PostEth',
  229. 'B12142O30-T9/2019-07-03T10-43-12B12142O30-T9-ACDC-1mVsine-Pt-PostEth',
  230. 'B12784O18-T1/2019-07-05T08-04-13B12784O18-T1-1mVVgsSweep-PostEth-ICN2',
  231. 'B12784O18-T2/2019-07-23T16-18-20B12784O18-T2-ACDC-PostEth-1mV_2',
  232. 'B12784O18-T3/2019-07-23T18-55-56B12784O18-T3-ACDC-PostEth-PostLong',]############
  233. LogFiles = [
  234. 'B12142O30-T4/B12142O30-T4-PreEth-ACDC1mV-AgAgCl-2.txt',
  235. 'B12142O37-T2/B12142O37-T2-ACDC-PostEthx2-Pt.txt',
  236. 'B12142O37-T5/B12142O37-T5-ACDC-Pt-PostEth.txt',
  237. 'B12142O37-T6/B12142O37-T6-ACDC-Pt-PostEth.txt',
  238. 'B12142O30-T6/B12142O30-T6_Pt_PostEth-ACDC.txt',
  239. 'B12142O30-T9/B12142o30-T9-ACDC-Pt-PostEth.txt',
  240. 'B12784O18-T1/B12784O18-T1-ACdc-postTH.txt',
  241. 'B12784O18-T2/B12784O18-T2-ACDC-PostEth_Cy2.txt',
  242. 'B12784O18-T3/B12784O18-T3-ACDC-PostEth-PostLong.txt']
  243. UrmsTot = {}
  244. IrmsTot = {}
  245. GmTot = {}
  246. IdsTot = {}
  247. VGS = {}
  248. for iFile, File in enumerate(Files):
  249. StartCycle = -1
  250. LogFile = LogFiles[iFile]
  251. InFileM = File + '.h5'
  252. InFileS = File + '_2.h5'
  253. LogVals = ReadLogFile(LogFile)
  254. delta = np.mean([t-LogVals['Time'][it] for it, t in enumerate(LogVals['Time'][1:])])*pq.s
  255. Delay = delta * StartCycle
  256. DCch = ('ME5', 'ME7', 'ME29', 'ME31', 'SE5', 'SE7', 'SE29', 'SE31')
  257. TrigChannel = 'SE29'
  258. TrigThres = 5e-5
  259. Vgs = np.array(LogVals['Vgs'])
  260. Vds = LogVals['Vds'][0]
  261. VGS[File] = Vgs
  262. ivgain1 = 12e3*pq.V
  263. ivgain2 = 101
  264. ACgain = 10*1
  265. DCgain = 1*pq.V
  266. Fsig = 10
  267. StabTime = 10*pq.s
  268. GuardTime = 1*pq.s
  269. BW = 100
  270. ivgainDC = 118.8*pq.V #the gain (1e6) is already applied to the saved signal ## Check this gain
  271. ivgainAC = 1188*pq.V
  272. Rec = ReadMCSFile(InFileM,
  273. OutSeg=None,
  274. SigNamePrefix='M')
  275. Rec = ReadMCSFile(InFileS,
  276. OutSeg=Rec,
  277. SigNamePrefix='S')
  278. # %% Detect Vgs switch time and arrange DC signals into SlotsDC
  279. plt.close('all')
  280. plt.ion()
  281. SwTimes = GetSwitchTimes(Sig=Rec.GetSignal(TrigChannel),
  282. Thres=TrigThres,
  283. Plot=False)
  284. SlotsDC = []
  285. for sig in Rec.Signals():
  286. if sig.name not in DCch:
  287. continue
  288. SlotsDC.append(Rplt.WaveSlot(sig,))
  289. SwTimes = LogVals['Time']*pq.s+SwTimes[0]+Delay
  290. #%% calc IV DC
  291. DevDCVals = {}
  292. Ids = {}
  293. for sl in SlotsDC:
  294. Ids[sl.name] = []
  295. for isw, (t, vg) in enumerate(zip(SwTimes, Vgs)):
  296. ts = SwTimes[isw]+delta
  297. TWind = (t+StabTime, ts-GuardTime)
  298. s = sl.GetSignal(TWind, Units='V')
  299. vio = np.mean(s).magnitude
  300. ids = (vio*101-(-vg+Vds))/12e3 #apply hardware gain calibration
  301. Ids[sl.name].append(ids)
  302. IdsTot[File.split('/')[1]] = Ids
  303. #%% Calc GM and integrated noise Irms
  304. GM = {}
  305. Irms = {}
  306. Urms = {}
  307. fig, (AxPsd, Axt) = plt.subplots(2,1)
  308. fig2, (AxPs, Axt) = plt.subplots(2,1)
  309. for sig in Rec.Signals():
  310. if sig.name[0:3] == 'SEn': #discard encoder channels
  311. continue
  312. GM[sig.name] = []
  313. Irms[sig.name] = []
  314. Urms[sig.name] = []
  315. for isw, (t, vg) in enumerate(zip(SwTimes, Vgs)):
  316. if isw == len(SwTimes)-1:
  317. ts = sl.Signal.t_stop
  318. else:
  319. ts = SwTimes[isw+1]
  320. TWind = (t+StabTime, ts-GuardTime)
  321. s = sig.GetSignal(TWind, Units ='V')
  322. if s.name in DCch:
  323. s = (s*ivgain2-(-vg+Vds)*pq.V)/ivgain1
  324. else:
  325. s = s/(ivgain1*ACgain/ivgain2)
  326. PS = Ran.PlotPSD((s,),
  327. Time = TWind,
  328. Ax=AxPs,
  329. FMin=1,
  330. Label=str(vg),
  331. scaling='spectrum')
  332. ps = PS[sig.name]['psd']
  333. Fps = PS[sig.name]['ff']
  334. indicesPeak = np.where( ((Fps >= Fsig-4) & (Fps<=Fsig+4)))
  335. IDSpeak = np.sqrt(ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]]+
  336. ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]+1]+
  337. ps[np.argmax(ps[indicesPeak])+indicesPeak[0][0]-1])
  338. gm = IDSpeak*1000/0.707
  339. GM[sig.name] = np.append(GM[sig.name],gm)
  340. PSD = Ran.PlotPSD((s,),
  341. Time = TWind,
  342. Ax=AxPsd,
  343. FMin=1,
  344. Label=str(vg),
  345. scaling='density')
  346. psd = PSD[sig.name]['psd'][:,0]
  347. Fpsd = PSD[sig.name]['ff']
  348. irms = Integrate(psd, Fpsd, 1.9, 1.9*3.3)
  349. Irms[sig.name] = np.append(Irms[sig.name],irms*2) #
  350. # square root of 2 adjusts the 1/f integrated noise to a 1 order of magnitude frequency range
  351. Irms[sig.name] = Irms[sig.name]
  352. Urms[sig.name] = Irms[sig.name]/GM[sig.name]
  353. plt.close('all') #close psd figures created
  354. UrmsTot[File.split('/')[1]] = Urms
  355. IrmsTot[File.split('/')[1]] = Irms
  356. GmTot[File.split('/')[1]] = GM
  357. plt.figure()
  358. GMmean, GMstd = MeanStdGM(GM)
  359. plt.plot(Vgs-0.70, GMmean*1000/0.1,'k',label = '1 metal layer')
  360. 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)
  361. plt.xlabel('V$_{gs}$ - V$_{CNP}$ (V)')
  362. plt.ylabel('G$_m$ (mS/V)')
  363. plt.legend()
  364. plt.figure()
  365. IrmsMean, IrmsStd = MeanStdGM(Irms)
  366. plt.semilogy(Vgs-0.70, IrmsMean,'k',label = 'rms')
  367. plt.fill_between(Vgs-0.70, IrmsMean-IrmsStd, IrmsMean+IrmsStd ,color = 'k',alpha =0.3)
  368. plt.figure()
  369. UrmsMean, UrmsStd = MeanStdGM(Urms)
  370. plt.semilogy(Vgs-0.70, UrmsMean,'k',label = '1 metal layer')
  371. plt.fill_between(Vgs-0.70, UrmsMean-UrmsStd, UrmsMean+UrmsStd ,color = 'k',alpha =0.3)
  372. plt.xlabel('V$_{gs}$ - V$_{CNP}$ (V)')
  373. plt.ylabel('U$_{rms}$ (A)')
  374. plt.legend()
  375. # dd.io.save('GmIrmsUrmsIds10Probe_2.h5',(GmTot, IrmsTot, UrmsTot, IdsTot))
  376. #%% plot map Urms
  377. plt.figure()
  378. A=np.log10(np.ones((11,6))*5e-17)
  379. import matplotlib.colors as colors
  380. for Trt in Urms.keys():
  381. ch = MCSMapI[Trt]
  382. A[MCSMapFacingDown[ch][1],MCSMapFacingDown[ch][0]] = (Urms[Trt][9])*1e6
  383. plt.imshow(A, interpolation='nearest', vmin=3, vmax=30, norm=colors.LogNorm(vmin=3, vmax=30))
  384. plt.grid(True)
  385. cbar=plt.colorbar()
  386. plt.xlabel('column',fontsize=12)
  387. plt.ylabel('row',fontsize=12)
  388. cbar.set_label('U$_{gs-rms}$ ($\mu$V)', rotation=270, labelpad=15,fontsize=13)
  389. #%% plot map Gm
  390. plt.figure()
  391. A=np.log10(np.ones((11,6))*5e-17)
  392. import matplotlib.colors as colors
  393. for Trt in Urms.keys():
  394. ch = MCSMapI[Trt]
  395. A[MCSMapFacingDown[ch][1], MCSMapFacingDown[ch][0]] = (GM[Trt][9]*1000/0.1)
  396. plt.imshow(A, interpolation='nearest', vmin=1, vmax=3, norm=colors.LogNorm(vmin=1, vmax=3))
  397. plt.grid(True)
  398. cbar=plt.colorbar()
  399. plt.xlabel('column',fontsize=12)
  400. plt.ylabel('row',fontsize=12)
  401. cbar.set_label('G$_{m}$ (mS/V)', rotation=270, labelpad=15,fontsize=13)