Data Science for Fun and Motorsport

Posted on Jan 1, 2022

One of my favorite things about motorsport is telemetry. It’s a wealth of information that, with a human eye, is overwhelming. Data science or, more specifically, data visualization really breaks down data to something instantly digestible for consideration, analysis, and action.

Table Of Contents

Start your engines

Telemetry, and electronics in general, are vital to motorsport as we know it. Through data transmission and collection we can audit adherence to rule sets, learn about and diagnose issues while the vehicle is still out on the track, and iterate on vehicle performance with assistance from data analysis. Another component, which also strikes me as very interesting, is the ability for telemetry and data analysis to enrich the spectator experience.

All of these components are, perhaps, of equal interest to me however they all have a commonality that may not be obvious at first glace: financial cost. Motorsport, itself, is a costly endeavor and the telemetry systems and associated sensors and communications equipment are part and parcel with building and running the rest of the vehicle. As a surrogate I’ve taken to Forza Horizon 5, a newly released game for Xbox One, Xbox Series S/X, and PC. Forza Horizon is definitely a more “arcade” entry into racing games however it does use the same system as Forza Motorsport 7 for sending vehicle telemetry out to a listener. This is probably more appropriate as I used an Xbox One controller as opposed to a race wheel which, in my case, allows for more realistic input.

💡 At no point is this a flex on my skills in Forza Horizon 5.

This is done over UDP and there are some specifications with regards to how the data is delivered but I skipped over creating my own listener and opted to use forza telemetry by Austin Baccus to record the data to CSV. This is a Windows-only electron application (by the looks of it–had some issues building dotnet 6 on my M1 MBA that I chose to not troubleshoot) that also provides a HUD. Very cool.

Fields

There is a wealth of information delivered by the Forza game engine to the telemetry endpoint. It is potentially overwhelming and this is very specifically simulation–a professional vehicle would have many more sensors being recorded if not also being transmitted back to the garage via wireless link.

IsRaceOn
TimestampMS
EngineMaxRpm
EngineIdleRpm
CurrentEngineRpm
AccelerationX
AccelerationY
AccelerationZ
VelocityX
VelocityY
VelocityZ
AngularVelocityX
AngularVelocityY
AngularVelocityZ
Yaw
Pitch
Roll
NormalizedSuspensionTravelFrontLeft
NormalizedSuspensionTravelFrontRight
NormalizedSuspensionTravelRearLeft
NormalizedSuspensionTravelRearRight
TireSlipRatioFrontLeft
TireSlipRatioFrontRight
TireSlipRatioRearLeft
TireSlipRatioRearRight
WheelRotationSpeedFrontLeft
WheelRotationSpeedFrontRight
WheelRotationSpeedRearLeft
WheelRotationSpeedRearRight
WheelOnRumbleStripFrontLeft
WheelOnRumbleStripFrontRight
WheelOnRumbleStripRearLeft
WheelOnRumbleStripRearRight
WheelInPuddleDepthFrontLeft
WheelInPuddleDepthFrontRight
WheelInPuddleDepthRearLeft
WheelInPuddleDepthRearRight
SurfaceRumbleFrontLeft
SurfaceRumbleFrontRight
SurfaceRumbleRearLeft
SurfaceRumbleRearRight
TireSlipAngleFrontLeft
TireSlipAngleFrontRight
TireSlipAngleRearLeft
TireSlipAngleRearRight
TireCombinedSlipFrontLeft
TireCombinedSlipFrontRight
TireCombinedSlipRearLeft
TireCombinedSlipRearRight
SuspensionTravelMetersFrontLeft
SuspensionTravelMetersFrontRight
SuspensionTravelMetersRearLeft
SuspensionTravelMetersRearRight
CarOrdinal
CarClass
CarPerformanceIndex
DrivetrainType
NumCylinders
PositionX
PositionY
PositionZ
Speed
Power
Torque
TireTempFl
TireTempFr
TireTempRl
TireTempRr
Boost
Fuel
Distance
BestLapTime
LastLapTime
CurrentLapTime
CurrentRaceTime
Lap
RacePosition
Accelerator
Brake
Clutch
Handbrake
Gear
Steer
NormalDrivingLine
NormalAiBrakeDifference

