MATLAB Techniques: Self-identifying (by type) methods

We all know MATLAB by default fill numbers with 0 if we haven’t specified them (such as expanding a matrix by injecting values beyond the original matrix size). Cells are default filled with {[]} even if you meant to have cellstr() {”} across the board. Sometimes it’s not what we want. 0 can be legitimate value, so we want NaN to denote undefined values. Same as cellstr(), we don’t want to choke the default string processing programs because one stupid {[]} turns the entire cell array into to a non-cellstr array.

For compatibility reasons (and it’s also hard to do so), it’s not a good idea to simply modify the factory behavior. I have something similar to table() objects that requires similar expansion on arbitrary data types, but MATLAB’s defaults proves to be clumsy.

Instead of writing swtich()-case() statements or a bunch of if() statements that relies on type information like this:

function x = makeUndefined(x)
  switch class(x)
    case {'double', 'single'}
      x = NaN(size(x));
    case 'cell'
      if( iscellstr(x) )
        x = repmat({''}, size(x));
      end
    % ...
  end

I found a slick way to do it so I don’t have to keep track of it again if I need the same defaults in other places: take advantage of the fact that MATLAB selectively will load the right method depending on the first input argument(s)*:

Create a commonly named method (e.g. makeUndefined()) for the PODs and put it under the POD’s @folder (e.g. /@double/makeUndefined.m, /@cell/makeUndefined.m). The functions look something like this:

function y = makeUndefined(x)
% This function must be put under /@double
  y = NaN(size(x));
function x = makeUndefined(x)
% This function must be put under /@cell
  if( iscellstr(x) )
    x = repmat({''}, size(x));
  end

Similarly, you can make your isundefined() implementation for @double, @cell, etc, just like the factory-shipped @categorical/isundefined() corresponding to the same rules you set for makeUndefined().

Actually, the switch-case approach is analogous to the common abuses of RTTI in C++: every time a new type is added, you have to open all the methods that depends on the type info and update them, instead of having the classes implement those methods (with proper object hierarchy and overloading).

MATLAB does not have proper polymorphism, but can call the right method based on the first argument (or the latter ones if they have a proper dominance relationship: mind you that most PODs don’t), but this approach is as close as it can get to proper OO design despite we are just talking about PODs here.


* This is tricky business. MATLAB doesn’t have polymorphism, but will look into the FIRST dominant input argument and load the appropriate classes. Usually it’s the first argument, but for non-POD classes, you can specify the dominance relationship (Inferior classes). Actually little has been said about such relationship in PODs in the official documentation.

I called support and found that there’s no dominance relationship in PODs, so it’s pretty much the first argument. That means this trick does not work if you want to overload bsxfun() for say, nominal() objects (which doesn’t have a bsxfun() implementation) keeping the same input argument order because the first argument is a function handle for both the factory and the user method. Bummer!

This is why the new ‘*_fun’ functions I write, I always put the object to operate on as the first argument whenever possible. Gets a little bit ugly when I want to support multiple inputs like cellfun(), so I have to weight whether it’s worth the confusion for the overloading capability.

 

271 total views, 0 views today

Quote of the day: You can’t learn too much linear algebra

Benedict Gross, Professor of Mathematics at Harvard said in his E-222 lecture: ‘You can’t learn too much linear algebra’.

If you read my WordPress pages in Signals and Systems, I’m trying a new approach to explain the materials done under the classical approach in a much more compact way using basic ideas in linear algebra.

Linear algebra is fun and easy to learn (at intro levels), once you get used to the fact that it’s a carefully picked set of restrictions that most physical problems boils down to. In high school algebra, it’s disguised as ‘method of detached coefficients’ when you solve systems of simultaneous equations.

Once you model your problem into linear equations (the hardest part), you will see the equivalence (or mathematically equivalent analogs) of different problems ranging from economics to circuits and mechanics. The beauty of the ‘detached coefficients’ approach separates the context of the problem from its mathematical structure as the application specific variables are often grouped as a vector (or matrix) that you deal with as a unit. In fact, most problem boils down to this:

    \[ \bf{Ax = b} \]

It’s your job to construct \bf{A}, \bf{x} and \bf{b} and tell people what they mean.

I agree with Gilbert Strang, Professor of Mathematics at MIT that it’s time to make linear algebra the standard curriculum over calculus. Digital control used to be a very advanced graduate class, but after a few decades, it’s undergraduate material. Linear algebra has very few knowledge dependencies (hard pre-requisites), so it’s great material to teach at any level.

1,365 total views, 0 views today

Agilent Infiniium (Motorola VP22) Motherboard USB Pinouts for DOM SSD

