Load Cell Probing Algorithm Testing

AKA, the thread that will probably have more math and algorithms in it that anyone can stand. I think this discussion will be more productive in its own thread. I’m here for ideas, improvements, suggestions, verification etc.

I created a Jupyter notebook in the scripts directory of the fork: test_collisions.ipynb
Github will run this for you and you can download it and play around.

The idea is to test the effectiveness of the two main algorithms involved:

  • The “Elbow Finder” which tries to find the first point in the data set that contains probe collision data
  • The “Collision Finder” which takes the elbow point and tries to compute the exact time that the collision occurred.

I created the test collision data from a straight line at y=0 that runs from 0.0 to 10.0 and these polynomials:

  • 50x
  • 30x^2
  • 4x + 3x^2
  • 20x - x^2 + 3x^3
  • 25*log(x + 1) + x^3
  • 4x^1/3 + 3x^1/3
    Which run from 10.0 to 11.0:

This is a mix of concave, convex and linear functions. The nice part about using functions is that they are continuous and can be sampled at any interval we want to simulate. I don’t think these functions are in any way ideal, but they give us somewhere to get started. One way this can be improved is for us to pick test function that better model real world collision data.

Each function is sampled using a sliding window that sweeps across the collision point. This lets me generate the full range of conditions that I couldn’t replicate on demand in a printer. For 6 polynomials I get a set of 10 sample for 60 total test cases.

Noise can then be added to each sample set. So far I have random noise and 60Hz power line noise. (I haven’t worked out how this noise model maps to noise on my printer yet)


I started working on the “collision finder” evaluation first. Job 1 in any scientific context is to establish a control. Some benchmark that we should easily be able to beat. I have 2 control algorithms:


This just returns the time at the elbow.


Named after the cursed bogosort. This takes advantage of the fact that the collision point is somewhere between [elbow-1, elbow]. So it guesses a random value in that range. And I am very sorry to say that this is annoyingly effective. In some scenarios it outperforms all other algorithms which makes it an excellent control.

Collision Finders

So then I have some genuine attempts to solve the problem:


Crowd favorite linear regression does what it says on the tin. Perform linear regression from the elbow to the end of the data set and then solves for y=0 on the regression line. It performs brilliantly on 50x and is absolutely destroyed by bogo_collision_finder on every other function. So this cant handle data with curves in it.


This tries to fit a degree 3 polynomial to the collision data. Then the root that is nearest the elbow is selected as its guess. I really had high hopes for this one. But for curves that are concave and shallow (30x^2) it fits a function that flattens out near y=0. This makes the predicted collision point very sensitive to noise and it generally performs worse than bogo_collision_finder unless noise is low. This has the advantage that it only requires numpy to run.


This is the algorithm I came up with that’s in the code right now. It tries to make a guess based on the average rate of force increase during the collision, and what fraction of that is seen in the elbow point. Its results are clamped to the range of [elbow-1, elbow] so it cant perform worse than dumb_collision_finder. But unexpectedly is beats all of the algorithms above. Its not “good” at any particular polynomial but its not horribly bad at any of them due to the clamping. I’m both pleased and dismayed I did this well with my first guess.


This fits a b-spline to the collision data and uses it to extrapolate back to the collision. BSplines can’t be solved for y=0 in the same way as a polynomial, so I just solve it 100 times at an even spacing over the [elbow-1, elbow] range and pick the value where y is minimized. This is the best performing algorithm so far. At high noise levels it performs on par with estimator_finder but as the noise drops off it can do about an order of magnitude better. Unfortunately this requires scipy and they are using fortran code internally, it wont be something I can port out into python easily.


You can see here that if the SD of the noise is less than 0.001 we get a pretty reasonable ranking of the finder functions, lower is better:

If the noise was raised to SD of 0.1 it a different story:

