3.2.1. Python projects

3.2.1.1. Setting up a Python project

  1. Start VSCode and make sure you are working in the Lab C folder. If needed, on the menu bar select Terminal / New Terminal and select Lab C, to make a terminal in the correct location.

  2. In the VSCode terminal enter:

    cd /workspaces/`ls /workspaces`/lab-c
    uv init .
    

    Remember to enter these one at a time, not both together.

    This will make a new Python project in the current folder. It will be named automatically after the folder name.

    To analyze these lines:

    • cd /workspaces/`ls /workspaces`/lab-c makes sure we are working in the lab-c folder.

    • uv init . is the interesting command. This actually sets up our virtual environment.

  3. You’ll see that three files have been automatically created for you:

    • .python-version

    • pyproject.toml

    • main.py

    VSCode after making a new Python project

    Screenshot of VSCode, software from Microsoft. See course copyright statement.

    .python-version sets the Python version to use. We don’t need to look at it, it will have been set to a default version.

  4. Open the pyproject.toml file. This will look like

    [project]
    name = "lab-c"
    version = "0.1.0"
    description = "Add your description here"
    readme = "README.md"
    requires-python = ">=3.14"
    dependencies = []
    

    The project has been given a name (lab-c) based on the folder name. There’s the option to give a version number and some description. At the moment we haven’t added any dependencies, so the dependencies list is empty.

  5. Open the main.py file. This is where our Python code will go. We can of course change the file name if we would like to. You’ll see that some boilerplate code has been added to get started

    def main():
        print("Hello from lab-c!")
    
    if __name__ == "__main__":
        main()
    

    Run the code by entering the command

    uv run main.py
    

    You’ll see Hello from lab-c! displayed in the terminal. You’ll also see that a virtual environment has been automatically created and is being used. (The uv init . command doesn’t actually make the environment for you, it just makes the files that say what should be in the environment.) Due to the setup of VSCode, the graphical buttons to run a Python script won’t work until the virtual environment has been created.

    Running a script with uv run

    Screenshot of VSCode, software from Microsoft. See course copyright statement.

  6. main.py uses functions. The block in if __name__ == "__main__": is what is actually run when the code starts. Here it just calls the function called main.

    A function is defined with the def keyword, followed by the name of the function. Here the function main just displays some text to the screen.

    Good practice is generally to do as little as possible under if __name__ == "__main__": and instead put most of the code in functions. This makes it easier to test the code later, as we’ll learn about in Lab D.

3.2.1.2. Porting the sine wave example from Lab B

