I wrote some GCode to calibrate pressure advance. I wasn't satisfied with how uncertain I was in reading the other ones I found. They usually try various PA values as a sort of gradient, which sounds fine until you have other artifacts confusing the issue. It also requires some effort to convert the measured height into a k value in many cases.
But what most lacked entirely is a "normal" reference adjacent to each test value. I produced this reference by first laying down some lines at a very slow, steady speed, then putting the test lines right next to it. The picture doesn't quite show how much easier this is to read; I think I succeeded in what I was trying to do. Once removed from the bed, you can try various lighting, including back lighting.
Features:
Only 2 layers, so it doesn't take long.
Raft, so it's not sensitive to initial nozzle height.
Controlled by variables set at the beginning of the code.
PA test values separated by configurable space, so you can read just by counting bands.
Configurable number of lines in each band.
Configurable for machines with multiple tools.
Configurable speeds, temperatures, retraction, layer height & width, bed position, and of course, k values for PA.
Pictured is eSun Fire Engine Red PETG on an E3DV6 (my secondary hot end) at 243°, k values from 0.05 (bottom) to 0.25 (top), increasing 0.01 each band. The bottom of each band is 4 lines at 1,200mm/min. The top of each band is 4 lines of 35mm on each side at 1,200mm/min sandwiching 70mm at 6,000mm/min in the center.
In my experience you can use something like this to find the general value, then do another print with fewer bands and more lines per band to confirm the best k value. My best band on this is the 8th from the bottom, so I'm using k=0.12.
This code uses RFF 3.x meta-commands, so it's for Duet hardware. Further, RFF 3.3 and earlier have a bug which doesn't end the lifetime of local variables when a job ends or gets canceled, so you have to do an M999, an emergency stop, or cycle the power between attempts. This will be fixed in RFF 3.4, which has been in beta for several weeks, so it should be out soon.
Please consider this "copylefted".
; set variables
var StartX = 50
var StartY = 50
var LinesPerTest = 4
var LinesBetweenTests = 4
var TempBed = 74
var TempTool = 243
var ToolNum = 1
var Width = 0.48
var Height = 0.25
var Retract = 1
var Prime = 7.9 ; Before Raft
var PALow = 0.05
var PAHigh = 0.25
var PAIncrement = 0.01
var SpeedRaft = 2000
var SpeedSlow = 1200
var SpeedFast = 6000
var SpeedTravelXY = 9000
var SpeedTravelZ = 1200
var SpeedRetract = 4500
; Calculated and Utility Variables
var TestCount = 1 + floor((var.PAHigh - var.PALow) / var.PAIncrement + 0.5)
var FilFactor = var.Width * var.Height / (pi * 1.75 * 1.75 / 4)
var PA = var.PALow - var.PAIncrement
var Dist = 0
; PREPARE
;M42 P1 S1 ; Lights Bright
T{var.ToolNum}
M82 ; Extruder Absolute Mode
; Heat Bed and set Hot Ends to Standby
M400
M117 "Heat"
M140 S{var.TempBed} ; set Bed Temp
M568 P{var.ToolNum} S{var.TempTool} A2 ; set Tool Temp
M116 H{var.ToolNum + 1} S1 ; Wait for temp
G4 S12 ; Delay to Allow for Overshoot
M116 H{var.ToolNum + 1} S1 ; Wait for Recovery
M116 H0 S1 ; Wait for Bed
M400
M117 "Home"
G28
; BEGIN RAFT
M400
M117 "Raft"
; Go to StartX + Width, StartY
G90 ; Absolute
G92 E0
G0 E{-var.Retract} F{var.SpeedRetract}
G1 X{var.StartX + var.Width} Y{var.StartY} F{var.SpeedTravelXY}
G1 Z{var.Height} F{var.SpeedTravelZ}
G91 ; Relative
; Prime
G0 E{var.Prime} F{var.SpeedRetract}
G92 E0
var RaftLineCount = floor((floor(139 / var.Width) - 1) / 3) + 1
set var.Dist = (2 * var.TestCount * var.LinesPerTest + var.LinesBetweenTests * (var.TestCount - 1)) * var.Width
while iterations < var.RaftLineCount
; Draw Raft Line
G0 Y{var.Dist} E{abs(var.Dist) * var.FilFactor} F{var.SpeedRaft}
G92 E0
; Break here if last time
if iterations + 1 >= var.RaftLineCount
break
; Move Over
G0 X{3 * var.Width} E{3 * var.Width * var.FilFactor} F{var.SpeedRaft}
G92 E0
set var.Dist = -var.Dist
G0 E{-var.Retract} F{var.SpeedRetract} ; Retract
; BEGIN TEST PATTERN
M400
M117 "Test Pattern"
; Go to StartX, StartY
G90 ; Absolute
G1 Z{2 * var.Height} F{var.SpeedTravelZ}
G1 X{var.StartX} Y{var.StartY} F{var.SpeedTravelXY}
G91 ; Relative
while iterations < var.TestCount
; set PA
set var.PA = var.PA + var.PAIncrement
M572 D{var.ToolNum} S{var.PA}
echo "PA=",{var.PA}
; Draw Reference Lines
while iterations < var.LinesPerTest
G0 E0 F{var.SpeedRetract} ; Unretract
G0 X140 F{var.SpeedSlow} E{140 * var.FilFactor}
G92 E0
G0 E{-var.Retract} F{var.SpeedRetract} ; Retract
G1 Y{var.Width} F{var.SpeedTravelXY}
G1 X-140 F{var.SpeedTravelXY}
; Draw Test Lines
while iterations < var.LinesPerTest
G0 E0 F{var.SpeedRetract} ; Unretract
G0 X35 F{var.SpeedSlow} E{35 * var.FilFactor}
G0 X70 F{var.SpeedFast} E{105 * var.FilFactor}
G0 X35 F{var.SpeedSlow} E{140 * var.FilFactor}
G92 E0
G0 E{-var.Retract} F{var.SpeedRetract} ; Retract
G1 Y{var.Width} F{var.SpeedTravelXY}
G1 X-140 F{var.SpeedTravelXY}
; Move to start of next comparison
G1 Y{var.LinesBetweenTests * var.Width} F{var.SpeedTravelXY}
; Finish up
M400
M117 "Done"
G1 Z10 F{var.SpeedTravelZ}
G90 ; Absolute
G1 X10 Y280 F{var.SpeedTravelXY}
G0 E0 F{var.SpeedRetract} ; Unretract