Suddenly bogo_collision_finder is near the top of the results :frowning:. Also the noise absolutely confuses polyfit_finder. So a big learning here is that noise is a huge factor and no algorithm is going to be successful under noisy conditions without some clever filtering. On the electronics side increasing signal to noise is important.

On the physical side, squishy printers make for gently curving collisions which are difficult to plot solutions for. We might want to try and characterize what is “too squishy” and warn people or reject such probes.


Can you elaborate on the output of the test_collision_finders function? Theres a synthax error in line 19 as “sample_width” is not defined in this context

Is the result of the dumb_collision_finder just 10 ± noise?

Also, just for my understanding of the klipper system, what do you do with the time? How do you know the z-position at a given time? Does klipper provide that rtos-like functionality?

I don’t understand your “Overall Result” value shown in these bar graphs (without looking at your code at least, no time to dig into it right now). Can you elaborate what it means? I guess I can already say from the fact that your bogo_collision_finder is so far up in the ranking that the value you are computing is not a good ranking.

Also I do not understand why you expect non-linear behaviour. Which physics do you expect to give you such non-linear results? All my observations were pretty much linear. Sometimes there might be a kink (i.e. a slope change), but this can be clearly linked to a mechanical issue. I have observed this when using a somewhat loosely attached heat bed surface, so there is an air gap between the upper part of the build plate and the solid part of the heat bed. When the nozzle pushes the upper part down and the air gap gets reduced to 0, you will see of course a change in the slope.

As a physicist I would say this should be the only non-linear behaviour to expect. Every other non-linear behaviour would mean that something has been deformed permanently in the process (because some maximum force has been exceeded). Of course I am now talking about the relationship between force and z position, so I am assuming the move has constant velocity and the force is properly calibrated (a bad measurement setup might have non-linear force to ADC value relationship, but in that case I would fix the hardware or perform a non-linear calibration).

That said, I would expect the linear regression finder to perform best. I have already implemented one and it delivers at a real setup very good results, despite the hardware setup is far from perfect. I see absolutely no reason to try to improve on that one first. I understand you want to improve the probing speed by using a continuous movement rather then doing small steps (as my implementation does), but for this you need to work on the “Elbow Finder”. Feel free to use the “Collision Finder” from my code (in whatever way it may suit you), it is well tested by several people. (Maybe this can be at least one small contribution I can make in the end, given that my time is rather limited recently… sorry, I really would like to help more, I just don’t find the time!)

(EDIT: Noise is also non-linear behaviour, but of course this plays an important role. Linear fits can deal with nose rather easily, my code estimates the precision of the result based on the quality of fit and will retry if it is not good enough. That is very helpful because there might be external disturbances sometimes like touching the printer accidentally.)

I think you could expect nonlinear behavior if there is plastic buildup under the nozzle. This might result in a plastic deformation to some degree. But that would result in a wrong value anyway, so the nozzle should be cleaned before. That being said I agree that it should be linear.

Doh, my link didn’t go to the latest version of the file. Link is now fixed and that problem is also fixed.

Its the time (x axis value) that the collision started. It is basically 10 ± noise, but the range for the noise is restricted to the x values at [elbow-1, elbow]. Those values sweep from elbow-1 = 10 to elbow = 10 across the 10 generated samples.

klipper takes a print time and converts it into a z coordinate. The output of the homing function home_wait is usually the time the endstop triggered.

Yeah, my units here are :poop:. I was going for average % error but I never multiplied by 100. Its based on the time error / sample width.

I’m having a go at showing percentages. I could also plot the standard deviation instead.

My results are pretty much linear too. Its just that, experimentally, they are all curves.

This is pretty typical on my machine:

It starts out as as a convex curve and switches to concave. It “looks linear” and the collision is sharp. But the linear regression plot line there ends up pointing to a collision time that’s too early. It would be about a whole sample period off in this case. I think this was 400SPS @ 5mm/s so 0.0125mm.

