Saturday, February 21, 2026

The Engineer in Me is Jubilant — Julia, A Language for System-Level Experimentation for engineers...



There are moments in an engineer’s life when a tool just clicks.

For me, that moment came while implementing a simple PID-controlled DC motor model in Julia.

Not because PID control is revolutionary.
Not because DC motors are exotic.

But because the process felt frictionless.

And that matters.


From Equation to Experiment — Without Friction

In classical control engineering, we begin with mathematics:


G(s) = K / (Js + b)(Ls + R) + K^2

This is not just a formula.
It represents inertia, friction, electrical dynamics — physics captured in Laplace space.

In many languages, translating this into working simulation code involves:

  • Verbose syntax

  • Data structure boilerplate

  • External tools for plotting

  • Type mismatches

  • Build steps

But in Julia, using ControlSystems.jl, the translation from equation to executable model feels almost poetic:

using ControlSystems

s = tf("s")
motor = K / ((J*s + b)*(L*s + R) + K^2)

pid = Kp + Ki/s + Kd*s
closed_loop = feedback(pid * motor, 1)

Look at that.

The code mirrors the mathematics.
No impedance mismatch between theory and implementation.

For an engineer, that is deeply satisfying.


System-Level Thinking — Not Just Coding

Engineering is not about syntax.

It is about:

  • Modeling

  • Interconnection

  • Feedback

  • Stability

  • Response

  • Iteration

Julia allows you to move from:

  • Transfer function

  • → Closed-loop interconnection

  • → Step response

  • → Parameter tuning

in minutes.

With Plots.jl, visualizing behavior is immediate:

y, t = step(closed_loop, 0:0.01:2)
plot(t, vec(y))

Change Kp.
Re-run.
Observe overshoot change.

Change Ki.
Re-run.
Observe steady-state error vanish.

This is experimentation at the speed of thought.


Why This Feels Different

Many ecosystems split engineering work across tools:

  • MATLAB for modeling

  • Python for data

  • C++ for performance

  • Simulink for block diagrams

Julia collapses these layers.

You can:

  • Write high-level control logic

  • Drop to numerical linear algebra

  • Move into differential equation solvers

  • Even implement custom integrators

All in one language.

For someone who enjoys digging into source code, understanding numerical methods, and experimenting at system scale — this coherence is powerful.


Engineers Think in Systems

When I modeled the PID loop, what struck me was not that it worked.

It was how naturally system interconnections are expressed:

feedback(pid * motor, 1)

That single line captures decades of control theory.

This is not scripting.

This is system architecture expressed symbolically.


Performance Without Compromise

Unlike prototyping languages that eventually require rewriting in C/C++, Julia compiles to efficient machine code.

That means:

  • Rapid experimentation

  • No performance guilt

  • No "rewrite later" tax

For control engineers dealing with:

  • High-order systems

  • State-space models

  • Optimization loops

  • Model predictive control

This matters enormously.


The Quiet Joy

There is a quiet joy when:

  • Mathematics maps directly to code

  • Systems behave as predicted

  • Tuning becomes interactive

  • The tool does not get in the way

That is what I felt implementing the PID example.

Not hype.
Not trendiness.

Just alignment between engineering thought and computational expression.


Julia as an Engineering Workbench

Julia is not just a language.

It feels like:

  • A modeling lab

  • A numerical toolbox

  • A systems sandbox

  • A research instrument

For engineers who think in equations, dynamics, and feedback loops — it feels native.


Final Thought

The engineer in me is jubilant.

Because experimentation should be easy.
Modeling should feel direct.
And computation should not stand between idea and insight.

With Julia, system-level experimentation feels natural again.

And that, for an engineer, is everything.

Here's the source code of the PID Control...

Enjoy...

using ControlSystems
using Plots

# ----------------------------
# Motor Parameters
# ----------------------------
J = 0.01 # inertia
b = 0.1 # friction
K = 0.01 # motor constant
R = 1.0 # resistance
L = 0.5 # inductance