I realize now that this list may be difficult to scroll down so this will likely cause me to improve on the theme of this website by creating an expandable code fence of some type. But the impression holds true: it’s a lot of data and it’s coming in at, from my estimation, with one full record (every one of those fields) approximately every 116 milliseconds. That’s a significant amount of data for a human to go through. It would be a bit of a chore to go through the significance of every field at this moment so I will do so as they come up.

time = ford_falcon['TimestampMS']
difference = time.diff(periods=-1)
print (np.mean(difference))

That’s the strictly operational code that I used to find the difference and that bring about the discussion of how this data is structured and manipulated. Python is all the rage in data science for a reason–structures and packages exist to make this process as capable as it can be. If you thought I was going to say “painless” you were right, I was thinking that, but I didn’t want to lie. The learning curve is significant to someone who is inexperienced with Python and even greater to someone who is inexperienced with Python and data visualization (e.g. me).

Pandas 🐼

pandas is a widely used data analysis library and can be considered standard at this point. It provides functions and structures that will be leveraged heavily throughout this process, most specifically the DataFrame, however there is no tremendous need to jump over and read their documentation–I plan on easing into every concept as it comes up through this journey. Matplotlib is another library that makes this all possible and is similarly standard in this realm. We will also be using NumPy and SciPy for some other functionality. If you would want to break off and read the documentation now I fear that you may get caught up in quite the tangled web–these libraries contain a large amount of functionality and it’s not always obvious how they’ll behave or how that functionality can be applied.

Let me see what spring is like on Jupyter

Jupyter Notebooks are a relatively new concept that’s, if you can dig it, a shareable shell. Jupyter Notebooks can be saved, shared, and messed around with. I’ll have a notebook up on Github afterwards. It is a great way to learn new languages or packages. This is a good example of one of those times. Homebrew conquers all things and it’s straightforward to install.

brew install jupyterlab

I had some issues with jupyterlab on my M1 MacBook but on Linux it works like gangbusters. Since I’m not on my Linux box and I still want to work on my laptop. Jupyter Notebook isn’t particularly suited for that, though. SSH has the ability to forward a part and, as Jupyter Notebook likes to run only available to localhost. There are ways to get around this but it isn’t necessary for this.

Google’s Colaboratory

Google Colab is a product that leverages GCP to provide Jupyter (or Jupyter-comaptible–there’s a lot of nuance there with regards to IPython and various other back ends and functionality) runtimes and can load Jupyter Notebooks straight up while also being able to have some local storage or connect to your GCP storage or Google Drive. I’ve migrated my Jupyter Notebook over to Colab and all I got was this lousy blog post section.

Migration Blues

I didn’t start this project on Google Colab because, as is my wont, I jumped in to the deep end and pip3 didn’t find the package that I was wanting to work with, specifically. In looking for the quickest way forward I set up Jupyter Notebook at home and made progress only to find that Python, and specifically matplotlib, examples vary greatly and lack context. I like context. Context helps one make better decisions. So that’s why there’s an entire section here on moving from Jupyter to Colab.

Moving the files was a simple matter. Create a folder in your Google Drive and drop everything in there together. That’s my CSVs and the Jupyter .ipynb file. Sign up for a free Google Colab account (or spend $9.99/mo for more premium access–free should be fine for what we’re doing here but for machine learning it may be worth your while to jump to that paid tier. I have some experience there and I’ll say that it may not necessarily be faster for all workloads but it will not dominate the use of your machine while it’s running so you are free to do other things and, as always, YMMV but I have some posts on that coming up).

