The Fugue

Counterpoint by Hans Fugal

Clojure DSP Longing

Posted by Hans Fugal Mon, 17 Nov 2008 17:46:00 GMT

I often find myself longing to be able to use Clojure, a very enticing lispy language that runs on the JVM.

I could possibly be using it right now in my dissertation research. It has the promise of dynamic languages, functional programming, almost-as-cool-as-Erlang concurrency, JVM performance, and Java library soup. It could be so awesome. A few months ago I started briefly down this road, unaware that…

Clojure sucks. Not generally, but it sucks for DSP. More specifically, Java and therefore Clojure has no real support for complex numbers. In order to do serious DSP, you need native syntactic, semantic, and performance support for complex numbers. Java has none of the above. Older versions of C didn't have syntactic or semantic support, but the performance of using arrays was plenty fast. Not so in Java, at least not to the extent necessary to override the lack of syntactic and semantic.

So someday, when I'm writing general purpose code again and not high performance DSP code, I will have an opportunity to use Clojure, and I think that will make me very happy. By then the book will be out of beta. The community will be in full swing. There will be awesome libraries. Children will play in pristine parks with formerly-ravenous ravens.

In the meantime, if anyone sees the scene change, do let me know.

no comments |

RTDX OLE API

Posted by Hans Fugal Fri, 05 May 2006 02:28:00 GMT

And now, ladies and gentlemen, I will answer the questions you have been dying to have answered! Right before your very eyes I will demystify The Texas Instruments TMS320C6416DSK RTDX OLE API!

Ok, so most of you don't care. I'm putting it on the web for posterity's sake, because it's dreadfully impossible to find. I'm no OLE expert and maybe everyone that wants to do OLE just uses some OLE browser built into Visual Studio or something, but I'm too lazy to install the copy of Visual Studio I won in a programming contest (hey, getting me to use Windows at all is a feat).

I wrote a nifty little ruby script to dump what I believe is probably the relevant info:

    require 'win32ole'
    rtdx = WIN32OLE.new('RTDX')
    rtdx.ole_methods.each do |m|
      print "#{m.return_type}\t#{m}("
      print m.params.collect{|p| 
        "#{p.ole_type} #{p}" +
        if p.default
          "=#{p.default}"
        else
          ""
         end
       }.join(", ")
      puts ")"
    end

And here is the result:

VOID  QueryInterface(GUID riid, VOID,VOID ppvObj)
UI4  AddRef()
UI4  Release()
VOID  GetTypeInfoCount(UINT pctinfo)
VOID  GetTypeInfo(UINT itinfo, UI4 lcid, VOID,VOID pptinfo)
VOID  GetIDsOfNames(GUID riid, I1,I1 rgszNames, UINT cNames, UI4 lcid, I4 rgdispid)
VOID  Invoke(I4 dispidMember, GUID riid, UI4 lcid, UI2 wFlags, DISPPARAMS pdispparams, VARIANT pvarResult, EXCEPINFO pexcepinfo, UINT puArgErr)
I4  Open(BSTR Channel_String, BSTR Read_Write)
I4  Close()
I4  Read(VARIANT pArr, I4 dataType, I4 numBytes)
I4  ReadI1(UI1 pData)
I4  ReadI2(I2 pData)
I4  ReadI4(I4 pData)
I4  ReadF4(R4 pData)
I4  ReadF8(R8 pData)
I4  ReadSAI1(VARIANT pArr)
I4  ReadSAI2(VARIANT pArr)
I4  ReadSAI4(VARIANT pArr)
I4  ReadSAF4(VARIANT pArr)
I4  ReadSAF8(VARIANT pArr)
VARIANT  ReadSAI2V(I4 pStatus)
VARIANT  ReadSAI4V(I4 pStatus)
I4  WriteI1(UI1 Data, I4 numBytes)
I4  WriteI2(I2 Data, I4 numBytes)
I4  WriteI4(I4 Data, I4 numBytes)
I4  WriteF4(R4 Data, I4 numBytes)
I4  WriteF8(R8 Data, I4 numBytes)
I4  Write(VARIANT Arr, I4 numBytes)
I4  Rewind()
I4  Flush()
I4  Seek(I4 MsgNum)
I4  SeekData(I4 numBytes)
I4  StatusOfWrite(I4 numBytes)
I4  GetNumMsgs(I4 pNum)
I4  GetChannelID(BSTR Channel_String, I4 chanId)
I4  GotoNextMsg()
I4  GetMsgID(I4 pMsgId)
I4  GetMsgNumber(I4 pMsgNum)
I4  GetMsgLength(I4 pLength)
I4  EnableRtdx()
I4  DisableRtdx()
I4  EnableChannel(BSTR ChannelName)
I4  DisableChannel(BSTR ChannelName)
I4  GetChannelStatus(BSTR ChannelName, I4 pChannelStatus)
I4  ConfigureRtdx(I2 Mode, I4 MainBufferSize, I4 NumOfMainBuffers)
I4  ConfigureLogFile(BSTR FileName, I4 FileSize, I2 FileFullMode, I2 FileOpenMode)
I4  GetRTDXRev(I4 RevNum)
I4  GetStatusString(BSTR StatusString)
I4  GetCapability(I4 Capability)
I4  RunDiagnostics(I2 TestType, I4 TestMode, I4 TestInfo)
BSTR  GetDiagFilePath(I2 TestType)
I4  SetProcessor(BSTR Board, BSTR Cpu)
HRESULT  GetTypeInfoCount(UINT pctinfo)
HRESULT  GetTypeInfo(UINT itinfo, UI4 lcid, VOID,VOID pptinfo)
HRESULT  GetIDsOfNames(GUID riid, I1,I1 rgszNames, UINT cNames, UI4 lcid, I4 rgdispid)
HRESULT  Invoke(I4 dispidMember, GUID riid, UI4 lcid, UI2 wFlags, DISPPARAMS pdispparams, VARIANT pvarResult, EXCEPINFO pexcepinfo, UINT puArgErr)

Posted in , , | no comments |

Convergent Rounding

Posted by Hans Fugal Fri, 07 Apr 2006 02:37:00 GMT

The rounding they taught you in elementary school has an eventual bias. i.e. over time you find that you've rounded up more often than you've rounded down. Bias is a bad thing, especially in DSP and other numerically-intensive computing.

Convergent rounding is one good way to eliminate this bias. It works the same as regular rounding except that instead of rounding 0.5 up, you round 0.5 to the nearest even number. So 1.5 goes to 2.0, 2.5 goes to 2.0, etc.

A quick tutorial on short fixed-point programming in C. The decimal point is between bits 15 and 14, and bit 15 is your sign bit. So, you have a range of 1-2^-15 to -1. So 0.5 is 0x4000, and -0.5 is 0xC000 (two's complement). Now, when you multiply two numbers together you get twice as many bits of precision, so multiplying two shorts gives you an int, and in that int the decimal point is between bits 30 and 29, and bits 30 and 31 are sign bits. We want to round at bit 15 so we can fit the result back into a short. Clear as mud?

The point of this post is to get this C code out there, because as simple as it seems it was a devil to debug:

int cround(int a)
{
    if (a & 0x3fff)
        a += 0x4000;              // normal rounding
    else
        a += (a>>1) & 0x4000;     // convergent rounding

    return a & 0xffff8000;
}

If you don't see why this works (I didn't when I first read the "add half of the lsb uf the upper part" algorithm), then fill out this truth table as an excercise:

0.00
0.01
0.10
0.11
1.00
1.01
1.10
1.11

Here's an example of the function in use:

short x,y;
int a;
x = 0x7ffd;     // x = almost 1
y = 0x4000;     // y = 1/2
a = x*y;        // a = 0x1fff4000
a = cround(a);  // a = 0x1fff0000
x = a>>15;      // x = 0x3ffe

Posted in , | no comments |