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 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 my original solution for the non-MSOs, there’s no good reason doing so.


Now that I have a seek thermal camera module, here’s the thermal picture after the fan has been installed (accompanied with the picture of the board):

You can see from the thermal 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, yet it cools 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 cool 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. The fan mod is complimentary with any repair/service I do for 54640 series oscilloscope that exceeds $800 after parts and labor.


Since I’m now selling 54640-series oscilloscopes with this as a value-added service, I’d ask my kind readers NOT TO use the technique learned here to offer products and services that might compete with my offerings. Feel free to apply it to units that you’ll keep for yourself. I’ll trust you 🙂

1,142 total views, 1 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.

480 total views, no 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.


Rik has pointed out in the comments below that TMW introduced implicit expansion that makes the bsxfun() obsolete. This is an excellent move (readability), despite it won’t police matrix crimes anymore so educators should teach about implicit expansion as the first thing as it’d be hard to debug is the user is not aware of the behavior. Thanks Rik!

616 total views, 2 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.

877 total views, 1 views today

How I learned MATLAB inside out

Back when I was a 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.

 

732 total views, no views today

MATLAB Quirks: cellfun() high-performance trap

cellfun() is a powerful function in MATLAB which mirrors the idea of applying a ‘map’ operation (as in functional programming) to monads (cells: a datatype that holds any arbitrary data type, including itself).

One common use is to identify which cells are empty so you can ignore them. Typically, you can do

index.emptyCells = cellfun(@isempty, C);

According to the help (H1) page, there is a limited set of strings that you can use in place of the function handle (functor) for backward compatibility:

 
A = CELLFUN('fun', C), where 'fun' is one of the following strings,
returns a logical or double array A the elements of which are computed 
from those of C as follows:
 
   'isreal'     -- true for cells containing a real array, false
                   otherwise 
   'isempty'    -- true for cells containing an empty array, false 
                   otherwise 
   'islogical'  -- true for cells containing a logical array, false 
                   otherwise 
   'length'     -- the length of the contents of each cell 
   'ndims'      -- the number of dimensions of the contents of each cell
   'prodofsize' -- the number of elements of the contents of each cell
 
A = CELLFUN('size', C, K) returns the size along the K-th dimension of
the contents of each cell of C.
 
A = CELLFUN('isclass', C, CLASSNAME) returns true for each cell of C
that contains an array of class CLASSNAME.  Unlike the ISA function, 
'isclass' of a subclass of CLASSNAME returns false.

Turns out these functions have their native implementation and runs super-fast. But I got burned once when I tried to use this on cells containing table() objects:

index.emptyCells = cellfun('isempty', cellsOfTables);

I meant to find out if I have zero-row or zero-column (empty) table objects with that. It gave me all false even when my cells have these 0-by-0 tables. What a Terrible Failure?! Turns out these ‘backward compatibility’ native implementations (I guess they already have cellfun() before having function handles) looks at the raw data stream like PODs (Plain Old Datatypes) as a C program would do.

A table() object has lots of stuff stored in it like variable (column) names, so there’s no way a program looking at an arbitrary binary stream without accounting for such data type will consider that object empty. It’s up to the overloaded isempty() or numel() of the class to tell what is empty and what’s not, but it needs to be called by the function handle to establish which method to call.

Lesson learned: don’t use those special string based functor in cellfun() unless you know for sure it’s a POD. Otherwise it will get you the wrong answer at the speed of light.

1,636 total views, no views today

Make your MATLAB code work everywhere

MATLAB is used in many different setups that it’s hard to expect every line of your code you write generalizes to all other versions, platform and deployments. The following code examples helps you identify what envirnoment you are in and so you can branch accordingly:

% 32 bit vs 64 bit MATLAB
% This exploits the fact that mex is on the same platform as your MATLAB
is64bit = strcmpi( mexext(), 'mexw64');

% Handling different MATLAB versions
if( verLessThan('matlab', yourVersionString) )
  error('This code requires %s or above to run!', yourVersionString);
end

% Headless (Parallel) workers
% This exploits the fact that JVM is not loaded for parallel workers. 
% Starting MATLAB with '/nojvm' will be considered headless
isHeadless = ~usejava('desktop');

% DCOM / ActiveX /Automation Server
isDCOM = enableservice('AutomationServer');

% Test for compiled MATLAB:
isdeployed()

553 total views, 1 views today

Auto Mouse Mover / Clicker