Once your .ipynb is on Google Drive and you’re signed up for Google Colab you can actually just double-click it from your Drive window. Obviously if you’re starting from scratch you won’t need to do that and can just create a new Notebook in Colab. To get access to your files from Google Drive you’ll need to add a mount cell at the top like this:

from google.colab import drive
drive.mount('/content/drive')

This is in-built and will provide a link that you must visit to sign-in and receive a code to authorize the access of Colab to your Google Drive. If you’re very concerned about the contents of your Drive then there are a number of other ways to get your files in there (pulling them from Git being one of them) but just be aware of that as we navigate through directory structures. By clicking the “Refresh” button on the directory view on the left you’ll see a folder called drive come up in the root. So now I’m going to go through and change all of my file paths to /content//drive/MyDrive/ForzaData from what they were before,

import pandas as pd
from matplotlib import pyplot as plt
from matplotlib.pyplot import figure

# read csv file
amg_one = pd.read_csv('/content/drive/MyDrive/ForzaData/amg_one.csv')
z_car = pd.read_csv('/content/drive/MyDrive/ForzaData/240z_2.csv')
ford_falcon = pd.read_csv('/content/drive/MyDrive/ForzaData/ford_falcon.csv')
# display DataFrame
print(amg_one)

That should work swimmingly. If it doesn’t, definitely use the “refresh” button on your directory view to see what the pathname should be but once Drive is hooked up it should be cruise control to read and write to it. I’ll also say that writing to Drive is slow so use the scratch disk in your instance if you want to write out a lot of operations. pd.read_csv takes in a CSV from disk and converts it directly to a DataFrame. In online examples you’ll usually see a DataFrame object represented as df. You can think of a df as a spreadsheet or a database table–“records” are rows and “fields” are columns. Records are all related to each other in some way and will tend to keep that relationship. The DataFrame (I won’t be doing the code block for it the whole time–it’ll be a lot–it’s just a normal word now) will be the primary structure to interact with the data that you have. It doesn’t work quite like a two-dimensional array but we’ll go through some of those operations as they come up.

The only other issue I had was that, seeming in this version of the libraries installed, the command ax.set_box_aspect(aspect = (1,1,1)) does not exist. That being said the plot still worked as expected (it’s a 3D plot–we’ll get there).

Graph it up, B

In this instance I have telemetry from three vehicles. I definitely want to filter the data so I get exactly what I’m looking for so I run the following as Forza sets the IsRaceOn field to 1 during a race.

race_amg_one = amg_one.loc[(amg_one['IsRaceOn'] == 1)]
race_240z = z_car.loc[(z_car['IsRaceOn'] == 1)]
race_falcon = ford_falcon.loc[(ford_falcon['IsRaceOn'] == 1)]

This is a good time to bring up the issue of data sanitation. Forza doesn’t really do any organization for you and the best you get is lap counts and IsRaceOn. I took a few captures but the Ford Falcon FPV capture was the latest one so it was the one where I’d already made the mistakes of starting the recording too early and getting strange data. The lessons learned there were:

  1. Dirty data can make this task more difficult so having the cleanest data possible is ideal but sanitation is necessary to ensure accuracy
  2. Start recording right as you hit “Start Race” in Forza Horizon. You have a couple of seconds between hitting that and the race starting.
  3. Make sure your telemetry is actually recording. I had some issues with forza-telemetry only successfully recording the first session after opening it. I’ll poke around and see if I can find out what the problem is and how to remediate it but just know to check so you don’t need to repeat your data capture session.
  4. Anomalous data in an arcade-style game is to be expected. It comes from the strangest places.

ford_falcon.loc is a method that will help select records. All DataFrame objects have this method and it’s one of the bet ways to cherry pick or slice up data. By passing it the boolean expression ford_falcon['IsRaceOn'] == 1 the loc function will evaluate that for every record and return a DataFrame where the condition is True.

Let’s start with setting up a very basic pyplot object. Recall that we imported from matplotlib import pyplot as plt. That’s a very particular Python convention–aliasing your imports. Pyplot also uses that plt as somewhat of a singleton which is also a very Pythonic convention. This was all a bit confusing to me, initially. These aliases are also very standardized and readily used in examples without any context so just keep your wits about you and note the conventions.

