I know you have already solved it, but here's my take on it:
(uses Rojo's Canvas plugin)
The solution of the first layout distorts a sine wave, offsetting each X proportionally to an interpolated linear function that goes from 0 on the edges to 1 at the center. The interpolation power can be controlled by the bottom slider. It can easily be transformed into a single function but it would get long and hard to read. It also gives a seamless tilling.
In the second layout I tested just interpolating a "sine wave skeleton" to see if it could work. It doesn't tile so well when distorted, but it's interesting that you can adjust the interpolation on the fly to go from a triangle wave to a rounded square, passing through a sine. The downfall is that with too much center offset it kinda breaks the smaller spike, but maybe if a damping is added to not allow the smaller spike to approximate too much from the edge it could give better results. It also uses conditionals to generate the base skeleton, so it's not easily transformed into a single function, but it could be done.
*Just to clarify that I was lazy and the graph is upside down, with top-left being (0,0) and bottom right (1,1).