How to use stanvar() to specify a circular phase parameter in a non-linear brms model

I want to create a model with a periodic component, and the phase parameter is tricky. If I declare it as a standard parameter for a non-linear model, for example with using only prior(uniform(-3.14159265359,3.14159265359),lb=-3.14159265359,ub=3.14159265359,nlpar="c") I get convergence problems due to the circularity.

To solve this, I want to use the unit_vector type from stan and add it using stanvar(), but can’t get it to work. Here is what I tried :

prior1 <- prior(normal(0,5),nlpar="a")+
          prior(normal(0,5),nlpar="b")+
          prior(uniform(-3.14159265359,3.14159265359),lb=-3.14159265359,ub=3.14159265359,nlpar="c")+
          prior(normal(0,20),nlpar="d")

stanvars <- stanvar(scode = "unit_vector[2] v;",block = "parameters")  + 
            stanvar(scode = "real<lower = -pi(), upper = pi()> c = atan2(v[2], v[1]);",
                    block = "tparameters",name="c")

fitRTh <-brm(bf( rt~ b * sin(h + c )+ d,
                 b~1+(1|id),c~1,d~1+(1|id),
                 nl=TRUE,family=shifted_lognormal()),
             data = t, prior=prior1, iter=2000, cores=4, stanvars=stanvars)

If I do this my stanvar parameter c is not used by the model, which I can verify using make_stancode. If I omit c~1 from the bf() argument list I get an error and so do I if I remove c from the priors. Is there any solution to this befor fully writing the model in stan ?

You can’t build a linear predictor (c ~ 1) for a transformed parameter. I suspect that the fastest route to giving what you want a try would be to use brms to write stan code and stan data for the model with no phase shift at all, and then add the phase shift back in by hand. Alternatively, you could write a custom family with two auxiliary unconstrained distributional parameters (both predicted with ~1), from which you first apply the constraining transforms to get your ordered vector, then apply your atan2 transform to get c, and then take sin(h + c) inside the custom likelihood. Everything (applying the constraining transform, taking the arctangent, and taking the sin) would have to happen inside the custom likelihood computation.