Experimentally my repeatability improve significantly when I switched over to the estimator_finder implementation. I added a 0 to that number, SD of 0.0012mm. Mostly because it respects the selected elbow, its never catastrophically wrong.

I’ve seen sample plots from @D4SK that are very curved. They trend linear but start out with an arc. Maybe he can post some examples.

linear_regression_finder is like your implementation, it just doesn’t reject bad fits, that would defeat the purpose of comparative testing. It performs brilliantly on the linear function, nothing can touch it in that one case:

I think we need to understand this problem (if it really is one) first before doing anything else.

Ah, yes. In contrast to me, you are sampling faster and moving continuously. So we might expect dynamic effects, which of course I do not see (I am doing every measurement at rest). What we are seeing here is basically a bump at the very beginning of the curve. This might be caused by a mechanical oscillation due to the impact.

If this is correct, the shape and strength of this bump will depend highly on the speed. Can you repeat this measurement with different speeds to confirm this? At very low speeds I would expect then no such bump and a perfect linear behaviour.

Still assuming this is true: Try doing a linear fit on the sample points after the bump, i.e. starting with the purple one around 2,072.267. Doing the fit with a straight edge on my screen looks very promising :wink:

Btw: I think in the end a precision of 0.01mm (all errors taken into account, including potential systematic ones) should be sufficient. So even the linear fit with the non-linear sample points is not too far off, but I agree it should be improved.

Well, this was meant for the final production implementation of course. In any case I do not think this comparative testing leads anywhere. Of course the function which can reproduce your input shape best will always win. If you want to explore possibilities of extracting information from the non-linear regime, you need to have a good enough Physics model which shows the non-linear behaviour, or at least you have to make assumptions about the exact shape of the non-linearity. It is mathematically impossible to extract the information we need from an arbitrary shape. One way or the other you will start introducing strong dependencies on some Physical variables which define the shape of this bump, like mechanical resonance frequencies of the load cell etc., which will be different for each printer model and load cell setup. You might be able to get very good results for your setup, but most people will not be able to reproduce this without substantial parameter tuning.

So as a general rule of thumb: Avoid dealing with non-linearities, unless you really have to :slight_smile:

“You cant do this” is the kind of feedback I love to get. I’ve made my entire career out of showing people that it can, in fact, be done.

bspline_finder does a better job at curves than anything else I have tried and its nearly a tie with linear regression for linear functions:

And this is the noisy case. If you could turn the noise off it gives almost perfect results on the test set:

I haven’t tried it in the printer yet but its on the TODO list.

Sorry, there are in fact mathematical obstacles to take into account. You can ignore them, and maybe you can even get somewhat decent results with that, but you will be far away from some optimal implementation. Here is why:

The only information you want to extract is the position (or time, can be considered equivalent for constant movement) of the intersection of whatever function you assume with the zero line (which I define hereby as the average of all measurements without bed contact). You have to ask yourself now, which information is contributing in what way to that single value of interest. Of course you can fit a spline to the data, but you will essentially ignore all sample points except of the first 3 or so (depending on your exact spline function of course). That is a total waste. Especially if you have stronger noise (again: this depends on the hardware and we are trying to support a broad spectrum of hardware implementations, right?) you need to use more data points to get to an acceptable precision. You need to over-constraint the fit somehow, splines do not do that or only to a very small extend. To over-constraint your fit you have to put in some model knowledge. You cannot do that (mathematically speaking) with generic functions like a spline. The model can be phenomenological, but you have to model somehow the physical effects seen as features in the plot and not just apply some common interpolation functions.

I think a very important hint is that your “stupid” implementations like the bogo_collision_finder and the dumb_collision_finder are already delivering quite good results. This means that you do not really need any fit. Your data points are already dense enough and have so little noise that just picking the first one which is different (within the noise band) from the zero line will give you a good enough resolution.