The Motorola VP22 motherboard used in a variety of modern Agilent’s Infiniium series oscilloscope (the ones with Megazoom) and logic analyzers has a 5-pin USB port that’s not quite the same as the standard headers on most motherboards.

The reason I needed the pinouts of the USB port is because I have a 40-pin DOM SSD to replace the old clunky mechanical hard drive, which needs 5V for power.

I don’t want to modify/resolder the original wire harness (for the LS-120 and CD-ROM drive) nor I have the molex connectors to make a power splitter. Luckily, I found somewhere that I can safely tap a 5V for low power devices: the internal USB header. Here’s a picture with the DOM SSD module wired:

VP22 USB Power Tap

This post serves as a reminder to myself that the ground is the second pin to the left and 5V is the rightmost pin. The pinout diagram as follow:

306 total views, no views today

(Front-end) Attenuator Autopsy of HP 54616B Digital Oscilloscope

One day I got a call from a friend saying that he accidentally fed high voltage signal (line voltage) and broke one of the channels.

My hunch is that since he didn’t feed kilo-volts into it, the damage is limited to the (front-end) attenuator (an expensive part). I had an extra unit lying around so I just swapped it for him so he can get it up and running.

Once I got the time, I opened it up the broken unit to see the damage. My hunch was correct:

Fried 1NB7-8303 54616B Attenuator Block

The 500Mhz attenuator used in 54616B, 54615B, 54520A, 54540A, 54503A and early Infiniiums 54810A, etc. are all the same: 1NB7-8303. The resistive trace was blown open circuit (charred), so bad that it spot welded the metal casing.

I took a good attenuator and measured resistance that the blown open ‘trace’ should have been. Turns out it’s a little less than 1Ohm so I used 4-lead Kelvin sensing from my Agilent 34401A multimeter. I calibrated that meter using my Data Precision 8200 reference and agreed with my Fluke DMM, so hopefully I wasn’t way off.

I could have put a small SMD resistor matching the resistance of the blown trace, but since I have a few back up attenuators lying around, I’d rather not risk the signal integrity by doing so, since I cannot guarantee the temperature specification if I just replaced it with a resistor. The scope was up and running in perfect condition after replacing the attenuator.

Now you know what happens when you feed line voltage to a scope. The damage is usually limited, but the front-end (attenuator) is the most expensive RF part that makes a scope truly a scope (see Dave’s rant on EEVblog). The ADC hybrid can get just as expensive, but usually the attenuator takes the hit before your input gets to fry the ADC.

767 total views, no views today

Agilent 54641D (Mixed Signal) 54642A (Digital) Oscilloscope Fan Mod

Agilent 54641D has a ADC hybrid (1NB7-8394) converter that runs very hot. The heatsink does a very good job extracting the heat from the chip, but there’s nothing to carry the heat away from the heatsink. The heatsink is actually hand-burning hot when passively cooled. Even with the case, the bottom of the unit gets so hot that it actually warms up the instrument below it.

For longetivity, I decided to give it a tiny fan. But given the tight space at the bottom, how can I squeeze a standard 5mm fan? A squirrel cage fan might do the trick, but where am I supposed to secure it? Turns out there’s a screw hole for the fan and there’s only one place I can screw it down:

Fan for 54642D's ADC

I padded the fan with 3 plastic washers to create a surface level with the two ASIC chips the fan is sitting on.

Where should I get the power for the fan? It’s not a low-end 100Mhz scope, so I took extra precaution to not have a DC power line flying all over the circuit board to generate noise. I twisted the power wires together just to lower the EMI and follow the same holes Agilent designed to let the power cable go through.

It’s a little risky to steal power from the circuit board directly when I don’t have the schematics, but luckily I found a printer power port which nowadays nobody uses which I can steal the power from.

I could have tapped the 12V fan power from the power module for the power supply fan, but I noticed the printer power port is even better: it’s around 7~9V:  I don’t want the noise from running it at full speed (squirrel cage fan are typically noisier).

54642D Printer Power

 

Finally I made an internal terminal for the printer power so the fan can be easily detached. Weakly wrapped it in a clear heat shrink tube so it won’t get accidentally disconnected yet reminds myself that a connector was built instead of directly soldered on.

At last I tie-wrapped the power wire to the other power wires Agilent already secured so they won’t dangle during transportation.

54642D Tie-wrapped

Self-calibration expects the temperature to be stable, so the oscilloscope needs to be warmed up before a cal would register. That means before the fan, it’d take a long while for the ADC to heat up to a guaranteed temperature.

With the new fan, the calibration needs to be done again because it’s much cooler now. Even better, it takes nearly no time to warm the oscilloscope up for calibration because the steady temperature isn’t high anymore.

