Designing Butterworth filter
Figured out how to correctly change from the zero-poles coefficients to the numerator/denominator coefficients.

Essentially this simply requires a convolution of the negative of each value with 1 being added as the first value in the results vector.

The implementation of this for the application of convolution in the instance of filter design is:

var result = new List&lt;Complex&gt;
{
    1
};

for (var i = 0; i &lt; roots.Length; i++)
{
    var value = -roots[i];
    result.Add(result[result.Count - 1] * value);
    for (var j = result.Count - 2; j &gt;= 1; j--)
    {
        result[j] = result[j] + value * result[j - 1];
    }
 }


To visualise this we start with the roots as being:
[0.954697396423354, 0.8855894564017569, 0.86046511627906985, 0.8855894564017569, 0.954697396423354]

Before iteration:

result = [1]


First iteration:

result = [1, -0.9546974]
result[length-1] = 1 * -0.954697396423354


Second iteration:

result = [1, -1.84028685  0.84546995]
result[length-1] = -0.9546974  * -0.8855894564017569
result[length-2] = -0.9546974 + -0.8855894564017569 * 1


Third iteration:

result = [1, -2.70075197  2.42897259 -0.7274974]
result[length-1] = 0.84546995 * 0.86046511627906985
result[length-2] = 0.84546995 + 0.86046511627906985 * -1.84028685
result[length-3] = -1.84028685 + 0.86046511627906985 * 1


And so continues until you reach the end of the input vector.

The main thing to note is that the initial value (1) must never change in the result vector so it is required in the inner loop to make sure you skip the last value, as you've just calculated and added it, and also the first value.