# ----------------------------
# Transfer Function of Motor
# G(s) = K / [(Js + b)(Ls + R) + K^2]
# ----------------------------
s = tf("s")

motor = K / ((J*s + b)*(L*s + R) + K^2)

println("Motor Transfer Function:")
display(motor)

# ----------------------------
# PID Controller
# C(s) = Kp + Ki/s + Kd*s
# ----------------------------
Kp = 100
Ki = 200
Kd = 10

pid = Kp + Ki/s + Kd*s

# ----------------------------
# Closed-loop System
# ----------------------------
closed_loop = feedback(pid * motor, 1)

println("Closed Loop Transfer Function:")
display(closed_loop)

# ----------------------------
# Step Response
# ----------------------------
t = 0:0.01:2
y, t = step(closed_loop, t)

p = plot(t, vec(y),
xlabel="Time (s)",
ylabel="Speed",
title="Closed-Loop Step Response",
legend=false)

display(p)
wait()

And here's my PID study - an implementation using Java done many years ago.

One thing you will understand - Julia is a boon for engineers.

Friday, February 20, 2026

Paradigm shift - from behaviours inside object in OOAD to Julia where behaviours emerge from type of function parameters...


OOAD Thought Processing

    Concept → Owner

  • Behavior → Object
  • Polymorphism → Virtual methods
  • Extension → Subclassing
  • Encapsulation → Methods inside class


Julia Thought Processing

    Concept → Owner

  • Behavior → Generic function
  • Polymorphism → Multiple dispatch
  • Extension → Add new methods
  • Encapsulation → Types + modules


OO Design Thinking

  • Identify entities (classes)
  • Attach behavior to them
  • Use inheritance for variation


Julia Design Thinking

  • Identify operations (functions)
  • Define data types
  • Implement methods for combinations of types


Worldview Comparison

OOP worldview

The world is made of interacting objects.

Julia worldview

The world is made of operations applied to data.


The State Pattern in Pure Julia Style

Enjoy the State pattern written in Julia.

Note that this works without the context class of the original State Pattern, which is typically implemented using object-oriented languages like C++, Java, or Python.

abstract type ChickenState end

struct Uncleaned <: ChickenState end
struct Washed <: ChickenState end
struct Marinated <: ChickenState end
struct Cooked <: ChickenState end

function wash(::Uncleaned)
println("Chicken is getting cleaned → Washed")
sleep(2)
return Washed()
end

wash(s::ChickenState) = s # default: no change

function marinate(::Washed)
println("Chicken is being marinated → Marinated")
sleep(2)
return Marinated()
end

marinate(s::ChickenState) = s

function cook(::Marinated)
println("Chicken is being cooked → Cooked")
sleep(4)
return Cooked()
end

cook(s::ChickenState) = s

function serve(::Cooked)
println("Chicken is being served. Final state.")
return Cooked()
end

serve(s::ChickenState) = s

state = Uncleaned()

state = wash(state)
state = marinate(state)
state = cook(state)
state = serve(state)


Here's the Python implementation of the State Design Pattern.

Feel the difference - Pythonian way and the Julian way.

Tuesday, February 17, 2026

Horns of the dilemma - C++ & Python binding or Julia - implementation of strategy design pattern in Julia...

 


Aah… I am at the crossroads - tried-and-true marriage (C++/Python) or solo act (Julia).

For the past few months, I delved into many tools that act as a glue between C++ and Python, like nanobind, pybind11, SWIG, Boost.Python, etc. All of these looked good. This is the industry-wise power couple for performance and ease of use.

Yesterday, while trying to understand why so many top-level AI scientists are leaving bigtech, I got a clue about scientific AI and Julia, the programming language especially made for this field.

Yes, I am not talking about LLM - because I am sure AI ≠ the next word suggestion. There is a vast field in AI to cover vis-à-vis Scientific AI and simulation. In fields like climate modeling, drug discovery, or fluid dynamics, we aren't just predicting tokens; we are constrained by the laws of physics.

This is where Julia has carved out a unique, dominant niche through a movement called SciML.

