Framerate is calculated by taking the duration of one or more past frames, averaging them, and dividing one second by the result to get the number of frames that would be drawn in a second assuming each would take as long as the average.
avgTimeMS = (totalTimeMS / numFrames)
fps = 1000 / avgTimeMS
This would yield the average number of frames per second over the last $numFrames frames. If $numFrames is 1, you get the effective frame rate of the last frame. If $numFrames is 60, you'll get the averaged frame rate over the last 60 frames (about 1 second at 60fps).
Assume we happen to have a steady framerate of 16.666ms per frame, and that we're averaging the last 10 frames, the last of which has now doubled (2 * 16.666) since we missed a vsync. We would have:
totalTimeMS = (9 * 16.666) + (1 * 33.333)
numFrames = 10
fps = 54.54
Now assume our numFrames is 1, and we skip a frame:
totalTimeMS = 1 * 33.33;
numFrames = 1
fps = 30
Your figures, then, are correct only when $numFrames is 1, since 30 is half of 60 (which I'm assuming matches vsync.)
So the perceived drop in frame rate due to one long frame is directly related to the number of frames you take in your average. When you skip a frame, you're increasing $totalTimeMS and not increasing $numFrames.