Now imagine you have worse hardware, like a hx711. You have only 80sps, so you have 0.0625mm distance between samples. Also you have noise in the order of let’s say 5 grams (standard deviation) and a slope of 3000 g/mm. Those are actually quite realistic values. You will need a couple of data points to contribute to your fit so you can get down to 0.01mm precision.

One more thing: The deviation from the linear shape is caused by a disturbance. How do you extract the information from that disturbance?

@mhier thanks,

I believe your thesis is that the printer is either a perfect rigid body, or a system of springs that obey Hooke’s Law. Finding anything non-linear in the data is suspect and must be due to noise, outside influence (“a disturbance”) or structural defect. Thus all non-linear data should be rejected. Over fitting to anything non-linear is a mistake because those artifacts are not real data from the underlying system.

I hope I’m making an accurate summary and you feel heard. :pray:

My thesis is that the printer is a system of non-linear springs. The curves in the data are measured evidence of the complex system. This model best fits the data that I have collected. Based on the variety of materials and construction techniques in a 3D printer, I have no basis for assuming linear behavior. Testing non-linear methods show real world improvements in accuracy over linear methods. I will continue to pursue those improvements.

We used different equipment, different methods and are looking at different data sets and have come to different conclusions. That seems pretty normal to me. We don’t agree and we don’t have to, I’m fine with that. I don’t want to argue about this anymore as its derailing the thread. If you want to continue, please do it in a DM.

I’d like to hear if anyone else has something to contribute?

  • I’d like ideas on modeling of the test functions so they can be more easily configured to match real world observations. Maybe InterpolatedUnivariantSpline? Having a representation in coordinate space would let me make certain things configurable. Working with polynomials directly is a pain.
  • The ability to use the same curve at different sampling rates would also be helpful to simulate different probing speeds separate from sample rate.
  • What should I do about matching noise levels in the model to the real system?

I think both of your approaches are valid. @mhier is a physicist and says if you want the perfect algorithm you have to understand the system completely. You take a more practical approach, taking algorithms and the best will win. In the end, it only thing that matters is that the accuracy is sufficient.

In theory, it should be linear. But there is friction in real world systems. Could be the air under the nozzle as gas springs are in fact not linear. It could also be friction between nozzle and bed. As you push on the nozzle, the load cell will bend. This results in the nozzle being pushed up, but also slightly sideways. Could also just be the impact (and reflections) that travels though the loadcell. Also it’s still a dynamic event and you assume a constant velocity. The control circuit of the stepper motors could also contribute to this output. Before the elbow point they just have to carry the weight of the bed, after the collision the load on the steppers is higher. That change could cause a non linear output as it depends on how the control circuit responds to the change of load.

For a better understanding, it would be nice to have an additional graph with a x-axis showing travel instead of time. Is the Force in Newton? Would be nice if the results are shown as a distance rather than time, as we are measuring a distance in the end.

I’m looking at your measured values and I think there are not enough data points to approach the problem with pure data science because theres just not enough information in it. You can fill the information gap if you understand the physical principals behind it. All of that stuff being said on the thread could be true, the question is which physical effect is big enough that it interferes with our data.

If you try to get an algorithm empirically, it should be based on a lot of real world data. If you try to do this with the functions you listed, your algorithm race is based on the assumption that these functions match the reality, which has to be validated too.

That being said, with the information we have right now, our best bet could be to take the middle of elbow and elbow-1. We know the point is between these two points. I do not see an advantage in guessing a random value, I would try to just use 0.5. Keep in mind that you will do multiple measurements across the bed. With a fixed value, we might have a slight (maybe negligible) z-offset, but at least its the same across the bed, which means the bed will at least be leveled without a random value messing with it.

1 Like

This is taking a very bad turn. You want to silence me. I am not giving into that so easily.

We are talking about fundamental Physics here. Classical mechanics, this is all known for centuries and very well understood. The mechanical parts of every 3D printer in the world can be described perfectly by classical mechanics. You can deny that, but the fact remains. This is not negotiable. Also this is not an opinion or a “thesis”. If you fail to understand that, you will likely fail to solve your problems.