While Python and C++ can do this, Julia has structural advantages that make it the "lab equipment" of choice for this decade.

To train an AI, you need gradients (derivatives). In Python, you can only differentiate through code written in specific frameworks like PyTorch or JAX. In Julia, the entire language is essentially differentiable. You can take the derivative of a complex simulation, a CAD model, or a custom physics engine without rewriting it in a "tensor" format.

Remember, scientific models are often written by scientists, not software engineers.

  • The Old Way: A scientist writes a model in Python; it’s too slow for the Supercomputer, so a software engineer rewrites it in C++.

  • The Julia Way: The scientist writes high-level code that is automatically compiled to LLVM (machine code). The prototype is the production code.

Some important use cases for Julia…

  • Climate Modeling: The CliMA project (MIT/Caltech) is rebuilding global climate models in Julia to better integrate satellite data with fluid dynamics.

  • Pharmaceuticals: Pumas is a Julia-based tool used for "quantitative pharmacology" to predict how drugs move through the body.

  • Aerospace: Organizations like NASA use Julia for trajectory optimization because it handles the massive matrix math of orbital mechanics at C++ speeds

Julia isn't a "Python killer" for building a website or a simple chatbot. But for Scientific AI—where you need to solve a partial differential equation while training a transformer—it is currently the only language that doesn't make you choose between your sanity (Python) and your performance (C++).

So… here we go… my exploration of Julia has begun today. The way I learn new software languages is by doing the same thing for Julia - using Julia to implement some of the GoF Design Patterns, here the Strategy Pattern.

Here is the source code of the Strategy Pattern developed using Julia.

abstract type JourneyToTheAirport end

struct Bus <: JourneyToTheAirport end
struct Metro <: JourneyToTheAirport end
struct Auto <: JourneyToTheAirport end

gotoairport(::Bus)   = println("🚌 Journey by bus... hope there's no traffic!")
gotoairport(::Metro) = println("🚇 Journey by metro... fast and efficient.")
gotoairport(::Auto)  = println("🛺 Journey by auto... hold on tight!")

# 1. Create a mapping of strings to Type Constructors
choices = Dict(
    "bus"   => Bus(),
    "metro" => Metro(),
    "auto"  => Auto()
)

function run_app()
    println("How do you want to get to the airport? (bus, metro, auto):")

    # 2. Get user input and clean it up (lowercase and strip whitespace)
    user_input = lowercase(strip(readline()))

    # 3. Look up the strategy in our dictionary
    if haskey(choices, user_input)
        strategy = choices[user_input]
        gotoairport(strategy)
    else
        println("❌ Sorry, '$user_input' is not a valid transport option.")
    end
end

run_app()

Enjoy…

Saturday, February 7, 2026

Many private engineering colleges in India who made a lot of money by just printing out CS degrees for gullible students have closed their shops...

It’s a classic case of the "education bubble" finally popping. For nearly two decades, opening a private engineering college in India was seen as a guaranteed gold mine—often dubbed the "CS Degree Mill."

​The trend we are noticing is backed by some pretty stark data. Since the mid-2010s, the All India Council for Technical Education (AICTE) has overseen a massive "market correction."

​Why the "Shops" are Closing

​The decline wasn't just due to a lack of students, but a systemic failure in the business model of these institutions:

  • The 30% Rule: The AICTE enacted a strict policy where colleges with less than 30% enrollment for five consecutive years face forced closure. This effectively weeded out the "ghost colleges" that existed only on paper.
  • The Employability Gap: Industry reports (like those from Aspiring Minds) consistently pointed out that nearly 80% of Indian engineering graduates were unemployable in core technical roles. When companies stopped showing up for "Day 0" placements at Tier-3 colleges, the "gullible students" (and their parents) stopped signing up.
  • Pivot to "Premium": High-quality private players and "Deemed Universities" (like BITS, VIT, or newer ones like Shiv Nadar and Bennett) consolidated the market. Smaller colleges that couldn't compete with their labs or placement cells simply couldn't survive.
  • Phased Mergers: Many colleges aren't just "shutting down" but are being absorbed into larger private universities or converting their campuses into international schools or management institutes.