fig, ax = plt.subplots()
ax.plot(race_falcon['CurrentRaceTime'],race_falcon['AccelerationX'], color="orange", label="Ford Falcon FPV")
ax.set_xlabel("Race Time")
ax.set_ylabel("Acceleration X")
ax.legend()

“This is the plot of X-axis acceleration versus race time of the Ford Falcon FPV in Forza Horizon 5.”

I realize now that yours may not be formatted quite like this but, in running through the notebook I changed the style at some point. As plt is a singleton the style gets changed across the board until it’s changed back. I will discuss styles in a later post. But you’ll notice some things here that aren’t really desirable. The two that jump out at me are the unit of measure in the Y-axis and the race time being presented in what looks to be seconds. These are both obstacles that can be readily overcome.

Ticking away the moments that make up a dull race

Every index on an axis is called a “tick” in the parlance of matplotlib. There are definite ways to format a tick and, in this case, the conversion of seconds into the format of minutes:seconds would be ideal. We can start that process by defining a function that will perform that operation.

def racetime_fmt(x, y):
    minutes, seconds = divmod(x, 60)
    return "{:.0f}".format(minutes) + ':' + "{:.0f}".format(seconds)

Python is a very pithy language so this may be difficult to interpret but I’ll do my best to explain it. The name of the function is racetime_fmt and the parameters, x and y, are the x axis tick value or the y axis tick value. I’m specifically wanting to format the x axis so I just ignored y for the time being. When you see minutes, seconds that’s very strange (but it’s already appeared) and that’s when functions can return multiple values, or even objects, and is also extremely Pythonic. divmod returns two values, the integer quotient and then the modulo (I need to look up that term to see if it’s correct) or remainder. Dividing x, which is measured in seconds, by 60 will give us the number of minutes and then the remained will be the number of seconds left. The actual string is constructed in the return statement by providing a string literal that’s the format that we want and applying it to the literal that is passed as a parameter (in this case the minutes and seconds values returned by divmod).

There’s significant documentation on Python strings and their formatting however it’s simplest to point out that this will give us integers with, very specifically, 0 digits after the decimal in a floating point number. We apply this formatter to the x axis with a simple declaration.

fig, ax = plt.subplots()
ax.plot(race_falcon['CurrentRaceTime'],race_falcon['AccelerationX'], color="orange", label="Ford Falcon FPV")
ax.set_xlabel("Race Time")
ax.set_ylabel("Acceleration X")
def racetime_fmt(x, y):
    minutes, seconds = divmod(x, 60)
    return "{:.0f}".format(minutes) + ':' + "{:.0f}".format(seconds)
ax.xaxis.set_major_formatter(tick.FuncFormatter(racetime_fmt))
ax.legend()

That function is a “functional formatter” for the tick object and will be applied to “major ticks” as seen by the function name. There are minor ticks as well but they aren’t being addressed currently.

“Formatted the x-axis to reflect standard minute and second notation.”

Nuthin but a g thang

The second grievance is that the measurements on y for acceleration are odd. We, as humans, tend to measure lateral acceleration–especially in vehicles–in the unit g. A g is the equivalent of the acceleration of planet Earth on objects on its surface. It’s literally one Earth “gravity” and you can think of the force on an object to be it’s weight on the surface of the earth if you’d like to. The acceleration of the Earth on objects is, for our purposes, 9.81 meters per second per second as 1 g. This means that 1 g of lateral acceleration means it feels like you would be pushed up against the side of the car with the same amount of force as your weight. DataFrames are very cool in that they can take what would ordinarily be operations on a singular thing and perform them on a row or column quickly.

race_falcon['AccelerationX'] / 9.81

0      -0.000418
1       0.000232
2      -0.002438
3      -0.001309
4       0.004816
          ...   
