2
$\begingroup$

Some introductory questions:

  • What is the unit of the group delay in a digital filter (is it samples?)
  • What is $\Omega$ in the equations below (is it $\Omega=2 \pi\frac{f}{f_{sample}} ?) $

If I got any of these wrong, then there is no point reading the rest of this question. Just correct me.

What I want to achieve

I am using a Karplus-Strong algorithm to simulate a steel string. I noticed, that I need to detune the harmonics to higher frequencies, so it really sounds like a steel string (see here). To achive this, I added an allpass to the delay in the feedback loop.

$$H(z) = \frac{a + z^{-1}}{1 + az^{-1}}$$

However the allpass adds an additional delay and detunes my string (lower). So I tried compensating for that additional delay by subtracting the group delay of the allpass from the main delay.

The result was: it still detunes, but in the opposite direction.

The allpass delay:

Matt L. gave me this formula for the group delay

$$\tau_g(\Omega) = \frac{1 - a^2}{1 + 2a \cos(\Omega) + a^2} $$

$$\Delta t = \frac{\tau_g}{f_{sample}}$$

But robert pointed out that it is the phase delay which determines the pitch and gave me this formula:

$$ \tau_\phi(\Omega) \ = \ \frac{1}{\Omega} \arctan\left(\frac{(1-a^2)\sin(\Omega)}{(1+a^2)\cos(\Omega) + 2a} \right) $$

But alas, when I subtract either of the two from the total delay in the feedback loop (i.e. the regular delay plus the allpass) it appears I am overcompensating. There is no problem with posive $a$ which leaves the fundamental undelayed, but for negative $a$ (e.g. $a=-0.93$) the string is about half a semitone too high.

Edit (1)

I had an error in the formulas which is fixed by now (thanks to Matt L.). Originally my string was tuned too low, after the fix it is too high.

Edit(2)

Meanwhile (thanks to Matt L. and robert) I have little doubt, that my calculations are basically correct. I ran my allpass through scilab and the group delay is reported as apx. 30 samples. With the formulas from Matt and Robert I get values around 31 samples. Hoever, to tune the string correctly (by ear) I must compensate for 24 samples only.

Interestingly Miguel Negrão who did some research on plucked steel strings wrote in his thesis: Generally a negative value of a would have been used, which would have delayed the lower frequencies more than the high frequencies (phase delay), and would require a re-tuning of the main delay in the string loop to keep the string at the same fundamental frequency. In the SupaStrings system case, after some listening tests, a positive value of a was used instead (non-physical) which keeps the low partials more a less in the same frequency but detunes the high partials down to a lower frequency.

It seems like he faced similar difficulties and couldn't solve them, even though he is quite a brilliant guy.

$\endgroup$
4
  • $\begingroup$ You are right about the first two questions: the group delay of a digital filter has the unit 'samples', and $\Omega$ is the normalized frequency in radians. I think one of your problems is that the group delay of the allpass filter is not constant but a function of frequency (as you can see from the formula). So you cannot compensate for it by a constant (negative) delay. And this is what I think you're trying to do, right? $\endgroup$
    – Matt L.
    Commented Jun 6, 2014 at 11:32
  • $\begingroup$ At the moment I am only playing a 110Hz note (A-string) and I only want to compensate the fundamental. $\endgroup$ Commented Jun 6, 2014 at 11:38
  • $\begingroup$ How do you choose the value of $a$? $\endgroup$
    – Matt L.
    Commented Jun 7, 2014 at 10:54
  • $\begingroup$ By ear. I went with a negative a because it is physically more correct. Values $0 > a > -0.9$ give very little inharmonic partials and it still sounds like a nylon string. Values $-0.90 > a > -0.94$ sound about right. Values $ a < -0.94$ result in a bell-like sound. $\endgroup$ Commented Jun 10, 2014 at 6:19

2 Answers 2

4
$\begingroup$

For the Karplus-Strong algorithm, your primary concern is for phase delay, $$ \tau_\phi(\omega) \ = \ - \frac{\phi(\omega)}{\omega} $$

rather than group delay. $$ \tau_g(\omega) \ = \ - \frac{d \phi(\omega)}{d \omega} $$

where $$ \phi(\omega) \ \triangleq \ \arg \left\{ H(e^{j \omega}) \right\} $$ and $H(z)$ is the transfer function of your filter, and $$ H(e^{i \omega}) \ = \ \left| H(e^{j \omega}) \right| e^{j \phi(\omega)} $$

For phase delay, it is important to unwrap the phase, which is not necessary for 1st-order APFs.

This is because, for a sinusoid, it's the phase delay that is the actual delay, in units of time, that the filter delays a simple sinusoid. The group delay is the amount the envelope of the sinusoid is delayed.

For linear-phase filters, $\tau_\phi(\omega)=\tau_g(\omega)$ for all $\omega$ and for any filter $\tau_\phi(0)=\tau_g(0)$. Phase delay and group delay are not generally the same value in other circumstances.