​While the "degree mills" are closing, it has left a generation of graduates with "paper degrees" that hold little market value. The industry has moved toward skills-based hiring, where a GitHub portfolio often carries more weight than a certificate from a defunct college.

Thursday, February 5, 2026

nanobind: the bridge between C++ and Python...

Python is where ideas move fast. C++ is where performance lives. For years, gluing the two together meant choosing between power, safety, and sanity. Enter nanobind—a modern, minimalist bridge that lets C++ and Python talk to each other cleanly, efficiently, and without ceremony.

nanobind is a C++17-first binding library, inspired by pybind11 but redesigned with a sharper focus on performance, compile times, and modern C++ practices. It’s built for developers who care about control—over lifetimes, memory, ABI stability, and error handling—without drowning in boilerplate.

What makes nanobind special is how unapologetically low-level it is, while still feeling elegant. It avoids heavy template metaprogramming where possible, compiles fast, and produces smaller binaries. If you’re working on large C++ codebases—CAD kernels, physics engines, solvers, graphics pipelines—this matters a lot.

Memory management is another strong point. nanobind gives you explicit control over object ownership between C++ and Python, making it ideal for systems where Python is embedded inside a C++ application (think Blender, FreeCAD, game engines, or simulation tools). You’re not just exporting functions—you’re designing an API boundary.

Compared to older tools like SWIG, nanobind doesn’t try to “auto-magically” generate bindings. That’s a feature, not a bug. You write bindings intentionally, so the Python API feels Pythonic, not like a leaked C++ header. And compared to pybind11, nanobind is leaner, stricter, and more future-facing.

In short:

  • Python for orchestration and scripting

  • C++ for performance-critical logic

  • nanobind as the clean, modern handshake between them

If you’re building serious software where Python is a first-class citizen—but not the performance bottleneck—nanobind is one of the best bridges you can choose today.

Here's my today's exploration on nanobind - the Factory pattern written in C++ being given a python interface using nanobind.

Enjoy...

The Factory Pattern written in C++.

/*

* Food.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef FOOD_H_

#define FOOD_H_

#include <string>


using namespace std;


class Food {

public:

virtual string getName() = 0;


virtual ~Food(){


}

};



#endif /* FOOD_H_ */


/*

* Biscuit.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef BISCUIT_H_

#define BISCUIT_H_


#include "Food.h"


class Biscuit: public Food {

public:

Biscuit();

string getName();

~Biscuit();

};


#endif /* BISCUIT_H_ */


/*

* Biscuit.cpp

*

* Created on: Mar 10, 2021

* Author: som

*/

#include <iostream>

#include "Biscuit.h"

using namespace std;



Biscuit::Biscuit() {

// TODO Auto-generated constructor stub

cout<<"Biscuit is made..."<<endl;


}


Biscuit::~Biscuit(){}



string Biscuit::getName(){

return "It's a Biscuit";

}



/*

* Chocolate.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef CHOCOLATE_H_

#define CHOCOLATE_H_


#include <iostream>

#include "Food.h"


class Chocolate: public Food {

public:

Chocolate();

virtual ~Chocolate();

string getName();

};



#endif /* CHOCOLATE_H_ */




/*

* Chocolate.cpp

*

* Created on: Mar 10, 2021

* Author: som

*/


#include "Chocolate.h"



Chocolate::Chocolate() {

// TODO Auto-generated constructor stub

cout<<"Chocolate is made..."<<endl;


}


Chocolate::~Chocolate() {

// TODO Auto-generated destructor stub

}


string Chocolate::getName(){

return "It's a Chocolate";

}



/*

* Factory.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef FACTORY_H_

#define FACTORY_H_


#include <nanobind/nanobind.h>

#include <iostream>

#include <string>


#include "Biscuit.h"

#include "Chocolate.h"


using namespace std;


class Factory{

public:

static Factory* instance;

static Factory* getInstance();


Food* makeFood(const string& type);


private:

Factory(){}


// Delete copy constructor & assignment operator (Singleton pattern)

Factory(const Factory&) = delete;

Factory& operator=(const Factory&) = delete;

};

//Factory* Factory:: instance = NULL;



#endif /* FACTORY_H_ */