2061   -0.579115
2062   -0.361294
2063   -0.224737
2064   -0.083242
2065    0.000677
Name: AccelerationX, Length: 2066, dtype: float64

This looks for normal for a measurement in g. What else can we see about this column?

print ( abs(race_falcon['AccelerationX']).min() / 9.81 )
print ( abs(race_falcon['AccelerationX']).max() / 9.81 )
print ( abs(race_falcon['AccelerationX']).mean() / 9.81 )

4.253134556574923e-07
5.471163608562692
1.021939719205032

Note that I used abs to get the absolute value of the values in the column because Acceleration is a vector. According to the Forza documentation it’s lateral to the car (i.e from driver’s side to passenger’s side) with negative values being towards the left and positive values being towards the right. Using abs makes certain that we examine the magnitude of these values and not their directionality. 5 g’s of lateral acceleration is the anomalous value I mentioned before and, through analysis, I learned where it came from. You won’t ever get 5 g’s of turning in a Class A Ford Falcon FPV under normal circumstances–that’s Formula 1 territory. The takeaway here is that this raw data needs to be converted from meters per second per second to g to make sense (in the way I’m thinking about it). It’s actually trivially easy to make this happen, thankfully.

import matplotlib.ticker as tick #this is a new import to allow us to access the ticks on the axis
fig, ax = plt.subplots()
ax.plot(race_falcon['CurrentRaceTime'],race_falcon['AccelerationX'] / 9.81, color="orange", label="Ford Falcon FPV")
ax.set_xlabel("Race Time (M:S)")
ax.set_ylabel("Acceleration X (g)")

def racetime_fmt(x, y):
    minutes, seconds = divmod(x, 60)
    return "{:.0f}".format(minutes) + ':' + "{:.0f}".format(seconds)

ax.xaxis.set_major_formatter(tick.FuncFormatter(racetime_fmt))
ax.legend()

Yes, I realize that 9.81 is a “magic number” and when you get into “code smells” and the like this is not a recommended practice but for the sake of brevity I just used it. This gets us a more readable plot. Go ahead and add those units in there, too, otherwise your Physics teacher will be pissed.

“Formatted the x-axis and changed the plot of the y-axis to reflect desired measurement.”

That’s just step 1 in plotting and data analysis but it’s already been a beefy post. Keep your eyes peeled for part 2.