In Lab B you wrote a Python script to plot a sine wave. Let’s repeat that example, but using the new project structure.

  1. Replace the code in your main.py file with the following

    import math
    
    import plotly.express as px
    
    
    def make_sine_wave():
        """
        Make a sine wave signal
        TO DO: replace range with a numpy array
    
        Returns: t: time samples
        v_out: voltage samples
        """
        sample_start = 0
        sample_stop = 100
        A = 1  # Volts
        f = 0.1  # Hz
        t = range(sample_start, sample_stop)  # interpret as representing 1 s, 2 s, 3 s, ...
        v_out = [A * math.sin(2 * math.pi * f * time) for time in t]
        return t, v_out
    
    
    def plot_sine_wave(t, v_out):
        """Plot a sine wave using plotly and label the axes"""
        fig = px.line(x=t, y=v_out, labels={"x": "Time [s]", "y": "Voltage [V]"})
        fig.show()
    
    
    if __name__ == "__main__":
        t, v_out = make_sine_wave()
        plot_sine_wave(t, v_out)
    

    This requires the external library plotly, so we need to add that as a dependency. (It also needs numpy and pandas.) If you press the Run button before installing these dependencies, the program won’t work.

  2. To install the dependencies, at the terminal enter

    uv add plotly numpy pandas ipykernel==6.31.0
    
  3. Once the dependencies are installed, you can run the code with

    uv run main.py
    

    or by using the Run button in VSCode.

    You should see the sine wave plot displayed as a graph in a web browser. You can use the buttons in this to zoom in, and so on, to explore the plot

    Sine wave plot in a web browser

    Screenshot of a web browser, software from Brave. See course copyright statement.

  4. Although the above example is brief, there’s lots to explore and think about.

    Firstly, open the pyproject.toml file again. It will now contain something like

    [project]
    name = "lab-c"
    version = "0.1.0"
    description = "Add your description here"
    readme = "README.md"
    requires-python = ">=3.14"
    dependencies = [
        "numpy>=2.3.5",
        "pandas>=2.3.3",
        "plotly>=6.4.0",
    ]
    

    It now contains details on what version of Python, and the external libraries, are needed for the code to run. If you were to share this project with someone else, they could use this file to set up their own virtual environment with the correct dependencies automatically. (There is a uv sync command to make a virtual environment match a pyproject.toml file.)

    For a small project like this, the precise versions of the different tools used probably doesn’t matter too much. However, it can be very important for larger projects developed over a period of time.

  5. Secondly, the code that runs when the program starts is

    if __name__ == "__main__":
        t, v_out = make_sine_wave()
        plot_sine_wave(t, v_out)
    

    The aim is for this in main to be readable, by inspection, to see that the code does what we want it to conceptually. This is easy when there’s only two steps as in the above, we want to make a sine wave and then plot it.

    To understand the other parts of the code:

    • make_sine_wave() doesn’t take any inputs, there’s nothing between the brackets ().

    • plot_sine_wave(t, v_out) takes two inputs. These inputs are the outputs of make_sine_wave(), assigned by placing them on the left hand side of the = sign.

    • Inside the definition of the make_sine_wave() function, the two outputs are defined by the return statement.

    • Inside the definition of the plot_sine_wave(t, v_out) function, the two inputs are defined by the items between the brackets (t, v_out). Otherwise, the Python code is unchanged from previously (just indented to show which code belongs to which block).

    • Both functions start with a docstring to add some documentation.

3.2.1.3. Porting the RC circuit simulation example from Lab B

Let’s now port the other example that we had in Lab B, the RC circuit simulation. This was simulating the potential divider shown below

Drawing of a potential divider

where \(Z_{1}\) is a resistor and \(Z_{2}\) is a capacitor with impedance

\[Z = \frac{1}{j\omega C}\]

where \(\omega\) is the angular frequency

\[\omega = 2\pi f\]

The output voltage is given by

\[V_{out} = \frac{Z_{2}V_{in}}{Z_{1} + Z_{2}}\]

Your code in Lab B will have looked like the below.

# Potential divider where z2 is a capacitor
import cmath
import math

f = 160000  # Hz
w = 2 * math.pi * f  # rad/s

v_in = 5 * cmath.exp(1j * w)

z1 = 1  # kOhm
c = 1e-9  # Farads
z2 = 1 / (1j * w * c)

v_out = (z2 * v_in) / (z1 + z2)  # Volts
vout_mag = abs(v_out)
vout_phase = cmath.phase(v_out)
  1. Refactor this code to use an if __name__ == "__main__": block and functions, similar to the sine wave example above. Also, add code to display vout_mag and vout_phase to the screen.

    In your Lab C files you will see that a number of files have been pre-downloaded for you. A file called lpf.py which contains some starter code for this task. Open in. Inside the file, ... indicates where you need to add code.

  2. In practice in electronics it’s common to display \(V_{out}\) not as a Voltage, but as the gain of the circuit. That is, the ratio

    \[G = \frac{V_{out}}{V_{in}}\]

    Moreover, this is usually expressed in decibels (dB) by using the equation

    \[G_{dB} = 20 \log_{10}\left(\frac{V_{out}}{V_{in}}\right)\]

    Modify your code to display the gain in dB instead of the output voltage magnitude.

  3. Check in your code to Git before proceeding.

    1. Click on the Source Control tab in the left hand menu. You may need to click Refresh for it to pick up your changes.

    2. Enter a message such as “Completed the first part of Lab C” in the message box.

    3. Click Commit. This checks the files in to the local repository.

      Committing Lab C files

      Screenshot of VSCode, software from Microsoft. See course copyright statement.

    4. Click Sync Changes. This checks the files in to the remote repository.

      Syncing Lab C files with the remote repository

      Screenshot of VSCode, software from Microsoft. See course copyright statement.

    Enter the commands

    git commit -a -m "Completed the first part of Lab C"
    git pull
    git push