Once I changed your table definition for the Grade column from VARCHAR to NUMERIC(10,2), this works for me:
WITH cte AS
(
SELECT CourseDate, PersonID, Grade,
ROW_NUMBER() OVER(PARTITION BY CourseDate ORDER BY Grade) AS RowNum,
COUNT(*) OVER(PARTITION BY CourseDate) As cnt
FROM estats
)
SELECT CourseDate, AVG(Grade) AS Median
FROM cte
WHERE RowNum IN((Cnt + 1) / 2, (Cnt + 2) / 2)
GROUP BY CourseDate
ORDER BY CourseDate;
It returns medians of 90, 76, and 90.5 for CourseDates of 2010-03-01, 2011-03-02, and 2012-03-01, respectively.
I'm not sure why you would define the Grade column to be VARCHAR() when all your data are numerics. I haven't looked into this more, but it may be that this is a source of error. I suspect that you're getting an implicit conversion from VARCHAR() to INT, which leads to loss of necessary accuracy when the final AVG() function is called.
Rich