Skip to content

Commit 305a16c

Browse files
committed
probe_eddy_current: filter noisy calibration points
Signed-off-by: Timofey Titovets <[email protected]>
1 parent edaa614 commit 305a16c

File tree

1 file changed

+54
-20
lines changed

1 file changed

+54
-20
lines changed

klippy/extras/probe_eddy_current.py

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ def handle_batch(msg):
107107
move(next_pos, move_speed)
108108
# Note sample timing
109109
start_query_time = toolhead.get_last_move_time() + 0.050
110-
end_query_time = start_query_time + 0.100
111-
toolhead.dwell(0.200)
110+
# Gather ~36 samples
111+
end_query_time = start_query_time + 0.150
112+
toolhead.dwell(0.250)
112113
# Find Z position based on actual commanded stepper position
113114
toolhead.flush_step_generation()
114115
kin_spos = {s.get_name(): s.get_commanded_position()
@@ -134,16 +135,21 @@ def handle_batch(msg):
134135
raise self.printer.command_error(
135136
"Failed calibration - incomplete sensor data")
136137
return cal
138+
139+
def _median(self, values):
140+
values = sorted(values)
141+
n = len(values)
142+
if n % 2 == 0:
143+
return (values[n//2 - 1] + values[n//2]) / 2.0
144+
return values[n // 2]
137145
def calc_freqs(self, meas):
138-
total_count = total_variance = 0
139146
positions = {}
140147
for pos, freqs in meas.items():
141-
count = len(freqs)
142-
freq_avg = float(sum(freqs)) / count
143-
positions[pos] = freq_avg
144-
total_count += count
145-
total_variance += sum([(f - freq_avg)**2 for f in freqs])
146-
return positions, math.sqrt(total_variance / total_count), total_count
148+
freq_median = self._median(freqs)
149+
mads = [abs(f - freq_median) for f in freqs]
150+
mad = self._median(mads)
151+
positions[pos] = (freq_median, mad, len(freqs))
152+
return positions
147153
def post_manual_probe(self, kin_pos):
148154
if kin_pos is None:
149155
# Manual Probe was aborted
@@ -166,24 +172,52 @@ def post_manual_probe(self, kin_pos):
166172
# Perform calibration movement and capture
167173
cal = self.do_calibration_moves(self.probe_speed)
168174
# Calculate each sample position average and variance
169-
positions, std, total = self.calc_freqs(cal)
170-
last_freq = 0.
171-
for pos, freq in reversed(sorted(positions.items())):
172-
if freq <= last_freq:
173-
raise self.printer.command_error(
174-
"Failed calibration - frequency not increasing each step")
175-
last_freq = freq
175+
positions = self.calc_freqs(cal)
176+
last_freq = 40000000.
177+
last_pos = last_mad = .0
176178
gcode = self.printer.lookup_object("gcode")
179+
filtered = []
180+
total_mad = []
181+
total_mad_mm = []
182+
total = 0
183+
for pos, (freq_median, mad, count) in sorted(positions.items()):
184+
if freq_median > last_freq:
185+
gcode.respond_info(
186+
"Frequency stops decreasing at step %.3f" % (pos))
187+
break
188+
diff_mad = math.sqrt(last_mad**2 + mad**2)
189+
# Calculate if samples have a significant difference
190+
freq_diff = last_freq - freq_median
191+
if freq_diff < 2.5 * diff_mad:
192+
gcode.respond_info(
193+
"Frequency too noisy at step %.3f" % (pos))
194+
break
195+
distance = pos - last_pos
196+
sensitivity = freq_diff / distance
197+
mad_mm = mad / sensitivity
198+
filtered.append((pos, freq_median))
199+
total_mad.append(mad)
200+
total_mad_mm.append(mad_mm)
201+
total += count
202+
last_freq = freq_median
203+
last_mad = mad
204+
last_pos = pos
205+
if len(filtered) <= 1:
206+
raise self.printer.command_error(
207+
"Failed calibration - No usable data")
208+
avg_mad = sum(total_mad)/len(total_mad)
209+
avg_mad_mm = sum(total_mad_mm)/len(total_mad_mm)
177210
gcode.respond_info(
178-
"probe_eddy_current: stddev=%.3f in %d queries\n"
211+
"probe_eddy_current: MAD=%.3fHz ~ %.4fmm in %d queries\n"
179212
"The SAVE_CONFIG command will update the printer config file\n"
180-
"and restart the printer." % (std, total))
213+
"and restart the printer." % (avg_mad, avg_mad_mm, total))
181214
# Save results
182215
cal_contents = []
183-
for i, (pos, freq) in enumerate(sorted(positions.items())):
216+
for i, (pos, freq) in enumerate(filtered):
184217
if not i % 3:
185218
cal_contents.append('\n')
186-
cal_contents.append("%.6f:%.3f" % (pos - probe_calibrate_z, freq))
219+
z_height = round(pos - probe_calibrate_z, 3)
220+
cal_contents.append("%.3f:%.3f" % (z_height, freq))
187221
cal_contents.append(',')
188222
cal_contents.pop()
189223
configfile = self.printer.lookup_object('configfile')

0 commit comments

Comments
 (0)