/*

* Factory.cpp

*

* Created on: Jan 30, 2025

* Author: som

*/

#include "Factory.h"

Factory* Factory::instance = NULL;


Factory* Factory:: getInstance(){

if(Factory::instance == NULL){

Factory::instance = new Factory();

}

return Factory::instance;

}


Food* Factory::makeFood(const string& type){

if(type.compare("bi") == 0){

return new Biscuit();

}

if(type.compare("ch") == 0){

return new Chocolate();

}


return NULL;

}



The bindings.cpp - defining the bridge...



#include <nanobind/nanobind.h>

#include <nanobind/stl/string.h> // Required for std::string support

#include "Factory.h"


namespace nb = nanobind;


// Use NB_MODULE to define the extension

NB_MODULE(foodfactory, m) {

// 1. Wrap the Base Class

// We use nb::class_<T> and provide the name it will have in Python

nb::class_<Food>(m, "Food")

.def("getName", &Food::getName);


// 2. Wrap the Subclasses

// Note: We specify the base class <Biscuit, Food> so Python knows the relationship

nb::class_<Biscuit, Food>(m, "Biscuit")

.def(nb::init<>());


nb::class_<Chocolate, Food>(m, "Chocolate")

.def(nb::init<>());


// 3. Wrap the Singleton Factory

nb::class_<Factory>(m, "Factory")

.def_static("get_instance", &Factory::getInstance, // Renamed to snake_case for Python idiomatic style

nb::rv_policy::reference)


.def("make_food", &Factory::makeFood, // Match your Python script's call

nb::rv_policy::take_ownership);}



And here is the CMakeLists.txt for compiling and creating the shared object


cmake_minimum_required(VERSION 3.15)

project(FactoryPattern_nanobind)


set(CMAKE_CXX_STANDARD 17)

set(CMAKE_CXX_STANDARD_REQUIRED ON)


# 1. Find Python

find_package(Python 3.9 COMPONENTS Interpreter Development REQUIRED)


# 2. Get nanobind paths manually to bypass the "Target Not Found" bug

execute_process(

COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir

OUTPUT_VARIABLE NB_DIR OUTPUT_STRIP_TRAILING_WHITESPACE

)

execute_process(

COMMAND "${Python_EXECUTABLE}" -m nanobind --include_dir

OUTPUT_VARIABLE NB_INC OUTPUT_STRIP_TRAILING_WHITESPACE

)


# 3. Load the nanobind logic

list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")

find_package(nanobind REQUIRED CONFIG)


# 4. Create the module

nanobind_add_module(foodfactory

LTO

Biscuit.cpp

Chocolate.cpp

Factory.cpp

bindings.cpp

)


# 5. MANUALLY fix the missing target link

# This bypasses the error by providing the includes and libraries directly

target_include_directories(foodfactory PRIVATE "${NB_INC}" "${Python_INCLUDE_DIRS}")

target_link_libraries(foodfactory PRIVATE Python::Module)


# If nanobind still complains about the target, we define it as an alias

if(NOT TARGET nanobind::nanobind)

add_library(nanobind::nanobind INTERFACE IMPORTED)

set_target_properties(nanobind::nanobind PROPERTIES

INTERFACE_INCLUDE_DIRECTORIES "${NB_INC}"

)

endif()


After compiling and creating the shared object, you need to put it

inside the Python project and import it.


The Python code looks as follows.


import foodfactory
# Access get_instance THROUGH the Factory class
factory = foodfactory.Factory.get_instance()
biscuit = factory.make_food("bi")
print(biscuit.getName())
chocolate = factory.make_food("ch")
print(chocolate.getName())

And here are my earlier explorations on C++-Python bridge like pybind11, Boost.Python, SWIG, etc.

Enjoy