Experiment-08 (1)

html

School

University of British Columbia *

*We aren’t endorsed by this school

Course

219

Subject

Electrical Engineering

Date

Dec 6, 2023

Type

html

Pages

15

Report

Uploaded by DeanRedPandaMaster745

Experiment 08 - Operational Amplifiers 2nd November, 2023 Aaryan Jogina (24280893) Lab Partner: Laura Liu The Operational Amplifier (Op-Amp) In electronics, the term Op-Amp typically refers to a voltage amplifier that has a differential input, meaning there are two inputs: $V−$ and $V+$, and a single ended output $V_{out}$. The difference between the two voltage inputs is amplified and produced as an output. Below is an image of the Op-Amp's symbol and its internal structure: In [1]: # import image module from IPython.display import Image # get the image Image(url="OpAmp_Image.png") Out[1]: Inverting Voltage Amplifier A simple inverting amplifier circuit is shown below: In [2]: # import image module from IPython.display import Image # get the image Image(url="InvertingAmplifier.png") Out[2]: Assuming the Op-Amp is treated as ideal, the closed loop voltage gain is: $$\frac{V_{out}}{V_{in}} = −\frac{R_f}{R_g} \equiv G$$ Our Circuit – Set-up We built our circuit according to the sketch above, keeping it as 2-dimensional as possible. Below is an image of our final built circuit: In [3]: # import image module from IPython.display import Image # get the image Image(url="Lab08_FinalCircuit.jpeg") Out[3]:
Plot with no power In [4]: # import image module from IPython.display import Image # get the image Image(url="Plot_NoPower.jpeg") Out[4]: Our Observations and Measurements Before taking amplification measurements, we observed that the amplitude of the output signal almost $\times10$ that of the input signal. The phase difference between the input and output signals was $\pi$. We took measurements at two different frequencies: $100Hz$ and at $500Hz$. $At$ $100Hz$ At a frequency of $100Hz$, we took measurements at varying amplitude and offset: one for positive values of offset and the one for negative values of offset, and found the offset values for distortion at each particular amplitude increasing at a step of $100mV$. We then measured $V_{in}$ vs $V_{out}$, which is shown later on below. Below is the table for both the positive and the negative values of offset at which the plot became distorted, for each amplitude In [5]: # import the packages that you need, including data_entry2 import numpy as np import data_entry2 import array import pandas as pd import matplotlib.pyplot as plt de = data_entry2.sheet("Lab08_100fpn") Sheet name: Lab08_100fpn.csv Note: When the amplitude was kept at $100V$, it became very difficult to observe any distortions. At $100mV$, the wave disappeared when $V_{off}=-500mV$ These limiting voltages on the positive and negative side depend on the particular Op-Amp and are always less than the power supply voltages of +-5V. Plot Images In [6]: # import image module from IPython.display import Image # get the image Image(url="Plot_NoDistortion.jpeg") Out[6]:
Amplification with no distortion at $V_{in}=100mV$ and $V_{off}=0mV$ In [7]: # import image module from IPython.display import Image # get the image Image(url="Plot_WithDistortion.jpeg") Out[7]: Amplification with heavy distortion at $V_{in}=100mV$ at a high offset $V_{in}$ vs $V_{out}$ We took 11 measurements at varying input voltages from $100mV$ up to $600mV$ with an increment step of $50mV$. For our plot, we will use the linear range that is up till $V_{in}=450mV$. All measurements were done after keeping the offset voltage at a low value of $V_{off}=107mV$. In [8]: # import the packages that you need, including data_entry2 import numpy as np import data_entry2 import array import pandas as pd import matplotlib.pyplot as plt de = data_entry2.sheet("Lab08_100fV") Sheet name: Lab08_100fV.csv In [9]: # import the library numpy and rename it np import numpy as np import array # import the library matplotlib and rename it plot import matplotlib.pyplot as plt #name the input file with the data fname = 'Lab08_100fV.csv' # This block reads in data - the file is assumed to be in csv format (comma separated variables). # Files need to be specified with a full path OR they have to be saved in the same folder as the script # data = np.loadtxt(fname, delimiter=',', comments='#',usecols=(0,1,2,3),skiprows=2) # generate an array which is the first column of data. Note the first column is # indexed as zero. x = data[:,0] # generate an array for the x uncertainty (column index 1)
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
x_sigma = data[:,1] # generate an array for the y values (column index 2) y = data[:,2] # generate an array for y uncertainty (column index 3) y_sigma = data[:,3] # This block creates a plot plt.errorbar(x,y,xerr=x_sigma,yerr=y_sigma,marker='.',linestyle='',label="measured data") plt.xlabel('Input Voltage (V)') plt.ylabel('Output Voltage (V) ') plt.title('Input Voltage vs Output Voltage') plt.show() In [10]: # The script below fits to a sine wave, but can be modified for other functions # First, we load some python packages import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit # LIST OF ALL INPUTS # fname is assumed to be in a four-column .csv file (comma separated values). The first two rows are # assumed to be headers, like those produced in our code for packing oscilloscope data. # The four columns are x-values, x-uncertainties, y-values, y-uncertainties.
# The .csv file must be in the same # folder as this fit program, otherwise the full file extension must be added # to fname: e.g. fname = 'folder/subfolder/subsubfolder/file.csv' """ Modify the following line to change the file name containing your data """ fname = "Lab08_100fV.csv" x_name = "Input Voltage" x_units = "V" y_name = "Output Voltage" y_units = "V" # The model you will fit to is defined below, in this case a sine wave. # The parameters in the model are amplitude, freqency, and phase. # To get a least squares fitting process started, it is necessary to provide good # initial guesses for the parameters. From your plots of the data so far, you can make good guesses at these parameters. param_names = ["slope", "intercept"] # definition of the fit function # def fit_function(x, amplitude,tau): # fit function is a linear model with slope and intercept def fit_function(x, slope, intercept): return x * slope + intercept # load the file "fname", defined above data = np.loadtxt(fname, delimiter=",", comments="#", usecols=(0, 1, 2, 3), skiprows=2) """ Here is where you access the data columns. You may need tyo alter these to choose what is on the y-axis and what is on the x-axis. """ x = data[:, 0] y = data[:, 2] y_sigma = data[:, 3] # calculate the best fit slope - this is the analytical solution for a 2-parameter fit to a striaght line Delta = sum(1/y_sigma**2)*sum((x/y_sigma)**2) - (sum(x/y_sigma**2)**2) m = (sum(1/y_sigma**2)*sum(x*y/y_sigma**2) - sum(x/y_sigma**2)*sum(y/y_sigma**2))/Delta # calculate uncertainty of the best fit slope m_sigma = np.sqrt(sum(1/y_sigma**2)/Delta)
print ("Slope is", m, "+/-", m_sigma) # calculate the best fit intercept b = (sum((x/y_sigma)**2)*sum(y/y_sigma**2) - sum(x/y_sigma**2)*sum(x*y/y_sigma**2))/Delta # calculate uncertainty of the best fit intercept b_sigma = np.sqrt(sum((x/y_sigma)**2)/Delta) print ("Intercept is", b, "+/-", b_sigma) ############################################################################### # calculates and prints the chi-squared, degrees of freedon, and weighted chi-squared ############################################################################### # function that calculates the chi square value of a fit def chi_square (param1, param2, x, y, sigma): # return np.sum((y-fit_function(x, param1, param2))**2/sigma**2) # calculate and print chi square as well as the per degree-of-freedom value chi2 = chi_square(m,b,x,y,y_sigma) # degrees of freedom is the number of data points minus the number of parameters dof = len(x) - 2 print ("\nGoodness of fit - Chi-squared measure:") print ("degrees of freedom = {}, Chi2 = {}, Chi2/dof = {}\n".format(dof, chi2, chi2/dof)) # residual is the difference between the data and model x_fitfunc = np.linspace(min(x), max(x), 500) y_fitfunc = fit_function(x_fitfunc, m ,b) y_fit = fit_function(x, m,b) residual = y-y_fit # creates a histogram of the residuals hist,bins = np.histogram(residual,bins=30) fig = plt.figure(figsize=(7,15)) ax1 = fig.add_subplot(311) ax1.errorbar(x,y,yerr=y_sigma,marker='.',linestyle='',label="measured data") ax1.plot(x_fitfunc,y_fitfunc,marker="",linestyle="-",linewidth=2,color="r", label=" fit") # add axis labels and title ax1.set_xlabel('{} [{}]'.format(x_name,x_units)) ax1.set_ylabel('{} [{}]'.format(y_name,y_units)) ax1.set_title('Best fit of 2-Parameter Linear Model') # set the x and y boundaries of your plot #plt.xlim(lower_x,upper_x) #plt.ylim(lower_y,upper_y) # show a legend. loc='best' places legend where least amount of data is # obstructed. ax1.legend(loc='best',numpoints=1)
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
# this code produces a figure with a plot of the residuals as well # as a histogram of the residuals. # fig = plt.figure(figsize=(7,10)) ax2 = fig.add_subplot(312) ax2.errorbar(x,residual,yerr=y_sigma,marker='.',linestyle='', label="residual (y-y_fit)") ax2.hlines(0,np.min(x),np.max(x),lw=2,alpha=0.8) ax2.set_xlabel('{} [{}]'.format(x_name,x_units)) ax2.set_ylabel('y-y_fit [{}]'.format(y_units)) ax2.set_title('Residuals for the Best Fit') ax2.legend(loc='best',numpoints=1) ax3 = fig.add_subplot(313) ax3.bar(bins[:-1],hist,width=bins[1]-bins[0]) ax3.set_ylim(0,1.2*np.max(hist)) ax3.set_xlabel('y-y_fit [{}]'.format(y_units)) ax3.set_ylabel('Number of occurences') ax3.set_title('Histogram of the Residuals') """ Modify the following lines to change the name of the file used to store a JPEG of your best fit graphs """ # Before showing the plot, you can also save a copy of the figure as a JPEG. # The order is important here because plt.show clears the plot information after displaying it. plt.savefig('Lab08_100fV_results.jpeg') plt.show() Slope is 9.732044141283126 +/- 0.005292806868873698 Intercept is -0.004106324026396805 +/- 0.000915460254967999 Goodness of fit - Chi-squared measure: degrees of freedom = 6, Chi2 = 42.37097015454932, Chi2/dof = 7.061828359091553
We see that the plot is a good fit, with a chi-squared value of $7.06$. Our Gain which is given by the slope is $9.732$, which shows that our amplification matches our expected voltage amplification of $\times 10$ $At$ $500kHz$ At this very high frequency, it takes much longer for the plot to get distorted, We took input voltages from $100mV$ up till $2.6V$, with a step increment of $50mV$ up till $800mV$ and $200mV$ from $800mV-2.6V$, totaling 24 measurements. We plot our data up till $V_{in}=1.2V$, after which our plot no longer appears linear. All measurements were done after keeping the offset voltage at a low value of $V_{off}=107mV$. In [11]: # import the packages that you need, including data_entry2 import numpy as np import data_entry2 import array import pandas as pd import matplotlib.pyplot as plt de = data_entry2.sheet("Lab08_500fV") Sheet name: Lab08_500fV.csv In [12]: # import the library numpy and rename it np import numpy as np import array # import the library matplotlib and rename it plot import matplotlib.pyplot as plt #name the input file with the data fname = 'Lab08_500fV.csv' # This block reads in data - the file is assumed to be in csv format (comma separated variables). # Files need to be specified with a full path OR they have to be saved in the same folder as the script # data = np.loadtxt(fname, delimiter=',', comments='#',usecols=(0,1,2,3),skiprows=2) # generate an array which is the first column of data. Note the first column is # indexed as zero. x = data[:,0] # generate an array for the x uncertainty (column index 1) x_sigma = data[:,1] # generate an array for the y values (column index 2) y = data[:,2] # generate an array for y uncertainty (column index 3) y_sigma = data[:,3] # This block creates a plot plt.errorbar(x,y,xerr=x_sigma,yerr=y_sigma,marker='.',linestyle='',label="measured data") plt.xlabel('Input Voltage (V)') plt.ylabel('Output Voltage (V) ')
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
plt.title('Input Voltage vs Output Voltage') plt.show() In [13]: # The script below fits to a sine wave, but can be modified for other functions # First, we load some python packages import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit # LIST OF ALL INPUTS # fname is assumed to be in a four-column .csv file (comma separated values). The first two rows are # assumed to be headers, like those produced in our code for packing oscilloscope data. # The four columns are x-values, x-uncertainties, y-values, y-uncertainties. # The .csv file must be in the same # folder as this fit program, otherwise the full file extension must be added # to fname: e.g. fname = 'folder/subfolder/subsubfolder/file.csv' """ Modify the following line to change the file name containing your data """ fname = "Lab08_500fV.csv" x_name = "Input Voltage" x_units = "V" y_name = "Output Voltage"
y_units = "V" # The model you will fit to is defined below, in this case a sine wave. # The parameters in the model are amplitude, freqency, and phase. # To get a least squares fitting process started, it is necessary to provide good # initial guesses for the parameters. From your plots of the data so far, you can make good guesses at these parameters. param_names = ["slope", "intercept"] # definition of the fit function # def fit_function(x, amplitude,tau): # fit function is a linear model with slope and intercept def fit_function(x, slope, intercept): return x * slope + intercept # load the file "fname", defined above data = np.loadtxt(fname, delimiter=",", comments="#", usecols=(0, 1, 2, 3), skiprows=2) """ Here is where you access the data columns. You may need tyo alter these to choose what is on the y-axis and what is on the x-axis. """ x = data[:, 0] y = data[:, 2] y_sigma = data[:, 3] # calculate the best fit slope - this is the analytical solution for a 2-parameter fit to a striaght line Delta = sum(1/y_sigma**2)*sum((x/y_sigma)**2) - (sum(x/y_sigma**2)**2) m = (sum(1/y_sigma**2)*sum(x*y/y_sigma**2) - sum(x/y_sigma**2)*sum(y/y_sigma**2))/Delta # calculate uncertainty of the best fit slope m_sigma = np.sqrt(sum(1/y_sigma**2)/Delta) print ("Slope is", m, "+/-", m_sigma) # calculate the best fit intercept b = (sum((x/y_sigma)**2)*sum(y/y_sigma**2) - sum(x/y_sigma**2)*sum(x*y/y_sigma**2))/Delta # calculate uncertainty of the best fit intercept b_sigma = np.sqrt(sum((x/y_sigma)**2)/Delta) print ("Intercept is", b, "+/-", b_sigma) ############################################################################### # calculates and prints the chi-squared, degrees of freedon, and weighted chi-squared
############################################################################### # function that calculates the chi square value of a fit def chi_square (param1, param2, x, y, sigma): # return np.sum((y-fit_function(x, param1, param2))**2/sigma**2) # calculate and print chi square as well as the per degree-of-freedom value chi2 = chi_square(m,b,x,y,y_sigma) # degrees of freedom is the number of data points minus the number of parameters dof = len(x) - 2 print ("\nGoodness of fit - Chi-squared measure:") print ("degrees of freedom = {}, Chi2 = {}, Chi2/dof = {}\n".format(dof, chi2, chi2/dof)) # residual is the difference between the data and model x_fitfunc = np.linspace(min(x), max(x), 500) y_fitfunc = fit_function(x_fitfunc, m ,b) y_fit = fit_function(x, m,b) residual = y-y_fit # creates a histogram of the residuals hist,bins = np.histogram(residual,bins=30) fig = plt.figure(figsize=(7,15)) ax1 = fig.add_subplot(311) ax1.errorbar(x,y,yerr=y_sigma,marker='.',linestyle='',label="measured data") ax1.plot(x_fitfunc,y_fitfunc,marker="",linestyle="-",linewidth=2,color="r", label=" fit") # add axis labels and title ax1.set_xlabel('{} [{}]'.format(x_name,x_units)) ax1.set_ylabel('{} [{}]'.format(y_name,y_units)) ax1.set_title('Best fit of 2-Parameter Linear Model') # set the x and y boundaries of your plot #plt.xlim(lower_x,upper_x) #plt.ylim(lower_y,upper_y) # show a legend. loc='best' places legend where least amount of data is # obstructed. ax1.legend(loc='best',numpoints=1) # this code produces a figure with a plot of the residuals as well # as a histogram of the residuals. # fig = plt.figure(figsize=(7,10)) ax2 = fig.add_subplot(312) ax2.errorbar(x,residual,yerr=y_sigma,marker='.',linestyle='', label="residual (y-y_fit)") ax2.hlines(0,np.min(x),np.max(x),lw=2,alpha=0.8) ax2.set_xlabel('{} [{}]'.format(x_name,x_units)) ax2.set_ylabel('y-y_fit [{}]'.format(y_units)) ax2.set_title('Residuals for the Best Fit')
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
ax2.legend(loc='best',numpoints=1) ax3 = fig.add_subplot(313) ax3.bar(bins[:-1],hist,width=bins[1]-bins[0]) ax3.set_ylim(0,1.2*np.max(hist)) ax3.set_xlabel('y-y_fit [{}]'.format(y_units)) ax3.set_ylabel('Number of occurences') ax3.set_title('Histogram of the Residuals') """ Modify the following lines to change the name of the file used to store a JPEG of your best fit graphs """ # Before showing the plot, you can also save a copy of the figure as a JPEG. # The order is important here because plt.show clears the plot information after displaying it. plt.savefig('Lab08_500fV_results.jpeg') plt.show() Slope is 3.687857643032923 +/- 0.001550352978679342 Intercept is 0.012486252767426664 +/- 0.000340788637469608 Goodness of fit - Chi-squared measure: degrees of freedom = 15, Chi2 = 1843.5682962372305, Chi2/dof = 122.90455308248202
This time, our plot is slightly worse, giving us a chi-squared value of $122.9$ and a much lower Gain (slope) of $\approx3.69$. Further Observations The Open Loop Voltage Gain (A) is amount of differential gain provided by the Op-Amp when no feedback is provided, i.e., $V_{out} = \hat{A} \times (V_+ − V_−)$, where $\hat{A}$ is a function of frequency. $$\hat{A} = \frac{A_0}{1 + if /f_c}$$ where $i = \sqrt{−1}$, $A_0$ is the open loop gain at zero frequency and $f_c$ is the cutoff frequency beyond which the gain drops rapidly. We clearly see that at a higher frequency, the amplification, albeit not as much as when compared to at lower frequency, takes much higher input voltages for it to lose its amplification power. That is, our Gain for $100Hz$ is 9.732, whereas for $500kHz$ it is 3.69. This means that at a frequency of $100Hz$ we have a much higher voltage amplification of almost 10 times than at a frequency of $500kHz$. Thus, we observe that beyond a certain cutoff frequency, our Gain has dropped rapidly. In [ ]:
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help