You can't compare your code to a Welch estimate. A Welch estimate does not simply use a window. A Welch estimate breaks up the data into (usually overlapped) windowed segments, estimates the PSD for each segment, and then averages those segments together.
The Welch estimate greatly reduces the variance of the PSD estimate (by increasing the degrees of freedom) compared to the periodogram (or modified periodogram). Your code using fft() essentially produces a periodogram.
To get a smooth PSD you have a few choices:
1.) Compute a parametric PSD using pburg() for example. These estimates are very smooth, however (big however), you have to specify a model for the PSD and it is very sensitive to model misspecification.
2.) Use pwelch() or pmtm() -- these are nonparametric methods that estimate the PSD. They smooth the PSD estimate in fundamentally different ways, but I think you can use either. I prefer pmtm() but pwelch() is also good.
I would recommend option #2