Of course this mod works for 54641A, 54641D, 54642A, 54642D as well. Technically you can put it in any 5462X oscilloscope, but since they are 100Mhz, you don’t need to cool the ADC down that much.


I recently tried it on a 54642A, which doesn’t has only one stream instead of two, so one chip with glued heatsink and one ASIC (1821-5733) is gone. Looks like I can use the screw hole on the top left (the one with a red condom over it). Unfortunately, since the only way to use that screw hole is to flip the fan over, it became an inferior choice because

  • The suction part came from the bottom of the case instead of the board. That means I’m blocking ventilation for some components.
  • The fan’s power line is now close to the board, creating potential signal integrity issues (might not be material, but why mess with EMI issues when there’s no real advantage anyway?)

In other words, even if it looks tempting to deviate from the solution above, there’s no good reason doing so.


Now that I have a seek thermal camera module, here’s the thermal picture after the fan compared to the board:

You can see from the picture how effective the heatsink is. It took only a very weak breeze to carry the majority of the heat away. The 12V squirrel cage fan running at ~7V is pretty quiet, and I don’t feel the wind speed coming from the fan, yet it cool the ADC hybrid down to near room temperature.


The real reason why I did this fan mod is because I had some units (like 54641A) bought from the used market that after powering it up for 30 minutes, the signal displayed just went nuts and jumped all over the place. I opened up the ADC and the metal bracket holding it down had a lot of heat stress pattern on it (the golden bracket looked purple-rainbowish). The unit was fixed after swapping the ADC hybrid from a donor unit, but now I know the ADC hybrid really needs to be kept cold to ensure longevity.

By the way, if you need a replacement ADC hybrid (1NB7-8394), I have 2 pcs at $660/ea.

First come first served. Call me at 650-804-5024 if you suspect it’s the ADC hybrid that needs to be replaced.

435 total views, no views today

MATLAB Techniques: Resuming loops in a script

If you have a time-consuming for-loop in a script and you want to terminate it for some reason (like checking partial results, debugging, etc) but you don’t want to start over again. What would you do if you want minimal typing each time you stop?

Here’s how I do it:

if( exist('k', 'var') ) k0=k; else k0=1; end
for k=k0:1000
  % Your code here
end

If you want to restart the loop, simply enter k=1 in the command prompt and you’re good to go. Otherwise it will pick up where you left off.

213 total views, 0 views today

MATLAB Fundamentals: Vectorization

A coworker whose background is in embedded systems (with a C background and no MATLAB at all), after hearing my rants that people are coding MATLAB like C using way more for-loops than necessary, asked me if he has two vectors,

a = 0:32767;
b = 0:32767;

and he want all combinations of the elements in a and b so that for each index pair (i, j), he will get

    \[ 167\left(\frac{a_j+42}{b_j+17} \right)\]

There are 32768^2 combinations out there. At first, I showed him the typical method shown in the MATLAB’s introduction materials:

% Should have used ndgrid() for a more natural (column first) layout
[B, A] = meshgrid(a, b);

C = 167*(A+42)./(B+17)

Then he asked, ‘This way I have to store the matrices A and B. Wouldn’t it be memory intensive? Is there a better way to do it like with functional programming?’ Now I have to show him a more advanced trick that requires some mental leaps (the ones necessary to get sophisticated at the MATLAB language):

