A Comet!

Monday, April 13, 2026

[Updated 14 April 2026]
Another clear night, and another go at C/2025 R3 (PanSTARRS). Started earlier this time, and managed more shots and a slightly higher gain:

DM12-03-3241ge.webp

This was 60 15-second photos at gain 70. Gamma and equalisation in PhotoDesk. I centred the shoot on a star slightly above the comet, to get more of the tail in.

Comets are fairly fast-moving things, especially when near the sun, and a current limitation of the Dwarf Mini is that it tracks the stars, not the comet. You can see there’s a slight elongation of the comet’s head here, as it’s moved slightly over the course of the exposures.

Here’s a screenshot of the in-progress shoot, showing the location between the trees:

DM12-04screenshot.webp

[Original post:]

Comets are tricky things to image. They’re brightest when they’re closest to the sun, which means they’re low in the sky and best visible around sunset or sunrise.

There’s a comet around now with the rather unexciting name of C/2025 R3 (PanSTARRS). There’s a naming convention here: the “C” denotes a non-periodic comet (meaning it’s unlikely to return); “2025 R3” gives the year and half-month when it was first observed (so “R”, the 18th letter, is the first half of September, the 9th month) and it’s the third comet discovered in that period; and “(PanSTARRS)” is who or what discovered it, in this case the automated sky survey system Pan-STARRS in Hawaii.

As of today, 13 April 2026, it’s low in the eastern sky before sunrise. We’re surrounded by houses and trees here, but looking at the comet in Stellarium it looked like it might be observable from an upstairs window between a fortuitous gap in the trees, at around 5am.

And indeed it was!

DM12-01comet01egc.webp

This was 25 15-second shots at gain 60, with two failures: one satellite, and one tracking problem, unsurprising given the comet’s altitude (about 10°) and proximity of dawn. It would have been better to take a lot more shots with longer exposures, but the sky was inexorably lightening as the dawn approached.

The alarm was set for 4am, and while waiting for the comet to rise I tested out the Mini by imaging the North American nebula, as below (or part of it — the bit here is Florida and the Gulf of Trump America Mexico; rotate it 90° clockwise and you can see the vague resemblance). It was fortunate I did this, as the focus was clearly off somewhat. Still, a preview of what will be available in the summer months at more sensible times.

DM12-02NAnebulaeg.webp

Starlink Annoyances

Sunday, April 12, 2026

A few nights ago I took some more images of Markarian’s Chain, and while it wasn’t a great session (clouds), I did learn something about when to observe.

I took 210 photos with 30-second exposures, and the Mini rejected 14 of them — all due to satellites, mostly Starlinks I think.

Here’s a quick manual stack of the rejected frames:

DM11-01flat0.webp

They haven’t been demosaiced or aligned (hence the green tint); I just wanted to see the satellite tracks, all in a pretty small area of the sky.

What I learned was this: sessions should start as late as possible. I started imaging at 9:10pm, and finished at 23:12. All the failures happened before 22:22pm, by which time the sun had moved far enough below the horizon that the satellites weren’t illuminated any more — all those Starlinks are in low orbit.

