def data(): noiseCov = 0.01 amplitude = np.asarray([0.5, 0.5, 1.0]) * 10 chemshift = np.asarray([3.0, 3.05, 2.0]) - 4.65 lw = [10, 10, 10] phases = [0, 0, 0] g = [0, 0, 0] basisNames = ['Cr', 'PCr', 'NAA'] basisFIDs = [] for idx, _ in enumerate(amplitude): tmp, basisHdr = syntheticFID(noisecovariance=[[0.0]], chemicalshift=[chemshift[idx]], amplitude=[1.0], linewidth=[lw[idx] / 5], phase=[phases[idx]], g=[g[idx]]) basisFIDs.append(tmp[0]) basisFIDs = np.asarray(basisFIDs) synFID, synHdr = syntheticFID(noisecovariance=[[noiseCov]], chemicalshift=chemshift, amplitude=amplitude, linewidth=lw, phase=phases, g=g) synMRS = MRS(FID=synFID[0], header=synHdr, basis=basisFIDs, basis_hdr=basisHdr, names=basisNames) return synMRS, amplitude
def test_FIDToSpec_SpecToFID(): testFID, hdr = synth.syntheticFID(amplitude=[10], chemicalshift=[0], phase=[0], damping=[20]) # SVS case spec = misc.FIDToSpec(testFID[0]) reformedFID = misc.SpecToFID(spec) assert np.allclose(reformedFID, testFID) testMRSI = np.tile(testFID, (4, 4, 4, 1)).T testspec = misc.FIDToSpec(testMRSI) assert np.argmax(np.abs(testspec[:, 2, 2, 2])) == 1024 testspec = misc.FIDToSpec(testMRSI.T, axis=3) assert np.argmax(np.abs(testspec[2, 2, 2, :])) == 1024 reformedFID = misc.SpecToFID(testspec, axis=3) assert np.allclose(reformedFID, testMRSI.T) reformedFID = misc.SpecToFID(testspec.T) assert np.allclose(reformedFID, testMRSI) # Odd number of points - guard against fftshift/ifftshift errors testFID, hdr = synth.syntheticFID(amplitude=[1], chemicalshift=[0], phase=[0], damping=[20], points=1025) assert np.allclose(misc.SpecToFID(misc.FIDToSpec(testFID[0])), testFID)
def mrsi_data_diff(tmp_path): reps = 2 noiseconv = 0.1*np.eye(reps) coilamps = np.ones(reps) coilphs = np.zeros(reps) FID, hdr = syntheticFID(noisecovariance=noiseconv, coilamps=coilamps, coilphase=coilphs) coilamps = np.ones(reps) coilphs = np.random.randn(reps) FID2, hdr = syntheticFID(noisecovariance=noiseconv, coilamps=coilamps, coilphase=coilphs) testFile, testFile2 = [], [] data, data2 = [], [] for idx, f in enumerate(FID): testname = f'mrsidata_{idx}.nii' testFile.append(op.join(tmp_path, testname)) affine = np.eye(4) data.append(np.tile(f, (3, 3, 3, 1))) fsl_io.saveNIFTI(testFile[idx], data[idx], hdr, affine=affine) for idx, f in enumerate(FID2): testname = f'mrsidata_{idx}.nii' testFile2.append(op.join(tmp_path, testname)) affine = np.eye(4) data2.append(np.tile(f, (3, 3, 3, 1))) fsl_io.saveNIFTI(testFile2[idx], data2[idx], hdr, affine=affine) return testFile, testFile2, data, data2
def test_align_diff(): shift0 = np.random.randn(10) * 0.15 phs = np.random.randn(10) * 0.1 * np.pi shiftedFIDs0 = [] shiftedFIDs1 = [] for s0, p in zip(shift0, phs): testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 1], chemicalshift=[-2 + s0, 3 + s0], phase=[p + np.pi, p], damping=[100, 100], points=2048, noisecovariance=[[1E-6]]) shiftedFIDs0.append(testFIDs[0]) testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 1], chemicalshift=[-2, 3], phase=[0, 0], damping=[100, 100], points=2048, noisecovariance=[[1E-6]]) shiftedFIDs1.append(testFIDs[0]) testFIDs0, _ = syn.syntheticFID(amplitude=[2, 1], chemicalshift=[-2, 3], phase=[np.pi, 0], damping=[100, 100], points=2048, noisecovariance=[[1E-6]]) testFIDs1, _ = syn.syntheticFID(amplitude=[2, 1], chemicalshift=[-2, 3], phase=[0, 0], damping=[100, 100], points=2048, noisecovariance=[[1E-6]]) tgt = testFIDs0[0] + testFIDs1[0] mrs = MRS(FID=tgt, header=testHdrs) sub0_aa, sub1_aa, phi, eps = preproc.phase_freq_align_diff( shiftedFIDs0, shiftedFIDs1, testHdrs['bandwidth'], testHdrs['centralFrequency'], target=tgt, shift=False, ppmlim=(-5, 5)) # align.phase_freq_align_diff_report(shiftedFIDs0,shiftedFIDs1,sub0_aa,sub1_aa,testHdrs,eps,phi,shift=False,ppmlim=(-5,5)) shiftInHz = shift0 * testHdrs['centralFrequency'] assert np.allclose(eps, shiftInHz, atol=1E-0) assert np.allclose(phi, phs, atol=1E-0)
def test_combine_FIDs(): testFIDs, testHdrs = syn.syntheticFID(noisecovariance=np.zeros((2, 2)), coilamps=[1.0, 1.0], coilphase=[0.0, np.pi]) combfids = preproc.combine_FIDs(testFIDs, 'mean') assert np.isclose(combfids, 0).all() testFIDs, testHdrs = syn.syntheticFID(noisecovariance=np.zeros((4, 4)), coilamps=[1.0, 1.0, 1.0, 1.0], coilphase=[0.0, 0.0, 0.0, 0.0]) weigths = [ np.exp(1j * 0), np.exp(1j * np.pi / 2), np.exp(1j * np.pi), np.exp(1j * 3 * np.pi / 2) ] combfids = preproc.combine_FIDs(testFIDs, 'weighted', weights=weigths) assert np.isclose(combfids, 0).all() #Generate high SNR data coilvar = 0.001 noiseCov = [[coilvar, 0], [0, coilvar]] coilamps = 0.5 + np.random.rand(2) * 0.4 coilphs = np.random.rand(2) * np.pi * 2 testFIDs, testHdrs = syn.syntheticFID(noisecovariance=noiseCov, coilamps=coilamps, coilphase=coilphs, points=4096) invcovMat = coilvar * np.linalg.inv(noiseCov) analyticalRoemer = [] testFIDs = np.asarray(testFIDs).T cmplxW = coilamps * np.exp(1j * coilphs) for f in testFIDs: tmp = (f @ invcovMat @ cmplxW.conj()) / np.sqrt( cmplxW.conj() @ invcovMat @ cmplxW) analyticalRoemer.append(tmp) analyticalRoemer = np.asarray(analyticalRoemer) combfid = preproc.combine_FIDs(testFIDs, 'svd', do_prewhiten=True) # Check only the first few points otherwise the relative tolarence has to be very high. assert np.isclose(np.abs(combfid[:200]), np.abs(analyticalRoemer[:200]), atol=1E-4, rtol=1E-1).all()
def data(): noiseCov = 0.001 amplitude = np.asarray([0.5, 0.5, 1.0]) * 10 chemshift = np.asarray([3.0, 3.05, 2.0]) - 4.65 lw = [10, 10, 10] phases = [0, 0, 0] g = [0, 0, 0] basisNames = ['Cr', 'PCr', 'NAA'] begintime = 0.00005 basisFIDs = [] for idx, _ in enumerate(amplitude): tmp, basisHdr = syntheticFID(noisecovariance=[[0.0]], chemicalshift=[chemshift[idx] + 0.1], amplitude=[1.0], linewidth=[lw[idx] / 5], phase=[phases[idx]], g=[g[idx]], begintime=0) basisFIDs.append(tmp[0]) basisFIDs = np.asarray(basisFIDs) synFID, synHdr = syntheticFID(noisecovariance=[[noiseCov]], chemicalshift=chemshift, amplitude=amplitude, linewidth=lw, phase=phases, g=g, begintime=begintime) synMRS = MRS(FID=synFID[0], header=synHdr, basis=basisFIDs, basis_hdr=basisHdr, names=basisNames) metab_groups = [0] * synMRS.numBasis Fitargs = { 'ppmlim': [0.2, 4.2], 'method': 'MH', 'baseline_order': -1, 'metab_groups': metab_groups, 'MHSamples': 100, 'disable_mh_priors': True } res = fit_FSLModel(synMRS, **Fitargs) return res, amplitude
def test_syntheticFID(): testFID, hdr = syn.syntheticFID(noisecovariance=[[0.0]], points=16384) # Check FID is sum of lorentzian lineshapes # anlytical solution T2 = 1 / (hdr['inputopts']['damping'][0]) M0 = hdr['inputopts']['amplitude'][0] f0 = hdr['inputopts']['centralfrequency'] * hdr['inputopts'][ 'chemicalshift'][0] f1 = hdr['inputopts']['centralfrequency'] * hdr['inputopts'][ 'chemicalshift'][1] f = hdr['faxis'] spec = (M0 * T2) / (1 + 4 * np.pi**2 * (f0 - f)**2 * T2**2) + 1j * ( 2 * np.pi * M0 * (f0 - f) * T2**2) / (1 + 4 * np.pi**2 * (f0 - f)**2 * T2**2) spec += (M0 * T2) / (1 + 4 * np.pi**2 * (f1 - f)**2 * T2**2) + 1j * ( 2 * np.pi * M0 * (f1 - f) * T2**2) / (1 + 4 * np.pi**2 * (f1 - f)**2 * T2**2) # Can't quite get the scaling right here. testSpec = FIDToSpec(testFID[0]) spec /= np.max(np.abs(spec)) testSpec /= np.max(np.abs(testSpec)) assert np.isclose(spec, FIDToSpec(testFID[0]), atol=1E-2, rtol=1E0).all()
def test_timeshift(): # Create data with lots of points and some begin time delay testFID, testHdrs = syn.syntheticFID(begintime=-0.001, points=4096, noisecovariance=[[0.0]]) testFID2, testHdrs2 = syn.syntheticFID(begintime=0.000, points=4096, noisecovariance=[[0.0]]) # Reduce points and pad to remove first order phase shiftedFID, _ = preproc.timeshift(testFID[0], 1 / testHdrs['inputopts']['bandwidth'], 0.001, 0.0, samples=4096) # assert shiftedFID.size == 2048 assert np.allclose(shiftedFID, testFID2[0], atol=1E-1)
def test_phaseCorrect(): testFIDs, testHdrs = syn.syntheticFID(amplitude=[1.0], chemicalshift=[0.0], phase=[np.pi / 2], noisecovariance=[[1E-5]]) corrected, phs, pos = preproc.phaseCorrect(testFIDs[0], testHdrs['bandwidth'], testHdrs['centralFrequency'], ppmlim=(-0.5, 0.5), shift=False) assert np.isclose(phs, -np.pi / 2, atol=1E-2)
def test_freqshift(): testFID, testHdrs = syn.syntheticFID(amplitude=[0.0, 1.0 ]) # Single peak at 3 ppm # Shift to 0 ppm dt = 1 / testHdrs['inputopts']['bandwidth'] shift = testHdrs['inputopts']['centralfrequency'] * -3.0 shiftedFID = preproc.freqshift(testFID[0], dt, shift) maxindex = np.argmax(np.abs(FIDToSpec(shiftedFID))) freqOfMax = testHdrs['faxis'][maxindex] assert freqOfMax < 5 and freqOfMax > -5
def test_noisecov(): # Create positive semi-definite noise covariance inputnoisecov = np.random.random((2, 2)) inputnoisecov = np.dot(inputnoisecov, inputnoisecov.T) testFID, hdr = syn.syntheticFID(coilamps=[1.0, 1.0], coilphase=[0.0, 0.0], noisecovariance=inputnoisecov, amplitude=[0.0, 0.0], points=32768) outcov = np.cov(np.asarray(testFID)) # Noise cov is for both real and imag, so multiply by 2 assert np.isclose(outcov, 2 * inputnoisecov, atol=1E-1).all()
def mrsi_data_uncomb(tmp_path): coils = 4 noiseconv = 0.1*np.eye(coils) coilamps = np.random.randn(coils) coilphs = np.random.random(coils)*2*np.pi FID, hdr = syntheticFID(noisecovariance=noiseconv, coilamps=coilamps, coilphase=coilphs) testname = 'mrsidata_uncomb.nii' testFile = op.join(tmp_path, testname) affine = np.eye(4) data = np.tile(np.asarray(FID).T, (3, 3, 3, 1, 1)) fsl_io.saveNIFTI(testFile, data, hdr, affine=affine) return testFile, data
def svs_data(tmp_path): reps = 3 noiseconv = 0.1*np.eye(reps) coilamps = np.ones(reps) coilphs = np.zeros(reps) FID, hdr = syntheticFID(noisecovariance=noiseconv, coilamps=coilamps, coilphase=coilphs) testFile = [] data = [] for idx, f in enumerate(FID): testname = f'svsdata_{idx}.nii' testFile.append(op.join(tmp_path, testname)) affine = np.eye(4) data.append(f) fsl_io.saveNIFTI(testFile[idx], data[idx], hdr, affine=affine) return testFile, data
def test_shiftToRef(): testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 0], chemicalshift=[-2.1, 0], phase=[0, 0], points=1024, noisecovariance=[[1E-3]]) shiftFID, _ = preproc.shiftToRef(testFIDs[0], -2.0, testHdrs['bandwidth'], testHdrs['centralFrequency'], ppmlim=(-2.2, -2.0), shift=False) mrs = MRS(FID=shiftFID, header=testHdrs) maxindex = np.argmax(mrs.getSpectrum(shift=False)) position = mrs.getAxes(axis='ppm')[maxindex] assert np.isclose(position, -2.0, atol=1E-1)
def test_hlsvd(): # low noise testFIDs, testHdrs = syn.syntheticFID(noisecovariance=[[1E-6]], amplitude=[1.0, 1.0], chemicalshift=[-2, 0]) limits = [-2.5, -1.5] # (FID,dwelltime,centralFrequency,limits,limitUnits = 'ppm',numSingularValues=50) removedFID = preproc.hlsvd(testFIDs[0], testHdrs['dwelltime'], testHdrs['centralFrequency'], limits, limitUnits='ppm', numSingularValues=20) onResFID = np.exp(-testHdrs['inputopts']['damping'][1] * testHdrs['taxis']) assert np.isclose(np.real(removedFID), np.real(onResFID), atol=1E-2, rtol=1E-2).all()
def test_phase_freq_align(): peak1Shift = np.random.rand(10) * 0.1 peak1Phs = np.random.randn(10) * 2 * np.pi shiftedFIDs = [] for s, p in zip(peak1Shift, peak1Phs): testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 1], chemicalshift=[-2 + s, 3], phase=[p, 0.0], points=2048, noisecovariance=[[1E-1]]) shiftedFIDs.append(testFIDs[0]) # Align across shifted peak alignedFIDs, _, _ = preproc.phase_freq_align(shiftedFIDs, testHdrs['bandwidth'], testHdrs['centralFrequency'] * 1E6, niter=2, verbose=False, ppmlim=(-2.2, -1.7), shift=False) meanFID = preproc.combine_FIDs(alignedFIDs, 'mean') assert np.max(np.abs(FIDToSpec(meanFID))) > 0.09 # Align across fixed peak alignedFIDs, _, _ = preproc.phase_freq_align(shiftedFIDs, testHdrs['bandwidth'], testHdrs['centralFrequency'] * 1E6, niter=2, verbose=False, ppmlim=(2, 4), shift=False) meanFID = preproc.combine_FIDs(alignedFIDs, 'mean') assert np.max(np.abs(FIDToSpec(meanFID))) > 0.09
def test_pad(): testFIDs, testHdrs = syn.syntheticFID() paddedFID1 = preproc.pad(testFIDs[0], 1, 'first') assert paddedFID1[0] == 0.0 paddedFID1 = preproc.pad(testFIDs[0], 1, 'last') assert paddedFID1[-1] == 0.0
def test_truncate(): testFIDs, testHdrs = syn.syntheticFID() truncatedFID1 = preproc.truncate(testFIDs[0], 1, 'first') assert (testFIDs[0][1:] == truncatedFID1).all() truncatedFID1 = preproc.truncate(testFIDs[0], 1, 'last') assert (testFIDs[0][:-1] == truncatedFID1).all()
def test_calcQC(): # Syntetic data synFID, synHdr = syntheticFID(noisecovariance=[[0.1]], points=2 * 2048, chemicalshift=[0], amplitude=[6.0], linewidth=[10]) synFIDNoise, synHdrNoise = syntheticFID(noisecovariance=[[0.1]], points=2 * 2048, chemicalshift=[0], amplitude=[0], linewidth=[10]) basisFID, basisHdr = syntheticFID(noisecovariance=[[0.0]], points=2 * 2048, chemicalshift=[0], amplitude=[0.1], linewidth=[2]) synMRS = MRS(FID=synFID[0], header=synHdr) synMRSNoise = MRS(FID=synFIDNoise[0], header=synHdrNoise) synMRSNoNoise = MRS(FID=synHdr['noiseless'], header=synHdr) synMRS_basis = MRS(FID=synFID[0], header=synHdr, basis=basisFID[0], basis_hdr=basisHdr, names=['Peak1']) truenoiseSD = np.sqrt(synHdrNoise['cov'][0, 0]) pureNoiseMeasured = np.std(synMRSNoise.getSpectrum()) realnoise = np.std(np.real(synMRSNoise.getSpectrum())) imagNoise = np.std(np.imag(synMRSNoise.getSpectrum())) print( f'True cmplx noise = {truenoiseSD:0.3f}, pure noise measured = {pureNoiseMeasured:0.3f} (real/imag = {realnoise:0.3f}/{imagNoise:0.3f})' ) # Calc SNR without apodisation from the no noise and pure noise spectra truePeakHeight = np.max(np.real(synMRSNoNoise.getSpectrum())) SNR_noApod = truePeakHeight / pureNoiseMeasured print( f'SNR no apod: {SNR_noApod:0.1f} ({truePeakHeight:0.2e}/{pureNoiseMeasured:0.2e})' ) # Calc SNR with apodisation from the no noise and pure noise spectra trueLW = synHdr['inputopts']['linewidth'][0] trueApodSpec_Noise = specApodise(synMRSNoise, trueLW) apodNoise = np.std(trueApodSpec_Noise) trueApodSpec_noNoise = specApodise(synMRSNoNoise, trueLW) peakHeigtApod = np.max(np.real(trueApodSpec_noNoise)) SNR = peakHeigtApod / apodNoise print(f'SNR w. apod: {SNR:0.1f} ({peakHeigtApod:0.2e}/{apodNoise:0.2e})') metab_groups = [0] Fitargs = { 'ppmlim': [2.65, 6.65], 'method': 'Newton', 'baseline_order': -1, 'metab_groups': [0] } res = fit_FSLModel(synMRS_basis, **Fitargs) fwhm_test, SNRObj = calcQC(synMRS_basis, res, ppmlim=[2.65, 6.65]) print(f'Measured FWHM: {fwhm_test.mean().to_numpy()[0]:0.1f}') print(f'Measured spec SNR: {SNRObj.spectrum:0.1f}') print(f'Measured peak SNR: {SNRObj.peaks.mean().to_numpy()[0]:0.1f}') assert np.isclose(fwhm_test.mean().to_numpy(), trueLW, atol=1E0) assert np.isclose(SNRObj.spectrum, SNR_noApod, atol=1E1) assert np.isclose(SNRObj.peaks.mean().to_numpy(), SNR, atol=2E1)