Now for the 1st-order APF with its pole at $p$: $$ H(z) \ = \ \frac{1-pz}{z-p}$$ the phase delay in sample units is $$ \tau_\phi(\omega) \ = \ \frac{1}{\omega} \arctan\left(\frac{(1-p^2)\sin(\omega)}{(1+p^2)\cos(\omega) - 2p} \right) $$ and the group delay in sample units is (same expression MattL gets) $$ \tau_g(\omega) \ = \ \frac{1-p^2}{1+p^2 - 2p\cos(\omega)} $$

the delay (phase or group) at DC is $\tau_\phi(0) = \tau_g(0) = \frac{1+p}{1-p}$ and we normally have $-1 \le p \le 0$ to get a delay of between 0 and 1 sample.

Now, in the Karplus-Strong algorithm, the frequency of every harmonic (perhaps better called a "partial"), including the 1st harmonic (which we'll call the "fundamental") is the reciprocal of the total loop delay (phase delay) at the frequency of that partial. That is a circular mathematical relationship. For the $k$th partial (and assuming normalized sampling frequency $f_s=1$): $$ f_k \ = \ \frac{k}{n + \tau_\phi(2 \pi f_k)} $$ where $n$ are the integer number of samples in the delay line that is in series with the APF. Given your fundamental frequency $f_1$, the value of $n$ is $$ n \ = \ \left\lfloor \frac{1}{f_1} \right\rfloor \ = \ \mbox{floor}\left(\frac{1}{f_1}\right) $$ (Be sure to add 1 sample that is necessary in a digital filter with feedback.)

Now, often we approximate using the DC delay, but to design this exactly, you need to somehow solve that frequency-dependent phase delay at the frequency of each partial. That's a bitch. So you would need to solve $$ \frac{k}{f_k} \ = \ n + \tau_\phi(2 \pi f_k) \ = \ n + \frac{1}{2 \pi f_k} \arctan\left(\frac{(1-p^2)\sin(2 \pi f_k)}{(1+p^2)\cos(2 \pi f_k) - 2p} \right) $$ for $f_k$ given every integer $k$.

$\endgroup$
8
  • $\begingroup$ (1) I don't quite understand why you talk about partials. I only want my fundamental to have the correct pitch. The partials are deliberately detuned. (2) Confusing group delay with phase delay would certainly explain my problems. I tried the DC formula, but it overcompensates (my pole is at 0.94), and the pitch is higher than with p=0.5. $\tau_\Phi$ is around 32. Still haven't tried the exact formula. Is there any fomula between the DC and the exact formula ("for low frequencies") $\endgroup$ Commented Jun 8, 2014 at 22:05
  • $\begingroup$ I tried the exact formula. The difference to the DC formula is one sample at most. Both overcompensate (my pole is at 0.94) (positive!) $\tau_\Phi$ is around 32. The pitch with P=0.94 is higher than with e.g. p=0.5 or with negative p. Without the compensation is (much) lower. $\endgroup$ Commented Jun 8, 2014 at 22:25
  • $\begingroup$ how are you deliberately detuning the partials? using an all-pass filter? to get the exact pitch of the fundamental, assuming you don't have any other filter in the loop besides the delay line and the little 1st-order APF, then you have to solve the last equation for $k=1$ to get $f_1$. $\endgroup$ Commented Jun 9, 2014 at 3:05
  • $\begingroup$ are you using an APF with more than 1 sample in its internal delay? $\endgroup$ Commented Jun 9, 2014 at 3:45
  • $\begingroup$ I am using a frequency-independant ("flat") delay in series with an allpass. The allpass has has a negative a (positive p) and delays the low frequencies more than the high frequencies. This moves the partials further apart. Very high partials have the correct pitch (I believe) but my fundamental's frequency gets too low. Thus I need to reduce the delay of the flat delay ("compensate") to get the fundamental right while the partials will end up too high. This would be the desired outcome. The allpass is a regular $1^{st}$ order allpass with a one-sample-delay. $\endgroup$ Commented Jun 9, 2014 at 10:40
3
$\begingroup$

As I mentioned in my comment, you're right that the unit of group delay of a discrete-time system is samples. And $\Omega$ is indeed the normalized frequency in radians.

The problem is that your final formula for the group delay of a first-order allpass filter is wrong (I didn't check the original formula). If you have an allpass system

$$H(z)=\frac{a+z^{-1}}{1+az^{-1}}$$

then its group delay is given by

$$\tau(\Omega)=\frac{1-a^2}{1+2a\cos\Omega +a^2}\tag{1}$$

Try what you did using formula (1). I'm curious to see if this solves your problem.

$\endgroup$
1
  • $\begingroup$ Thanks for that formula. There was an error in my transformations of the formulae (fixed now). But now my string gets too high. $\endgroup$ Commented Jun 6, 2014 at 14:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.