Recovering symmetric parameters from sum of sine waves

I have a setup where 2 sine waves (each parametrised by amplitude and frequency) are added together and I want to recover the original 4 parameters. Data is blue dots and red line is the ‘true’ function:

My model is as follows:

# True values
#freq1 = 20
#ampl1 = 2
#freq2 = 10
#ampl2 = 3

# Define priors
_noise = pm.HalfNormal("sigma", sigma=50)
_freq1 = pm.HalfNormal("freq1", sigma=10)
_ampl1 = pm.HalfNormal("ampl1", sigma=10)
_freq2 = pm.HalfNormal("freq2", sigma=10)
_ampl2 = pm.HalfNormal("ampl2", sigma=10)

# Define likelihood
temp = (
    (_ampl1 * pm.math.sin((2*np.pi/_freq1) * x)) + 
    (_ampl2 * pm.math.sin((2*np.pi/_freq2) * x))
likelihood = pm.Normal("liklihood", mu=temp, sigma=_noise, observed=y)

and it learns the overall function pretty well. Showing many reconstructed functions from the posterior parameter

However, if I look at the posterior distributions themselves the true values for both frequencies are showing up in both frequency parameter distributions:

Is there any way to get around this symmetry issue? Perhaps by specifying that freq1 is greater than freq2 as a constrain or is the only way to play with the priors so their support doesn’t overlap?

Right, you’re seeing multimodality because each sine wave could be the other one. And you’re right that the way to address it is doing something like imposing an ordering via priors. Take a look at the ordered transform, or you could define your priors on say the frequency something like:

freq1 = pm.SomePositiveDistribution("freq1", ...)
delta_freq = pm.SomePositiveDistribution("delta_freq", ...)
freq2 = pm.Deterministic("freq2", freq1 + delta_freq)

to get the same effect. Another way to do it would be with pm.Potential.

1 Like