Abstract: Nei precedenti post (Risonanza Elettronica di Spin, Risonanza Elettronica di Spin – Parte HW) abbiamo descritto i principi generali e la parte hardware del nostro apparato ESR DIY. Nel presente post completiamo la descrizione dell’apparato soffermandoci sulla parte firmware di gestione e sulla parte software di registrazione dei dati.
Firmware
La gestione dell’apparato per la risonanza elettronica di spin è fatta con un microcontrollore della serie PSoC 5lp della Cypress. Si tratta di un cosìdetto “system on chip”. Oltre alle classiche funzionalità di un microcontrollore, questo componente integra funzionalità avanzate che includono ADC e DAC di precisione, op amp programmabili e logica FPGA-like, il tutto configurabile tramite una comoda interfaccia grafica e programmabile in C.
Il convertitore ADC è del tipo delta-sigma a 18 bit, con range 0 – 6V e la conversione avviene in modalità multiplexer. I canali acquisiti sono il trimmer presente sulla scheda, il segnale del sensore Hall per il campo magnetico ed il segnale ESR rilevato e amplificato dal lock-in detector. L’immagine seguente mostra lo schema della parte ADC dello PSoC.
La lettura del segnale prodotto dal sensore Hall va convertita nel corrispondente valore del campo magnetico misurato in mT. Il codice seguente mostra la funzione di conversione.
/******************************************************************************* * Function Name: CalcBfield ******************************************************************************** * Summary: * ********************************************************************************/ double CalcBfield(double HallSensorReading){ int offsetHallSensor = 2585; // 2585mv means 0mT int HallSensorRatio = 100; // 100mV/mT double Bfield = (HallSensorReading-offsetHallSensor)/HallSensorRatio; // mag. field in mT return Bfield; }
Il PSoC ci serve anche per la misura della frequenza del segnale generato dall’oscillatore Robinson. Come descritto nel post precedente sulla parte HW, il segnale viene diviso per un fattore 128 da un circuito prescaler. La frequenza viene misurata dal componente counter come descritto nello schema seguente.
Il codice seguente mostra l’istruzione per il calcolo della frequenza.
/* Counter pulse reading - frequency calculation*/ osc_freq = ((Counter_ReadCounter()*(1000.0/readingPeriod))/1000000)*128; //128 presc. factor
Il nostro PSoC effettua anche la generazione del segnale di pilotaggio delle bobine di Helmholtz e del segnale modulante a 1KHz. Per questa operazione vengono utilizzati i componenti DAC dello PSoC, tra i quali anche il WaveDAC che permette la generazione di forme d’onda prestabilite, come mostrato nello schema seguente.
Il segnale di pilotaggio delle bobine di Helmholtz è una rampa crescente che parte da un valore iniziale di 200mV e termina al valore massimo determinato dalla lettura del trimmer; gli step di incremento sono di 16mV ed avvengono con cadenza determinata dalla variabile stepPeriod; il codice seguente mostra l’implementazione della rampa.
/* DAC Variables */ static int sweepValue = 0; // sweep value (mV) static int sweepInitValue = 200; // init value 200mV static int sweepEndValue; // from trimmer static int stepValue = 16; // step value 16mV static int stepPeriod = 250; // step period 250ms /******************************************************************************* * Function Name: SweepingTimerInt_ISR ******************************************************************************* * Summary: * Sweeping Timer Interrupt (every period). *******************************************************************************/ CY_ISR(SweepingTimerInt_ISR){ /* Calculation of the sweep value */ sweepValue = sweepInitValue + stepValue*stepCount; /* Assign DAC value */ DACvalue = (uint8)((sweepValue*256)/4096); CoilDriver_SetValue(DACvalue); /* increment number of steps */ stepCount++; /* check final value reached */ if(sweepValue >= sweepEndValue){ /* Reset */ stepCount = 0; } /* Reset timer */ Sweeping_Timer_ReadStatusRegister(); }
Software Python
I dati acquisiti con il PSoC vengono inviati via interfaccia USB/seriale ad un PC linux sul quale gira un programma python che legge i dati del campo magnetico e del segnale ESR e li visualizza in grafico (come quello mostrato nella immagine di copertina). I dati vengono inoltre registrati su file csv per analisi ulteriori.
Il codice riportato sotto mostra un esempio del programma python di acquisizione e plotting dati.
################################ # serial reading /dev/ttyACM0 # and plotting data ################################ import time import serial import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation # file definition filenameESR = "ESRData.csv" outFile = open(filenameESR,"a+") outFile.write("**************\n") outFile.write("** ESR Data **\n") outFile.write("**************\n") # parameters x_len = 500 # time interval 0.1s y1_range=[0,5] # B field intensity mT y2_range=[1000,3500] # ESR signal mv # create figure for plotting fig = plt.figure() ax1 = fig.add_subplot(2,1,1) ax2 = fig.add_subplot(2,1,2) xs = list(range(0,x_len)) y1s = [0]*x_len y2s = [0]*x_len ax1.set_ylim(y1_range) ax2.set_ylim(y2_range) # create figure for plotting ax1.set_title('Magnetic Field') ax1.set_xlabel('time [0.1s]') ax1.set_ylabel('B [mT]') ax2.set_title('ESR Signal') ax2.set_xlabel('time [0.1s]') ax2.set_ylabel('Signal [mV]') plt.subplots_adjust(hspace=0.5) # init serial ser=serial.Serial('/dev/ttyACM0') ser.flushInput() time.sleep(2) # give time to flush # create blank line linea1 = ax1.plot(xs,y1s)[0] linea2 = ax2.plot(xs,y2s)[0] # funcion called periodically from FuncAnimation def animate(i,y1s,y2s,outFile): try: line=ser.readline().strip() BFieldTxt,ESRSignalTxt=line.decode('ascii').split(";",1) BField=round(np.float32(BFieldTxt),2) ESRSignal=np.int(ESRSignalTxt) #print('BField',BField) #print('ESRSignal',ESRSignal) outFile.write(BFieldTxt+","+ESRSignalTxt+"\n") except ValueError: print('failed to read serial') # add data to lists y1s.append(BField) y1s=y1s[-x_len:] y2s.append(ESRSignal) y2s=y2s[-x_len:] # update lines linea1.set_ydata(y1s) linea2.set_ydata(y2s) return linea1,linea2 # animation ani = animation.FuncAnimation(fig,animate,fargs=(y1s,y2s,outFile),interval=100,blit=True) plt.show()
Conclusioni
Con questo post concludiamo la descrizione del nostro apparato DIY per la risonanza elettronica di spin. Nel prossimo post descriveremo alcune misure sperimentali effettuate con il nostro apparato.
Se ti è piaciuto questo articolo puoi condividerlo sui “social” Facebook, Twitter o LinkedIn con i pulsanti presenti sotto. In questo modo ci puoi aiutare ! Grazie !
Donazioni
Se vuoi contribuire allo sviluppo di questo sito ed allo sviluppo di nuove attività sperimentali puoi fare una donazione, Grazie !