A lot of statements in this and the related threads hurt my stomach as a Physicist. I can live with that and I am happy to explain the background to you. If you try to brush me off like this, I am pissed.

I strongly recommend you rethink your attitude here.

For everyone who is still interested in facts here:

  1. Springs (and all solid state material) has always a linear and a non-linear regime. Elastic deformation is linear. Elastic means, the original shape is restored after releasing the force.
  2. Non-linear behaviour is inelastic. This means the deformation is permanent, the original shape will not return after releasing the force.
  3. If you apply inelastic deformations to the mechanical parts of your 3D printer, your printer is broken. Stay away from the non-linearities.
  4. Non-linear elasticity is also a thing for special materials (intentionally designed that way), but you will most likely not find it in your 3D printer, and if you do, it must not be found in the parts relevant for us here. Every sane 3D printer must be built such that its frame is as rigid as possible. Nobody would put elastomers or similar materials in places which define the relative position of the nozzle and the bed, because that would destroy the precision during print operations.
  5. I am talking about static situations here, i.e. you apply a force “slowly” and keep it steady for a while, then take your measurement. You (@garethky) seem not even have tried that, which is kind of sad.
  6. You are performing dynamic movements, so expect dynamic effects. Dynamic means the forces are changing over time and your system has not yet reached a steady state.
  7. Common example for dynamic behaviour: Mechanical oscillations. Take a spring, fix it on top, attach a weight and hit the weight. This is called an elastic pendulum. You will see a sinusoidal movement of the weight. This is still called “linear” in Physics, because the differential equations describing this are linear. (The differential equations describe the time-dependent behaviour, so no, you cannot make something “non-linear” with “linear differential equations” in the static case.)
  8. I have already given you a hint what most likely is causing the non-linear bump in the data you have shown: You are hitting your elastic pendulum (because your printer is basically a bunch of springs with a bunch of weights attached in wild combinations) with a force (the nozzle is hitting the bed or vice versa) and it starts ringing. This is not surprising, on the contrary this is extremely likely the explanation for the shown behaviour. I already posted above some ideas how to verify this. If you have doubt, perform such measurements carefully and show the results.
  9. Another way of seemingly non-linear movement in a linear system is rotations when just looking at one axis. We are in fact looking only at one axis, so if e.g. the bed would rotate (because it is attached only at one side and you are applying the force at the far side), you would see a sinusoidal movement again. The sinus is very linear for small angles though, so for this to make a measurable difference you need to have rotations of several degrees. If that happens to any structural part of a 3D printer, it is again broken :wink:
  1. Friction does not make the system non-linear. In fact, the commonly known friction you will observe only when parts are sliding against each other, but again: There must not be any sliding parts in these structural components of a 3D printer for it to function properly. What we will have is internal friction of a solid state body, which produces a little bit of heat while being deformed (and hence takes out some energy of course). This is completely negligible here, it is exactly what is described by non-linear elasticity. Elastomers do that, this is used to dampen oscillations (by converting the mechanical energy into heat). If you don’t build a great deal of your 3D printer frame from soft elastic materials (:rofl:), you will not see such effects.
  2. If you really need to describe the non-linear behaviour for whatever reason, you need to have some mathematical description. You cannot obtain one which is universal enough (i.e. working also for different printer models) without basic understanding of the Physics happening here. Of course you may be able to fit something, but you can also fit a spline to an elephant. You are simply not using most of the information then. This is a simple fact from data science. The more parameters your fit function has, the less information goes into the one data point you seek to extract. Imagine you have 10 sample points (after the impact). You can do a linear fit, which has 2 degrees of freedom (axis offset and slope). This means your fit is 8 times over-constraint. This is kind of an averaging, so it improves the precision of your result even when the sample points are noisy. If you use a classic spline to fit, your fit eats up all degrees of freedom, because the spline is forced through all data points of your fit. The later data points have no influence on the earlier part of the resulting function, so you can also just discard them completely. Also your result will depend heavily on which data points you include in your fit close to the impact. Is that red circle there part of your fit or part of the baseline? How do you decide that? You need to have relative strict criteria to exclude data points from the fit (I would say 5 standard deviations away from your base line) and hence you must extrapolate the result over several sample points. A spline cannot do that for fundamental mathematical reasons as stated above.
  3. This is no rocket science. We should not expect wild behaviour. Everything here is classic Newtonian mechanics. Be realistic! Keep it simple to be successful!