C = 167*bsxfun(@rdivide, a'+42, b+17)

This one liner does not save intermediate input values, so it’s memory efficient as well.

bsxfun() is a function that takes two inputs (we call it a binary function) which any of them can be a matrix, vector or scalar. It will conceptually expand the dimensions so the function handle (e.g. @rdivide) get to apply to all combinations as if the inputs are expanded (repeated) to the longer of each dimension supplied. I bet under the hood it’s just a pair of for-loops with the loop increments managed so it doesn’t waste memory storing the intermediaries.

In the example above, I have a column a^T+42 and a row b+17. The output C is arranged as if a^T+42 is copied right to meet the length of b+17, and b+17 is copied down to meet the length of a^T+42.

This involves two major concepts one needs to program the MATLAB way : vectorization and anonymous functions. Not something you’d tell a day-zero beginner (probably scare them off), but showing them a Ninja trick after they understand the beginner’s method might motivate them to learn the true power of MATLAB.

214 total views, 0 views today

Structuring your MATLAB code base

When your MATLAB project gets large, or when you have a lot of projects, it’s time to consider restructuring your code and libraries so you can focus on what matters the most instead of plowing through the mess you just created.

For my projects, I usually create a file called ‘managedPathAndFiles_{myProjectName}.m’ at the top-level folder. The comments in the demo code below highlight the techniques used:

function [file, folder] = managedPathAndFile_myProject(isRegenerated)
% isRegenerated: set to 'false' to skip addpath() (which is slow)

 % Optional default input arguments by name instead of couting nargin
 if( ~exist('isRegenerated', 'var') )
   isRegenerated = true;
 end

 % Note the use of nested structures (like replacing _ with .)
 % You can use the hierarchy to group folders/files in a way you can 
 % operate on them in one-shot

 % Use the location of this file as anchor 
 % 'pwd' is unreliable because you can call this from other folders if
 % it's in MATLAB's path
 folder.root = fileparts( mfilename('fullpath') );
 
 % Include your project specific subroutines in the MATLAB path
 % Use fullfile() to generate platform independent folder structures
 folder.core.root = fullfile(folder.root, 'core');
 folder.core.helper = fullfile(folder.core.root, 'helper'); 
 % Add all the paths under the folder in one shot
 if( isRegenerated )
   % '-end' avoids name conflict by yielding to the incumbent paths 
   addpath( genpath(folder.core.root), '-end' );
 end
 
 % Automatically create data storage folder
 folder.data.root = fullfile(folder.root, 'data');
 folder.data.cache = fullfile(folder.data.cache, 'data');
 if( isRegenerated )
   % Outputting something will absorb the error if the path alreayd
   % exist. I made a mkdir_silent() in my libraries, but used the
   % native call here for demo.
   [~, ~] = structfun(@mkdir, folder.data);
 end
 
 % Sometimes you might have config or external files to load
 file.data.statistics = fullfile(folder.data.root, 'statistics.mat');
 
end

Many people don’t know about the function genpath() so they ended up lumping all their dependencies in one folder which makes my eyes bleed. Organize your files into a tree that makes sense now!

I’d recommend any serious MATLAB developer build their own library folder with a consistent naming and a sensible tree hierarchy. After looking into FEX and what’s natively available in MATLAB and you still need to roll out your own code, you’re likely to rediscover what you’ve already built just by establishing a new .m file/function you are about to write in the folder you’d most naturally put it in (like people with like mind: self, tend to pick the same names).

Sometimes you have to whip up some ‘crappy’ code that doesn’t generalize (or can be reused) in other contexts. Consider putting them in a /private folder under the caller so it won’t be visible to everybody else. Of course, I encourage people spend a little more time to write the code properly so it can be put in your own MATLAB library.

254 total views, 0 views today

How I learned MATLAB inside out

Back when I was in struggling graduate student working 3 university jobs to stay afloat, one of the job was to build a multi-center data collection system that take cares of remote data upload, store it in a database and visualize the waveforms and records.

I surveyed other platforms and languages for a couple of months and finally settled on MATLAB because at the time MATLAB had the most convenient data types (cells), data loading/saving (‘.mat’ files so I don’t have to manage the datatypes/format), external interfaces, and most importantly MATLAB FileExchange (FEX) pretty much cover every generic idea I can think of. With MATLAB, my work is pretty much down to coding the high level ‘business’ logic.

And no, I wasn’t biased towards MATLAB at the time because I have a signal processing background. I didn’t know much about MATLAB’s programming support back then other than number crunching (just like the 90% of the public who misundestood the power of the language), so I wouldn’t choose it for a software project at that level of complexity without much research.

Learning the guts of MATLAB, architecturing and coding the entire system took me only 3 months (well, it included a 1 month non-stop 16 hours a day, 7-days a week shut-in programming). Not a shabby platform for a project that is supposed to take 4 years. In fact, the rest of the time was spent

  1. reading the last owners *#@&ed up perl code and fighting to get the fragile linux setup to work on other machines, then reverse the entire project requirements from the source code because there wasn’t any documentation and the previous owners graduated.
  2. reconstruct Guidant’s half-finished (done by a 3rd party then abandoned) binary data reader by finishing the hardest part of the incomplete XSLT code.

The rest that has to do with MATLAB was relatively easy once I learned the main ideas through their documentation, newsgroups, Loren’s blog and the official support.

To understand and appreciate the beauty of MATLAB and use it effectively, you have to get past the following hurdles:

  1. Basic data structures: cell, struct and language features.
  2. Vectorization: use for-loops only in limited cases
  3. Anonymous function (Lambdas), cellfun(), arrayfun(), bsxfun(), structfun()
  4. Overloading and OOP
  5. Tables (Heterogeneous data structures) and Categorical objects (Nominal, Ordinal)

or else you are coding it like a C programmer: a complete waste of MATLAB’s license fees. If you know these 5 aspects of MATLAB well and would say there are strictly superior options out there, please let me know in the comments section and I’ll look into it.

 

296 total views, 0 views today