top of page

Spherical caps with kaiser window smooths out the spherical spectrum edges, yielding better suppression of sidelobes and linear distribution than with block window (see the plots below). For more discussion see Kronlachner's master thesis  : Spatial Transformations for the Alteration of Ambisonic Recordings (3.3 Directional Loudness Modifications). This can be used to focus specific region of the sound field and can be useful for scenario such as reducing room reflection of the recording space.  Note that the focus region is front center in the example. To direct the region to arbitrary point,  rotate/tumble/tilt the point to front center using HoaRTT.

 

(with the help of Joseph Anderson, thank you Jo!)


//choose order
~order = 3
~order = 5

// 1)  rotate to +Z
(
~rotToZMatrix = HoaMatrixXformer.newRotateAxis(\y, 0.5pi, ~order).matrix;
~rotToZMatrix.shape //hoa3 -[16, 16]
)

// 2) rotate & decode to spherical design
(
~numPoints = 240;// max size t-design
~design = TDesign.newHoa(~numPoints, optimize: \spreadE, order: ~order);
~beamShape = \basic;  //this yields better result, trust me or run the test on your own!
// ~beamShape = \energy;  //energy beamShape
// ~beamShape = \controlled; //control beamShape

~decSphDesMatrix = HoaMatrixDecoder.newSphericalDesign(~design, ~beamShape,  ~order).matrix;
// update / reuse ~decSphDesMatrix
~decSphDesMatrix =  (~decSphDesMatrix.mulMatrix(~rotToZMatrix))
)


// 3) weight the spherical design

// kaiser ============> best with /basic
(
~window = \kaiser;
~size = 180;
//try different a value 
// ~a = 2.5;
~a = 5;
// ~a = 10;
// ~a = 20;
// ~a = 50;

~table = Signal.kaiserWindow(~size * 2, a: ~a).keep(~size).as(Array);// we actually want the 1/2 window!!
// ~table.plot(("a = %").format(~a)); //to see the kaiser window plot
~weights = ~design.directions.flop.last.raddeg.round.asInteger.collect({ |index| ~table[index + 90] })
)

// make weight matrix
(
~weightMatrix = Matrix.newDiagonal(~weights); 

// weight the decoding matrix
~sphrCapMatrix = ~weightMatrix.mulMatrix(~decSphDesMatrix) 
)

// 4) re-encode to hoa___________________________
(
~reEncMatrix = HoaMatrixEncoder.newSphericalDesign(~design, ~beamShape, ~order).matrix;
~sphrCapReEncMatrix = ~reEncMatrix.mulMatrix(~sphrCapMatrix); 
)

// 5) rotate from +Z___________________________
(
~rotFromZMatrix = HoaMatrixXformer.newRotateAxis(\y, 0.5pi.neg, ~order).matrix;
~sphrCapMatrix = ~rotFromZMatrix.mulMatrix(~sphrCapReEncMatrix);  
)

// 6) make xformer___________________________
~sphrCapXformer = HoaMatrixXformer.newFromMatrix(~sphrCapMatrix, ~order)

// test...
(
~numTestDirs = 360;
~testDirs = (Array.series(~numTestDirs) - 180).neg.degrad;
~analysis = ~sphrCapXformer.analyzeDirections(~testDirs);
~analysis[\amp].abs.ampdb.plot("amp: % window, a = %, beamShape: %".format(~window, ~a, ~beamShape), maxval: 10, minval: -60); 
~analysis[\rE][\directions].flop.first.raddeg.plot("directions: % window, a = %,  beamShape: %".format(~window, ~a, ~beamShape));//kaiser & tukey
)

Screen Shot 2022-07-18 at 10.31.05 AM.png
Screen Shot 2022-07-18 at 10.44.26 AM.png
bottom of page