I sincerely hope this gets this derailed discussion back on track. The track is science, not pseudo science and snake oil. If you have doubts, please do background reading. Wikipedia is a very good source for these things.

1 Like

Agree with you that the printer itself ist mostly a system of linear springs.

Linear friction does not make the system non-linear. A non-linear friction will certainly result in a non-linear measurement of force. I have already described that the nozzle is sliding on the bed. Timing belts are made from elastomers. The magnetic bed can also be made from an elastomer. I also said that the movement itself might not be linear because of the motor control. When you have play in components the measurement will be non linear. The measurement itself looks non linear. There are several reasons why the measurement could be non linear. Question is why is the measuremnt like that. We can’t guess by our gut feeling what physical law has enough of an impact on our measurement.

Your list of facts might not be wrong, the question is if this helps solving the problem. I don’t really get whats your point. Do you think the measuremts are faulty? Do you think he should measure statically? No one is arguing against physical laws. As a mechanical engineer I certainly won’t, but whats to discuss here is if it matters? If you think the result must be perfectly linear, okay, but linear regression gives shit results, so what do we do?

Discussion should go back to solutions.

Also quick reminder that the graph is not force/distance. It’s force/time and we have no reason to assume that time and distance are sufficiently proportional.

I already gave a very likely explanation for the measurement. It has nothing to do with non-linear elasticity. My point is: non of the quoted non-linear functions are able to describe this type of behaviour, not even remotely, because the behaviour is dynamic. It levels off to a linear behaviour after a while (right part of the plot starting with the purple data point). Ignoring these facts will lead to wrong results. My point is that this needs to be understood before continuing. Just applying some random non-linear fit function without even trying to understand what’s going on is a guarantee for failure.

This dynamics is not exactly helping us to find the point we are looking for. So yes, I propose to start with static measurements. I have already done this. My printer is from 2015 and it was equipped with load cells for this purpose from the beginning. All this is not new to me. The problem with my printer electronics is that it is too slow to measure the dynamic behaviour, so I have to measure statically in any case.

Still, I think it is pretty obvious that dynamic behaviour is more complicated than static behaviour. So my strong recommendation is to start static. Everything you can learn from the static case is important in the dynamic case as well, because dynamics is added on top of the static behaviour. @garethky seems not to have tried the static approach, which would save us a great deal of discussion here.

Once the static case is understood one can try to understand the dynamics. Again, I would try to keep it simple at first by merely detecting the dynamic (non-linear) part of the measurement and just exclude it from the fit. Once that works, one can finally try to extract information also from the dynamic part - if that still seems to be necessary at that time, e.g. because precision is too bad otherwise when chooing a reasonable speed. (Yes, this is in the end merely a speed optimisation! You cannot gain anything else than speed by taking into account the dynamics!)

This would be a common sense approach. Start with the simple things and understand them. Then get to the more complicated stuff. Stop when you have reached sufficient results (precision, stability, portability to other printers etc.) to avoid dealing with unnecessary complexity which will make things only less precise, less stable, less portable and the source code less maintainable in the end. Of course, the real world is non-linear everywhere, it is only a question how precise you can measure. Even the best (reasonable) electronics and load cells will not make a precision instrument though. Also, you can turn around that statement: The world is linear everywhere, if you just stay in a small enough area. Even an elastomer behaves linear at the beginning, so if your build plate has a thin elastomer component and you are applying a small force to it everything will look still perfectly linear. So why bother?