Unfortunately, that means that in the summer (shorter nights) we’ll get many more trails. :-(

The Whirlpool again, and Markarian’s Chain

Tuesday, April 7, 2026

Last night was meant to be clear, but it started off with some cloud which then cleared until about midnight, when it hazed over again. So counts were limited. But here’s a Megastack of M51, the Whirlpool galaxy:

DM10-01M51Mega-c.webp

250 images taken over two nights, all 60 second exposures; 200 with gain 60, 50 with gain 100 (which was a mistake — high gain values are noisier). Compare with my first effort.

And this is Markarian’s Chain, a linked series of galaxies in the Virgo area, part of the major cluster which includes our own galaxy:

DM10-02Markarian-c.webp

100 60-second exposures, gain 80 (again, too high). As always, click for bigly. How many galaxies can you see?

ROCoding #4: ARM Wrestling

Saturday, April 4, 2026

[Edit 2026-04-18: Fixed incorrect byte ordering of colour channels.]
It’s been 25 years — blimey! — since I did any serious ARM coding. The last was fixing some bugs in my Lisp interpreter in 2001, after which my Iyonix died and I moved over to Linux.

Back with RISC OS now, and in the intervening years the ARM processor has had some substantial changes. Originally it was the Acorn RISC Machine, of course, and it first appeared in the Acorn Archimedes computer in 1987. It was a genuine breakthrough at the time, a custom-designed (by Sophie Wilson et al) 32-bit processor running at 8MHz. I’m now using a 4té2, a repackaged Raspberry Pi 4b containing an ARM Cortex-A72, running at 1.8GHz — over 200 times faster.

And while the original ARM chips were indeed Reduced Instruction Set Computers, with only about 25 instructions1, these days it’s something of a misnomer. So what’s been added? SIMD and NEON, mostly. This article is a simple introduction to using some SIMD instructions; we’ll cover NEON2 later.

The Dwarf Mini smart scope — see other posts — saves image files as FITS files. This is a standardised format for storing scientific and astronomical images and has a few peculiarities, as I found when I started investigating it.

First, the pixel data is encoded as a stream of signed 16-bit twos-complement integers (other numeric formats are possible, but that’s what I’m dealing with here). Why signed? I don’t know, but that’s the only format for 16-bit integers in the FITS specification. In order to get unsigned values we need to add a constant to each number, which is specified in the FITS header — in this case 32768. So we’re mapping the range -32768…32767 to 0…65535.

Second, FITS stores numbers the wrong way round (with respect to ARM processors, anyway), with the most significant byte first: big-endian, not little-endian.

It’s quite possible to cope with this in BASIC, though a bit of a faff. And slow. Which was what prompted me to investigate the new (to me) ARM features available. And the good people who look after RISC OS have ensured that BBC BASIC’s assembler has been updated to handle the new opcodes. To emphasise: in order to run these code fragments — the simple surrounding BASIC code to set up the assembler is left as an exercise — you’ll need to be running a recent RISC OS on a recent computer, with a recent BASIC. In BASIC, type HELP [ to get a list of ARM instructions — if it includes a load of interesting-sounding assembler mnemonics like UXTAB16, SXTH and UQASX you’re good to go.

SIMD

The ARM processor has 32-bit, 4-byte registers, and instructions usually operate on the whole 32-bit word. So add r0,r1,r2 adds r1 and r2 together, and puts the result in r0. SIMD stands for Single Instruction, Multiple Data, and lets us operate on only parts of a word. So, for example, you can perform four 8-bit additions in a single operation. It’s a kind of parallel processing, which can be very useful for dealing with images — remember that a full-colour pixel is a single word containing red, blue and green components in three of the four bytes.

To get the FITS data in a usable form, we first need to invert the byte order of each 16-bit word. If we read a whole word of FITS data into register r1 we’ll have the values for two pixels, and the SIMD ARM instruction rev16 will do exactly what we need:

.hreverse
; half-word byte reversal
;  IN - r1 = pair of half-words
; OUT - r0 = half-word bytes reversed
rev16 r0,r1
mov   pc,lk

Calling machine code from BASIC initialises registers r0 to r7 with whatever is in the variables A% to H%. So we set the BASIC variable B% to some value, &03B2C1D0 here, and call this code with USR, which returns r0. The single instruction swaps the byte order of each of the 16-bit words in r1, and puts the result in r0 which is then returned. For example:

Original: &03B2 C1D0
Reversed: &B203 D0C1

I’ve separated the 16-bit half-words with a space to make it clearer. Actually, ARM processors can now operate with big-endian data, but changing that globally makes me very nervous…

Now we need to add in the correction to get unsigned numbers; in other words, we normalise the data. Again, ARM can, er, lend a hand: the uadd16 instruction adds corresponding unsigned half-words together:

.hnormalise
; Half-word normalisation
;  IN - r1 = pair of half-words
;       r2 = offsets to normalise
; OUT - r0 = half-words added to the offsets
uadd16 r0,r1,r2
mov    pc,lk

Each half-word in r1 will be added to the corresponding half-word in r2. So with various values in B%, and &80008000 in C% (32768 in hex, in each half-word) we get:

Original  : &8000 8020
Normalised: &0000 0020

Original  : &7FFF 1234
Normalised: &FFFF 9234

Of course, you’d normally amalgamate these routines (or even define a macro — it’s only two instructions!):

.hrevnormalise
; Half-word byte-order correction and normalisation
;  IN - r1 = pair of half-words
;       r2 = offsets to normalise
; OUT - r0 = half-words reversed, and added to the offsets
rev16  r0,r1
uadd16 r0,r0,r2
mov    pc,lk

What’s very important to realise is that the operations on each half-word are entirely separate. If the sum exceeds the maximum value storable in the lower 16-bit word (65535), it won’t affect the bits in the other half-word; it just wraps round. Also note that these SIMD instructions don’t usually affect the flags (for obvious reasons: which half-word?), so you can’t use the S suffix with them. You can however use all the conditional codes.

It’s interesting to try to code this using old-style ARM instructions. It’s not difficult, but involves a lot of bit-twiddling, rotating, masking and separate treatment of each half-word. And needs a lot more instructions!

Saturation

I said above that results over the maximum storable will wrap round, so if you do a single byte addition of 230+70, you’ll get 44 (300-256). The uadd8 instruction adds the corresponding bytes in a pair of registers, like this:

.add_bytes
; uadd8 = add corresponding unsigned bytes
; IN - r1 B% = 4 byte values
;      r2 C% = 4 bytes to add
; OUT- r0 = result
uadd8 r0,r1,r2
mov   pc,lk

Adding &AAB0FFE6 to &442F0146 will give this, shown in hex and decimal:

Original  : &AA B0 FF E6 : 170 176 255 230
Plus      : &44 2F 01 46 :  68  47   1  70
Result    : &EE DF 00 2C : 238 223   0  44

Watch what happens with the usual add operation on the same inputs, add r0,r1,r2:

Word add  : &EE E0 01 2C : 238 224   1  44

The additions in the lowest two bytes have overflowed, causing carries into the next bytes.

The ARM offers saturated operations, where results are clamped to the minimum and maximum values storable in the bit-width. The uqadd8 instruction does unsigned saturated byte addition, like this:

; uqadd8 = unsigned add bytes, saturating
; IN - r1 B% = word
;      r2 C% = bytes to add
; OUT- r0 = result
uqadd8 r0,r1,r2
mov    pc,lk

With the same inputs as above, we get this:

Original  : &AA B0 FF E6 : 170 176 255 230
Plus      : &44 2F 01 46 :  68  47   1  70
Result    : &EE DF FF FF : 238 223 255 255

The overflow of the lowest two additions has been capped to 255.

One application of this would be simple brightness adjustment of an image. Full-colour pixels in RISC OS sprites are stored in a single word as 00BbGgRr, representing the blue, green and red channel values. (Though RISC OS can handle the 00RrGgBb format - PhotoDesk offers both options when saving.) To brighten an image, you just increase each channel byte like this:

; Brighten a pixel
; IN - r1 B% = colour word, in 00BbGgRr format
;      r2 C% = amount to brighten by (0..255)
; OUT- r0 = brightened pixel
orr    r2,r2,r2,lsl#16 ; high byte 2 is blue channel brightening…
orr    r2,r2,r2,lsr#8  ; …byte 1 is green
uqadd8 r0,r1,r2
mov    pc,lk

With a brightening of 40, we get this:

Original  : &00 DC BD FF :   0 220 189 255
Plus      : &00 28 28 28 :   0  40  40  40
Result    : &00 FF E5 FF :   0 255 229 255

The first two instructions copy the lowest byte of the brightening amount into bytes 1 and 2, which is then added to the colour word. And importantly, it saturates the resultant channel values — if it didn’t you’d get very odd results if it went over 255 and wrapped round.

To reduce brightness, just replace uqadd8 with uqsub8 — in this case, values are clamped to zero. And it’s a simple modification to allow different brightness modifiers for each channel, of course.

To invert the colours of a pixel, each channel is changed to 255-colour value, like this:

; Invert a pixel
; IN - r1 B% = colour word, in 00BbGgRr format
; OUT- r0 = inverted pixel
mvn    r0,#&ff000000
uqsub8 r0,r0,r1
mov    pc,lk

The mvn sets r0 to &00FFFFFF. Actually we don’t need SIMD to do this; using eor r0,r0,r1 would have the same effect.

Another common graphics operation is interpolation — generating a pixel’s colour values from two others, often its neighbours. Given two pixels, the single SIMD instruction uhadd8 can do this:

; Interpolate between two pixels
; IN - r1 B% = first colour word, in 00BbGgRr format
;      r2 C% = second colour word, in 00BbGgRr format
; OUT- r0 = interpolated pixel
uhadd8 r0,r1,r2
mov    pc,lk

What uhadd8 does is add correponding unsigned bytes, then halve the sum — so the result is the average of the channel values, like this:

Pixel 1   : &00 FF 7C F0 :   0 255 124 240
Pixel 2   : &00 01 24 3C :   0   1  36  60
Result    : &00 80 50 96 :   0 128  80 150

Note in particular the red channel in byte 0, which adds 240 and 60 giving 300. This can’t be stored in a byte, of course, but the addition stage is actually carried out with 9-bit accuracy so the halving gives the correct result, of 150.

Summary

It should be apparent that there’s some consistency to the names of SIMD mnemonics. The numeric suffix of 8 or 16 gives the data unit size. If the mnemonic starts with U the instruction deals with unsigned values, and an S prefix denotes signed values (we haven’t used any here, but for example sadd16 is the signed version of uadd16, adding pairs of signed half-words). A Q in the mnemonic means it’s a saturating operation, and an H does a halving. The convention isn’t always followed: uqadd8 does a saturated unsigned byte addition, but the signed version is just qadd8, not sqadd8.

We’ve only scratched the surface of the SIMD instructions here, but it should be enough to get you started. I recommend getting an up-to-date StrongHelp Assembler manual, which summarises all the SIMD instructions available.

Footnotes

  1. “Reduced” can be taken to extremes — it’s possible to implement a general-purpose computer with only one instruction. The usual example is subleq, “subtract and branch if less than or equal to zero”. Dawn is a whole operating system written using this instruction.
  2. NEON is basically SIMD on steroids

First Megastack

Saturday, April 4, 2026

It’s been a long wait, but we finally had some clear skies last night. And here’s a “Megastack” of M101, the Pinwheel galaxy. The Dwarf Mini can combine images taken over different observing sessions, at different times and dates. Here it’s a stack of 295 images taken over three nights — the Megastack processing takes a while, 50 minutes in this case:

DM08-01M101mega-gec.webp

Some post-processing in PhotoDesk: gamma, equalisation and cropping. Compare with the image taken on March 18.

I also managed a not entirely successful shot of Bode’s galaxy, this time getting the Cigar galaxy, M82, in the shot:

DM08-02bodecigarmerged.webp

Better luck next time; clouds started rolling in for this.

Finally, the Moon:

DM08-03moon.webp

Again not very good, due to haze.

Chasing variable stars

Sunday, March 29, 2026

The globular cluster M13 has a number of variable stars, which change in brightness by various amounts over time. Some, like Cepheid variables, are very predictable and can be used to estimate the distance of objects.

I surmised it might be possible to catch the variations with the Dwarf Mini, so after taking the 27 March image, I took another the next night in a brief cloudless spell and tried comparing them. Spoiler: this hasn’t worked very well!

DM07-01anim.gif

The image on the left is an animation of the two images. Both were taken with the same settings: 50 30-second exposures, 60 gain, Astro filter.

First of all the images had to be aligned. Because they were taken at different times the second had to be rotated by a small amount (about 2.1°), which was done in ArtWorks — it’s a bit easier than in PhotoDesk. The images were then imported into PhotoDesk and aligned using a layer for each image.

There are some obvious problems here. First, the images should have been taken at similar times. The second was taken earlier in the evening, so M13 was lower in the sky resulting in greater atmospheric attenuation, which alters the colours slightly — that’s why they’ve been converted to greyscale — and dims the image a bit. This would also reduce or eliminate any need for rotation.

Second, the weather for the second image was worse, with occasional cloud and some high haze.

Third, it turns out that most of the variables have fairly long cycles, between five days and three months, so the two photos should be separated by more than a day. And the amount of variation isn’t that much, so the two images do need to be as identical as possible.

So although it looks like some stars are varying, mostly fainter ones, this is an artefact. And they’re not quite aligned perfectly either.

DM07-02anno.webp

This Sky and Telescope article has a useful guide to M13 variable stars. About halfway down the page there’s an annotated image with the variable stars labelled and some asterisms — star patterns — outlined as guide aids. My image is on the right, and I’ve matched the asterisms, shown in green — an encouraging start — and marked a few of the variable stars, in red. It’s been zoomed in and cropped.

So my first attempt was, basically, rubbish. But I’ve learned a lot here…

M13, and M81 again

Saturday, March 28, 2026

Another Dwarf Mini session last night. I plugged in a power bank for an extended session, but I stupidly forgot to turn it on 😢 so halted things when the Mini’s battery was down to 25%, after about 3 hours. Doh.

Anyway, this is M13, the globular cluster in Hercules:

DM06-01M13Shs.webp
DM06-02M13prop.gif

As always, click for a bigger version. M13 is a small satellite galaxy of our own, and contains perhaps half a milliion stars. Stars are packed about 100 times closer together than in our neighbourhood, so the night-time sky of a planet in the cluster must be spectacular.

Here I took 50 30-second shots with 5 failures, gain 60, Astro filter. Slight sharpening and saturation in PhotoDesk.

There’s a feature called the propeller in this cluster, which the Mini has managed to resolve — see right. It’s just a chance arrangement of dust lanes in the cluster and our viewpoint.

And below is another attempt at Bode’s Galaxy, M81:

DM06-03M81.webp

This time I was more conservative with the settings, which has significantly improved the result. 200 images with no failures, 30 seconds each, gain 60 and Astro filter. No processing!

Pleiades, a first attempt

Saturday, March 21, 2026

Today started off with thick fog, which gradually cleared to hazy sunshine and milky skies. Not the best conditions for astrophotography, but I decided try shooting the Pleiades, or Seven Sisters, a prominent star cluster in Taurus.

It’s not well positioned from our location at this time of year, being lowish in the western sky. And it’s only visible from our front garden, with a bright street light just outside. Nevertheless I had a go, and set up a Heath Robinson affair of a towel — life’s essential — draped over another tripod to shade the Dwarf Mini from the glare of the street lamp.

Here’s how it went:

DM05-01pl02.webp

Not bad at all, considering the conditions! I set up the Mini to take 100 shots, with 60-second exposure and gain 60. But as you can see from the screenshot below, by 75 shots the hedge was getting in the way so I stopped the session. Unsurprisingly there were 12 failed shots, so this is a stack of 63. It’s been processed in PhotoDesk with equalisation and quite a strong gamma adjustment to bring out some of the faint blue nebulosity. This target really needs dark skies and long exposures, so we’ll have to wait until later in the year for a better result.

DM05-02screen.webp

I also took a quick shot of the 3-day-old Moon:

DM05-03moon.webp

Galaxies Update

Wednesday, March 18, 2026

A very clear night, and an opportunity to attempt some better shots of the galaxies I looked at last time.

I set up an equatorial mount, not “Perfect” but within 1°. I upped the exposure time to 60 seconds, and used a gain of 100. Click on the pictures for bigger versions. All have minimal PhotoDesk processing after passing through Stellar Studio — just small gamma and equalisation adjustments, and cropping.

So here’s M81, Bode’s galaxy, again. 50 exposures, two failures:

DM04-01bode.webp

The thing at the top is the Cigar galaxy, which I didn’t realise was there.

This is M101, the Pinwheel galaxy. 50 exposures, no failures:

DM04-02pinwheel.webp

And a new one, the small but pretty M51, the Whirlpool galaxy. 50 exposures, no failures again:

DM04-03whirlpool.webp

This has a companion galaxy, NGC5195, which is pulling out one of the spiral arms. Look carefully and you can see several smaller, more distant galaxies at lower right.

I also did the Hamburger galaxy, but I was jinxed again, this time by light pollution from our bathroom window.

[Update 20 Mar 2026]
Managed to get the Hamburger last night, although there was a lot of high cloud/haze. 100 shots, 30sec, gain 60:

DM04-04hamburger2gec.webp

Gradgrind Update

Monday, March 16, 2026
Gradgrind093window.webp

Gradgrind has been updated to 0.93beta. Changes:

  • GIMP palettes changes:
    • Doesn’t now ignore duplicates
    • Added paged display for large palettes (uses left/right arrows)
    • Description for these shows currently displayed colour numbers
    • Includes (commented) description when saving as gpl file
    • Added some sample GIMP palettes
  • Sprite save icon removed. Can now drag the gradient/swatches displays to save them as sprites. Filename has “S” or “G” appended.
  • Tidied up swatches display, and added option for outlines (toggle with ADJUST)

Download here.