At work I came across a piece of fine software (fine as the ‘F’ in RTFM) to access the data from an open-source project that decided to throw a warning dialog box every time when it come across some minor data integrity issues while going through tens of thousands of entries.

Upon inspecting the C code, they failed to provide a mechanism to suppress the warning dialog box for Windows (it can be done a function that uses with signals in linux though). Since this is a one-shot gig anyway and I don’t have the time to figure out the dependencies and recompile their code chain, I came up with something ghetto: automated mouse clicker.

It’s the kind of solution that is not too natural to come by for people with finer control over computers (aka, software engineers), but immediately obvious to middle-school level script kiddies.

I have to admit I almost lost the ‘street’ knack as it took me an hour digging through the documentation and code base to find a ‘proper’ way to do it before I even gave the ghetto patch a thought. That’s how seasoned engineers can get pwned by noobs who ‘don’t know a damn thing’ but ‘gets the job done’. Luckily, I remembered to switch hats early enough this time.

A ghetto trick or two can be used ONLY when we are really sure that it’s a one-time gig that won’t be reused. Any attempts to extend the one-time-wonder can only attribute to pain and misery for everybody, as a recurring theme in software and product development projects.

Sounds like a familiar situation at work? It’s always that one small thing your client asked you for. If you hack something up quick-‘n’-dirty and it worked, they are going to say, ‘by the way, one more one small thing…’. Lather, rinse, and repeat and soon you’re buried in brown, sticky foam.

This can be explained by the life lesson I learned in my first summer internship during high school: people in general don’t know what they really wanted and they don’t communicate well. Me included. The soft-skills coaching received at Stanford helped quite a bit, but I still consider myself ‘not there yet’.

Typically, your client is going to ask you for something specific (which is not what they really wanted because they haven’t figured it out yet) and keep revising and making sharp turns at your expense to make up for the ‘errors’ as in ‘trial-and-error’.

This is not a win-win scenario. It’s a tug of war between you and your client: you want your client to do their homework to figure out what they wanted and your client want to crap-shoot at your expense. It creates tension between you and your client. A work contract (or a specification agreed upon) might protect you from blame, but a client that doesn’t get what he/she wanted (regardless of who is at fault) is not going to be happy about your work.

One way out of it is to ask your client to start with a vague, underlying theme of what they are trying to accomplish. This way they won’t be overwhelmed by the pressure to get all the detailed specs right. If you have a long term relationship with the client, it pays to learn what are their general ‘interests’ are so you can piece the fragments together quicker. Gradually, you can ease them into thinking through their underlying goals aloud and you can take the opportunity to explore how you can help them accomplish it.

Guide them through their thought process, and maybe show a little prototype or design to help them visualize how they can accomplish their goals (through you). With the big picture in mind, you can make educated judgement, fill in details, and decide what intermediate/iterative steps are needed instead of letting the client unwittingly micromanage you based off his/her solution approach by saying ‘I need one small thing quick…’ one at a time. You are now in control over the project and in a very good position to help your client meet his/her true agenda.

It seemed like more upfront work to meet your client halfway and do part (or half) of their homework, but for anything other than a short hit-and-run, it’s less total work for you and a happier outcome for both. Using this approach, I was able to deliver a last minute change in ‘1 minute’ because the software architecture I designed was tailored towards the client’s underlying goal, so the feature he forgot to ask for was naturally built in and only requires one line of code to turn it on despite I hadn’t explicitly planned for it.

The bottom line is that humans are clueless (at various levels) and they want to further their interests (by doing something). If we take both parties’ interest into account and spot inefficiencies that we can correct, there’s at least an approach where everybody wins. Game-theoretic approach and market equilibrium is ‘optimal’ only when ‘technology’ is held unimproved and there is no on-going relationship between parties. Life doesn’t always have to be a war or struggle 🙂

465 total views, 1 views today

“Copy as path” option in Microsoft Windows

Very often I want to copy the full path of a file to my MATLAB environment for quick testing. Before my coworker showed me the trick, I tried to staple the filename I copied from the Explorer window to the address bar then re-copy the whole. That was dumb.

For some reason, Windows stowed away a slick feature called ‘Copy as Path’. You have to hold “SHIFT” key while right-clicking to get the good stuff displayed (same as “Open Command Window Here”).  What a crime!

This website shows you a way to have the menu option activated by default:
http://www.askvg.com/registry-tweak-to-add-copy-as-path-option-in-files-and-folders-context-menu-in-windows/

354 total views, no views today