Hi, this post was checked with vale which is a content-aware linter. It was checked using the Microsoft style as well as some rules that I made. A summary of those results is below. More details as to how this was put together check out this post. This post had: 9 errors, 104 warnings and 80 suggestions For details on the linting of this post
 ./content/posts/data-science-for-fun.md
 1:1      suggestion  You averaged 2.19 complex       marktoso.Kiss            
                      words per sentence                                       
 1:1      suggestion  Try to keep the Flesch-Kincaid  marktoso.Readability     
                      grade level (9.81) below 8.                              
 9:8      warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 9:143    error       More than 3 commas!             marktoso.TresComas       
 9:183    warning     Consider removing 'really'.     Microsoft.Adverbs        
 14:67    warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 14:79    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 14:120   warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 14:274   suggestion  Consider using 'help' instead   Microsoft.ComplexWords   
                      of 'assistance'.                                         
 14:313   suggestion  Consider using 'part' instead   Microsoft.ComplexWords   
                      of 'component'.                                          
 14:343   warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 14:349   warning     Consider removing 'very'.       Microsoft.Adverbs        
 16:1     warning     Consider using 'these' instead  Microsoft.Wordiness      
                      of 'All of these'.                                       
 16:60    warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 16:187   suggestion  Consider using 'try' instead    Microsoft.ComplexWords   
                      of 'endeavor'.                                           
 16:663   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 16:731   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 16:740   suggestion  Verify your use of 'allows'     Microsoft.Vocab          
                      with the A-Z word list.                                  
 16:821   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 18:1     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 18:6     suggestion  'is done' looks like passive    Microsoft.Passive        
                      voice.                                                   
 18:19    suggestion  'UDP' has no definition.        Microsoft.Acronyms       
 18:86    suggestion  'is delivered' looks like       Microsoft.Passive        
                      passive voice.                                           
 18:102   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 18:127   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 18:271   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 18:373   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 18:379   suggestion  'MBA' has no definition.        Microsoft.Acronyms       
 18:387   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 18:438   suggestion  'HUD' has no definition.        Microsoft.Acronyms       
 18:443   warning     Consider removing 'Very'.       Microsoft.Adverbs        
 21:96    error       Use 'it's' instead of 'It is'.  Microsoft.Contractions   
 21:96    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 21:102   warning     Consider removing               Microsoft.Adverbs        
                      'potentially'.                                           
 21:139   warning     Consider removing 'very'.       Microsoft.Adverbs        
 21:223   suggestion  'being recorded' looks like     Microsoft.Passive        
                      passive voice.                                           
 21:250   suggestion  'being transmitted' looks like  Microsoft.Passive        
                      passive voice.                                           
 109:1    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 109:1    warning     Use first person (such as 'I    Microsoft.FirstPerson    
                      ') sparingly.                                            
 109:88   warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 109:182  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 109:260  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 109:324  suggestion  Consider using 'about' instead  Microsoft.ComplexWords   
                      of 'approximately'.                                      
 109:519  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 115:12   warning     Consider removing 'strictly'.   Microsoft.Adverbs        
 115:42   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 115:126  suggestion  'is structured' looks like      Microsoft.Passive        
                      passive voice.                                           
 115:300  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 115:371  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 115:443  suggestion  'is inexperienced' looks like   Microsoft.Passive        
                      passive voice.                                           
 115:504  suggestion  'is inexperienced' looks like   Microsoft.Passive        
                      passive voice.                                           
 115:559  error       Use 'for example' instead of    Microsoft.Foreign        
                      'e.g.'.                                                  
 115:564  warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 118:85   suggestion  'be considered' looks like      Microsoft.Passive        
                      passive voice.                                           
 118:123  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 118:170  suggestion  'be leveraged' looks like       Microsoft.Passive        
                      passive voice.                                           
 118:183  warning     Consider removing 'heavily'.    Microsoft.Adverbs        
 118:358  suggestion  Consider using 'idea' instead   Microsoft.ComplexWords   
                      of 'concept'.                                            
 118:530  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'We'.                           
 118:642  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 118:703  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 118:897  suggestion  'be applied' looks like         Microsoft.Passive        
                      passive voice.                                           
 120:8    warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 121:64   suggestion  Consider using 'idea' instead   Microsoft.ComplexWords   
                      of 'concept'.                                            
 121:140  suggestion  'be saved' looks like passive   Microsoft.Passive        
                      voice.                                                   
 121:216  warning     Prefer 'afterward' over         Microsoft.Terms          
                      'afterwards'.                                            
 121:228  error       Use 'it's' instead of 'It is'.  Microsoft.Contractions   
 125:1    warning     Use first person (such as 'I    Microsoft.FirstPerson    
                      ') sparingly.                                            
 125:40   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 125:100  warning     Use first person (such as       Microsoft.FirstPerson    
                      'I'm') sparingly.                                        
 125:113  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 125:129  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 125:154  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 125:230  warning     Consider using 'can' instead    Microsoft.Wordiness      
                      of 'has the ability to'.                                 
 127:4    suggestion  'Google's Colaboratory'         Microsoft.Headings       
                      should use sentence-style                                
                      capitalization.                                          
 128:2    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 128:79   suggestion  'GCP' has no definition.        Microsoft.Acronyms       
 128:86   suggestion  Consider using 'give' or        Microsoft.ComplexWords   
                      'offer' instead of 'provide'.                            
 128:347  suggestion  'GCP' has no definition.        Microsoft.Acronyms       
 128:390  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 128:431  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 130:5    suggestion  'Migration Blues' should use    Microsoft.Headings       
                      sentence-style capitalization.                           
 131:1    warning     Use first person (such as 'I    Microsoft.FirstPerson    
                      ') sparingly.                                            
 131:1    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 131:60   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 131:136  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 131:179  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 131:218  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 131:341  warning     Consider removing 'greatly'.    Microsoft.Adverbs        
 131:367  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 133:122  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 133:161  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 133:274  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 133:370  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 133:477  error       Use 'won't' instead of 'will    Microsoft.Contractions   
                      not'.                                                    
 133:589  suggestion  'YMMV' has no definition.       Microsoft.Acronyms       
 133:597  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 140:27   suggestion  Consider using 'give' or        Microsoft.ComplexWords   
                      'offer' instead of 'provide'.                            
 140:95   suggestion  Consider using 'allow' instead  Microsoft.ComplexWords   
                      of 'authorize'.                                          
 140:147  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 140:157  warning     Consider removing 'very'.       Microsoft.Adverbs        
 140:341  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 140:513  warning     Use first person (such as       Microsoft.FirstPerson    
                      'I'm') sparingly.                                        
 140:548  warning     Consider using 'all' instead    Microsoft.Wordiness      
                      of 'all of'.                                             
 140:555  warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 153:30   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 153:154  suggestion  'is hooked' looks like passive  Microsoft.Passive        
                      voice.                                                   
 153:711  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 153:809  suggestion  Don't use language (such as     Microsoft.Accessibility  
                      'normal') that defines people                            
                      by their disability.                                     
 153:954  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 155:21   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 155:140  error       Use 'doesn't' instead of 'does  Microsoft.Contractions   
                      not'.                                                    
 155:161  suggestion  'being said' looks like         Microsoft.Passive        
                      passive voice.                                           
 155:223  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 158:17   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 158:18   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 158:95   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 158:115  warning     Use first person (such as       Microsoft.FirstPerson    
                      'I'm') sparingly.                                        
 158:133  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 164:77   warning     Consider removing 'really'.     Microsoft.Adverbs        
 164:160  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 164:161  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 164:203  suggestion  'FPV' has no definition.        Microsoft.Acronyms       
 165:126  suggestion  Verify your use of 'ensure'     Microsoft.Vocab          
                      with the A-Z word list.                                  
 167:186  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 168:49   suggestion  'be expected' looks like        Microsoft.Passive        
                      passive voice.                                           
 172:1    warning     Try to avoid using              Microsoft.We             
                      first-person plural like                                 
                      'Let's'.                                                 
 172:31   warning     Consider removing 'very'.       Microsoft.Adverbs        
 172:69   warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 172:130  warning     Consider removing 'very'.       Microsoft.Adverbs        
 172:259  warning     Consider removing 'very'.       Microsoft.Adverbs        
 172:317  warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 172:355  warning     Consider removing 'very'.       Microsoft.Adverbs        
 172:377  warning     Consider removing 'readily'.    Microsoft.Adverbs        
 180:80   suggestion  'FPV' has no definition.        Microsoft.Acronyms       
 182:1    warning     Use first person (such as 'I    Microsoft.FirstPerson    
                      ') sparingly.                                            
 182:34   suggestion  'be formatted' looks like       Microsoft.Passive        
                      passive voice.                                           
 182:99   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 182:223  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 182:310  warning     Consider removing 'really'.     Microsoft.Adverbs        
 182:353  warning     Use first person (such as       Microsoft.FirstPerson    
                      'me') sparingly.                                         
 182:412  suggestion  'being presented' looks like    Microsoft.Passive        
                      passive voice.                                           
 182:494  warning     Consider removing 'readily'.    Microsoft.Adverbs        
 185:24   suggestion  'is called' looks like passive  Microsoft.Passive        
                      voice.                                                   
 185:211  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'We'.                           
 191:13   warning     Consider removing 'very'.       Microsoft.Adverbs        
 191:83   warning     Use first person (such as       Microsoft.FirstPerson    
                      'my') sparingly.                                         
 191:106  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 191:238  warning     Use first person (such as       Microsoft.FirstPerson    
                      'I'm') sparingly.                                        
 191:288  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 191:367  warning     Consider removing 'very'.       Microsoft.Adverbs        
 191:445  suggestion  Consider using 'many' instead   Microsoft.ComplexWords   
                      of 'multiple'.                                           
 191:491  warning     Consider removing 'extremely'.  Microsoft.Adverbs        
 191:668  suggestion  'is measured' looks like        Microsoft.Passive        
                      passive voice.                                           
 191:708  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'us'.                           
 191:809  suggestion  'is constructed' looks like     Microsoft.Passive        
                      passive voice.                                           
 191:903  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 191:942  error       Use 'that's' instead of 'that   Microsoft.Contractions   
                      is'.                                                     
 191:947  suggestion  'is passed' looks like passive  Microsoft.Passive        
                      voice.                                                   
 193:1    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 193:178  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'us'.                           
 193:196  warning     Consider removing 'very'.       Microsoft.Adverbs        
 193:272  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'We'.                           
 205:74   suggestion  'be applied' looks like         Microsoft.Passive        
                      passive voice.                                           
 205:178  suggestion  'being addressed' looks like    Microsoft.Passive        
                      passive voice.                                           
 210:80   warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'We'.                           
 210:187  suggestion  Consider using 'equal' instead  Microsoft.ComplexWords   
                      of 'equivalent'.                                         
 210:261  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 210:453  warning     Try to avoid using              Microsoft.We             
                      first-person plural like                                 
                      'our'.                                                   
 210:511  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 210:585  suggestion  'be pushed' looks like passive  Microsoft.Passive        
                      voice.                                                   
 210:598  suggestion  Verify your use of 'against'    Microsoft.Vocab          
                      with the A-Z word list.                                  
 210:687  warning     Consider removing 'very'.       Microsoft.Adverbs        
 210:811  warning     Consider removing 'quickly'.    Microsoft.Adverbs        
 227:16   suggestion  Don't use language (such as     Microsoft.Accessibility  
                      'normal') that defines people                            
                      by their disability.                                     
 227:61   warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 237:10   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 237:112  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 237:338  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'we'.                           
 237:461  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 237:503  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 237:595  suggestion  'FPV' has no definition.        Microsoft.Acronyms       
 237:605  suggestion  Don't use language (such as     Microsoft.Accessibility  
                      'normal') that defines people                            
                      by their disability.                                     
 237:655  suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 237:704  suggestion  'be converted' looks like       Microsoft.Passive        
                      passive voice.                                           
 237:717  error       Don't spell out the number in   Microsoft.Units          
                      'from meters'.                                           
 237:782  warning     Use first person (such as       Microsoft.FirstPerson    
                      'I'm') sparingly.                                        
 237:856  warning     Consider removing               Microsoft.Adverbs        
                      'thankfully'.                                            
 252:1    suggestion  'be pissed' looks like passive  Microsoft.Passive        
                      voice.                                                   
 252:1    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                      30 words).                                               
 252:100  error       Use 'isn't' instead of 'is      Microsoft.Contractions   
                      not'.                                                    
 252:157  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 252:184  warning     Try to avoid using              Microsoft.We             
                      first-person plural like 'us'.                           
 258:40   suggestion  'was checked' looks like        Microsoft.Passive        
                      passive voice.                                           
 258:146  suggestion  'was checked' looks like        Microsoft.Passive        
                      passive voice.                                           
 258:184  suggestion  Verify your use of 'as well     Microsoft.Vocab          
                      as' with the A-Z word list.                              
 258:210  warning     Use first person (such as ' I   Microsoft.FirstPerson    
                      ') sparingly.                                            
 258:284  suggestion  'was put' looks like passive    Microsoft.Passive        
                      voice.                                                   

9 errors, 105 warnings and 84 suggestions in 1 file.