I studied computer science and physics on separate tracks. CS taught me to ship software before the semester ended; physics taught me what the numbers in a sensor CSV actually mean. uranashel sits at the intersection of those two educations, and nearly every feature that works across our five apps followed the same sequence: a real-world problem appeared, physics described why the naive approach fails, and code was written to respect that description rather than fight it. Nobody at this studio ever sat down and said "AI is hot, let's wrap an API." Every product began as a physical annoyance that happened to one of us personally.
The five apps look like separate ideas (parking navigation, sleep audio, a pocket lab, an acoustics toolkit, a save-for-later tool), but four of them are one idea wearing different sensors. Find the physical quantity the phone can actually measure, work out its noise floor, and refuse to display anything the noise cannot support. The rest of this post walks through how that played out app by app, with the numbers behind each decision.
Wheria: when the map lies
The origin story lives in its own post. The short version is a photo of pillar E9 on floor B2, taken because nothing on my phone could remember where the car was. GPS fails underground for reasons no map vendor can patch: L-band microwave signals attenuate badly in reinforced concrete, and the reflections that do arrive have travelled longer paths than the straight line, so multipath biases pseudorange estimates by tens of meters. The naive software response is to show the blue dot anyway, maybe smooth it a little. That is lying to the user with extra steps.
The physics-informed response is pedestrian dead reckoning. Steps come from accelerometer peaks. For heading, integrate the gyro and correct it with the magnetometer whenever the field looks clean. The barometer supplies floor hints, and a Kalman filter fuses everything into a position that carries its own uncertainty instead of false precision. The full pipeline is in the Kalman post, and the step detector has its own writeup. I would not have written any of it without knowing why double integration of accelerometer data drifts meters per second, or why compass readings become worthless near steel columns. CS alone would have produced a prettier map tile. Physics alone would never have made it through App Store review.
The arithmetic of drift
The drift claim deserves numbers, because that one fact shapes the entire Wheria architecture. A phone accelerometer carries a residual bias b on the order of 0.03 m/s² even after calibration. Integrate twice and position error grows as x_err(t) = ½·b·t². At t = 60 s that is 0.5 · 0.03 · 3600 = 54 m. Walk for one minute and the naive dot sits two garage aisles away from you. Step counting sidesteps the whole mechanism: a step is a detected event, stride length is bounded by human biomechanics, and error grows linearly with distance walked at roughly 2%. The quadratic term never gets a chance to exist.
The barometer earns its seat by the same logic. Near sea level, pressure falls about 12 Pa per metre of altitude, from Δh = ΔP/(ρg) with ρ ≈ 1.2 kg/m³ and g = 9.81 m/s². The garages we measure have floors 3.2 m apart, so one floor is a step of roughly 38 Pa. Phone barometer noise sits at 0.3–1 Pa RMS (bench note: 4 phones on a shelf for 48 h, logged at 1 Hz, 10-sample median filter). A floor change therefore stands about 40 σ clear of the noise even on our worst unit. Weather is the real enemy; a front can move absolute pressure by more than a floor's worth in an hour, so the detector only looks at short-window differences and re-anchors after every confirmed change.
// floor hint from barometer, evaluated at 1 Hz
p = median(last 10 samples) // kills the 0.3–1 Pa RMS noise
dp = p - p_ref // Pa, relative to last confirmed floor
dh = dp / 12.0 // metres, ~12 Pa per metre
if abs(dh) > 2.4 { // 75% of a 3.2 m floor
floors = round(dh / 3.2)
emitFloorHint(floors)
p_ref = p // re-anchor; weather drift dies here
}
The full derivation, hysteresis and all, is in the barometer math post.
Sonarish: when the machine hums differently
Sonarish started because an air conditioner began humming at 127 Hz after three years of service — a harmonic of mains frequency and motor pole count. Rotating machinery has a vocabulary: shaft frequency at f_shaft = RPM/60, bearing defect sidebands spaced around it, broadband noise from loose mounts. The tempting shortcut is a cloud-trained AI classifier. What shipped instead is an on-device FFT with A-weighted LAeq integration, a baseline snapshot taken while the machine is healthy, and a diff view showing which frequency bins rose more than 6 dB since last month.
We deliberately do not auto-diagnose bearing failures. A failing bearing's spectrum depends on ball count, race diameters and shaft speed; without the nameplate the physics is ambiguous, so the app shows the spectrum diff and you call a technician with data instead of vibes. Every choice upstream of that screen is physics too. Nyquist's theorem, f_s ≥ 2·f_max, sat behind picking the 48 kHz sample rate. A-weighting (the reason a 100 Hz hum reads about 19 dB lower than it measures) sat behind making readings comparable to a municipal noise ordinance and to the NIOSH 8-hour limit of 85 dB(A). Get either wrong and the app becomes confidently misleading. Bench note from our own log: one AC unit, one 60 s clip every Monday for 14 months from the same tripod position; the 127 Hz bin ended 8 dB above its healthy baseline. The baseline post and the A-weighting post go deeper on both halves.
Estua and Phyzix: perception and pedagogy
Estua exists because the human auditory system detects periodicity in looped recordings within minutes — a psychoacoustics problem, not a compression problem. The fix is real-time synthesis: 1/f noise shaped by uncorrelated LFO modulation, generated fresh forever, so there is no loop point for the ear to find. That synthesis runs on the audio thread under hard real-time rules (no malloc, no locks, every 48 kHz buffer delivered on deadline), documented in the audio thread post. Miss one deadline and the person you are easing into sleep hears a click. The other end of the pipeline is delicate too: Sonarish's breathing sonar resolves chest displacement of 118 µm, which is the scale of signal in play when the goal is keeping someone asleep.
Phyzix approaches from the opposite direction. Students treat phones as consumption devices, while the same hardware carries an accelerometer, gyroscope, magnetometer, barometer and microphone that a 1990s university lab would have envied. Phyzix draws live sensor graphs with SI units, exports CSV, and places each simulation's equation beside its animation so the link between formula and motion stays visible on one screen. Neither app required a physics degree to conceive. Both required physics to implement correctly — psychoacoustic masking for one, sampling and unit discipline for the other. The pocket lab post has the full tour.
What each discipline alone would miss
Computer science without physics produces apps that compile, pass review and confidently display wrong answers. You integrate accelerometer data because the API returns acceleration values and integration is what programmers do with time-series data. Then you wonder why the parking dot teleports. Physics without computer science produces correct equations in notebooks that never survive Android foreground service rules, iOS background location limits, Compose recomposition jank, or ktuyen's test matrix — the one that caught compass drift on iPhone 15 in a steel-frame garage while the Pixel 8 sailed through.
uranashel is three people precisely because the skill set has to span both. I write the sensor pipelines and the DSP. atuan makes the backend and release infrastructure real. ktuyen makes the quality gate real, in Vietnamese and English, on real devices in real garages. Stashio is the honest outlier in the catalogue: no physics anywhere, just the 2,400 unsorted links in my Apple Notes and the discovery that after three months of daily use, 94% of retrieval attempts finish in under 10 s. The Stashio post explains why a sensor studio ships a save-for-later app. The answer is the same problem-first sequence with the physics swapped out.
You do not need two degrees
You need curiosity about the sensor underneath the API documentation, and honesty when the math says your UX is lying. A degree is one path to that honesty; garage logs are another. Garage logs at Landmark 81 taught me more about multipath than any textbook chapter did. Listening to an AC unit change pitch over three years taught me more about bearing degradation than any lecture. The Lab page on this site exists so you can reproduce some of those observations with the phone you already own. For the studio context, start with the welcome post and follow the links wherever your curiosity points: magnetometer ellipsoids, pink noise spectra, Kalman covariance traces.
Mình học CNTT và vật lý trên hai track tách biệt. Bên CNTT dạy cách ship software trước khi hết học kỳ. Bên vật lý dạy con số trong file CSV cảm biến thật ra nghĩa là gì. uranashel nằm đúng chỗ giao nhau đó. Gần như mọi feature chạy ổn trên năm app đều đi qua một trình tự: gặp bài toán ngoài đời, vật lý giải thích vì sao cách naive fail, rồi mới viết code tôn trọng lời giải thích ấy thay vì chống lại nó. Chưa ai trong studio ngồi xuống bảo "AI đang hot, bọc cái API là xong". Sản phẩm nào cũng bắt đầu từ một cái bực mình vật lý xảy ra với chính một trong ba đứa.
Năm app nhìn như năm ý tưởng rời (chỉ đường bãi xe, audio ngủ, phòng lab bỏ túi, bộ đo âm học, công cụ lưu link), nhưng bốn trong số đó là một ý tưởng khoác cảm biến khác nhau. Tìm đại lượng vật lý mà điện thoại đo được thật, tính noise floor, rồi từ chối hiển thị bất cứ thứ gì noise floor không đỡ nổi. Phần còn lại của bài đi qua từng app, kèm con số đứng sau mỗi quyết định.
Wheria: khi bản đồ nói dối
Chuyện gốc nằm trong bài riêng. Bản ngắn: một tấm ảnh chụp cột E9 tầng B2, vì chẳng thứ gì trên điện thoại nhớ nổi xe đỗ đâu. GPS chết dưới hầm và không hãng bản đồ nào vá được. Sóng vi ba băng L suy hao mạnh trong bê tông cốt thép. Tia phản xạ tới được máy thì đã đi đường vòng, nên multipath làm pseudorange lệch hàng chục mét. Cách xử lý naive là cứ hiện chấm xanh rồi smooth cho mượt. Nói dối user, kèm thêm vài bước phụ.
Cách xử lý có vật lý là pedestrian dead reckoning. Bước chân lấy từ peak gia tốc kế. Heading thì tích phân gyro, chỉnh bằng từ kế mỗi khi từ trường sạch. Áp kế gợi ý tầng, còn Kalman filter fuse tất cả thành một vị trí luôn kèm uncertainty thay vì độ chính xác giả. Pipeline đầy đủ nằm ở bài Kalman, còn bộ đếm bước có bài riêng. Không biết vì sao tích phân hai lần gia tốc trôi vài mét mỗi giây, hay vì sao la bàn vô dụng cạnh cột thép, thì mình đã không viết nổi pipeline này. Chỉ có CNTT thì ra được tile bản đồ đẹp hơn. Chỉ có vật lý thì không qua nổi App Store review.
Số học của drift
Khẳng định về drift cần con số, vì chính nó định hình toàn bộ kiến trúc Wheria. Gia tốc kế điện thoại mang bias dư b cỡ 0,03 m/s² kể cả sau calibration. Tích phân hai lần thì sai số vị trí tăng theo x_err(t) = ½·b·t². Tại t = 60 s: 0,5 · 0,03 · 3600 = 54 m. Đi bộ một phút, chấm naive đã nhảy sang dãy xe khác. Đếm bước né được cả cơ chế: mỗi bước là một event, độ dài sải chân bị cơ sinh học chặn trên chặn dưới, sai số chỉ tăng tuyến tính theo quãng đường cỡ 2%. Số hạng bậc hai không có cửa xuất hiện.
Áp kế ngồi cùng bàn nhờ đúng logic đó. Gần mực nước biển, áp suất giảm khoảng 12 Pa mỗi mét độ cao, theo Δh = ΔP/(ρg) với ρ ≈ 1,2 kg/m³ và g = 9,81 m/s². Hầm xe bọn mình đo có các tầng cách nhau 3,2 m, tức mỗi tầng là một bậc ~38 Pa. Noise áp kế điện thoại cỡ 0,3–1 Pa RMS (ghi chú bench: 4 máy nằm im trên kệ 48 giờ, log 1 Hz, lọc median 10 sample). Đổi tầng vì thế nổi cao chừng 40 σ trên nền noise, kể cả ở máy tệ nhất. Kẻ thù thật là thời tiết: một đợt front có thể kéo áp suất tuyệt đối đi quá một tầng chỉ trong một giờ. Nên detector chỉ nhìn hiệu số trong cửa sổ ngắn rồi neo lại sau mỗi lần xác nhận.
// floor hint from barometer, evaluated at 1 Hz
p = median(last 10 samples) // kills the 0.3–1 Pa RMS noise
dp = p - p_ref // Pa, relative to last confirmed floor
dh = dp / 12.0 // metres, ~12 Pa per metre
if abs(dh) > 2.4 { // 75% of a 3.2 m floor
floors = round(dh / 3.2)
emitFloorHint(floors)
p_ref = p // re-anchor; weather drift dies here
}
Dẫn xuất đầy đủ, kèm cả hysteresis, nằm ở bài toán áp kế.
Sonarish: khi máy ù khác đi
Sonarish sinh ra từ cái điều hòa bắt đầu ù ở 127 Hz sau ba năm chạy — hài của tần số lưới điện nhân số cực motor. Máy quay có từ vựng riêng: tần số trục f_shaft = RPM/60, sideband lỗi bạc đạn kẹp quanh nó, noise broadband do chân máy lỏng. Cách naive: đem audio lên cloud train classifier. Cách có vật lý: FFT on-device kèm tích phân LAeq theo A-weighting, chụp baseline lúc máy còn khỏe và màn hình diff chỉ ra bin tần số nào tăng quá 6 dB so với tháng trước.
Bọn mình cố tình không auto chẩn đoán hỏng bạc đạn. Phổ của bạc đạn hỏng phụ thuộc số bi, đường kính rãnh và tốc độ trục; thiếu nameplate thì vật lý mơ hồ. App hiện diff phổ, bạn gọi thợ với số liệu trong tay thay vì cảm giác. Mọi lựa chọn phía trên màn hình đó cũng toàn vật lý. Định lý Nyquist, f_s ≥ 2·f_max, đứng sau con số sample rate 48 kHz. A-weighting (lý do tiếng ù 100 Hz đọc thấp hơn giá trị thực đo khoảng 19 dB) đứng sau việc so được reading với quy chuẩn ồn đô thị và với định mức 8 giờ 85 dB(A) của NIOSH. Sai một trong hai là app tự tin dẫn người dùng đi lạc. Ghi chú bench từ log của studio: một máy lạnh, mỗi thứ Hai thu 60 s suốt 14 tháng, cùng vị trí tripod; bin 127 Hz kết thúc cao hơn baseline khỏe 8 dB. Đọc sâu hơn ở bài baseline và bài A-weighting.
Estua và Phyzix: tri giác và sư phạm
Estua tồn tại vì tai người bắt được tính tuần hoàn trong recording loop chỉ sau vài phút — bài toán psychoacoustics chứ không phải compression. Cách sửa là synthesis real-time: nhiễu 1/f với LFO modulation không tương quan, sinh mới liên tục, nên không có điểm loop nào cho tai bám vào. Phần synthesis chạy trên audio thread theo luật hard real-time (không malloc, không lock, buffer 48 kHz nào cũng phải giao đúng deadline), mô tả ở bài audio thread. Trễ một buffer là người sắp ngủ nghe một cái click. Đầu kia của pipeline cũng mong manh: sonar đo nhịp thở của Sonarish phân giải được dịch chuyển lồng ngực 118 µm — đó là cỡ tín hiệu phải làm việc quanh khi mục tiêu là giữ người ta ngủ tiếp.
Phyzix đi từ hướng ngược lại. Học sinh coi điện thoại là máy tiêu thụ nội dung, trong khi phần cứng đó mang gia tốc kế, gyro, từ kế, áp kế và micro mà phòng lab vật lý thập niên 1990 phải ghen tị. Phyzix vẽ graph cảm biến live với đơn vị SI, export CSV và đặt phương trình của mỗi mô phỏng ngay cạnh animation, để công thức với chuyển động nằm chung một màn hình. Nghĩ ra hai app này không cần bằng vật lý. Làm đúng thì cần: masking curve psychoacoustic cho app này, kỷ luật sampling và đơn vị cho app kia. Chi tiết ở bài pocket lab.
Thiếu một trong hai ngành thì hụt gì
CNTT không vật lý cho ra app compile được, pass review, rồi tự tin hiện đáp án sai. Bạn tích phân data gia tốc vì API trả về gia tốc, còn tích phân là thứ programmer hay làm với time-series. Rồi ngồi thắc mắc vì sao chấm đỗ xe teleport. Vật lý không CNTT cho ra phương trình đúng nằm trong sổ, không sống nổi qua luật foreground service của Android, giới hạn location chạy nền của iOS, jank recomposition bên Compose, hay ma trận test của ktuyen — cái ma trận từng bắt được la bàn trôi trên iPhone 15 trong hầm khung thép mà Pixel 8 lại chẳng sao.
uranashel là ba người đúng vì skill set phải phủ cả hai phía. Mình viết pipeline cảm biến và DSP. atuan lo backend và hạ tầng release. ktuyen giữ cổng chất lượng, bằng tiếng Việt lẫn tiếng Anh, trên máy thật trong hầm thật. Stashio là đứa lạc loài trung thực trong danh mục: không dính tí vật lý nào, chỉ có 2.400 link chưa sort trong Apple Notes của mình và con số 94% lần tìm lại xong dưới 10 giây sau ba tháng dùng hằng ngày. Bài Stashio giải thích vì sao một studio cảm biến lại ship app lưu link. Câu trả lời vẫn là trình tự problem-first, chỉ thay phần vật lý ra.
Không cần hai tấm bằng
Cần tò mò về con cảm biến nằm dưới trang tài liệu API và thẳng thắn khi phép toán bảo UX đang nói dối. Bằng cấp là một con đường; log hầm xe là con đường khác. Log hầm ở Landmark 81 dạy mình về multipath nhiều hơn mọi chương giáo trình. Nghe điều hòa đổi pitch qua ba năm dạy về suy thoái bạc đạn nhiều hơn mọi bài giảng. Trang Lab trên site này tồn tại để bạn tự lặp lại vài quan sát đó bằng chính chiếc điện thoại đang cầm. Muốn hiểu bối cảnh studio thì bắt đầu từ bài chào sân rồi lần theo link tùy hứng: ellipsoid từ kế, phổ pink noise, hay trace hiệp phương sai Kalman.