In any case, the shown measurement is pretty much excluding non-linear elastics, because it ends up to be perfectly linear after the initial bump (non-linear elastics would be increasingly non linear for higher forces). So once again: this is not what happens here. If you go that way, you are going into the wrong direction.

This discussion feels differently in part. I have been arguing with physical laws and essentially I was told to go away. For me this means that science is being denied. This is really sad and makes me loosing hope for this project.

I am now going to stop taking part in this discussion until @garethky acknowledges at least some basic physical laws here. My request to @garethky is to redo the measurement at different speeds and compare the results. Please change your x-axis of the plots into a length scale (mm or micrometer or so) for simpler comparison and show the results for different speeds in one plot. Once you have done that we can continue talking. Otherwise this whole thing is a waste of everyone’s time.

err, sorry, he clearly stated he is moving at 5mm/s. time and distance is hence perfectly proportional.

Fair enough - I get why you are feeling this way. I’m also for finding the root of the behavior if the current measurement is not good enough. I would also try different speeds at first.

Hard disagree. Just stating moving the bed at 5mm/s does not make it move at 5mm/s. The bed is being moved by stepper motors, which have steps and characteristics. Actually, you are not measuring the force resulting from the moving bed, you are measuring the force which is applied to the loadcell by the z-motors. I would not bet on this to be accurate enough not to intefere with a measurement that is this sensitive (in a dynamic event).

This is ridiculous. Take dynamics out of the equation and we can talk again.

Agree, this conversation is nonsense.

@garethky If you take the average between the elbow and elbow-1, wouldn’t that be sufficient?

[elbow-1, elbow] should be a timespan of 1/340s with 340sps. With 5mm/s this should be a distance of 0,0156mm. If you take the average, your max. error (resulting of the finder algorithm) is half this distance → 0,00781mm, which is quite good? If you do half the speed, you get half the max. error. You could do a fast measurement, then move to like z=0,5mm and do a slow measurement. You can do like three to five “slow” measurements and take the average.

Downside to this is you are dependent on only two samples per measurement which makes it prone to noise.

O.K., garethky asked for ideas on modeling of the test functions. I have held back from contributing as my mathematical understanding is mostly patchy and often sucky. Having said that, I have spent a good deal of time trying to extract a reliable Z position datum from transducer data in various bed leveling probes. my lack of mathematical chops has caused me to adopt a morphological approach - what is the shape of the data?

My attitude has been to firstly always generate a value, even if wildly inaccurate. What we do not want is for the nozzle contact event to be missed and the nozzle to push on the build stage until the Z motor(s) stall.

Only after the Z contact value has been generated should the data be interogated to see if it was good. This can be a binary signal or a set of values that can be used to show that a Z datum is an outlier and can be discounted.

To find what the shape is I divide it into three parts: The baseline, the knee, and the rise. If the rise is approximately a straight line and has the right slope when a threshold is passed then the longer term (ca 500ms) baseline is checked. If this was within tolerance then the near baseline is checked that it close to the long term baseline.

If a higher threshold is met without all variables being within tolerance then a nozzle contact is flagged but without a “good contact” signal.

The longer-term baseline is found with exponential moving average and mean absolute deviation, the trigger value with a simple average of a small set (8 points), and a stored value of the same average is used for the baseline immediately before the knee and the slope is found with a Savitsky-Golay 9 point differentiating filter.
btw, I use Savitsky-Golay in the “monkey see monkey do” mode - I don’t understand it, but it works.

The MCU used for this is a PIC16F1705 and the sensors are 1 or more piezoelectric discs. Sampling is at 4000 samples per second of 10-bit data. A good trigger will occur within approximately 10µm with a variability of ±3µm from actual contact at a nozzle speed of 2mm/sec.