def rare_standalone( init_gpa=False, # Starts the gpa nScans=1, # NEX larmorFreq=3.08, # MHz, Larmor frequency rfExAmp=0.3, # a.u., rf excitation pulse amplitude rfReAmp=0.3, # a.u., rf refocusing pulse amplitude rfExTime=35, # us, rf excitation pulse time rfReTime=70, # us, rf refocusing pulse time echoSpacing=10, # ms, time between echoes preExTime=0., # ms, Time from preexcitation pulse to inversion pulse inversionTime=0., # ms, Inversion recovery time repetitionTime=200., # ms, TR fov=np.array([140., 150., 180.]), # mm, FOV along readout, phase and slice dfov=np.array([0., 0., 0.]), # mm, displacement of fov center nPoints=np.array([140, 80, 10]), # Number of points along readout, phase and slice etl=10, # Echo train length acqTime=4, # ms, acquisition time axes=np.array([2, 1, 0]), # 0->x, 1->y and 2->z defined as [rd,ph,sl] axesEnable=np.array([1, 1, 1]), # 1-> Enable, 0-> Disable sweepMode=1, # 0->k2k (T2), 1->02k (T1), 2->k20 (T2), 3->Niquist modulated (T2) rdGradTime=5, # ms, readout gradient time rdDephTime=2, # ms, readout dephasing time phGradTime=1, # ms, phase and slice dephasing time rdPreemphasis=1.00, # readout dephasing gradient is multiplied by this factor drfPhase=0, # degrees, phase of the excitation pulse dummyPulses=1, # number of dummy pulses for T1 stabilization shimming=np.array([-70, -90., 10]), # a.u.*1e4, shimming along the X,Y and Z axes parFourierFraction=1.0 # fraction of acquired k-space along phase direction ): freqCal = 1 # rawData fields rawData = {} # Conversion of variables to non-multiplied units larmorFreq = larmorFreq * 1e6 rfExTime = rfExTime * 1e-6 rfReTime = rfReTime * 1e-6 fov = np.array(fov) * 1e-3 dfov = np.array(dfov) * 1e-3 echoSpacing = echoSpacing * 1e-3 acqTime = acqTime * 1e-3 shimming = shimming * 1e-4 repetitionTime = repetitionTime * 1e-3 preExTime = preExTime * 1e-3 inversionTime = inversionTime * 1e-3 rdGradTime = rdGradTime * 1e-3 rdDephTime = rdDephTime * 1e-3 phGradTime = phGradTime * 1e-3 # Inputs for rawData rawData['seqName'] = 'RareBatches_Standalone' rawData['nScans'] = nScans rawData['larmorFreq'] = larmorFreq # Larmor frequency rawData['rfExAmp'] = rfExAmp # rf excitation pulse amplitude rawData['rfReAmp'] = rfReAmp # rf refocusing pulse amplitude rawData['rfExTime'] = rfExTime # rf excitation pulse time rawData['rfReTime'] = rfReTime # rf refocusing pulse time rawData['echoSpacing'] = echoSpacing # time between echoes rawData['preExTime'] = preExTime rawData['inversionTime'] = inversionTime # Inversion recovery time rawData['repetitionTime'] = repetitionTime # TR rawData['fov'] = fov # FOV along readout, phase and slice rawData['dfov'] = dfov # Displacement of fov center rawData[ 'nPoints'] = nPoints # Number of points along readout, phase and slice rawData['etl'] = etl # Echo train length rawData['acqTime'] = acqTime # Acquisition time rawData[ 'axesOrientation'] = axes # 0->x, 1->y and 2->z defined as [rd,ph,sl] rawData['axesEnable'] = axesEnable # 1-> Enable, 0-> Disable rawData[ 'sweepMode'] = sweepMode # 0->k2k (T2), 1->02k (T1), 2->k20 (T2), 3->Niquist modulated (T2) rawData['rdPreemphasis'] = rdPreemphasis rawData['drfPhase'] = drfPhase rawData['dummyPulses'] = dummyPulses # Dummy pulses for T1 stabilization rawData['parFourierFraction'] = parFourierFraction rawData['rdDephTime'] = rdDephTime rawData['shimming'] = shimming # Miscellaneous larmorFreq = larmorFreq * 1e-6 gradRiseTime = 400e-6 # Estimated gradient rise time gSteps = int(gradRiseTime * 1e6 / 5) * 0 + 1 addRdPoints = 10 # Initial rd points to avoid artifact at the begining of rd randFactor = 0e-3 # Random amplitude to add to the phase gradients if rfReAmp == 0: rfReAmp = rfExAmp if rfReTime == 0: rfReTime = 2 * rfExTime resolution = fov / nPoints rawData['resolution'] = resolution rawData['gradRiseTime'] = gradRiseTime rawData['randFactor'] = randFactor rawData['addRdPoints'] = addRdPoints # Matrix size nRD = nPoints[0] + 2 * addRdPoints nPH = nPoints[1] * axesEnable[1] + (1 - axesEnable[1]) nSL = nPoints[2] * axesEnable[2] + (1 - axesEnable[2]) # ETL if nPH = 1 if etl > nPH: etl = nPH # parAcqLines in case parAcqLines = 0 parAcqLines = int(int(nPoints[2] * parFourierFraction) - nPoints[2] / 2) rawData['partialAcquisition'] = parAcqLines # BW BW = nPoints[0] / acqTime * 1e-6 BWov = BW * hw.oversamplingFactor samplingPeriod = 1 / BWov rawData['bw'] = BW rawData['samplingPeriod'] = samplingPeriod # Readout gradient time if rdGradTime > 0 and rdGradTime < acqTime: rdGradTime = acqTime rawData['rdGradTime'] = rdGradTime # Phase and slice de- and re-phasing time if phGradTime == 0 or phGradTime > echoSpacing / 2 - rfExTime / 2 - rfReTime / 2 - 2 * gradRiseTime: phGradTime = echoSpacing / 2 - rfExTime / 2 - rfReTime / 2 - 2 * gradRiseTime rawData['phGradTime'] = phGradTime # Max gradient amplitude rdGradAmplitude = nPoints[0] / (hw.gammaB * fov[0] * acqTime) * axesEnable[0] phGradAmplitude = nPH / (2 * hw.gammaB * fov[1] * (phGradTime + gradRiseTime)) * axesEnable[1] slGradAmplitude = nSL / (2 * hw.gammaB * fov[2] * (phGradTime + gradRiseTime)) * axesEnable[2] rawData['rdGradAmplitude'] = rdGradAmplitude rawData['phGradAmplitude'] = phGradAmplitude rawData['slGradAmplitude'] = slGradAmplitude # Readout dephasing amplitude rdDephAmplitude = 0.5 * rdGradAmplitude * (gradRiseTime + rdGradTime) / ( gradRiseTime + rdDephTime) rawData['rdDephAmplitude'] = rdDephAmplitude # Phase and slice gradient vector phGradients = np.linspace(-phGradAmplitude, phGradAmplitude, num=nPH, endpoint=False) slGradients = np.linspace(-slGradAmplitude, slGradAmplitude, num=nSL, endpoint=False) # Now fix the number of slices to partailly acquired k-space nSL = (int(nPoints[2] / 2) + parAcqLines) * axesEnable[2] + (1 - axesEnable[2]) # Add random displacemnt to phase encoding lines for ii in range(nPH): if ii < np.ceil(nPH / 2 - nPH / 20) or ii > np.ceil(nPH / 2 + nPH / 20): phGradients[ii] = phGradients[ii] + randFactor * np.random.randn() kPH = hw.gammaB * phGradients * (gradRiseTime + phGradTime) rawData['phGradients'] = phGradients rawData['slGradients'] = slGradients # Set phase vector to given sweep mode ind = mri.getIndex(etl, nPH, sweepMode) rawData['sweepOrder'] = ind phGradients = phGradients[ind] def createSequence(): phIndex = 0 nRepetitions = int(nPH / etl + dummyPulses) scanTime = 20e3 + nRepetitions * repetitionTime rawData['batchTime'] = scanTime * 1e-6 if rdGradTime == 0: # Check if readout gradient is dc or pulsed dc = True else: dc = False # Set shimming mri.iniSequence(expt, 20, shimming) for repeIndex in range(nRepetitions): # Initialize time tEx = 20e3 + repetitionTime * repeIndex + inversionTime + preExTime # First I do a noise measurement. if repeIndex == 0: t0 = tEx - preExTime - inversionTime - 4 * acqTime mri.rxGate(expt, t0, acqTime + 2 * addRdPoints / BW) # Pre-excitation pulse if repeIndex >= dummyPulses and preExTime != 0: t0 = tEx - preExTime - inversionTime - rfExTime / 2 - hw.blkTime mri.rfRecPulse(expt, t0, rfExTime, rfExAmp / 90 * 90, 0) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, preExTime * 0.5, -0.005, gSteps, axes[0], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, preExTime * 0.5, -0.005, gSteps, axes[1], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, preExTime * 0.5, -0.005, gSteps, axes[2], shimming) # Inversion pulse if repeIndex >= dummyPulses and inversionTime != 0: t0 = tEx - inversionTime - rfReTime / 2 - hw.blkTime mri.rfRecPulse(expt, t0, rfReTime, rfReAmp / 180 * 180, 0) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[0], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[1], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[2], shimming) # DC gradient if desired if (repeIndex == 0 or repeIndex >= dummyPulses) and dc == True: t0 = tEx - 10e3 mri.gradTrap(expt, t0, gradRiseTime, 10e3 + echoSpacing * (etl + 1), rdGradAmplitude, gSteps, axes[0], shimming) # Excitation pulse t0 = tEx - hw.blkTime - rfExTime / 2 mri.rfRecPulse(expt, t0, rfExTime, rfExAmp, drfPhase) # Dephasing readout t0 = tEx + rfExTime / 2 - hw.gradDelay if (repeIndex == 0 or repeIndex >= dummyPulses) and dc == False: mri.gradTrap(expt, t0, gradRiseTime, rdDephTime, rdDephAmplitude * rdPreemphasis, gSteps, axes[0], shimming) # Echo train for echoIndex in range(etl): tEcho = tEx + echoSpacing * (echoIndex + 1) # Refocusing pulse t0 = tEcho - echoSpacing / 2 - rfReTime / 2 - hw.blkTime mri.rfRecPulse(expt, t0, rfReTime, rfReAmp, drfPhase + np.pi / 2) # Dephasing phase and slice gradients if repeIndex >= dummyPulses: # This is to account for dummy pulses t0 = tEcho - echoSpacing / 2 + rfReTime / 2 - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, phGradTime, phGradients[phIndex], gSteps, axes[1], shimming) mri.gradTrap(expt, t0, gradRiseTime, phGradTime, slGradients[slIndex], gSteps, axes[2], shimming) # Readout gradient if (repeIndex == 0 or repeIndex >= dummyPulses ) and dc == False: # This is to account for dummy pulses t0 = tEcho - rdGradTime / 2 - gradRiseTime - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, rdGradTime, rdGradAmplitude, gSteps, axes[0], shimming) # Rx gate if (repeIndex == 0 or repeIndex >= dummyPulses): t0 = tEcho - acqTime / 2 - addRdPoints / BW mri.rxGate(expt, t0, acqTime + 2 * addRdPoints / BW) # Rephasing phase and slice gradients t0 = tEcho + acqTime / 2 + addRdPoints / BW - hw.gradDelay if (echoIndex < etl - 1 and repeIndex >= dummyPulses): mri.gradTrap(expt, t0, gradRiseTime, phGradTime, -phGradients[phIndex], gSteps, axes[1], shimming) mri.gradTrap(expt, t0, gradRiseTime, phGradTime, -slGradients[slIndex], gSteps, axes[2], shimming) elif (echoIndex == etl - 1 and repeIndex >= dummyPulses): mri.gradTrap(expt, t0, gradRiseTime, phGradTime, +phGradients[phIndex], gSteps, axes[1], shimming) mri.gradTrap(expt, t0, gradRiseTime, phGradTime, +slGradients[slIndex], gSteps, axes[2], shimming) # Update the phase and slice gradient if repeIndex >= dummyPulses: phIndex += 1 if repeIndex == nRepetitions - 1: mri.endSequence(expt, scanTime) # Changing time parameters to us rfExTime = rfExTime * 1e6 rfReTime = rfReTime * 1e6 echoSpacing = echoSpacing * 1e6 repetitionTime = repetitionTime * 1e6 gradRiseTime = gradRiseTime * 1e6 phGradTime = phGradTime * 1e6 rdGradTime = rdGradTime * 1e6 rdDephTime = rdDephTime * 1e6 inversionTime = inversionTime * 1e6 preExTime = preExTime * 1e6 # Calibrate frequency if freqCal == 1: mri.freqCalibration(rawData, bw=0.05) mri.freqCalibration(rawData, bw=0.005) larmorFreq = rawData['larmorFreq'] * 1e-6 drfPhase = rawData['drfPhase'] # Run the experiment dataFull = [] dummyData = [] overData = [] noise = [] for slIndex in range(nSL): expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] BW = 1 / samplingPeriod / hw.oversamplingFactor acqTime = nPoints[0] / BW # us createSequence() for ii in range(nScans): print("Scan %s, slice %s ..." % (ii + 1, slIndex + 1)) rxd, msgs = expt.run() rxd['rx0'] = rxd[ 'rx0'] * 13.788 # Here I normalize to get the result in mV # Get noise data noise = np.concatenate( (noise, rxd['rx0'][0:nRD * hw.oversamplingFactor]), axis=0) rxd['rx0'] = rxd['rx0'][nRD * hw.oversamplingFactor::] # Get data if dummyPulses > 0: dummyData = np.concatenate( (dummyData, rxd['rx0'][0:nRD * etl * hw.oversamplingFactor]), axis=0) overData = np.concatenate( (overData, rxd['rx0'][nRD * etl * hw.oversamplingFactor::]), axis=0) else: overData = np.concatenate((overData, rxd['rx0']), axis=0) expt.__del__() print('Scans done!') rawData['noiseData'] = noise rawData['overData'] = overData # Fix the echo position using oversampled data if dummyPulses > 0: dummyData = np.reshape( dummyData, (nSL * nScans, etl, nRD * hw.oversamplingFactor)) dummyData = np.average(dummyData, axis=0) rawData['dummyData'] = dummyData overData = np.reshape( overData, (nScans * nSL, int(nPH / etl), etl, nRD * hw.oversamplingFactor)) for ii in range(nScans * nSL): overData[ii, :, :, :] = mri.fixEchoPosition( dummyData, overData[ii, :, :, :]) overData = np.squeeze( np.reshape(overData, (1, nRD * hw.oversamplingFactor * nPH * nSL * nScans))) # Generate dataFull dataFull = sig.decimate(overData, hw.oversamplingFactor, ftype='fir', zero_phase=True) # Get index for krd = 0 # Average data dataProv = np.reshape(dataFull, (nSL, nScans, nRD * nPH)) dataProv = np.average(dataProv, axis=1) # Reorganize the data acording to sweep mode dataProv = np.reshape(dataProv, (nSL, nPH, nRD)) dataTemp = dataProv * 0 for ii in range(nPH): dataTemp[:, ind[ii], :] = dataProv[:, ii, :] dataProv = dataTemp # Check where is krd = 0 dataProv = dataProv[int(nPoints[2] / 2), int(nPH / 2), :] indkrd0 = np.argmax(np.abs(dataProv)) if indkrd0 < nRD / 2 - addRdPoints or indkrd0 > nRD / 2 + addRdPoints: indkrd0 = int(nRD / 2) # indkrd0 = int(nRD/2) # Get individual images dataFull = np.reshape(dataFull, (nSL, nScans, nPH, nRD)) dataFull = dataFull[:, :, :, indkrd0 - int(nPoints[0] / 2):indkrd0 + int(nPoints[0] / 2)] dataTemp = dataFull * 0 for ii in range(nPH): dataTemp[:, :, ind[ii], :] = dataFull[:, :, ii, :] dataFull = dataTemp imgFull = dataFull * 0 for ii in range(nScans): imgFull[:, ii, :, :] = np.fft.ifftshift( np.fft.ifftn(np.fft.ifftshift(np.squeeze(dataFull[:, ii, :, :])))) rawData['dataFull'] = dataFull rawData['imgFull'] = imgFull # Average data data = np.average(dataFull, axis=1) # Do zero padding dataTemp = np.zeros((nPoints[2], nPoints[1], nPoints[0])) dataTemp = dataTemp + 1j * dataTemp dataTemp[0:nSL, :, :] = data data = np.reshape(dataTemp, (1, nPoints[0] * nPoints[1] * nPoints[2])) # Fix the position of the sample according to dfov kMax = np.array(nPoints) / (2 * np.array(fov)) * np.array(axesEnable) kRD = np.linspace(-kMax[0], kMax[0], num=nPoints[0], endpoint=False) # kPH = np.linspace(-kMax[1],kMax[1],num=nPoints[1],endpoint=False) kSL = np.linspace(-kMax[2], kMax[2], num=nPoints[2], endpoint=False) kPH = kPH[::-1] kPH, kSL, kRD = np.meshgrid(kPH, kSL, kRD) kRD = np.reshape(kRD, (1, nPoints[0] * nPoints[1] * nPoints[2])) kPH = np.reshape(kPH, (1, nPoints[0] * nPoints[1] * nPoints[2])) kSL = np.reshape(kSL, (1, nPoints[0] * nPoints[1] * nPoints[2])) dPhase = np.exp(-2 * np.pi * 1j * (dfov[0] * kRD + dfov[1] * kPH + dfov[2] * kSL)) data = np.reshape(data * dPhase, (nPoints[2], nPoints[1], nPoints[0])) rawData['kSpace3D'] = data img = np.fft.ifftshift(np.fft.ifftn(np.fft.ifftshift(data))) rawData['image3D'] = img data = np.reshape(data, (1, nPoints[0] * nPoints[1] * nPoints[2])) # Create sampled data kRD = np.reshape(kRD, (nPoints[0] * nPoints[1] * nPoints[2], 1)) kPH = np.reshape(kPH, (nPoints[0] * nPoints[1] * nPoints[2], 1)) kSL = np.reshape(kSL, (nPoints[0] * nPoints[1] * nPoints[2], 1)) data = np.reshape(data, (nPoints[0] * nPoints[1] * nPoints[2], 1)) rawData['kMax'] = kMax rawData['sampled'] = np.concatenate((kRD, kPH, kSL, data), axis=1) data = np.reshape(data, (nPoints[2], nPoints[1], nPoints[0])) # Save data mri.saveRawData(rawData) # Plot data for 1D case if (nPH == 1 and nSL == 1): # Plot k-space plt.figure(3) dataPlot = data[0, 0, :] plt.subplot(1, 2, 1) if axesEnable[0] == 0: tVector = np.linspace( -acqTime / 2, acqTime / 2, num=nPoints[0], endpoint=False) * 1e-3 sMax = np.max(np.abs(dataPlot)) indMax = np.argmax(np.abs(dataPlot)) timeMax = tVector[indMax] sMax3 = sMax / 3 dataPlot3 = np.abs(np.abs(dataPlot) - sMax3) indMin = np.argmin(dataPlot3) timeMin = tVector[indMin] T2 = np.abs(timeMax - timeMin) plt.plot(tVector, np.abs(dataPlot)) plt.plot(tVector, np.real(dataPlot)) plt.plot(tVector, np.imag(dataPlot)) plt.xlabel('t (ms)') plt.ylabel('Signal (mV)') print("T2 = %s us" % (T2)) plt.title(rawData['fileName']) plt.legend(['Abs', 'Real', 'Imag']) else: plt.plot(kRD[:, 0], np.abs(dataPlot)) plt.yscale('log') plt.xlabel('krd (mm^-1)') plt.ylabel('Signal (mV)') echoTime = np.argmax(np.abs(dataPlot)) echoTime = kRD[echoTime, 0] print("Echo position = %s mm^{-1}" % round(echoTime, 1)) plt.title(rawData['fileName']) # Plot image plt.subplot(122) img = img[0, 0, :] if axesEnable[0] == 0: xAxis = np.linspace( -BW / 2, BW / 2, num=nPoints[0], endpoint=False) * 1e3 plt.plot(xAxis, np.abs(img), '.') plt.xlabel('Frequency (kHz)') plt.ylabel('Density (a.u.)') print("Smax = %s mV" % (np.max(np.abs(img)))) plt.title(rawData['fileName']) else: xAxis = np.linspace(-fov[0] / 2 * 1e2, fov[0] / 2 * 1e2, num=nPoints[0], endpoint=False) plt.plot(xAxis, np.abs(img)) plt.xlabel('Position RD (cm)') plt.ylabel('Density (a.u.)') plt.title(rawData['fileName']) else: # Plot k-space plt.figure(3) dataPlot = data[round(nSL / 2), :, :] plt.subplot(131) plt.imshow(np.log(np.abs(dataPlot)), cmap='gray') plt.axis('off') # Plot image if sweepMode == 3: imgPlot = img[round(nSL / 2), round(nPH / 4):round(3 * nPH / 4), :] else: imgPlot = img[round(nSL / 2), :, :] plt.subplot(132) plt.imshow(np.abs(imgPlot), cmap='gray') plt.axis('off') plt.title(rawData['fileName']) plt.subplot(133) plt.imshow(np.angle(imgPlot), cmap='gray') plt.axis('off') # plot full image if nSL > 1: plt.figure(4) img2d = np.zeros((nPoints[1], nPoints[0] * nPoints[2])) img2d = img2d + 1j * img2d for ii in range(nPoints[2]): img2d[:, ii * nPoints[0]:(ii + 1) * nPoints[0]] = img[ii, :, :] plt.imshow(np.abs(img2d), cmap='gray') plt.axis('off') plt.title(rawData['fileName']) plt.show()
def haste(self, plotSeq): init_gpa = False # Starts the gpa nScans = self.nScans # NEX larmorFreq = self.larmorFreq # MHz, Larmor frequency rfExAmp = self.rfExAmp # a.u., rf excitation pulse amplitude rfReAmp = self.rfReAmp # a.u., rf refocusing pulse amplitude rfExTime = self.rfExTime # us, rf excitation pulse time rfReTime = self.rfReTime # us, rf refocusing pulse time rfEnvelope = self.rfEnvelope # 'Rec' -> square pulse, 'Sinc' -> sinc pulse echoSpacing = self.echoSpacing # ms, time between echoes inversionTime = self.inversionTime # ms, Inversion recovery time repetitionTime = self.repetitionTime # ms, TR fov = np.array(self.fov) # mm, FOV along readout, phase and slice dfov = np.array(self.dfov) # mm, displacement of fov center nPoints = np.array( self.nPoints) # Number of points along readout, phase and slice acqTime = self.acqTime # ms, acquisition time axes = np.array(self.axes) # 0->x, 1->y and 2->z defined as [rd,ph,sl] axesEnable = self.axesEnable # 1-> Enable, 0-> Disable sweepMode = self.sweepMode # 0->k2k (T2), 1->02k (T1), 2->k20 (T2), 3->Niquist modulated (T2) rdGradTime = self.rdGradTime # ms, readout gradient time rdDephTime = self.rdDephTime # ms, readout dephasing time phGradTime = self.phGradTime # ms, phase and slice dephasing time rdPreemphasis = self.rdPreemphasis # readout dephasing gradient is multiplied by this factor ssPreemphasis = self.ssPreemphasis # slice rephasing gradient is multiplied by this factor crusherDelay = self.crusherDelay # delay of the crusher gradient drfPhase = self.drfPhase # degrees, phase of the excitation pulse dummyPulses = self.dummyPulses # number of dummy pulses for T1 stabilization shimming = self.shimming # a.u.*1e4, shimming along the X,Y and Z axes parFourierFraction = self.parFourierFraction # fraction of acquired k-space along phase direction freqCal = True demo = False # rawData fields rawData = {} # Conversion of variables to non-multiplied units larmorFreq = larmorFreq * 1e6 rfExTime = rfExTime * 1e-6 rfReTime = rfReTime * 1e-6 fov = np.array(fov) * 1e-3 dfov = np.array(dfov) * 1e-3 echoSpacing = echoSpacing * 1e-3 acqTime = acqTime * 1e-3 shimming = np.array(shimming) * 1e-4 repetitionTime = repetitionTime * 1e-3 inversionTime = inversionTime * 1e-3 rdGradTime = rdGradTime * 1e-3 rdDephTime = rdDephTime * 1e-3 phGradTime = phGradTime * 1e-3 crusherDelay = crusherDelay * 1e-6 # Inputs for rawData rawData['seqName'] = 'HASTE' rawData['nScans'] = nScans rawData['larmorFreq'] = larmorFreq # Larmor frequency rawData['rfExAmp'] = rfExAmp # rf excitation pulse amplitude rawData['rfReAmp'] = rfReAmp # rf refocusing pulse amplitude rawData['rfExTime'] = rfExTime # rf excitation pulse time rawData['rfReTime'] = rfReTime # rf refocusing pulse time rawData['rfEnvelope'] = rfEnvelope rawData['echoSpacing'] = echoSpacing # time between echoes rawData['inversionTime'] = inversionTime # Inversion recovery time rawData['repetitionTime'] = repetitionTime # TR rawData['fov'] = fov # FOV along readout, phase and slice rawData['dfov'] = dfov # Displacement of fov center rawData[ 'nPoints'] = nPoints # Number of points along readout, phase and slice rawData['acqTime'] = acqTime # Acquisition time rawData[ 'axesOrientation'] = axes # 0->x, 1->y and 2->z defined as [rd,ph,sl] rawData['axesEnable'] = axesEnable # 1-> Enable, 0-> Disable rawData[ 'sweepMode'] = sweepMode # 0->k2k (T2), 1->02k (T1), 2->k20 (T2), 3->Niquist modulated (T2) rawData['rdPreemphasis'] = rdPreemphasis rawData['ssPreemphasis'] = ssPreemphasis rawData['drfPhase'] = drfPhase rawData['dummyPulses'] = dummyPulses # Dummy pulses for T1 stabilization rawData['partialFourierFraction'] = parFourierFraction rawData['rdDephTime'] = rdDephTime rawData['crusherDelay'] = crusherDelay rawData['shimming'] = shimming # Miscellaneous slThickness = fov[2] rfSincLobes = 7 # Number of lobes for sinc rf excitation, BW = rfSincLobes/rfTime larmorFreq = larmorFreq * 1e-6 gradRiseTime = 200e-6 # Estimated gradient rise time gSteps = int(gradRiseTime * 1e6 / 5) addRdPoints = 10 # Initial rd points to avoid artifact at the begining of rd if rfReAmp == 0: rfReAmp = 2 * rfExAmp if rfReTime == 0: rfReTime = rfExTime resolution = fov / nPoints rawData['resolution'] = resolution rawData['gradRiseTime'] = gradRiseTime rawData['addRdPoints'] = addRdPoints # Matrix size nRD = nPoints[0] + 2 * addRdPoints nPH = nPoints[1] * axesEnable[1] + (1 - axesEnable[1]) # parAcqLines nPHreal = int(nPoints[1] * parFourierFraction) parAcqLines = int(nPHreal - nPoints[1] / 2) rawData['parAcqLines'] = parAcqLines print(parAcqLines) del nPHreal # BW BW = nPoints[0] / acqTime * 1e-6 BWov = BW * hw.oversamplingFactor samplingPeriod = 1 / BWov rawData['samplingPeriod'] = samplingPeriod # Readout gradient time if rdGradTime < acqTime: rdGradTime = acqTime rawData['rdGradTime'] = rdGradTime # Phase de- and re-phasing time if phGradTime == 0 or phGradTime > echoSpacing / 2 - rfExTime / 2 - rfReTime / 2 - 2 * gradRiseTime: phGradTime = echoSpacing / 2 - rfExTime / 2 - rfReTime / 2 - 2 * gradRiseTime rawData['phGradTime'] = phGradTime # Slice selection dephasing gradient time ssDephGradTime = (rfExTime - gradRiseTime) / 2 rawData['ssDephGradTime'] = ssDephGradTime # Max redaout and phase gradient amplitude rdGradAmplitude = nPoints[0] / (hw.gammaB * fov[0] * acqTime) * axesEnable[0] phGradAmplitude = nPH / (2 * hw.gammaB * fov[1] * (phGradTime + gradRiseTime)) * axesEnable[1] rawData['rdGradAmplitude'] = rdGradAmplitude rawData['phGradAmplitude'] = phGradAmplitude # Slice selection gradient if rfEnvelope == 'Sinc': ssGradAmplitude = rfSincLobes / (hw.gammaB * slThickness * rfExTime) * axesEnable[2] elif rfEnvelope == 'Rec': ssGradAmplitude = 1 / (hw.gammaB * slThickness * rfExTime) * axesEnable[2] rawData['ssGradAmplitude'] = ssGradAmplitude # Readout dephasing amplitude rdDephAmplitude = 0.5 * rdGradAmplitude * (gradRiseTime + rdGradTime) / ( gradRiseTime + rdDephTime) rawData['rdDephAmplitude'] = rdDephAmplitude # Phase gradient vector phGradients = np.linspace(-phGradAmplitude, phGradAmplitude, num=nPH, endpoint=False) # Get phase indexes for the given sweep mode ind = mri.getIndex(2 * parAcqLines, 2 * parAcqLines, sweepMode) ind = ind - parAcqLines + int(nPH / 2) ind = np.int32( np.concatenate((ind, np.linspace(int(nPH / 2) - parAcqLines - 1, -1, num=int(nPH / 2) - parAcqLines, endpoint=False)), axis=0)) rawData['sweepOrder'] = ind # Now fix the number of phases to partailly acquired k-space nPH = (int(nPoints[1] / 2) + parAcqLines) * axesEnable[1] + (1 - axesEnable[1]) phGradients = phGradients[0:nPH] phGradients = phGradients[ind] rawData['phGradients'] = phGradients def createSequenceDemo(): nRepetitions = int(1 + dummyPulses) scanTime = 20e3 + nRepetitions * repetitionTime rawData['scanTime'] = scanTime * 1e-6 acqPoints = 0 data = [] for repeIndex in range(nRepetitions): for echoIndex in range(nPH): if (repeIndex == 0 or repeIndex >= dummyPulses): acqPoints += nRD * hw.oversamplingFactor data = np.concatenate( (data, np.random.randn(nRD * hw.oversamplingFactor) + 1j * np.random.randn(nRD * hw.oversamplingFactor)), axis=0) return data, acqPoints def createSequence(): nRepetitions = int(1 + dummyPulses) scanTime = 20e3 + nRepetitions * repetitionTime rawData['scanTime'] = scanTime * 1e-6 print('Scan Time = ', (scanTime * 1e-6), 's') if rdGradTime == 0: # Check if readout gradient is dc or pulsed dc = True else: dc = False # Set shimming mri.iniSequence(expt, 20, shimming) for repeIndex in range(nRepetitions): # Initialize time tEx = 20e3 + repetitionTime * repeIndex + inversionTime # Inversion pulse if repeIndex >= dummyPulses and inversionTime != 0: t0 = tEx - inversionTime - rfReTime / 2 - hw.blkTime mri.rfRecPulse(expt, t0, rfReTime, rfReAmp / 180 * 180, 0) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[0], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[1], shimming) mri.gradTrap(expt, t0 + hw.blkTime + rfReTime, gradRiseTime, inversionTime * 0.5, 0.005, gSteps, axes[2], shimming) # DC radout gradient if desired if (repeIndex == 0 or repeIndex >= dummyPulses) and dc == True: t0 = tEx - rfExTime / 2 - gradRiseTime - hw.gradDelay mri.gradTrap(expt, t0, echoSpacing * (nPH + 1), rdGradAmplitude, axes[0]) # Slice selection gradient dephasing if (slThickness != 0 and repeIndex >= dummyPulses): t0 = tEx - rfExTime / 2 - gradRiseTime - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, rfExTime, ssGradAmplitude, gSteps, axes[2], shimming) # Excitation pulse t0 = tEx - hw.blkTime - rfExTime / 2 if rfEnvelope == 'Rec': mri.rfRecPulse(expt, t0, rfExTime, rfExAmp, drfPhase * np.pi / 180) elif rfEnvelope == 'Sinc': mri.rfSincPulse(expt, t0, rfExTime, rfSincLobes, rfExAmp, drfPhase * np.pi / 180) # Slice selection gradient rephasing if (slThickness != 0 and repeIndex >= dummyPulses): t0 = tEx + rfExTime / 2 + gradRiseTime - hw.gradDelay if rfEnvelope == 'Rec': mri.gradTrap(expt, t0, gradRiseTime, 0., -ssGradAmplitude * ssPreemphasis, gSteps, axes[2], shimming) elif rfEnvelope == 'Sinc': mri.gradTrap(expt, t0, gradRiseTime, ssDephGradTime, -ssGradAmplitude * ssPreemphasis, gSteps, axes[2], shimming) # Dephasing readout t0 = tEx + rfExTime / 2 - hw.gradDelay if (repeIndex == 0 or repeIndex >= dummyPulses) and dc == False: mri.gradTrap(expt, t0, gradRiseTime, rdDephTime, rdDephAmplitude * rdPreemphasis, gSteps, axes[0], shimming) # Echo train for echoIndex in range(nPH): tEcho = tEx + echoSpacing * (echoIndex + 1) # Crusher gradient if repeIndex >= dummyPulses: t0 = tEcho - echoSpacing / 2 - rfReTime / 2 - gradRiseTime - hw.gradDelay - crusherDelay mri.gradTrap(expt, t0, gradRiseTime, rfReTime + 2 * crusherDelay, ssGradAmplitude, gSteps, axes[2], shimming) # Refocusing pulse t0 = tEcho - echoSpacing / 2 - rfReTime / 2 - hw.blkTime if rfEnvelope == 'Rec': mri.rfRecPulse(expt, t0, rfReTime, rfReAmp, np.pi / 2 + drfPhase * np.pi / 180) if rfEnvelope == 'Sinc': mri.rfSincPulse(expt, t0, rfReTime, rfSincLobes, rfReAmp, np.pi / 2 + drfPhase * np.pi / 180) # Dephasing phase gradient t0 = tEcho - echoSpacing / 2 + rfReTime / 2 - hw.gradDelay if repeIndex >= dummyPulses: # This is to account for dummy pulses mri.gradTrap(expt, t0, gradRiseTime, phGradTime, phGradients[echoIndex], gSteps, axes[1], shimming) # Readout gradient t0 = tEcho - rdGradTime / 2 - gradRiseTime - hw.gradDelay if (repeIndex == 0 or repeIndex >= dummyPulses ) and dc == False: # This is to account for dummy pulses mri.gradTrap(expt, t0, gradRiseTime, rdGradTime, rdGradAmplitude, gSteps, axes[0], shimming) # Rx gate if (repeIndex == 0 or repeIndex >= dummyPulses): t0 = tEcho - acqTime / 2 - addRdPoints / BW mri.rxGate(expt, t0, acqTime + 2 * addRdPoints / BW) # Rephasing phase and slice gradients t0 = tEcho + acqTime / 2 + addRdPoints / BW - hw.gradDelay if (echoIndex < nPH - 1 and repeIndex >= dummyPulses): mri.gradTrap(expt, t0, gradRiseTime, phGradTime, -phGradients[echoIndex], gSteps, axes[1], shimming) elif (echoIndex == nPH - 1 and repeIndex >= dummyPulses): mri.gradTrap(expt, t0, gradRiseTime, phGradTime, +phGradients[echoIndex], gSteps, axes[1], shimming) if repeIndex == nRepetitions - 1: mri.endSequence(expt, scanTime) # Changing time parameters to us rfExTime = rfExTime * 1e6 rfReTime = rfReTime * 1e6 echoSpacing = echoSpacing * 1e6 repetitionTime = repetitionTime * 1e6 gradRiseTime = gradRiseTime * 1e6 phGradTime = phGradTime * 1e6 rdGradTime = rdGradTime * 1e6 rdDephTime = rdDephTime * 1e6 inversionTime = inversionTime * 1e6 crusherDelay = crusherDelay * 1e6 ssDephGradTime = ssDephGradTime * 1e6 # Calibrate frequency if not demo and freqCal and (not plotSeq): mri.freqCalibration(rawData, bw=0.05) mri.freqCalibration(rawData, bw=0.005) larmorFreq = rawData['larmorFreq'] * 1e-6 # Create full sequence if not demo: expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] BW = 1 / samplingPeriod / hw.oversamplingFactor acqTime = nPoints[0] / BW # us createSequence() # Run the experiment dataFull = [] dummyData = [] overData = [] for ii in range(nScans): if plotSeq: expt.plot_sequence() plt.show() break else: print("Scan %s ..." % (ii + 1)) if not demo: rxd, msgs = expt.run() rxd['rx0'] = rxd[ 'rx0'] * 13.788 # Here I normalize to get the result in mV else: data, acqPoints = createSequenceDemo() # Get data if not demo: if dummyPulses > 0: dummyData = np.concatenate( (dummyData, rxd['rx0'][0:nRD * nPH * hw.oversamplingFactor]), axis=0) overData = np.concatenate( (overData, rxd['rx0'][nRD * nPH * hw.oversamplingFactor::]), axis=0) else: overData = np.concatenate((overData, rxd['rx0']), axis=0) else: if dummyPulses > 0: dummyData = np.concatenate( (dummyData, data[0:nRD * nPH * hw.oversamplingFactor]), axis=0) overData = np.concatenate( (overData, data[nRD * nPH * hw.oversamplingFactor::]), axis=0) else: overData = np.concatenate((overData, data), axis=0) if not demo: expt.__del__() print('Scans done!') rawData['overData'] = overData # Fix the echo position using oversampled data if dummyPulses > 0: dummyData = np.reshape(dummyData, (nScans, nPH, nRD * hw.oversamplingFactor)) dummyData = np.average(dummyData, axis=0) rawData['dummyData'] = dummyData overData = np.reshape(overData, (nScans, 1, nPH, nRD * hw.oversamplingFactor)) for ii in range(nScans): overData[ii, :, :, :] = mri.fixEchoPosition( dummyData, overData[ii, :, :, :]) # Generate dataFull overData = np.squeeze( np.reshape(overData, (1, nRD * hw.oversamplingFactor * nPH * nScans))) dataFull = sig.decimate(overData, hw.oversamplingFactor, ftype='fir', zero_phase=True) # Get index for krd = 0 # Average data dataProv = np.reshape(dataFull, (nScans, nRD * nPH)) dataProv = np.average(dataProv, axis=0) # Reorganize the data acording to sweep mode dataProv = np.reshape(dataProv, (nPH, nRD)) dataTemp = dataProv * 0 for ii in range(nPH): dataTemp[ind[ii], :] = dataProv[ii, :] dataProv = dataTemp # Check where is krd = 0 dataProv = dataProv[int(nPoints[1] / 2), :] indkrd0 = np.argmax(np.abs(dataProv)) if indkrd0 < nRD / 2 - addRdPoints or indkrd0 > nRD / 2 + addRdPoints: indkrd0 = int(nRD / 2) # Get individual images dataFull = np.reshape(dataFull, (nScans, nPH, nRD)) dataFull = dataFull[:, :, indkrd0 - int(nPoints[0] / 2):indkrd0 + int(nPoints[0] / 2)] dataTemp = dataFull * 0 for ii in range(nPH): dataTemp[:, ind[ii], :] = dataFull[:, ii, :] dataFull = dataTemp imgFull = dataFull * 0 for ii in range(nScans): imgFull[ii, :, :] = np.fft.ifftshift( np.fft.ifftn(np.fft.ifftshift(dataFull[ii, :, :]))) rawData['dataFull'] = dataFull rawData['imgFull'] = imgFull # Average data data = np.average(dataFull, axis=0) data = np.reshape(data, (nPH, nPoints[0])) # Do zero padding dataTemp = np.zeros((nPoints[1], nPoints[0])) dataTemp = dataTemp + 1j * dataTemp dataTemp[0:nPH, :] = data data = np.reshape(dataTemp, (1, nPoints[0] * nPoints[1])) # Fix the position of the sample according to dfov kMax = np.array(nPoints) / (2 * np.array(fov)) * np.array(axesEnable) kRD = np.linspace(-kMax[0], kMax[0], num=nPoints[0], endpoint=False) kPH = np.linspace(-kMax[1], kMax[1], num=nPoints[1], endpoint=False) kPH, kRD = np.meshgrid(kPH, kRD) kRD = np.reshape(kRD, (1, nPoints[0] * nPoints[1])) kPH = np.reshape(kPH, (1, nPoints[0] * nPoints[1])) dPhase = np.exp(-2 * np.pi * 1j * (dfov[0] * kRD + dfov[1] * kPH)) data = np.reshape(data * dPhase, (nPoints[1], nPoints[0])) rawData['kSpace3D'] = data img = np.fft.ifftshift(np.fft.ifftn(np.fft.ifftshift(data))) rawData['image3D'] = img data = np.reshape(data, (1, nPoints[0] * nPoints[1])) # Create sampled data kRD = np.reshape(kRD, (nPoints[0] * nPoints[1], 1)) kPH = np.reshape(kPH, (nPoints[0] * nPoints[1], 1)) data = np.reshape(data, (nPoints[0] * nPoints[1], 1)) rawData['kMax'] = kMax rawData['sampled'] = np.concatenate((kRD, kPH, data), axis=1) data = np.reshape(data, -1) # Save data mri.saveRawData(rawData) return rawData, msgs, data, BW
def rabiflopStandalone( init_gpa=False, larmorFreq=3.0806, # MHz rfExAmp=0.4, # a.u. rfReAmp=0.8, # a.u. rfExTime=22, # us rfReTime=22, # us nPoints=100, acqTime=18, # ms echoTime=20, # ms repetitionTime=1000, # ms plotSeq=0, # 0 to run sequence, 1 to plot sequence pulseShape='Rec', # 'Rec' for square pulse shape, 'Sinc' for sinc pulse shape shimming0=[-0, -0, 0], nShimming=10, # number of samples to sweep in each gradient direction dShimming=[10, 10, 10] # shimming step in each direction ): freqCal = 1 plt.ion() # Miscellaneous deadTime = 400 # us, time between excitation and first acquisition shimming0 = np.array(shimming0) * 1e-4 dShimming = np.array(dShimming) * 1e-4 # Varibales to fundamental units larmorFreq *= 1e6 rfExTime *= 1e-6 rfReTime *= 1e-6 acqTime *= 1e-3 echoTime *= 1e-3 repetitionTime *= 1e-3 # Inputs for rawData rawData = {} rawData['seqName'] = 'ShimmingCal' rawData['larmorFreq'] = larmorFreq # Larmor frequency rawData['rfExAmp'] = rfExAmp # rf excitation pulse amplitude rawData['rfReAmp'] = rfReAmp rawData['rfExTime'] = rfExTime rawData['rfReTime'] = rfReTime rawData['nPoints'] = nPoints rawData['acqTime'] = acqTime rawData['echoTime'] = echoTime rawData['repetitionTime'] = repetitionTime rawData['pulseShape'] = pulseShape rawData['deadTime'] = deadTime * 1e-6 rawData['shimming0'] = shimming0 rawData['nShimming'] = nShimming rawData['dShimming'] = dShimming rawData['shimming'] = shimming0 rawData['addRdPoints'] = 10 # Bandwidth bw = nPoints / acqTime * 1e-6 # MHz bwov = bw * hw.oversamplingFactor # MHz samplingPeriod = 1 / bwov # us rawData['bw'] = bw rawData['samplingPeriod'] = samplingPeriod fVector = np.linspace(-bw / 2, bw / 2, num=nPoints, endpoint=False) # Time variables in us and MHz larmorFreq *= 1e-6 rfExTime *= 1e6 rfReTime *= 1e6 echoTime *= 1e6 repetitionTime *= 1e6 acqTime *= 1e6 # SEQUENCE ############################################################################################ def createSequence(expt, shimming): # Set shimming mri.iniSequence(expt, 20, shimming) # Initialize time tEx = 20e3 # Excitation pulse t0 = tEx - hw.blkTime - rfExTime / 2 if pulseShape == 'Rec': mri.rfRecPulse(expt, t0, rfExTime, rfExAmp, 0) elif pulseShape == 'Sinc': mri.rfSincPulse(expt, t0, rfExTime, 7, rfExAmp, 0) # Refocusing pulse t0 = tEx + echoTime / 2 - rfReTime / 2 - hw.blkTime if pulseShape == 'Rec': mri.rfRecPulse(expt, t0, rfReTime, rfReAmp, np.pi / 2) elif pulseShape == 'Sinc': mri.rfSincPulse(expt, t0, rfReTime, 7, rfReAmp, np.pi / 2) # Acquisition window t0 = tEx + echoTime - acqTime / 2 mri.rxGate(expt, t0, acqTime) # End sequence mri.endSequence(expt, repetitionTime) def runExperiment(shimmingExp, samplingRate): expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingRate, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] bw = 1 / samplingPeriod / hw.oversamplingFactor acqTime = nPoints / bw rawData['acqTime'] = acqTime rawData['bw'] = bw createSequence(expt, shimmingExp) print(shimmingExp * 1e4, '.- Running...') rxd, msgs = expt.run() expt.__del__() data = sig.decimate(rxd['rx0'] * 13.788, hw.oversamplingFactor, ftype='fir', zero_phase=True) return (data) def sweepAxis(axis): # First two samples to determine the sweep direction shimmingA = shimming0 * 1 shimmingB = shimming0 * 1 shimmingB[axis] = shimming0[axis] + dShimming[axis] dataA = runExperiment(shimmingA, samplingPeriod) fwhmA, maxA = getPeakProperties(fVector, dataA) print('Peak amplitude = ', maxA) print('Homogeneity = ', fwhmA / larmorFreq * 1e6, ' ppm \n') dataB = runExperiment(shimmingB, samplingPeriod) fwhmB, maxB = getPeakProperties(fVector, dataB) print('Peak amplitude = ', maxB) print('Homogeneity = ', fwhmB / larmorFreq * 1e6, ' ppm \n') if maxB < maxA: dShimming[axis] = -dShimming[axis] maxP = maxB maxB = maxA maxA = maxP shimmingP = shimmingB shimmingB = shimmingA shimmingA = shimmingP del maxP, shimmingP # Sweep axis until the max start to goes down while maxB > maxA: fwhmA = fwhmB maxA = maxB shimmingA = shimmingB * 1 shimmingB[axis] += dShimming[axis] dataB = runExperiment(shimmingB, samplingPeriod) fwhmB, maxB = getPeakProperties(fVector, dataB) print('Peak amplitude = ', maxB) print('Homogeneity = ', fwhmB / larmorFreq * 1e6, ' ppm \n˘') print('Axis ', axis, ' optimized!') # Return fwhm and max values return (fwhmA, maxA, shimmingA) # Calibrate frequency if freqCal == 1: mri.freqCalibration(rawData, bw=0.05) mri.freqCalibration(rawData, bw=0.005) larmorFreq = rawData['larmorFreq'] * 1e-6 for nSweep in range(3): for axis in range(3): fwhmOpt, maxOpt, shimmingOpt = sweepAxis(axis) shimming0 = shimmingOpt dShimming /= 2 # Save data mri.saveRawData(rawData) # plt.figure(3) # plt.plot(sxVector*1e4, gx, 'b.', # syVector*1e4, gy, 'g.', # szVector*1e4, gz, 'r.') # plt.title(rawData['fileName']) # plt.xlabel('Shimming (a.u.)') # plt.ylabel('FFT peak amplitude (a.u.)') # plt.legend(['x Axis', 'y Axis', 'z Axis']) # plt.figure(4) # plt.plot(sxVector*1e4, ppmx, 'b.', # syVector*1e4, ppmy, 'g.', # szVector*1e4, ppmz, 'r.') # plt.title(rawData['fileName']) # plt.xlabel('Shimming (a.u.)') # plt.ylabel('Homogeneity (ppm)') # plt.legend(['x Axis', 'y Axis', 'z Axis']) print('Best shimming = ', shimming0 * 1e4) plt.show(block=True)
def rabiflopStandalone( init_gpa= False, larmorFreq = 3.0806, # MHz rfExAmp = 0.4, # a.u. rfReAmp = 0.8, # a.u. rfExTime = 22, # us rfReTime = 22, # us nPoints = 100, acqTime = 18, # ms echoTime = 20, # ms repetitionTime = 1000, # ms plotSeq = 0, # 0 to run sequence, 1 to plot sequence pulseShape = 'Rec', # 'Rec' for square pulse shape, 'Sinc' for sinc pulse shape shimming0 = [-77.5, -70, 7.5], nShimming = 10, # number of samples to sweep in each gradient direction dShimming = [2.5, 2.5, 2.5] # shimming step in each direction ): freqCal = 0 plt.ion() # Miscellaneous deadTime = 400 # us, time between excitation and first acquisition shimming0 = np.array(shimming0)*1e-4 # Varibales to fundamental units larmorFreq *= 1e6 rfExTime *= 1e-6 rfReTime *= 1e-6 acqTime *= 1e-3 echoTime *= 1e-3 repetitionTime *= 1e-3 # Inputs for rawData rawData={} rawData['seqName'] = 'ShimmingCal' rawData['larmorFreq'] = larmorFreq # Larmor frequency rawData['rfExAmp'] = rfExAmp # rf excitation pulse amplitude rawData['rfReAmp'] = rfReAmp rawData['rfExTime'] = rfExTime rawData['rfReTime'] = rfReTime rawData['nPoints'] = nPoints rawData['acqTime'] = acqTime rawData['echoTime'] = echoTime rawData['repetitionTime'] = repetitionTime rawData['pulseShape'] = pulseShape rawData['deadTime'] = deadTime*1e-6 rawData['shimming0'] = shimming0 rawData['nShimming'] = nShimming rawData['dShimming'] = dShimming rawData['shimming'] = shimming0 rawData['addRdPoints'] = 10 # Shimming vectors dsx = nShimming*dShimming[0]*1e-4 dsy = nShimming*dShimming[1]*1e-4 dsz = nShimming*dShimming[2]*1e-4 sxVector = np.linspace(shimming0[0]-dsx/2, shimming0[0]+dsx/2, num=nShimming, endpoint=False) syVector = np.linspace(shimming0[1]-dsy/2, shimming0[1]+dsy/2, num=nShimming, endpoint=False) szVector = np.linspace(shimming0[2]-dsz/2, shimming0[2]+dsz/2, num=nShimming, endpoint=False) # Bandwidth bw = nPoints/acqTime*1e-6 # MHz bwov = bw*hw.oversamplingFactor # MHz samplingPeriod = 1/bwov # us rawData['bw'] = bw rawData['samplingPeriod'] = samplingPeriod fVector = np.linspace(-bw/2, bw/2, num=nPoints, endpoint=False) # Time variables in us and MHz larmorFreq *=1e-6 rfExTime *=1e6 rfReTime *=1e6 echoTime *=1e6 repetitionTime *=1e6 acqTime *=1e6 # SEQUENCE ############################################################################################ def createSequence(shimming): # Set shimming mri.iniSequence(expt, 20, shimming) # Initialize time tEx = 20e3 # Excitation pulse t0 = tEx-hw.blkTime-rfExTime/2 if pulseShape=='Rec': mri.rfRecPulse(expt, t0, rfExTime, rfExAmp, 0) elif pulseShape=='Sinc': mri.rfSincPulse(expt, t0, rfExTime, 7, rfExAmp, 0) # Refocusing pulse t0 = tEx+echoTime/2-rfReTime/2-hw.blkTime if pulseShape=='Rec': mri.rfRecPulse(expt, t0, rfReTime, rfReAmp, np.pi/2) elif pulseShape=='Sinc': mri.rfSincPulse(expt, t0, rfReTime, 7, rfReAmp, np.pi/2) # Acquisition window t0 = tEx+echoTime-acqTime/2 mri.rxGate(expt, t0, acqTime) # End sequence mri.endSequence(expt, repetitionTime) # Calibrate frequency if freqCal==1: mri.freqCalibration(rawData, bw=0.05) mri.freqCalibration(rawData, bw=0.005) larmorFreq = rawData['larmorFreq']*1e-6 # INIT EXPERIMENT dataAll = [] gx = [] gy = [] gz = [] ppmx = [] ppmy = [] ppmz = [] # shimming for Gx for sx in sxVector: shimming = np.array([sx, shimming0[1], shimming0[2]]) expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] bw = 1/samplingPeriod/hw.oversamplingFactor acqTime = nPoints/bw rawData['bw'] = bw createSequence(shimming) if plotSeq==1: expt.plot_sequence() plt.show(block=False) expt.__del__() elif plotSeq==0: print(shimming*1e4, '.- Running...') rxd, msgs = expt.run() expt.__del__() data = sig.decimate(rxd['rx0']*13.788, hw.oversamplingFactor, ftype='fir', zero_phase=True) fwhm, max = getPeakProperties(fVector, data) gx = np.concatenate((gx, np.array([max])), axis=0) ppmx = np.concatenate((ppmx, np.array([fwhm/larmorFreq*1e6])), axis=0) dataAll = np.concatenate((dataAll, data), axis=0) # Plots plt.figure(1) plt.plot(sx*1e4, max, 'b.') plt.figure(2) plt.plot(sx*1e4, fwhm/larmorFreq*1e6, 'b.') plt.show(block=False) plt.pause(0.05) idx = np.argmax(gx) sxOpt = sxVector[idx] # shimming for Gy for sy in syVector: shimming = np.array([sxOpt, sy, shimming0[2]]) expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] bw = 1/samplingPeriod/hw.oversamplingFactor acqTime = nPoints/bw rawData['bw'] = bw createSequence(shimming) if plotSeq==1: expt.plot_sequence() plt.show(block=False) expt.__del__() elif plotSeq==0: print(shimming*1e4, '.- Running...') rxd, msgs = expt.run() expt.__del__() data = sig.decimate(rxd['rx0']*13.788, hw.oversamplingFactor, ftype='fir', zero_phase=True) fwhm, max = getPeakProperties(fVector, data) gy = np.concatenate((gy, np.array([max])), axis=0) ppmy = np.concatenate((ppmy, np.array([fwhm/larmorFreq*1e6])), axis=0) dataAll = np.concatenate((dataAll, data), axis=0) plt.figure(1) plt.plot(sy*1e4, max, 'g.') plt.figure(2) plt.plot(sy*1e4, fwhm/larmorFreq*1e6, 'g.') plt.show(block=False) plt.pause(0.05) idx = np.argmax(gy) syOpt = syVector[idx] # shimming for Gz for sz in szVector: shimming = np.array([sxOpt, syOpt, sz]) expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] bw = 1/samplingPeriod/hw.oversamplingFactor acqTime = nPoints/bw rawData['bw'] = bw createSequence(shimming) if plotSeq==1: expt.plot_sequence() plt.show(block=False) expt.__del__() elif plotSeq==0: print(shimming*1e4, '.- Running...') rxd, msgs = expt.run() expt.__del__() data = sig.decimate(rxd['rx0']*13.788, hw.oversamplingFactor, ftype='fir', zero_phase=True) fwhm, max = getPeakProperties(fVector, data) gz = np.concatenate((gz, np.array([max])), axis=0) ppmz = np.concatenate((ppmz, np.array([fwhm/larmorFreq*1e6])), axis=0) dataAll = np.concatenate((dataAll, data), axis=0) plt.figure(1) plt.plot(sz*1e4, max, 'r.') plt.figure(2) plt.plot(sz*1e4, fwhm/larmorFreq*1e6, 'r.') plt.show(block=False) plt.pause(0.05) idx = np.argmax(gz) szOpt = szVector[idx] rawData['shimming'] = np.array([sxOpt, syOpt, szOpt]) # Get the values for the optimal case shimming = np.array([sxOpt, syOpt, szOpt]) # expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) # samplingPeriod = expt.get_rx_ts()[0] # bw = 1/samplingPeriod/hw.oversamplingFactor # acqTime = nPoints/bw # rawData['bw'] = bw # createSequence(shimming) # if plotSeq==1: # expt.plot_sequence() # plt.show(block=False) # expt.__del__() # elif plotSeq==0: # print(shimming*1e4, '.- Running...') # rxd, msgs = expt.run() # expt.__del__() # data = sig.decimate(rxd['rx0']*13.788, hw.oversamplingFactor, ftype='fir', zero_phase=True) # fwhm, max = getPeakProperties(fVector, data) # plt.figure(1) # plt.plot(0, max, 'k.') # plt.figure(2) # plt.plot(0, fwhm/larmorFreq*1e6, 'k.') # plt.show(block=False) # plt.pause(0.05) # Save data mri.saveRawData(rawData) plt.figure(3) plt.plot(sxVector*1e4, gx, 'b.', syVector*1e4, gy, 'g.', szVector*1e4, gz, 'r.') plt.title(rawData['fileName']) plt.xlabel('Shimming (a.u.)') plt.ylabel('FFT peak amplitude (a.u.)') plt.legend(['x Axis', 'y Axis', 'z Axis']) plt.figure(4) plt.plot(sxVector*1e4, ppmx, 'b.', syVector*1e4, ppmy, 'g.', szVector*1e4, ppmz, 'r.') plt.title(rawData['fileName']) plt.xlabel('Shimming (a.u.)') plt.ylabel('Homogeneity (ppm)') plt.legend(['x Axis', 'y Axis', 'z Axis']) print('Best shimming = ', shimming*1e4) plt.show(block=True)
def gre3d(self, plotSeq): init_gpa = False, # Starts the gpa nScans = self.nScans # NEX larmorFreq = self.larmorFreq # MHz, Larmor frequency rfExAmp = self.rfExAmp # a.u. rf excitation pulse amplitude rfExTime = self.rfExTime # us, rf excitation pulse time echoTime = self.echoTime # ms, TE repetitionTime = self.repetitionTime # ms, TR fov = self.fov # mm, FOV along readout, phase and slice dfov = self.dfov # mm, Displacement of fov center nPoints = self.nPoints # Number of points along readout, phase and slice acqTime = self.acqTime # ms, Acquisition time axes = self.axes # 0->x, 1->y and 2->z defined as [rd,ph,sl] rdGradTime = self.rdGradTime # ms, readout rephasing gradient time dephGradTime = self.dephGradTime # ms, Phase and slice dephasing time dummyPulses = self.dummyPulses # Dummy pulses for T1 stabilization shimming = self.shimming # a.u.*1e4, Shimming along the X,Y and Z axes parFourierFraction = self.parFourierFractionSl # fraction of acquired k-space along phase direction spoiler = self.spoiler # set 1 or 0 if you want or do not want to apply spoiler gradients freqCal = False demo = False # rawData fields rawData = {} # Conversion of variables to non-multiplied units larmorFreq = larmorFreq * 1e6 rfExTime = rfExTime * 1e-6 fov = np.array(fov) * 1e-3 dfov = np.array(dfov) * 1e-3 echoTime = echoTime * 1e-3 acqTime = acqTime * 1e-3 shimming = np.array(shimming) * 1e-4 nPoints = np.array(nPoints) repetitionTime = repetitionTime * 1e-3 rdGradTime = rdGradTime * 1e-3 dephGradTime = dephGradTime * 1e-3 # Inputs for rawData rawData['seqName'] = self.seq rawData['nScans'] = nScans rawData['larmorFreq'] = larmorFreq # Larmor frequency rawData['rfExAmp'] = rfExAmp # rf excitation pulse amplitude rawData['rfExTime'] = rfExTime # rf excitation pulse time rawData['echoTime'] = echoTime # time between echoes rawData['repetitionTime'] = repetitionTime # TR rawData['fov'] = fov # FOV along readout, phase and slice rawData['dfov'] = dfov # Displacement of fov center rawData[ 'nPoints'] = nPoints # Number of points along readout, phase and slice rawData['acqTime'] = acqTime # Acquisition time rawData[ 'axesOrientation'] = axes # 0->x, 1->y and 2->z defined as [rd,ph,sl] rawData['rdGradTime'] = rdGradTime rawData['dephGradTime'] = dephGradTime rawData['dummyPulses'] = dummyPulses # Dummy pulses for T1 stabilization rawData['shimming'] = shimming rawData['partialFourierFraction'] = parFourierFraction rawData['spoiler'] = spoiler # Miscellaneous larmorFreq = larmorFreq * 1e-6 gradRiseTime = 100e-6 # Estimated gradient rise time gSteps = int(gradRiseTime * 1e6 / 5) * 0 + 1 addRdPoints = 5 # Initial rd points to avoid artifact at the begining of rd resolution = fov / nPoints randFactor = 0. axesEnable = np.array([1, 1, 1]) for ii in range(3): if nPoints[ii] == 1: axesEnable[ii] = 0 if fov[0] > 1 and nPoints[1] == 1: axesEnable[0] = 0 rawData['randFactor'] = randFactor rawData['resolution'] = resolution rawData['gradRiseTime'] = gradRiseTime rawData['addRdPoints'] = addRdPoints # Matrix size nRD = nPoints[0] + 2 * addRdPoints nPH = nPoints[1] nSL = nPoints[2] # parAcqLines nSLreal = int(nPoints[2] * parFourierFraction) parAcqLines = int(nSLreal - nPoints[2] / 2) rawData['parAcqLines'] = parAcqLines del nSLreal # BW BW = nPoints[0] / acqTime * 1e-6 BWov = BW * hw.oversamplingFactor samplingPeriod = 1 / BWov rawData['samplingPeriod'] = samplingPeriod # Check if dephasing grad time is ok maxDephGradTime = echoTime - (rfExTime + rdGradTime) - 3 * gradRiseTime if dephGradTime == 0 or dephGradTime > maxDephGradTime: dephGradTime = maxDephGradTime # Max gradient amplitude rdGradAmplitude = nPoints[0] / (hw.gammaB * fov[0] * acqTime) rdDephAmplitude = -rdGradAmplitude * (rdGradTime + gradRiseTime) / ( 2 * (dephGradTime + gradRiseTime)) phGradAmplitude = nPH / (2 * hw.gammaB * fov[1] * (dephGradTime + gradRiseTime)) * axesEnable[1] slGradAmplitude = nSL / (2 * hw.gammaB * fov[2] * (dephGradTime + gradRiseTime)) * axesEnable[2] rawData['rdGradAmplitude'] = rdGradAmplitude rawData['rdDephAmplitude'] = rdDephAmplitude rawData['phGradAmplitude'] = phGradAmplitude rawData['slGradAmplitude'] = slGradAmplitude # Phase and slice gradient vector phGradients = np.linspace(-phGradAmplitude, phGradAmplitude, num=nPH, endpoint=False) slGradients = np.linspace(-slGradAmplitude, slGradAmplitude, num=nSL, endpoint=False) # Now fix the number of slices to partailly acquired k-space if nPoints[2] == 1: nSL = 1 else: nSL = int(nPoints[2] / 2) + parAcqLines nRepetitions = nPH * nSL # Add random displacemnt to phase encoding lines for ii in range(nPH): if ii < np.ceil(nPH / 2 - nPH / 20) or ii > np.ceil(nPH / 2 + nPH / 20): phGradients[ii] = phGradients[ii] + randFactor * np.random.randn() kPH = hw.gammaB * phGradients * (gradRiseTime + dephGradTime) rawData['phGradients'] = phGradients rawData['slGradients'] = slGradients # Changing time parameters to us rfExTime = rfExTime * 1e6 echoTime = echoTime * 1e6 repetitionTime = repetitionTime * 1e6 gradRiseTime = gradRiseTime * 1e6 dephGradTime = dephGradTime * 1e6 rdGradTime = rdGradTime * 1e6 scanTime = nRepetitions * repetitionTime rawData['scanTime'] = scanTime * nSL * 1e-6 # Create demo def createSequenceDemo(phIndex=0, slIndex=0, repeIndexGlobal=0): repeIndex = 0 acqPoints = 0 orders = 0 data = [] if (dummyPulses > 0 and nRD * 3 > hw.maxRdPoints) or ( dummyPulses == 0 and nRD * 2 > hw.maxRdPoints): print( 'ERROR: Too many acquired points or orders to the red pitaya.') return () while acqPoints + nRD <= hw.maxRdPoints and orders <= hw.maxOrders and repeIndexGlobal < nRepetitions: # First I do a noise measurement if repeIndex == 0: acqPoints += nRD data = np.concatenate( (data, np.random.randn(nRD * hw.oversamplingFactor)), axis=0) # Dephasing readout, phase and slice if (repeIndex == 0 or repeIndex >= dummyPulses): orders = orders + gSteps * 2 if repeIndex >= dummyPulses: orders = orders + gSteps * 4 # Rephasing readout gradient if (repeIndex == 0 or repeIndex >= dummyPulses): orders = orders + gSteps * 2 # Rx gate if (repeIndex == 0 or repeIndex >= dummyPulses): acqPoints += nRD data = np.concatenate( (data, np.random.randn(nRD * hw.oversamplingFactor)), axis=0) # Spoiler if (repeIndex == 0 or repeIndex >= dummyPulses): orders = orders + gSteps * 2 if repeIndex >= dummyPulses: orders = orders + gSteps * 4 # Update the phase and slice gradient if repeIndex >= dummyPulses: if phIndex == nPH - 1: phIndex = 0 slIndex += 1 else: phIndex += 1 if repeIndex >= dummyPulses: repeIndexGlobal += 1 # Update the global repeIndex repeIndex += 1 # Update the repeIndex after the ETL # Return the output variables return (phIndex, slIndex, repeIndexGlobal, acqPoints, data) # Create sequence instructions def createSequence(phIndex=0, slIndex=0, repeIndexGlobal=0, rewrite=True): repeIndex = 0 acqPoints = 0 orders = 0 # check in case of dummy pulse filling the cache if (dummyPulses > 0 and nRD * 3 > hw.maxRdPoints) or ( dummyPulses == 0 and nRD * 2 > hw.maxRdPoints): print( 'ERROR: Too many acquired points or orders to the red pitaya.') return () # Set shimming mri.iniSequence(expt, 20, shimming, rewrite=rewrite) # Run sequence batch while acqPoints + nRD <= hw.maxRdPoints and orders <= hw.maxOrders and repeIndexGlobal < nRepetitions: # Initialize time tEx = 20e3 + repetitionTime * repeIndex # First I do a noise measurement if repeIndex == 0: t0 = tEx - 4 * acqTime mri.rxGate(expt, t0, acqTime + 2 * addRdPoints / BW) acqPoints += nRD # Excitation pulse t0 = tEx - hw.blkTime - rfExTime / 2 mri.rfRecPulse(expt, t0, rfExTime, rfExAmp, 0.) # Dephasing readout, phase and slice if (repeIndex == 0 or repeIndex >= dummyPulses): t0 = tEx + rfExTime / 2 - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, dephGradTime, rdDephAmplitude, gSteps, axes[0], shimming) orders = orders + gSteps * 2 if repeIndex >= dummyPulses: t0 = tEx + rfExTime / 2 - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, dephGradTime, phGradients[phIndex], gSteps, axes[1], shimming) mri.gradTrap(expt, t0, gradRiseTime, dephGradTime, slGradients[slIndex], gSteps, axes[2], shimming) orders = orders + gSteps * 4 # Rephasing readout gradient if (repeIndex == 0 or repeIndex >= dummyPulses): t0 = tEx + echoTime - rdGradTime / 2 - gradRiseTime - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, rdGradTime, rdGradAmplitude, gSteps, axes[0], shimming) orders = orders + gSteps * 2 # Rx gate if (repeIndex == 0 or repeIndex >= dummyPulses): t0 = tEx + echoTime - acqTime / 2 - addRdPoints / BW mri.rxGate(expt, t0, acqTime + 2 * addRdPoints / BW) acqPoints += nRD # Spoiler if spoiler: t0 = tEx + echoTime + rdGradTime / 2 + gradRiseTime - hw.gradDelay mri.gradTrap(expt, t0, gradRiseTime, dephGradTime, -rdDephAmplitude, gSteps, axes[0], shimming) orders = orders + gSteps * 2 # Update the phase and slice gradient if repeIndex >= dummyPulses: if phIndex == nPH - 1: phIndex = 0 slIndex += 1 else: phIndex += 1 if repeIndex >= dummyPulses: repeIndexGlobal += 1 # Update the global repeIndex repeIndex += 1 # Update the repeIndex after the ETL # Turn off the gradients after the end of the batch mri.endSequence(expt, repeIndex * repetitionTime) # Return the output variables return (phIndex, slIndex, repeIndexGlobal, acqPoints) # Calibrate frequency if (not demo) and freqCal and (not plotSeq): mri.freqCalibration(rawData, bw=0.05) mri.freqCalibration(rawData, bw=0.005) larmorFreq = rawData['larmorFreq'] * 1e-6 drfPhase = rawData['drfPhase'] # Initialize the experiment dataFull = [] dummyData = [] overData = [] noise = [] nBatches = 0 repeIndexArray = np.array([0]) repeIndexGlobal = repeIndexArray[0] phIndex = 0 slIndex = 0 acqPointsPerBatch = [] while repeIndexGlobal < nRepetitions: nBatches += 1 if not demo: expt = ex.Experiment(lo_freq=larmorFreq, rx_t=samplingPeriod, init_gpa=init_gpa, gpa_fhdo_offset_time=(1 / 0.2 / 3.1)) samplingPeriod = expt.get_rx_ts()[0] BW = 1 / samplingPeriod / hw.oversamplingFactor acqTime = nPoints[0] / BW # us phIndex, slIndex, repeIndexGlobal, aa = createSequence( phIndex=phIndex, slIndex=slIndex, repeIndexGlobal=repeIndexGlobal, rewrite=False) repeIndexArray = np.concatenate( (repeIndexArray, np.array([repeIndexGlobal - 1])), axis=0) acqPointsPerBatch.append(aa) expt.plot_sequence() else: phIndex, slIndex, repeIndexGlobal, aa, dataA = createSequenceDemo( phIndex=phIndex, slIndex=slIndex, repeIndexGlobal=repeIndexGlobal) repeIndexArray = np.concatenate( (repeIndexArray, np.array([repeIndexGlobal - 1])), axis=0) acqPointsPerBatch.append(aa) for ii in range(nScans): print('Batch ', nBatches, ', Scan ', ii, ' runing...') if not demo: if plotSeq == 1: # What is the meaning of plotSeq?? print('Ploting sequence...') expt.plot_sequence() plt.show() expt.__del__() break else: rxd, msgs = expt.run() rxd['rx0'] = rxd[ 'rx0'] * 13.788 # Here I normalize to get the result in mV # Get noise data noise = np.concatenate( (noise, rxd['rx0'][0:nRD * hw.oversamplingFactor]), axis=0) rxd['rx0'] = rxd['rx0'][nRD * hw.oversamplingFactor::] # Get data if dummyPulses > 0: dummyData = np.concatenate( (dummyData, rxd['rx0'][0:nRD * hw.oversamplingFactor]), axis=0) overData = np.concatenate( (overData, rxd['rx0'][nRD * hw.oversamplingFactor::]), axis=0) else: overData = np.concatenate((overData, rxd['rx0']), axis=0) else: data = dataA noise = np.concatenate( (noise, data[0:nRD * hw.oversamplingFactor]), axis=0) data = data[nRD * hw.oversamplingFactor::] # Get data if dummyPulses > 0: dummyData = np.concatenate( (dummyData, data[0:nRD * hw.oversamplingFactor]), axis=0) overData = np.concatenate( (overData, data[nRD * hw.oversamplingFactor::]), axis=0) else: overData = np.concatenate((overData, data), axis=0) if not demo: expt.__del__() if plotSeq == 1: break del aa if not plotSeq: acqPointsPerBatch = (acqPointsPerBatch - nRD * (dummyPulses > 0) - nRD) * nScans print('Scans done!') rawData['noiseData'] = noise rawData['overData'] = overData # Fix the echo position using oversampled data if dummyPulses > 0: dummyData = np.reshape( dummyData, (nBatches * nScans, 1, nRD * hw.oversamplingFactor)) dummyData = np.average(dummyData, axis=0) rawData['dummyData'] = dummyData overData = np.reshape(overData, (-1, 1, nRD * hw.oversamplingFactor)) overData = mri.fixEchoPosition(dummyData, overData) overData = np.reshape(overData, -1) # Generate dataFull dataFull = sig.decimate(overData, hw.oversamplingFactor, ftype='fir', zero_phase=True) if nBatches > 1: dataFullA = dataFull[0:sum(acqPointsPerBatch[0:-1])] dataFullB = dataFull[sum(acqPointsPerBatch[0:-1])::] # Reorganize dataFull dataProv = np.zeros([nScans, nSL * nPH * nRD]) dataProv = dataProv + 1j * dataProv dataFull = np.reshape(dataFull, (nBatches, nScans, -1, nRD)) if nBatches > 1: dataFullA = np.reshape(dataFullA, (nBatches - 1, nScans, -1, nRD)) dataFullB = np.reshape(dataFullB, (1, nScans, -1, nRD)) for scan in range(nScans): if nBatches > 1: dataProv[ii, :] = np.concatenate( (np.reshape(dataFullA[:, ii, :, :], -1), np.reshape(dataFullB[:, ii, :, :], -1)), axis=0) else: dataProv[ii, :] = np.reshape(dataFull[:, ii, :, :], -1) dataFull = np.reshape(dataProv, -1) # Get index for krd = 0 # Average data dataProv = np.reshape(dataFull, (nScans, nRD * nPH * nSL)) dataProv = np.average(dataProv, axis=0) dataProv = np.reshape(dataProv, (nSL, nPH, nRD)) # Check where is krd = 0 dataProv = dataProv[int(nPoints[2] / 2), int(nPH / 2), :] indkrd0 = np.argmax(np.abs(dataProv)) if indkrd0 < nRD / 2 - addRdPoints or indkrd0 > nRD / 2 + addRdPoints: indkrd0 = int(nRD / 2) # Get individual images dataFull = np.reshape(dataFull, (nScans, nSL, nPH, nRD)) dataFull = dataFull[:, :, :, indkrd0 - int(nPoints[0] / 2):indkrd0 + int(nPoints[0] / 2)] imgFull = dataFull * 0 for ii in range(nScans): imgFull[ii, :, :, :] = np.fft.ifftshift( np.fft.ifftn(np.fft.ifftshift(dataFull[ii, :, :, :]))) rawData['dataFull'] = dataFull rawData['imgFull'] = imgFull # Average data data = np.average(dataFull, axis=0) data = np.reshape(data, (nSL, nPH, nPoints[0])) # Do zero padding dataTemp = np.zeros((nPoints[2], nPoints[1], nPoints[0])) dataTemp = dataTemp + 1j * dataTemp dataTemp[0:nSL, :, :] = data data = np.reshape(dataTemp, (1, nPoints[0] * nPoints[1] * nPoints[2])) # Fix the position of the sample according to dfov kMax = np.array(nPoints) / (2 * np.array(fov)) * np.array(axesEnable) kRD = np.linspace(-kMax[0], kMax[0], num=nPoints[0], endpoint=False) # kPH = np.linspace(-kMax[1],kMax[1],num=nPoints[1],endpoint=False) kSL = np.linspace(-kMax[2], kMax[2], num=nPoints[2], endpoint=False) kPH = kPH[::-1] kPH, kSL, kRD = np.meshgrid(kPH, kSL, kRD) kRD = np.reshape(kRD, (1, nPoints[0] * nPoints[1] * nPoints[2])) kPH = np.reshape(kPH, (1, nPoints[0] * nPoints[1] * nPoints[2])) kSL = np.reshape(kSL, (1, nPoints[0] * nPoints[1] * nPoints[2])) dPhase = np.exp(-2 * np.pi * 1j * (dfov[0] * kRD + dfov[1] * kPH + dfov[2] * kSL)) data = np.reshape(data * dPhase, (nPoints[2], nPoints[1], nPoints[0])) rawData['kSpace3D'] = data img = np.fft.ifftshift(np.fft.ifftn(np.fft.ifftshift(data))) rawData['image3D'] = img data = np.reshape(data, (1, nPoints[0] * nPoints[1] * nPoints[2])) # Create sampled data kRD = np.reshape(kRD, (nPoints[0] * nPoints[1] * nPoints[2], 1)) kPH = np.reshape(kPH, (nPoints[0] * nPoints[1] * nPoints[2], 1)) kSL = np.reshape(kSL, (nPoints[0] * nPoints[1] * nPoints[2], 1)) data = np.reshape(data, (nPoints[0] * nPoints[1] * nPoints[2], 1)) rawData['kMax'] = kMax rawData['sampled'] = np.concatenate((kRD, kPH, kSL, data), axis=1) data = np.reshape(data, (nPoints[2], nPoints[1], nPoints[0])) # Save data mri.saveRawData(rawData) # Reshape to 0 dimensional data = np.reshape(data, -1) return rawData, msgs, data, BW