Fitting
developed by Pauline Arriaga
When we interpret any kind of data, our scientific result may be a number that comes from
the average of the data points, or it can be some kind of correlation. There are some kinds of
correlations in physics we expect. For example, if we are dropping an object from a certain
height, we know that the position will be
$x = \frac{1}{2} gt^2$
Therefore, if we measure positions and measure times and plot them, we should see a
parabola. However, if we have some systematic errors, meaning some effect of our system
that will affect all measurements, we won't get a perfect parabola. We therefore need to fit
our data.
In [9]: import numpy as np
import random
import [Link] as plt
Below I'm going to use some functions that will create arrays x_data and y_data which hold
some linear data.
In [10]: ### Generate a line with random noise
# Generate x and y array for a line
x_data = [Link](100, dtype = float)
y_data = [Link](100, dtype = float) * 3. + 30.
# Generate random noise
noise = [[Link](-50,50) for i in range(100)]
y_data += noise
# Show data
[Link](x_data, y_data)
Out[10]: <[Link] at 0x7f90f444f350>
In order to fit a function, we first need two different functions. One of them will be the
function we're trying to fit. Let's try and fit a line to the data points above. We then create a
function line() which takes an x coordinate and some parameters as the inputs. We pass in
the parameters as an array with the first element being the slope of the line and the second
being the y offset. We can have the parameters in any order. Note that below, we have used
a doc sting (the text within the quotation marks) in order to tell the reader what the
parameters should be.
The second function will get the residuals of the function. This function can just be a formula
for any fitting as it will be the same for any fitting function where we don't have error bars.
The get residuals will go point by point on the data points and will find the distance between
each data point and the fitted line. The best fit will have the smallest residuals.
In [11]: def line(x, parameters):
'''
Plots a line
Inputs:
x: a coordinate
parameters: [slope of the line, y offset of the line]
'''
m = parameters[0]
b = parameters[1]
y = m * x + b
return y
def get_residuals_line(parameters, data, x):
residuals = [Link](data - line(x, parameters))
return -residuals
We now use the least squares which will maximize the function get residuals, finding the
best fit. Note where x and y data are input
In [12]: from [Link] import least_squares
guess_parameters = [1., 1.]
res_lsq = least_squares(get_residuals_line, guess_parameters, args = (y_data, x_dat
We now extract the best parameters from the results
In [13]: parameters = res_lsq['x']
print(parameters)
[ 2.95787579 29.64514846]
Let's check to see how good our fit is
In [14]: x_axis = [Link](110.)
fitted_line = line(x_axis, parameters)
[Link](x_axis, fitted_line, color = 'green', label = 'Fitted line')
[Link](x_data, y_data, label = 'Data')
[Link]()
Out[14]: <[Link] at 0x7f90ea6ae490>
Assignment
Simiarly to the previous tutorial, you will create a function, but one that discribes the
exponential charging of an RC circuit.
$v = v_0(1-exp(-t/\tau))$
where tau is the RC time constant and v0 is the maximum voltage the circuit will acheive. Use
the RC values descirbed in the slides and v0 = 1 V.
In [15]: # Create the exponential curve
def rc_exponential(t, parameters):
v0, tau = parameters
v = v0 * (1 - [Link](-t / tau))
return v
def get_residuals_rc(parameters, data, t):
residuals = [Link](data - rc_exponential(t, parameters))
return -residuals
In [24]: # Create a time array that is 5 times the length of the time constant
time_constant = 10e-3
time = [Link](0, 5 * time_constant, 500)
# Call the rc_exponential function and obtain the voltage values
v0 = 1 # Initial voltage
voltage_values = rc_exponential(time, [v0, time_constant])
# Plot your theoretical function
[Link]
[Link](time, voltage_values, label='Theoretical RC Curve', color='blue')
[Link]('Time (s)')
[Link]('Voltage (V)')
[Link]('Theoretical RC Exponential Charging Curve')
[Link]()
[Link]()
Now that you know how to plot a single RC curve, plot the following combinations:
Plot 1: 10 uF Capacitor with 100 Ohm Resistor and 10 uF Capacitor with 1k Ohm Resistor
Plot 2: 1k Ohm Resistor with 10 uF Capacitor and 1k Ohm Resistor with 100 uF Capacitor
To make your graphs look nice and even, choose you time vector to be as a function of the
greatest tau value.
In [25]: # Plot 1: 10 uF Capacitor with 100 Ohm Resistor and 10 uF Capacitor with 1k Ohm Res
# Define parameters for Plot 1
v0 = 1 # Initial voltage in volts
# Time constants for each combination
C1, R1 = 10e-6, 100 # 10 µF, 100 Ω
tau1 = C1 * R1 # Time constant for the first combination
C2, R2 = 10e-6, 1000 # 10 µF, 1 kΩ
tau2 = C2 * R2 # Time constant for the second combination
# Create a time array based on the greatest tau value (5 * max_tau)
max_tau = max(tau1, tau2)
time = [Link](0, 5 * max_tau, 500)
# Calculate voltage values for each combination
voltage1 = rc_exponential(time, [v0, tau1])
voltage2 = rc_exponential(time, [v0, tau2])
# Plot the RC curves
[Link]
[Link](time, voltage1, label=f'C=10 µF, R=100 Ω, τ={tau1:.2e} s', color='blue')
[Link](time, voltage2, label=f'C=10 µF, R=1 kΩ, τ={tau2:.2e} s', color='orange')
[Link]('Time (s)')
[Link]('Voltage (V)')
[Link]("Plot 1: 10 µF Capacitor with 100 Ω and 1 kΩ Resistors")
[Link]()
[Link]()
In [22]: # Define parameters for Plot 2
v0 = 1 # Initial voltage in volts
# Time constants for each combination
C1, R1 = 10e-6, 1000 # 10 µF, 1 kΩ
tau1 = C1 * R1 # Time constant for the first combination
C2, R2 = 100e-6, 1000 # 100 µF, 1 kΩ
tau2 = C2 * R2 # Time constant for the second combination
# Create a time array based on the greatest tau value (5 * max_tau)
max_tau = max(tau1, tau2)
time = [Link](0, 5 * max_tau, 500)
# Calculate voltage values for each combination
voltage1 = rc_exponential(time, [v0, tau1])
voltage2 = rc_exponential(time, [v0, tau2])
# Plot the RC curves
[Link](figsize=(10, 6))
[Link](time, voltage1, label=f'C=10 µF, R=1 kΩ, τ={tau1:.2e} s', color='blue')
[Link](time, voltage2, label=f'C=100 µF, R=1 kΩ, τ={tau2:.2e} s', color='orange')
[Link]('Time (s)')
[Link]('Voltage (V)')
[Link]("Plot 2: 1 kΩ Resistor with 10 µF and 100 µF Capacitors")
[Link]()
[Link]()
Take your RC charge plot you created in the previous python notebook and add 5-10% noise
to it. After adding noise to your theoretical plot, create
In [26]: import numpy as np
import [Link] as plt
import random
# Define the RC exponential function
def rc_exponential(t, parameters):
'''
Plots an RC exponential charging curve.
Inputs:
t: time
parameters: [initial voltage, time constant]
'''
v0, tau = parameters
return v0 * (1 - [Link](-t / tau))
# Parameters for the RC curve
v0 = 1 # Initial voltage
R = 1000 # Resistance in Ohms
C = 10e-6 # Capacitance in Farads
tau = R * C # Time constant
# Create the time array
time = [Link](0, 5 * tau, 500)
# Calculate the theoretical voltage values
theoretical_voltage = rc_exponential(time, [v0, tau])
# Generate random noise (similar to the provided example)
random_noise = [[Link](-10, 10) * 0.01 for _ in range(len(theoretical_volta
noisy_voltage = theoretical_voltage + random_noise
# Plot the theoretical and noisy data
[Link]
[Link](time, theoretical_voltage, label='Theoretical Curve', color='blue', linewi
[Link](time, noisy_voltage, label='Noisy Data', color='orange', s=10, alpha=0.
[Link]('Time (s)')
[Link]('Voltage (V)')
[Link]('Theoretical and Noisy RC Curve')
[Link]()
[Link]()
Lastly, take your noisy data and fit a the theoretical function back to it.
Plot all 3: Theoretical, Noisy, and Fit.
Did the input plot paramters change?
In [27]: # Perform least squares fit
guess_parameters = [0.9, tau * 0.9] # Initial guesses for [v0, tau]
res_lsq = least_squares(get_residuals_rc, guess_parameters, args=(noisy_voltage, ti
fitted_parameters = res_lsq['x']
print("Fitted Parameters:", fitted_parameters)
# Create a fit curve
fitted_curve = rc_exponential(time, fitted_parameters)
# Plot all 3 plots together and show legend
[Link]
[Link](time, theoretical_voltage, label='Theoretical Curve', color='blue', linewi
[Link](time, noisy_voltage, label='Noisy Data', color='orange', s=10, alpha=0.
[Link](time, fitted_curve, label='Fitted Curve', color='green', linestyle='--', l
[Link]('Time (s)')
[Link]('Voltage (V)')
[Link]('Theoretical, Noisy, and Fitted RC Curve')
[Link]()
[Link]()
Fitted Parameters: [1.00391179 0.01030179]
Developed by P. Arriaga
rev. 2.1 E. Kramer 04-15-2021
rev. 2.2 J. Carmona 10-15-2021
© Regents of the University of California
In [ ]: