Skip to content

Scanning speed and velocity mapping of Cybrid

vagfilm

RIP Where is filter defined? Is it intrinsic matlab function?

Per @gzpiano post I assume the FIR is computed in the microprocessor and the result fed to matlab.


RIP

vagfilm delvento Where is filter defined? Is it intrinsic matlab function?

Per @stem_piano post I assume the FIR is computed in the microprocessor and the result fed to matlab.

Perhaps, but the matlab code has a filter function call which is not defined in the provided source, so I wonder what that is.


gzpiano

RIP

Yeah, filter() is a Matlab function. Its just a convolution (denominator is set to [1] on line 56). You should be able to run this code with Octave as well, which is free open source. The hammer position sample data is provided in the same directory.

If anyone wants to go this route, its fairly easy to find DSP libraries that implement the taps on line 41. Those taps include a lowpass filter to reduce some of the differentiation noise.

Although I am happily building my worlds-most-unnecessarily-complicated-DIY-hybrid, I am also happy to help out other projects, for example providing a filter implementation pull request. However, I can't guarantee any schedule or deadlines.

vagfilm

Yes for sure, there needs to be more to the algorithm. FIR is just the subset for a continuous velocity calculation.


vagfilm

gzpiano FIR is just the subset for a continuous velocity calculation.

Thanks and "too bad"... It would be neat for my other things... But I may give it a spin since I never played with FIR filtering.


JayKominek

gzpiano For my DIY hybrid version, it continuously computes the velocity with an FIR digital filter (in a microprocessor).  See line 56 of Matlab code in linked github page above.

Any opinions on alternative filter constructions? I was fiddling with Savitzky-Golay on some old recorded data last night, getting decent looking results, and was thinking about trying to squish it into my firmware this afternoon.


gzpiano

JayKominek

Good idea. I convolved a boxcar (moving average, [1 1 1 1 1… 1]) with a first order numerical derivative [1 -1] to get the taps in that code on github. Rather simple. Where I have seen noise most problematic is in low velocity hammer strikes. Super quiet notes. Savitzky–Golay might be a great way to get better accuracy for that case.

The github data is relatively fast strikes, so it doesn't show the noise issue as much.


xooorx

gzpiano Any chance you could post some of the low velocity strike data? I've been messing around with the strike data that's on GitHub (and may post something about that soon) but if there's some more problematic data it would be good to see it.

Also, how constrained are you for processing power? Are you doing boxcar + first order just to try the simple stuff first or are you needing to avoid multiplications and divisions?


gzpiano

xooorx

Sure, next time I have everything put together I will try to remember.

Meanwhile, this link is the place in my algorithm video where I have a plot of the issue:

With respect to processing power, that was not really a factor.


RIP

gzpiano this link is the place in my algorithm

Thanks. You've done quite a number of interesting videos.

gzpiano With respect to processing power, that was not really a factor.

I agree. Even with a limited RP2040, I can do about almost one hundred of loops per ms. In each loop I synchronously and sequentially sample the position of three hammers (eventually will do that async with DMA, this is the slowest of everything done in each loop), do some calculations, send data synchronously via I2C (also slow, but done only when needed) and more. Doing a filter like (or even something more complicated) this is nothing.

I am banging my head wrt some stupid details (go https://github.com/davidedelvento/Rpi-pico-i2c-example if you are curious) when those will be solved I'll have a pretty decent 9-key electronics which I can install in the piano and with enough firmware to work (among other things, with some regulation possible via MIDI 😎️) and provide my own hammer strike data to further analyze.

Let me go do that right now…


JayKominek

RIP with a limited RP2040, I can do about almost one hundred of loops per ms. In each loop I synchronously and sequentially sample the position of three hammers (eventually will do that async with DMA, this is the slowest of everything done in each loop), do some calculations, send data synchronously via I2C (also slow, but done only when needed) and more. Doing a filter like (or even something more complicated) this is nothing.

You'll have plenty of clock cycles for any integer algorithm you could want, but with only M0 cores, I'd expect single precision floating point algorithms to be prohibitive. I think something like an RC filter at 20kHz might be the limit.


xooorx

gzpiano Good idea. I convolved a boxcar (moving average, [1 1 1 1 1… 1]) with a first order numerical derivative [1 -1] to get the taps in that code on github. Rather simple. Where I have seen noise most problematic is in low velocity hammer strikes. Super quiet notes.

The noise problems I saw when playing around with the samples on GitHub turned out to be due to the heavy quantisation of the data. (I see from comments in the Matlab code that you have a fix for this coming).

The numerical differentiation to get the velocity is differentiating the signal and the quantisation noise, which is OK if you've got enough bits but rapidly falls apart if you don't...

Numerically differentiating a 24 bit sine wave:
int24.png

Numerically differentiating a 16 bit sine wave:
int16.png

Numerically differentiating a 12 bit sine wave:
int12.png

Numerically differentiating an 8 bit sine wave:
int8.png


xooorx

OK I tried various filters and some of them sort of worked a bit, but nothing worked as well as just doing the differentiation between non-adjacent samples e.g. instead of V = P[0] - P[-1], using V = (P[0] - P[-4])/4.

Cleans up the 8-bit version to this:
int6.png

Cleans up the 12-bit version to this:
int7.png

(Also note the plots in the previous post used a fancy 4-point differentiator:
V = (P[-2] - 8P[-1] + 8P[1] - P[2])/12
which is worse than:
V = P[0] - P[-1])


luns

Will write more when I’m at a computer instead of the phone, but for now, I wanted to point out the (p(0)-p(-4))/4 differentiation is really just the p(0)-p(-1) followed by a length-4 unit-area boxcar. The differentiation is inherently high pass, emphasizing noise where there’s not really any signal you would care about, but the boxcar does a passable job of filtering out much of that noise.

The best filter to use in place of the boxcar depends on what we know of the signal we’re trying to detect. For a pure sine wave, the ideal filter would be a narrow bandpass filter tuned to the frequency of the sine wave. For a hammer position which is the second integral of what can look like a spikey acceleration, I would go for some second order lowpass filter, or basically a simple biquad filter.

More later…


xooorx

luns Will write more when I’m at a computer instead of the phone, but for now, I wanted to point out the (p(0)-p(-4))/4 differentiation is really just the p(0)-p(-1) followed by a length-4 unit-area boxcar.

Aha... I tried various ways of filtering the position signal before differentiating but got better results by, effectively, differentiating the position and low-pass filtering the result. (Am no longer sure which way round @gzpiano was doing it).

luns The best filter to use in place of the boxcar depends on what we know of the signal we’re trying to detect.

For quantisation noise it might be that prevention is better than cure i.e. use higher bit converters. @gzpiano's posted data was quantised to 3-digit decimal but came from a system that will soon be doing 24 bits. OTOH my own plans currently involve a 12-bit converter so I need to work out if that's enough or if I need to switch it up.


RIP

JayKominek You'll have plenty of clock cycles for any integer algorithm you could want, but with only M0 cores, I'd expect single precision floating point algorithms to be prohibitive. I think something like an RC filter at 20kHz might be the limit.

Well, unless we prove it otherwise by a big success, the RP2040 is just a test platform for a different ADC, namely one with only 12 bits (less than 9 ENOB) and higher frequency (up to 500kHz), the exact opposite of what @gzpiano is doing (IIRC he uses 24 bits and 8kHz, but check his videos for an authoritative answer).

As such the cost of fully fledged floating point live data processing on the RP2040 is irrelevant. That said, I grew up writing primitive numerical algorithms on a 6502 using just individual bytes. And later watched in awe FRACT386 (later still renamed FRACTINT). If needs be, we can experiment with numerical algorithms with bytes again, so I'll feel younger 🙂 -- the main limitation if one needs speed is that it'd be easier to use fixed point position, but I am wondering why I'm even getting there besides nostalgia, since I just said we won't do that "in production"…

Sorry for the short detour, let's go back to the good discussion @xooorx and @luns are having.



CyberGene

vagfilm that is Alexey Schterbakov, I think we exchanged some messages in the past regarding Cybrid, he was very interested in recreating it. He also promoted me on the Pianoteq forum (not knowing that I am a persona non grata there 🤣). You can invite him here, he will be interested.


spanishbuddha

CyberGene ah, just doing my end of working day forums catch up, PW first 😜and I posted on his entry there with some links.


luns

Totally orthogonal to everything: how does one quote text in this forum? I'm used to having a button that quotes an entire post I'm replying to, which I can then trim down, but best I can figure here, it looks like I would need to manually cut/paste (and corrupt) what I'm quoting here. That feels like putting words into somebody else's mouth, even if the intent that it be their own words.

CyberGene RIP Thanks for the welcome, guys. I imagine I was too terse in trying to make a minor point that it may have come across wrong. I agree that it doesn't fundamentally matter where the sensors are and I have no objections to the sensor being in either location. There was a post I'd seen - likely in a different thread rather than here (things are a little jumbled while I'm still taking everything in) that seemed to emphasize some significance in the hammers moving 5x the speed of the key, and my only point was that it doesn't really matter. I'll just leave it there rather than beat a dead horse. 🙂


luns

xooorx 1) Let-off is set at 4mm (page 10). Possibly slightly wider than a pure acoustic action to accommodate the stop rail? To make the sensing easier?

I imagine this is entirely to allow room for the stop rail to stop the hammers before they hit the strings.

3) From the section on adjusting the sensor height (page 12):

For instances, if the sensor is located at an extremely high position, the position of emitting sound may be higher than the position where the hammer stops by the stop rail. In this state, no electronic sound will be emitted.
On the contrary, if the sensor is located too low, this may cause deterioration of the functionality in detecting consecutive key stroking.

So... "too high" = past the stop rail, "too low" = repetition stops working i.e. below the let-off, so it seems that "just right" is indeed limited to the few mm of hammer position between let-off and hammer strike.

I think too low would be going below check. The window of acceptable sensor position is the distance between striking the stop rail and the hammer's check height, minus the distance between the two sensors. The let-off height isn't inherently part of this. I could well be wrong, but my gut feeling is the lower shutter threshold is somewhere below let-off, but of course above check.


« Previous Page Next Page »